i'm using httpclient 4. When i use
new DecompressingHttpClient(client).execute(method)
the client acccepts gzip and decompresses if the server sends gzip.
But how can i archieve that the client sends it's data gzipped?
HttpClient 4.3 APIs:
HttpEntity entity = EntityBuilder.create()
.setText("some text")
.setContentType(ContentType.TEXT_PLAIN)
.gzipCompress()
.build();
HttpClient 4.2 APIs:
HttpEntity entity = new GzipCompressingEntity(
new StringEntity("some text", ContentType.TEXT_PLAIN));
GzipCompressingEntity implementation:
public class GzipCompressingEntity extends HttpEntityWrapper {
private static final String GZIP_CODEC = "gzip";
public GzipCompressingEntity(final HttpEntity entity) {
super(entity);
}
#Override
public Header getContentEncoding() {
return new BasicHeader(HTTP.CONTENT_ENCODING, GZIP_CODEC);
}
#Override
public long getContentLength() {
return -1;
}
#Override
public boolean isChunked() {
// force content chunking
return true;
}
#Override
public InputStream getContent() throws IOException {
throw new UnsupportedOperationException();
}
#Override
public void writeTo(final OutputStream outstream) throws IOException {
final GZIPOutputStream gzip = new GZIPOutputStream(outstream);
try {
wrappedEntity.writeTo(gzip);
} finally {
gzip.close();
}
}
}
Related
I have the requirement to display a document in excel format in my spring mvc application. I have added excelViewResolver to my AppConfig but unable to process the excel file. Please help.
Following is the AppConfig class
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.testapps.myapps")
public class AppConfig extends WebMvcConfigurerAdapter {
private static final String autowire = null;
/*
* Configure ContentNegotiationManager
*/
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true).defaultContentType(
MediaType.TEXT_HTML);
}
/*
* Configure ContentNegotiatingViewResolver
*/
#Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(manager);
// Define all possible view resolvers
List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
resolvers.add(jspViewResolver());
resolvers.add(excelViewResolver());
resolver.setViewResolvers(resolvers);
return resolver;
}
/*
* Configure View resolver to provide XLS output using Apache POI library to
* generate XLS output for an object content
*/
#Bean(name="excelView")
public ViewResolver excelViewResolver() {
System.out.println("inside view resolver for excel");
return new ExcelViewResolver();
}
/*
* Configure View resolver to provide HTML output This is the default format
* in absence of any type suffix.
*/
#Bean
public ViewResolver jspViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean(name = "multipartResolver")
public StandardServletMultipartResolver resolver() {
return new StandardServletMultipartResolver();
}
}
WebAppInitializer.java
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "*.html" };
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(getMultipartConfigElement());
}
private MultipartConfigElement getMultipartConfigElement() {
MultipartConfigElement multipartConfigElement = new MultipartConfigElement( LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
return multipartConfigElement;
}
private static final String LOCATION = "C:/TESTdevelopments/files/"; // Temporary location where files will be stored
private static final long MAX_FILE_SIZE = 5242880; // 5MB : Max file size.
// Beyond that size spring will throw exception.
private static final long MAX_REQUEST_SIZE = 20971520; // 20MB : Total request size containing Multi part.
private static final int FILE_SIZE_THRESHOLD = 0; // Size threshold after which files will be written to disk
}
ExcelBuilder.java
public class ExcelBuilder extends AbstractXlsxView {
private static final DateFormat DATE_FORMAT = DateFormat.getDateInstance(DateFormat.SHORT);
#Override
protected void buildExcelDocument(Map<String, Object> model,
Workbook workbook,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
// change the file name
response.setHeader("Content-Disposition", "attachment; filename=\"my-xlsx-file.xlsx\"");
#SuppressWarnings("unchecked")
List<Course> courses = (List<Course>) model.get("courses");
// create excel xls sheet
Sheet sheet = workbook.createSheet("Spring MVC AbstractXlsxView");
// create header row
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("ID");
header.createCell(1).setCellValue("Name");
header.createCell(2).setCellValue("Date");
// Create data cells
int rowCount = 1;
for (Course course : courses){
Row courseRow = sheet.createRow(rowCount++);
courseRow.createCell(0).setCellValue(course.getId());
courseRow.createCell(1).setCellValue(course.getName());
courseRow.createCell(2).setCellValue(DATE_FORMAT.format(course.getDate()));
}
}
}
ExcelViewResolver.java
public class ExcelViewResolver implements ViewResolver{
#Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
ExcelBuilder view = new ExcelBuilder();
return view;
}
}
and finally controller class mapping...
#RequestMapping(value = "/downloadExcel.html", method = RequestMethod.GET)
public ModelAndView downloadExcel() {
// create some sample data
List<courseRecordParams> reports = courseRegisterService.generateReportsGeneral();
// return a view which will be resolved by an excel view resolver
return new ModelAndView("excelView", "reports", reports);
}
The problem is I am not able to view the excel file. Its generating a file not found error as in JBWEB000124: The requested resource is not available. since it tries to open a nonexisting jsp.
Please help.
Thanks in advance.
Found a solution to this problem.
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.favorPathExtension(true)
.favorParameter(false)
.ignoreAcceptHeader(true)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON);
}
Also, I removed the excelviewresolver which was unnecessary since this is already handled by multipartviewresolver.
After this the excel file was getting generated without any problem.
UPDATE:
I have learned what I am looking to do is to use the Async within Retrofit with multiple queries too. I have updated my code, but I cannot get the async with the queries.
I am using Retrofit to make my data calls to a movie database and need to change the sort order depending on user settings. I am not clear how I could add this functionality to my interface.
sort_by=highest_rating.desc
or
sort_by=popularity.desc
Interface:
public interface MovieDatabaseApiCient {
#GET("/3/discover/movie")
void getData(#Query("api_key") String apiKey, #Query("sort_by") String sortByValue, Callback<MovieDbModel> response);
}
UPDATED API INTERFACE:
public interface MovieDatabaseApiCient {
#GET("/3/discover/movie?sort_by=popularity.desc&api_key=xxxxxxx")
void getMoviesByPopularityDesc(Callback<MovieDbModel> response);
#GET("/3/discover/movie?sort_by=vote_average_desc&api_key=xxxxxxxx")
void getMoviesByVotingDesc(Callback<MovieDbModel> response);
}
UPDATED DATA CALL THAT WORKS:
private void makeDataCall(String sortPreference) {
final RestAdapter restadapter = new RestAdapter.Builder().setEndpoint(ENDPOINT_URL).build();
MovieDatabaseApiCient apiLocation = restadapter.create(MovieDatabaseApiCient.class);
if (sortPreference.equals(this.getString(R.string.sort_order_popularity)) ){
apiLocation.getMoviesByPopularityDesc (new Callback<MovieDbModel>() {
#Override
public void success(MovieDbModel movieModels, Response response) {
movieDbResultsList = movieModels.getResults();
MoviesGridViewAdapter adapter = new MoviesGridViewAdapter(getApplicationContext(), R.layout.movie_gridview_item, movieDbResultsList);
gridView.setAdapter(adapter);
}
#Override
public void failure(RetrofitError error) {
Log.d("ERROR", error.toString());
Toast.makeText(getApplicationContext(), "Error: " + error.toString(), Toast.LENGTH_SHORT).show();
}
});
} else {
apiLocation.getMoviesByVotingDesc( new Callback<MovieDbModel>() {
#Override
public void success(MovieDbModel movieModels, Response response) {
movieDbResultsList = movieModels.getResults();
MoviesGridViewAdapter adapter = new MoviesGridViewAdapter(getApplicationContext(), R.layout.movie_gridview_item, movieDbResultsList);
gridView.setAdapter(adapter);
}
#Override
public void failure(RetrofitError error) {
Log.d("ERROR", error.toString());
Toast.makeText(getApplicationContext(), "Error: " + error.toString(), Toast.LENGTH_SHORT).show();
}
});
}
}
My call for the data:
private void makeDataCall (String apiKey, String sortPreference) {
final RestAdapter restadapter = new RestAdapter.Builder().setEndpoint(ENDPOINT_URL).build();
MovieDatabaseApiCient apiLocation = restadapter.create(MovieDatabaseApiCient.class);
apiLocation.getData(apiKey, sortPreference, new Callback<MovieDbModel>){
#Override
public void success(MovieDbModel movieModels, Response response) {
movieDbResultsList = movieModels.getResults();
MoviesGridViewAdapter adapter = new MoviesGridViewAdapter(getApplicationContext(), R.layout.movie_gridview_item, movieDbResultsList);
gridView.setAdapter(adapter);
}
#Override
public void failure(RetrofitError error) {
Log.d("ERROR", error.toString());
Toast.makeText(getApplicationContext(), "Error: " + error.toString(), Toast.LENGTH_SHORT).show();
}
});
}
I found a way to do Synchronously, but not asynchronously.
From your question and comment, IHMO, you should import retrofit.Callback; instead of import com.squareup.okhttp.Callback;
My code as the following has no compile error:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// creating a RestAdapter using the custom client
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API_URL_BASE)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setClient(new OkClient(mOkHttpClient))
.build();
WebService webService = restAdapter.create(WebService.class);
retrofit.Callback<GetRoleData> callback = new Callback<GetRoleData>() {
#Override
public void success(GetRoleData getRoleData, retrofit.client.Response response) {
}
#Override
public void failure(RetrofitError error) {
}
};
webService.getData("api_key", "sort_by", callback);
}
Interface:
public interface WebService {
#GET("/3/discover/movie")
void getData(#Query("api_key") String apiKey, #Query("sort_by") String sortByValue, Callback<GetRoleData> response);
}
So, please check your code again
I'm using Retrofit and RxJava but can't seem to do what I want.
Here's my declaration of my web service:
Observable<Response> rawRemoteDownload(#Header("Cookie") String token, #Path("programId") int programId);
The problem I have is the webservice is returning a 403 and a json payload with details.
Retrofit calls onError, only passing the Throwable so I can't check the response body.
Here's part of my test code
apiManager.rawRemoteDownloadRequest("token", 1).subscribe(new Observer<Response>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
// this is called and I've lost the response!
}
#Override
public void onNext(Response response) {
}
});
SOLUTION:
Thanks to Gomino, I went with this as a solution:
new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
if (throwable instanceof RetrofitError) {
Response response = ((RetrofitError) throwable).getResponse();
System.out.println(convertToString(response.getBody()));
}
}
where convertToString looks like:
private String convertToString(TypedInput body) {
byte[] bodyBytes = ((TypedByteArray) body).getBytes();
return new String(bodyBytes);
}
Check if the throwable is a RetrofitError:
#Override
public void onError(Throwable e) {
if (e instanceof RetrofitError) {
Response response = ((RetrofitError) e).getResponse();
}
}
I have a simple resource like:
#Path("/")
public class RootResource {
#Context WebConfig wc;
#PostConstruct
public void init() {
assertNotNull(wc);
}
#GET
public void String method() {
return "Hello\n";
}
}
Which I am trying to use with JerseyTest (2.x, not 1.x) and the GrizzlyTestContainerFactory.
I can't work out what I need to do in terms of config to get the WebConfig object injected.
I solved this issue by creating a subclass of GrizzlyTestContainerFactory and explicitly loading the Jersey servlet. This triggers the injection of the WebConfig object. The code looks like this:
public class ExtendedGrizzlyTestContainerFactory implements TestContainerFactory {
private static class GrizzlyTestContainer implements TestContainer {
private final URI uri;
private final ApplicationHandler appHandler;
private HttpServer server;
private static final Logger LOGGER = Logger.getLogger(GrizzlyTestContainer.class.getName());
private GrizzlyTestContainer(URI uri, ApplicationHandler appHandler) {
this.appHandler = appHandler;
this.uri = uri;
}
#Override
public ClientConfig getClientConfig() {
return null;
}
#Override
public URI getBaseUri() {
return uri;
}
#Override
public void start() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Starting GrizzlyTestContainer...");
}
try {
this.server = GrizzlyHttpServerFactory.createHttpServer(uri, appHandler);
// Initialize and register Jersey Servlet
WebappContext context = new WebappContext("WebappContext", "");
ServletRegistration registration = context.addServlet("ServletContainer", ServletContainer.class);
registration.setInitParameter("javax.ws.rs.Application",
appHandler.getConfiguration().getApplication().getClass().getName());
// Add an init parameter - this could be loaded from a parameter in the constructor
registration.setInitParameter("myparam", "myvalue");
registration.addMapping("/*");
context.deploy(server);
} catch (ProcessingException e) {
throw new TestContainerException(e);
}
}
#Override
public void stop() {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO, "Stopping GrizzlyTestContainer...");
}
this.server.stop();
}
}
#Override
public TestContainer create(URI baseUri, ApplicationHandler application) throws IllegalArgumentException {
return new GrizzlyTestContainer(baseUri, application);
}
Notice that the Jersey Servlet configuration is being loaded from the ApplicationHandler that is passed in as a parameter using the inner Application object's class name (ResourceConfig is a subclass of Application). Therefore, you also need to create a subclass of ResourceConfig for this approach to work. The code for this is very simple:
package com.example;
import org.glassfish.jersey.server.ResourceConfig;
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
super(MyResource.class);
}
}
This assumes the resource you are testing is MyResource. You also need to override a couple of methods in your test like this:
public class MyResourceTest extends JerseyTest {
public MyResourceTest() throws TestContainerException {
}
#Override
protected Application configure() {
return new MyResourceConfig();
}
#Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new ExtendedGrizzlyTestContainerFactory();
}
#Test
public void testCreateSimpleBean() {
final String beanList = target("test").request().get(String.class);
Assert.assertNotNull(beanList);
}
}
Finally, for completeness, here is the code for MyResource:
#Path("test")
public class MyResource {
#Context WebConfig wc;
#PostConstruct
public void init() {
System.out.println("WebConfig: " + wc);
String url = wc.getInitParameter("myparam");
System.out.println("myparam = "+url);
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Collection<TestBean> createSimpleBean() {
Collection<TestBean> res = new ArrayList<TestBean>();
res.add(new TestBean("a", 1, 1L));
res.add(new TestBean("b", 2, 2L));
return res;
}
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public TestBean roundTrip(TestBean s) {
return s;
}
}
The output of running the test shows that the WebConfig is loaded and the init param is now available:
WebConfig: org.glassfish.jersey.servlet.WebServletConfig#107d0f44
myparam = myvalue
The solution from #ametke worked well but wasn't picking up my ExceptionMapper classes. To solve this I simplified the start() method to:
#Override
public void start() {
try {
initParams.put("jersey.config.server.provider.packages", "my.resources;my.config");
this.server = GrizzlyWebContainerFactory.create(uri, initParams);
} catch (ProcessingException | IOException e) {
throw new TestContainerException(e);
}
}
This was based on Problems running JerseyTest when dealing with HttpServletResponse
I'm trying to implement this Jsonp Filter.
However, whenever I call my url /server/api.jsonp?callback=something it cuts of the last part of the response (ContentLength has the length of the original response output. In this case that would be 15 since {test: 'blaat'} is my original response output - see Controller).atleast this is what I assume since the output I get is test({test: 'bl. Does someone know how to get the filter to work and send the correct response back?
(I even try to force the Content-length - see JsonpCallbackFilter)
Filter:
public class JsonpCallbackFilter implements Filter {
protected final Log logger = LogFactory.getLog(JsonpCallbackFilter.class);
#Override
public void init(FilterConfig fConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
Map<String, String[]> params = httpRequest.getParameterMap();
if (params.containsKey("callback")) {
if (logger.isDebugEnabled()) {
logger.debug("Wrapping response with JSONP callback: " + params.get("callback")[0]);
}
OutputStream out = httpResponse.getOutputStream();
GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);
chain.doFilter(request, wrapper);
byte[] callBack = (params.get("callback")[0] + "(").getBytes();
byte[] callBackEnd = (");").getBytes();
byte[] jsonpResponse = new byte[callBack.length + wrapper.getData().length + callBackEnd.length];
System.arraycopy(callBack, 0, jsonpResponse, 0, callBack.length);
System.arraycopy(wrapper.getData(), 0, jsonpResponse, callBack.length, wrapper.getData().length);
System.arraycopy(callBackEnd, 0, jsonpResponse, callBack.length + wrapper.getData().length, callBackEnd.length);
logger.debug(new String(jsonpResponse));
logger.debug("Length: " + jsonpResponse.length);
out.write(jsonpResponse);
wrapper.setContentType("text/javascript;charset=UTF-8");
wrapper.setContentLength(jsonpResponse.length);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No callback found, resort to default json request!");
}
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
}
}
Generic Response Wrapper:
public class GenericResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream output;
private FilterServletOutputStream filterStream;
private PrintWriter printWriter;
private int contentLength;
private String contentType;
public GenericResponseWrapper(HttpServletResponse response) {
super(response);
output = new ByteArrayOutputStream();
filterStream = new FilterServletOutputStream(output);
printWriter = new PrintWriter(output, true);
}
public byte[] getData() {
printWriter.close();
return output.toByteArray();
}
#Override
public ServletOutputStream getOutputStream() {
return filterStream;
}
#Override
public PrintWriter getWriter() {
return printWriter;
}
public int getContentLength() {
return contentLength;
}
#Override
public void setContentLength(int length) {
this.contentLength = length;
super.setContentLength(length);
}
#Override
public String getContentType() {
return contentType;
}
#Override
public void setContentType(String contentType) {
this.contentType = contentType;
super.setContentType(contentType);
}
}
Custom Filter outputstream:
public class FilterServletOutputStream extends ServletOutputStream {
private DataOutputStream stream;
public FilterServletOutputStream(OutputStream output) {
stream = new DataOutputStream(output);
}
#Override
public void write(int b) throws IOException {
stream.write(b);
}
#Override
public void write(byte[] b) throws IOException {
stream.write(b);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
stream.write(b, off, len);
}
}
web.xml filter mapping:
<filter>
<filter-name>jsonpCallbackFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>jsonpCallbackFilter</filter-name>
<url-pattern>*.jsonp</url-pattern>
</filter-mapping>
bean mapping in applicationContext.xml
<bean id="jsonpCallbackFilter" class="com.world2.utils.spring.filters.jsonp.JsonpCallbackFilter" />
Controller:
#Controller
public class ApiRequests {
protected final Logger logger = Logger.getLogger(ApiRequests.class);
#RequestMapping(value = "api.json", produces = {"application/json"}, method = RequestMethod.GET)
#ResponseBody
public String handleActionJson(final HttpServletRequest request){
return "{test: 'blaat'}";
}
#RequestMapping(value = "api.jsonp", produces = {"text/javascript", "application/javascript", "application/json"}, method = RequestMethod.GET)
#ResponseBody
public String handleActionJsonp(final HttpServletRequest request){
return "{test: 'blaat'}";
}
}
Url I try to call:
http://host:8084/MyProject/server/api.jsonp?callback=test&_=1364980436087
Debug output:
11:13:57,776 DEBUG JsonpCallbackFilter:57 - test({test: 'blaat'});
11:13:57,776 DEBUG JsonpCallbackFilter:58 - Length: 22
Result:
test({test: 'bl
instead of expected result:
test({test: 'blaat'});
Apparently I had to first set the content length and then write the ouput.
Right:
wrapper.setContentType("text/javascript;charset=UTF-8");
wrapper.setContentLength(jsonpResponse.length);
out.write(jsonpResponse);
Wrong:
out.write(jsonpResponse);
wrapper.setContentType("text/javascript;charset=UTF-8");
wrapper.setContentLength(jsonpResponse.length);