Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Thursday, March 29, 2018

Making Http Post request with MultipartForm data

My requirement was to upload a file and pass some JSON in an API in Java. So I googled and found some code as below:

HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(UPLOAD_URI);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.setCharset(Charset.defaultCharset());
String text = "{\"name\":\"manish\",\"occupation\":\"engineer\"}";
builder.addTextBody("info", text);
builder.addPart("doc", new FileBody(file));
httpPost.addHeader("content-type", MediaType.MULTIPART_FORM_DATA);
httpPost .setEntity(builder.build()); httpclient.execute(httpPost);

When I used this code then I got 400 error with reason as "Bad Request" and empty response body. The target server was also in my control and was running Jersey framework on Tomcat. I checked the logs and found just error as 400. Absolutely no message or other info on the reason of the error.
When I ran the API from CURL then it worked with no issues. Thats makes me believe that the issue is in code above.

After a lot of hit and trial I found that the missing piece is the "boundary". Boundary was not added into the "content-type" header. I changed the code above to:

HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(UPLOAD_URI);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.setCharset(Charset.defaultCharset());
String text = "{\"name\":\"maniildersh\",\"occupation\":\"engineer\"}";
builder.setBoundary("------------------------f8ee5b62c27a1db3");
builder.addTextBody("info", text);
builder.addPart("doc", new FileBody(file));
httpPost.addHeader("content-type", MediaType.MULTIPART_FORM_DATA+ "; boundary=------------------------f8ee5b62c27a1db3");
httpPost .setEntity(builder.build()); httpclient.execute(httpPost);

Thats it !  Code started working. Later I changed the boundary to be generated dynamically instead of being static.

Sunday, March 25, 2018

Learnings in handling input and output streams in Java

I learned it hard way that working with streams in Java can be tricky, specially when you are writing to an output stream. It happened to me a couple of times that I found that although I am writing to stream but still I lost some data. That happened because I forgot to close the stream. And sometimes I closed a stream which I should not have. Below I am providing some points that I have learnt while working with streams:

Flush the streams frequently: Main benefit of working with streams is you process the data as you receive from input stream and push the processed data into the output stream. So, you must flush your data into the output stream as you process. This ensures that the listener on the other end of the output stream gets the data continuously. And also make sure you flush the data when the processing is done to ensure even the last bits are sent to the output stream.

Close the stream only if you open it: It is a rule of thumb that you close any stream (input or output) only if you have open it. Simple reason is, if the caller method has opened the stream and passed it to you( in your method) then it is possible that caller can use it after your method call. Example is, input and output stream in a servlet is opened by the application container and then passed to the servlet, you don't have to close these streams. Container closes these streams when the http request is completed.
This includes the stream that you have created as wrapper on another stream.




Tuesday, February 6, 2018

Execute different methods based on accept header and set priority when no accept header provided

I had a REST API which was accepting a file upload and in response generating another file. This was working fine without any issue with below code:
@POST 
@Path("/convert")
@Produces("application/octet-stream")
@Consumes(MediaType.MULTIPART_FORM_DATA)
 But, later I had to add a requirement where in certain cases the response in NOT stream but a JSON object. I wanted to keep the API same but behave differently only for limited number of cases. After looking into some Jersey docs and some testing below is what implemented
@POST
@Path("/convert")
@Produces("application/octet-stream;qs=1")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@POST
@Path("/convert")
@Produces("application/json;qs=.5")
@Consumes(MediaType.MULTIPART_FORM_DATA) 
Note that both of the APIs have signature, and only difference is in response type. With these signatures client when passes "accept" header as  "application/octet-stream" then first method is called. And when "accept" header is "application/json" then second method is called.
In addition to this, I also used the "quality" (note qs), this is set to 1 for first method and 0.5 for the second method. Because of this my code change was backward compatible. Which means, when no accept header is provided. In that case the first method is called because qs=1.

Tuesday, October 2, 2012

Override the properties in wro.properties

Sometimes there is a need to override some properties on local environment to facilitate faster development. If you have implemented the wro4j using spring then it is very easy to override any property in wro.properties file.

Just replace the  wroProperties bean in the applicationContext.xml with below code and spring will look for the property file from other locations.
    <bean id="wroProperties"
       
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
       
<property name="ignoreResourceNotFound" value="true"></property>
       
<property name="locations">
           
<list>
               
<value>file:${catalina.home}/conf/wro.properties</value>
               
<value>file:${catalina.home}/wro.properties</value>
               
<value>file:${user.home}/wro.properties</value>
           
</list>
       
</property>
   
</bean>

Property "<property name="ignoreResourceNotFound" value="true"></property>" ensures that bean creation will not fail even if the wro.properties file is missing. And property file at location mentioned latter overrides the property file before it. Means, if there is a property file at user home then it will override all the property file at other locations.

In my development setup I have placed a wro.properties i user home and set the managerfactoryclassname property to my custom class which disables the minimization. 
(To disable minimization check my blog at: http://msquare-tech.blogspot.in/2012/10/disable-minimizing-resources-when-using.html)

~Manish


Disable minimizing the resources when using wro4j


After implementing the wro4j in my application, the performance of the pages improved but there was one problem. Now because all the resources are minified, it become difficult to debug the Javascript issues from Firebug. 
I resolved the above issue by following below steps:

1. Extending the "DefaultGroupExtractor" class and overriding only one method :
/*
* Never minimize the resources
*/ 

@Override
  public boolean isMinimized(HttpServletRequest request) {
    return false;
  }
2.  Extending the "BaseWroManagerFactory" class and setting new group extractor as created in step 1:
/*
* Return the custom extractor as created above.
*/
  @Override
  protected GroupExtractor newGroupExtractor() {
    return new CustomDefaultGroupExtractor(); // extractor created in step 1
  }
3. In the wro.properties file add the manager factory class as below:
managerFactoryClassName=com.vmops.web.optimizer.CustomWroManagerFactory

4. Restart the server. Now you will see no resources are minimized.

~Manish

Wednesday, June 27, 2012

Implement wro4j in five steps.


WRO4J (Web Resource Optimizer For Java) is an awesome open source resource optimizer. I recently implemented it in my application. So here I am providing steps I followed to implement it and issues I faced.

Tools used: Maven

1. Add maven dependency for the WRO4J in you pom.xml as follows:

2. Add a filter in web.xml as follows:

3. Under WEB-INF create a folder wro.xml with content as follows:

This will create a js and css at runtime by combining all js and css under the group all and return and all.js and all.css respectively.

4. Under same folder WEB-INF create another file wro.properties with content as follows:
debug=true
disableCache=true
gzipResources=true
jmxEnabled=false
preProcessors=semicolonAppender
postProcessors=jsMin,cssCompressor,cssMin

5. Open any new existing JSP page and add a js call as follows:
and for css add the call as:
Thats it!! Now start your server and open your page.

I faced one issue while implementing wro4j and that is due to a dependency of wro4j jars. This version of wro4j requires commons-io.2.1 but because some other dependency older version of common-io got loaded. I did not get any error but was getting empty results when calling /wro/all.js and /wro/all.css. So, be careful.

~Manish