We are using REST endpoint as datasource for jasper reports, but everywhere using REST point its mandatory to create an adapter with rest url and header info and use that as datasource.
We don't want to use adapter, instead we want to use directly the constructor
public JsonDataSource(String location, String selectExpression) throws JRException
as a dataset expression so we formed expression as follow.
new net.sf.jasperreports.engine.data.JsonDataSource("http://vagrant.ptcnet.ptc.com:2280/Windchill/trustedAuth/servlet/odata/D...","value")
However this particular endpoint expects some header information from requestor ("Accept", "application/json") else it throws bad exception as error
Is there any way we can pass header info here?
You need to use the constructor where you pass a InputStream
public JsonDataSource(java.io.InputStream jsonStream,java.lang.String selectExpression)
The easiest way to provide the input stream is probably to create a method within your java project that execute the request and returns the result in for example a ByteArrayInputStream
If you need to do it directly within the report (jrxml) you need to do it in 1 expression (jrxml do not support multi-line code). In this case you could the apache HttpClients that already is included as dependency of the jasper report project.
It could be something like this
new net.sf.jasperreports.engine.data.JsonDataSource(
org.apache.http.impl.client.HttpClients.createDefault().execute(
org.apache.http.client.methods.RequestBuilder.
get().
setUri("http://vagrant.ptcnet.ptc.com:2280/Windchill/trustedAuth/servlet/odata/D...").
setHeader("Accept", "application/json").
build()
)
.getEntity()
.getContent()
,""
)
The getContent() will return the InputStream and jasper reports will close this stream when it is done. However both the client and the execute response are theoretically Closable which means that normally you should call close() to free up resource, hence I'm not sure that it is enough to close only the InputStream, you may risk leaking of resource. This is why I initially suggested to create a method within the/a java project where this can be handled appropriately.
Related
I am trying to serve a static html file let's call it index.html for all dynamic urls like /tachyon/someId. This someId is generated dynamically. I have tried multiple ways to do this but all failed. This is what all I have tried.
Tried adding controllers.Assets.at(path="/public", file="index.html") for GET url /tachyon/*someId. This failed saying missing parameter someId.
Tried rendering index.html through render. This also failed since index.html is not a scala.html template.
Tried returning routes.Assets.at("index.html") through controller. This also failed since I want to return Result but the return type for the method is different.
Tried returning ok(routes.Assets.at("index.html") through controller. This also failed saying not a valid Call for ok.
It would be better if there is a way to do this through controller and returning Result from method in task helper class to task since I am returning Promise<Result> from method in task class.
I think you can use Twirl to generate the page. Since you want a static html, you can ignore the parameter in the body.
so in routes, add:
GET /tachyon/*someId somecontroller.index(someId)
in the controller's index function, you can return
Ok(views.html.somepage(someId))
And you create a somepage.scala.html Twirl function in views folder, but do not use someId in the body.
I got it working. Not sure if it is the correct solution or not. I rendered the index.html by converting it to a byte array and then using ok to render using ByteArrayInputStream. Something like this.
File file = Play.getFile("path to the file", Play.current());
byte[] byteArray = IOUtils.toByteArray(new FileInputStream(file));
return ok(new ByteArrayInputStream(byteArray)).as("text/html");
Let me know if there is any better way to do this without using scala templating.
Thanks
I asked something like this previously, but upon re-reading my original post, it was not easy to understand what I was really asking. I have the following situation. We have (or at least I'm trying to get working) a custom file upload procedure that will take in the file, a set number of 'known' metadata values (and they will always be there), as well as potentially an unknown number of additional metadata values. The service that exists currently uses the Jersey framework (1.16)
I currently have both client and server code that handles dealing with the file upload portion and the known metadata values (server code below)
#POST
#Path("asset/{obfuscatedValue0}/")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public UUID uploadBlob(#PathParam("obfuscatedValue0") Integer obfuscatedValue0,
#FormDataParam("obfuscatedValue1") String obfuscatedValue1,
#FormDataParam("obfuscatedValue2") String obfuscatedValue2,
#FormDataParam("obfuscatedValue3") String obfuscatedValue3,
#FormDataParam("obfuscatedValue4") String obfuscatedValue4,
#FormDataParam("obfuscatedValue5") String obfuscatedValue5,
#FormDataParam("file") InputStream uploadedInputStream) {
.....
}
...and excerpt of client code:
Builder requestBuilder = _storageService
.path("asset")
.path(obfuscatedValue0.toString())
.type(MediaType.MULTIPART_FORM_DATA)
.accept(MediaType.APPLICATION_JSON);
FormDataMultiPart part = new FormDataMultiPart()
.field("file", is, MediaType.TEXT_PLAIN_TYPE) // 'is' is an inputstream from earlier in code.
.field("obfuscatedValue1", obfuscatedValue1)
.field("obfuscatedValue2", obfuscatedValue2)
.field("obfuscatedValue3", obfuscatedValue3)
.field("obfuscatedValue4", obfuscatedValue4)
.field("obfuscatedValue5", obfuscatedValue5);
storedAsset = requestBuilder.post(UUID.class, part);
However, I need to pass a map of additional parameters that will have an unknown number of values/names. From what I've seen, there is no easy way to do this using the FormDataParam annotation like my previous example.
Based upon various internet searches related to Jersey file uploads, I've attempted to convert it to use MultivaluedMap with the content type set to "application/x-www-form-urlencoded" so it resembles this:
#POST
#Path("asset/{value}/")
#Consumes("application/x-www-form-urlencoded")
public UUID uploadBlob(#PathParam(value), MultivaluedMap<String,String> formParams) {
....
}
It's my understanding that MultivaluedMap is intended to obtain a general map of form parameters (and as such, cannot play nicely together in the same method bearing #FormDataParam annotations.) If I can pass all this information from the Client inside some sort of map, I think I can figure out how to handle parsing the map to grab and 'doMagic()' on the data to get what I want done; I don't think I'll have a problem there.
What I AM fairly confused about is how to format the request client-side code when using this second method within the jersey framework. Can anyone provide some guidance for the situation, or some suggestions on how to proceed? I'm considering trying the solution proposed here and developing a custom xml adapter to deal with this situation, and sending xml instead of multipart-form-data but I'm still confused how this would interact with the InputStream value that will need to be passed. It appears the examples with MultivaluedMap that I've seen only deal with String data.
I have a REST service to upload images and this is the main code in charge of the registration in mongodb:
public String writeFiles(InputStream inputStream, String fileName, String contentType) throws IOException {
// save the file
GridFS gridFS = new GridFS(getDB(), Collections.PICTURES_FILES.name());
GridFSInputFile gridFSInputFile = gridFS.createFile(inputStream, fileName);
gridFSInputFile.setContentType(contentType);
gridFSInputFile.setMetaData(new BasicDBObject(ORIGINAL_PICT_COL, true));
gridFSInputFile.save();
return gridFSInputFile.getId();
}
The service then return the file ID to the client so that this one can ask for and display the uploaded image.
The problem is for very large images: sometime while requesting an image by its ID right after the upload gives a HTTP 404 error (due to unknown image ID on server side, this is a correct behavior).
I suppose it happens because registration time on the server side is greater than time used to get the ID back and request the new image on the client side - i.e the '.save()' operation is async, right ?
My question: How to be sure that the save operation has been completed before returning the ID in the given code ?
Or how to obtain a result object as for .insert operation ?
Does a
gridFSInputFile.validate();
would be enought ?
Or
getDB().getLastError()
?
I cannot reproduce easily this "bug" so i ask the question in case someone with experience already know how to solve this. Thanks in advance for your help.
If you are using a recent version of the Java driver (2.10 or later), try creating an instance of MongoClient instead of an instance of Mongo. The default write concern is WriteConcern.ACKNOWLEDGED for instances of MongoClient, so the save method will not complete until the write operation has completed.
Otherwise, in your getDB method (not shown), call the method DB.setWriteConcern(WriteConcern.SAFE) to change the default write concern.
The other possibility is that you are reading from a secondary member of your replica set. The default is to read from the primary, but if you are overriding that, then your reads will be eventually consistent, and you could see this problem in that case as well.
I've written the method below that is called by my doPost method to parse multipart/form-data given in the request. It all works great, I just don't really understand what is going on. If anyone could break down the three lines in my try I would really appreciate it. I've read through the Apache Commons File Upload documentation but it's just not making sense to me and I hate writing code that I do not fully understand. In particular, I would like to know what is actually happening when the factory and upload objects are created.
public static List<FileItem> parseFormRequest(HttpServletRequest request)
{
List<FileItem> items = null;
try
{
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
items = upload.parseRequest(request);
}
catch (FileUploadException error)
{
System.out.println("UploadFileServlet - Error With File Parsing - " + error.getMessage());
}
return items;
}
BONUS HELP!
I also get a warning under upload.parseRequest(request) that says Type safety: The expression of type List needs unchecked conversion to conform to List<FileItem>. If anyone could explain this too that would really help me get what I've done. Thanks
The factory is just a helper, i'll explain later. The main work is done by the ServletFileUpload.
ServletFileUpload will scan through all the uploaded files (using an Iterator which parses the MIME stuff and knows how to deal with the boundary markers, content length etc.).
For each uploaded file, the parse method asks the FileItemFactory to create a local representation for the uploaded file and then copies the contents from memory (e.g. from the HTTP POST request, which is held in memory) to the actual file on disk.
Simplified, the procedure is as follows:
Get next uploaded file
Ask factory for a local file ("FileItem")
Copy content from in-memory (from HttpServletRequest) to local file (a java.io.File in case of a DiskFileItemFactory)
Loop until end of HTTP request is reached
See the sources of the following classes for details
org.apache.commons.fileupload.FileUploadBase.parseRequest(RequestContext)
org.apache.commons.fileupload.FileUploadBase.FileItemIteratorImpl.FileItemStreamImpl
This design allows to switch to another storage facility for files, for example:
You could replace the DiskFileItemFactory with your own DatabaseFileItemFactory, so the uploaded files get stored in a database instead of a local file on the server. The code changes would only affect a single line and the rest of commons-fileupload can be use as-is (e.g. the parsing of the HTTP request, the iterating over the uploaded
files etc.)
For the second question: commons-fileupload seems to be Java 1.4 compatible, so the return type of parseRequest()
is actually an un-typed java.util.List - it's missing the declaration that the list only contains FileItem objects (e.g. java.util.List<FileItem>).
Since you declared your variable items to be of type List<FileItem>, the Java compiler warns you about this mismatch.
In this case, you did it correctly and you may ignore the warning by adding the following:
#SuppressWarnings( "unchecked" )
public static List<FileItem> parseFormRequest(HttpServletRequest request)
{
...
You need to spend some time in the documentation.
From what I can gather, the ServletFileUpload instance uses the factory you supplied to actually create the file instances that are in the request. You used a factory that writes the files to disk; there are other options though (e.g. memory). By specifying the factory, you are specifying the types of Files that are created.
When you call
upload.parseRequest(request)
the ServletFileUpload instance goes thru the request data and actually creates the files it finds, using the factory, and returns them to you in a list.
If you look at the parseRequest documentation you will notice that that method only returns a List. In your code, you are assigning that returned list to a List<FileItem>. That requires a cast, which is why you get the compiler warning.
I need the java code that is used to invoke this function...
I need the Servlet code that is used to add parameters to the HttpServletRequest
I need help. In my current development one of the requirements says:
The server will return 200-OK as a response(httpresponse).
If the panelist is verified then as a result, the server must also
return the panelist id of this panelist.
The server will place the panelist id inside the body of the 200-OK
response in the following way:
<tdcp>
<cmd>
<ack cmd=”Init”>
<panelistid>3849303</panelistid>
</ack>
</cmd>
Now I am able to put the httpresponse as
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
And I can put
String responseToClient= "<tdcp><cmd><ack cmd=”Init”><panelistid>3849303</panelistid></ack></cmd></tdcp>";
Now what does putting the above xml inside the body of 200-OK response mean and how can it be achieved?
You can write the XML directly to the response as follows:
This example uses a ServletResponse.getWriter(), which is a PrintWriter to write a String to the response.
String responseToClient= "<tdcp><cmd><ack cmd=”Init”><panelistid>3849303</panelistid></ack></cmd></tdcp>";
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
httpServletResponse.getWriter().write(responseToClient);
httpServletResponse.getWriter().flush();
You simply need to get the output stream (or output writer) of the servlet response, and write to that. See ServletResponse.getOutputStream() and ServletResponse.getWriter() for more details.
(Or simply read any servlet tutorial - without the ability to include data in response bodies, servlets would be pretty useless :)
If that's meant to be XML, Word has already spoiled things for you by changing the attribute quote symbol to ” instead of ".
It is worth having a look at JAXP if you want to generate XML using Java. Writing strings with < etc. in them won't scale and you'll run into problems with encodings of non-ASCII characters.