My Router class looks like below and i am trying to upload a video file and store it to a File location.
SpringBootRouter.java
package com.camelrest;
import java.util.HashMap;
import java.util.Map;
import org.apache.camel.component.restlet.RestletComponent;
import org.apache.camel.spring.boot.FatJarRouter;
import org.restlet.Component;
import org.restlet.ext.spring.SpringServerServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class MySpringBootRouter extends FatJarRouter {
#Autowired
private MultipartProcessor multipartProcessor;
#Override
public void configure() {
restConfiguration().component("restlet");
rest("/upload").post().to("direct:upload");
from("direct:upload")
.to("file://E:/RestTest");
}
#Bean
public ServletRegistrationBean servletRegistrationBean() {
SpringServerServlet serverServlet = new SpringServerServlet();
ServletRegistrationBean regBean = new ServletRegistrationBean(
serverServlet, "/rest/*");
Map<String, String> params = new HashMap<String, String>();
params.put("org.restlet.component", "restletComponent");
regBean.setInitParameters(params);
return regBean;
}
#Bean
public Component restletComponent() {
return new Component();
}
#Bean
public RestletComponent restletComponentService() {
return new RestletComponent(restletComponent());
}
}
I am trying to upload a video file using postman as per below screenshot :
My contents of the file that i upload are saved with a file name with some random camel ID generated by camel
However i want the filename that is passed in body
SampleVideo_1280x720_10mb.mp4
to be the name of the file and remove the following contents from the body
----------------------------948281627232093197119960
Content-Disposition: form-data; name="file"; filename="SampleVideo_1280x720_10mb.mp4"
Content-Type: video/mp4
So final output can be the video uploaded with the filename used during the upload with postman
You can use MimeMultipartDataFormat to unmarshal Multipart request. Using this, will prepare attachments, to Exchange.
After that you need somehow convert Attachment to InputStream and fill CamelFileName header. With this task can help you small Processor.
Route:
from("direct:upload")
.unmarshal().mimeMultipart().split().attachments()
.process(new PrepareFileFromAttachment())
.to("file://C:/RestTest");
Processor:
class PrepareFileFromAttachment implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
DataHandler dataHandler = exchange.getIn().getBody(Attachment.class).getDataHandler();
exchange.getIn().setHeader(Exchange.FILE_NAME, dataHandler.getName());
exchange.getIn().setBody(dataHandler.getInputStream());
}
}
The approach above does not work in case your form contains only single input in form. This is because MimeMultipartDataFormat marshals first form input into body (without storing file name) and other inputs to attachments where the file name is stored.
In this case you need to create Processor reading InputStream directly:
Route:
from("direct:upload")
.process(new ProcessMultipartRequest())
.to("file:c://RestTest");
Processor
public class ProcessMultipartRequest implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
InputStream is = exchange.getIn().getBody(InputStream.class);
MimeBodyPart mimeMessage = new MimeBodyPart(is);
DataHandler dh = mimeMessage.getDataHandler();
exchange.getIn().setBody(dh.getInputStream());
exchange.getIn().setHeader(Exchange.FILE_NAME, dh.getName());
}
}
Related
I am using GatewayFilterSpec.modifyResponseBody (marked as a "BETA" feature) to rewrite JSON payloads. This works well as long as the response payloads are in fact of content-type application/json. In my case, that is unfortunately not always guaranteed, and I would like it to only apply the modifyResponseBody if the reponse has the Content-Type: application/json header, else skip the filter. Is this possible with Spring Cloud Gateway, and how to do this? Thank you.
Now I'm getting this:
org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'text/html' not supported
at org.springframework.web.reactive.function.BodyInserters.lambda$null$11(BodyInserters.java:329)
at java.util.Optional.orElseGet(Optional.java:267)
at org.springframework.web.reactive.function.BodyInserters.lambda$bodyInserterFor$12(BodyInserters.java:325)
Here is a "solution", one that has all sorts of problems:
package my_package;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import static org.springframework.http.MediaType.APPLICATION_JSON;
#Component
#Primary
public class JsonOnlyModifyResponseBodyGatewayFilterFactory extends ModifyResponseBodyGatewayFilterFactory {
public JsonOnlyModifyResponseBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer) {
super(codecConfigurer);
}
#Override
public GatewayFilter apply(Config config) {
return new MyModifyResponseGatewayFilter(config);
}
public class MyModifyResponseGatewayFilter extends ModifyResponseGatewayFilter {
MyModifyResponseGatewayFilter(Config config) {
super(config);
}
#Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse serverHttpResponse = getServerHttpResponseFromSuper(exchange);
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
#Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (APPLICATION_JSON.isCompatibleWith(getDelegate().getHeaders().getContentType())) {
return serverHttpResponse.writeWith(body);
}
return super.writeWith(body);
}
};
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
private ServerHttpResponse getServerHttpResponseFromSuper(ServerWebExchange exchange) {
ServerHttpResponse[] serverHttpResponse = new ServerHttpResponse[1];
//noinspection UnassignedFluxMonoInstance
super.filter(exchange, chain -> {
serverHttpResponse[0] = chain.getResponse(); // capture the response when the super sets it
return null;
});
return serverHttpResponse[0];
}
}
}
The chosen approach is in lieu of just changing a copy of the existing ModifyResponseBodyGatewayFilterFactory. This allows version upgrades of Spring Boot Gateway to bring in minor changes of ModifyResponseBodyGatewayFilterFactory. But since JsonOnlyModifyResponseBodyGatewayFilterFactory is very dependent on the implementation of ModifyResponseBodyGatewayFilterFactory, this may easily get broken. Another flaw of this solution is that I had to put an #Primary annotation to avoid a required a single bean, but 2 were found exception, but it overrides the default which would presumably affect other uses of modifyResponseBody. It's ugly to call super.filter and not use its result. And so on. So, while this "works", it doesn't, well, fill me with joy.
What I'm trying to achieve - Simple unit test for my EmailUtil which i have written for a Spring MVC application.
Where I'm stuck - Though i have mocked the MIMEmessage and JavaMailSender, test case failing in MimeMessageHelper.set**** methods.
Appreciate any help on this as I have tried few different ways even using PowerMock and no luck for last couple of days.
EmailUtil.Java
import java.util.List;
import javax.activation.DataSource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.util.ByteArrayDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import com.dashboard.domain.Attachment;
import com.dashboard.domain.Email;
public class EmailUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(EmailUtil.class
.getName());
/**
* Private constructor to make sure that no one creating instance
*/
private EmailUtil() {
}
/**
* Functionality to send the mail. This method used the mail sender
* configuration from spring-context file.
*
* #param email
* #param mailSender
* #throws MessagingException
*/
public static void sendEmail(JavaMailSender mailSender, Email email)
throws MessagingException {
LOGGER.info("Start of the method: sendEmail");
MimeMessage mimeMessage = mailSender.createMimeMessage();
// use the true flag to indicate you need a multi part message
boolean hasAttachments = email.getAttachments() != null
&& !email.getAttachments().isEmpty();
LOGGER.info(" mimeMessage - {} ",mimeMessage);
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,
hasAttachments);
LOGGER.info(" MimeMessageHelper - {} ",helper);
helper.setTo(email.getTo());
helper.setFrom(email.getFrom());
helper.setCc(email.getCc());
helper.setSubject(email.getSubject());
helper.setText(email.getText(), true);
List<Attachment> attachments = email.getAttachments();
if (!attachments.isEmpty()) {
for (Attachment attachment : attachments) {
String filename = attachment.getFilename();
DataSource dataSource = new ByteArrayDataSource(
attachment.getData(), attachment.getMimeType());
if (attachment.isInline()) {
helper.addInline(filename, dataSource);
} else {
helper.addAttachment(filename, dataSource);
}
}
}
mailSender.send(mimeMessage);
LOGGER.info("End of the method: sendEmail");
}
}
EmailUtilTest.Java
import static org.easymock.EasyMock.expect;
import javax.mail.Address;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import org.easymock.EasyMock;
import org.easymock.Mock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import com.dashboard.domain.ApplicationConstant;
import com.dashboard.domain.Email;
/**
* PowerMockDemo
* #author s.arumugam
*
*/
#RunWith(PowerMockRunner.class)
#PrepareForTest(EmailUtil.class)
public class EmailUtilTest {
Email email = new Email();
#Mock
JavaMailSender javaMailSender;
#Mock
MimeMessage mimeMessage;
#Mock
MimeMessageHelper mimeMessageHelper;
#Before
public void initList() {
email.setFrom(ApplicationConstant.DEFAULT_MAIL_ID.getValue());
email.setSubject("Subject");
email.setTo("to.email#userdomain.com");
email.setCc("admin#dashboard.com");
email.setText("Body of the email");
}
#Test
public void sendEmailTest() throws Exception{
mimeMessageHelper.setSubject(email.getSubject());
mimeMessageHelper.setFrom(new InternetAddress(email.getFrom(), true));
mimeMessageHelper.setCc(new InternetAddress(email.getCc()[0], true));
mimeMessageHelper.setTo(new InternetAddress(email.getTo()[0], true));
mimeMessageHelper.setText(email.getText());
expect(javaMailSender.createMimeMessage()).andReturn(mimeMessage);
Address sendTo[]={new InternetAddress(email.getTo()[0])};
mimeMessage.setRecipients(RecipientType.TO,sendTo);
EasyMock.expectLastCall().times(1);
EasyMock.replay(mimeMessage);
EasyMock.replay(javaMailSender);
EmailUtil.sendEmail(javaMailSender, email);
EasyMock.verify(mimeMessage);
EasyMock.verify(javaMailSender);
}
}
Error Message:
java.lang.AssertionError: Unexpected method call MimeMessage.setRecipients(To, [to.email#userdomain.com]):
MimeMessage.setRecipients(To, [to.email#userdomain.com]): expected: 1, actual: 0 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94) at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97) at $javax.mail.internet.MimeMessage$$EnhancerByCGLIB$$a6025b60.setRecipients(<generated>) at org.springframework.mail.javamail.MimeMessageHelper.setTo(MimeMessageHelper.java:581) at org.springframework.mail.javamail.MimeMessageHelper.setTo(MimeMessageHelper.java:595) at com.dashboard.util.EmailUtil.sendEmail(EmailUtil.java:50)
Ohh.. I managed to fix the issue.. purely by random trial and error..! That says I need to get into deep understanding of how these mock utils works.. Working test case below with a hope someone can find a complete working example with test case;
#RunWith(EasyMockRunner.class)
public class EmailUtilTest extends EasyMockSupport{
#Mock
JavaMailSender mailSender;
#Mock
MimeMessage mimeMessage;
#Test
public void testSendEmail() throws MessagingException{
Email email = new Email();
email.setFrom("from.email#dashboard.com");
email.setSubject("Subject");
email.setTo("to.email#userdomain.com");
email.setCc("admin#dashboard.com");
email.setText("Body of the email");
EasyMock.expect(mailSender.createMimeMessage()).andReturn(mimeMessage);
mailSender.send(mimeMessage);
EasyMock.expectLastCall();
EasyMock.replay(mailSender);
EmailUtil.sendEmail(mailSender, email);
EasyMock.verify(mailSender);
}
}
The reason you are getting java.lang.AssertionError is because EasyMock uses the equals() method to compare parameters passed to methods, and you cannot use equals() to compare arrays.
Address toAddress = new InternetAddress("a#b.com");
Address[] a1 = { toAddress };
Address[] a2 = { toAddress };
if (a1.equals(a2)) { // this will be false
// so this won't happen
}
Thankfully, EasyMock provides us with several different argument matchers. In this case we should use EasyMock.aryEq(). So in order to mock out the call to setRecipients() method:
mimeMessage.setRecipients(EasyMock.eq(RecipientType.TO) , EasyMock.aryEq(sendTo));
I'm not sure how the accepted answer is working without changes to the EmailUtil class.
After upgrading from Play! 2.4 to Play! 2.5 there seems to be a problem with form-enconding. German umlauts for example really get messed up. For example the german word "Bär" becomes "Bär".
I already changed the way I access form data from
Form.form(Form.class).bindFromRequest();
to the injected way, as described in the migration guide:
formFactory.form(Form.class).bindFromRequest();
Is there a was to fix the character encoding in Play 2.5?
This is a bug in play 2.5 , see github issue: https://github.com/playframework/playframework/pull/5920
I resolve this with a custom body parser:
package com.kashi.ssff.services;
import akka.util.ByteString;
import play.api.http.HttpConfiguration;
import play.core.parsers.FormUrlEncodedParser;
import play.http.HttpErrorHandler;
import play.libs.F;
import play.libs.streams.Accumulator;
import play.mvc.BodyParser;
import play.mvc.BodyParsers;
import play.mvc.Http;
import play.mvc.Result;
import javax.inject.Inject;
import java.util.Map;
/**
* Created by mohsen on 3/21/16.
*/
public class FormBodyParser extends BodyParser.BufferingBodyParser<Map<String, String[]>> {
private final HttpErrorHandler errorHandler;
public FormBodyParser(long maxLength, HttpErrorHandler errorHandler) {
super(maxLength, errorHandler, "Error parsing form");
this.errorHandler = errorHandler;
}
#Inject
public FormBodyParser(HttpConfiguration httpConfiguration, HttpErrorHandler errorHandler) {
super(httpConfiguration, errorHandler, "Error parsing form");
this.errorHandler = errorHandler;
}
#Override
public Accumulator<ByteString, F.Either<Result, Map<String, String[]>>> apply(Http.RequestHeader request) {
return BodyParsers.validateContentType(errorHandler, request, "Expected application/x-www-form-urlencoded",
ct -> ct.equalsIgnoreCase("application/x-www-form-urlencoded"), super::apply);
}
#Override
protected Map<String, String[]> parse(Http.RequestHeader request, ByteString bytes) throws Exception {
String charset = request.charset().orElse("UTF-8");
return FormUrlEncodedParser.parseAsJavaArrayValues(bytes.decodeString(charset), charset);
}
}
and annotate controller with this body parser:
#BodyParser.Of(FormBodyParser.class)
public Result register() {
.
.
.
With special thanks #GregMethvin
in your form try adding the accept-charset="ISO-8859-1"
<form accept-charset="ISO-8859-1" action="whatever" method="post">
tested it for the word Bär and it works fine
EDIT:
For the arabic script the characters are stored as ISO-8859-1 encoded as well. An image to show that at the end all goes well.
I am new to Vaadin.
As in topic I would like to make http get reaquest in order to retieve some JSON data.
How could I do this ?
I have been trying to make this by com.google.gwt.http.client.RequestBuilder, but I have obtained
java.lang.UnsatisfiedLinkError: com.google.gwt.xhr.client.XMLHttpRequest.create().
I think the error is associated to GWT client - side nature.
So how could I make http get request in Vaadin 7 server - side ?
Here is my code:
package com.example.soaclient;
import javax.servlet.annotation.WebServlet;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
#SuppressWarnings("serial")
#Theme("soaclient")
public class SoaclientUI extends UI {
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = SoaclientUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
Button button = new Button("Click Me");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
layout.addComponent(new Label("Thank you for clicking"));
String url = "some URL goes here";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// Couldn't connect to server (could be timeout, SOP violation, etc.)
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// Process the response in response.getText()
} else {
// Handle the error. Can get the status text from response.getStatusText()
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
}
}
});
layout.addComponent(button);
}
}
With Vaadin you should not use anything from com.google.gwt.http.client package. That is only for client side development, e.g. when you make components that need client side counterparts.
Instead of GWT classes you should just stick to generic JDK libraries. E.g. you could simply use java.net.URL.openStream(). But if you are consuming some REST services, you could refer to my recent JAX-RS 2.0 Client article.
I am looking to read xls file using the gwt RPC and when I am using the code which excecuted fine in normal file it is unable to load the file and giving me null pointer exception.
Following is the code
{
{
import com.arosys.readExcel.ReadXLSX;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.Preview.client.GWTReadXL;
import java.io.InputStream;
import com.arosys.customexception.FileNotFoundException;
import com.arosys.logger.LoggerFactory;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
*
* #author Amandeep
*/
public class GWTReadXLImpl extends RemoteServiceServlet implements GWTReadXL
{
private String fileName;
private String[] Header=null;
private String[] RowData=null;
private int sheetindex;
private String sheetname;
private XSSFWorkbook workbook;
private XSSFSheet sheet;
private static Logger logger=null;
public void loadXlsxFile() throws Exception
{
logger.info("inside loadxlsxfile:::"+fileName);
InputStream resourceAsStream =ClassLoader.getSystemClassLoader().getSystemResourceAsStream("c:\\test2.xlsx");
logger.info("resourceAsStream-"+resourceAsStream);
if(resourceAsStream==null)
throw new FileNotFoundException("unable to locate give file");
else
{
try
{
workbook = new XSSFWorkbook(resourceAsStream);
sheet = workbook.getSheetAt(sheetindex);
}
catch (Exception ex)
{
logger.error(ex.getMessage());
}
}
}// end loadxlsxFile
public String getNumberOfColumns() throws Exception
{
int NO_OF_Column=0; XSSFCell cell = null;
loadXlsxFile();
Iterator rowIter = sheet.rowIterator();
XSSFRow firstRow = (XSSFRow) rowIter.next();
Iterator cellIter = firstRow.cellIterator();
while(cellIter.hasNext())
{
cell = (XSSFCell) cellIter.next();
NO_OF_Column++;
}
return NO_OF_Column+"";
}
}
}
I am calling it in client program by this code:
final AsyncCallback<String> callback1 = new AsyncCallback<String>() {
public void onSuccess(String result) {
RootPanel.get().add(new Label("In success"));
if(result==null)
{
RootPanel.get().add(new Label("result is null"));
}
RootPanel.get().add(new Label("result is"+result));
}
public void onFailure(Throwable caught) {
RootPanel.get().add(new Label("In Failure"+caught));
}
};
try{
getService().getNumberOfColumns(callback1);
}catch(Exception e){}
}
Pls tell me how can I resolve this issue as the code runs fine when run through the normal java file.
Why are using using the system classloader, rather than the normal one?
But, If you still want to use then look at this..
As you are using like a web application. In that case, you need to use the ClassLoader which is obtained as follows:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
This one has access to the all classpath paths tied to the webapplication in question and you're not anymore dependent on which parent classloader (a webapp has more than one!) has loaded your class.
Then, on this classloader, you need to just call getResourceAsStream() to get a classpath resource as stream, not the getSystemResourceAsStream() which is dependent on how the webapplication is started. You don't want to be dependent on that as well since you have no control over it at external hosting:
InputStream input = classLoader.getResourceAsStream("filename.extension");
The location of file should in your CLASSPATH.