Java- redirecting a request - java

I'm writing a Servlet in Java, that basically, gets a request with a XML in the Requests body, and then changes a few things in the XML and redirect/foreword the request with The new XML to a different Servlet that's on the same server, but its on a different web app.
How do redirect/foreword the request with The new XML? can i find code example any where?
this is what i have so far:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String body = getBody(request);
MapXml mapXml = new MapXml(body,
"C:\\Projects\\XmlMapper\\output.xml","C:\\Projects\\XmlMapper\\output\\");
String outputXml = mapXml.getOutputXml();
}
public static String getBody(HttpServletRequest request) throws IOException {
String body = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
return body;
}
And i have no idea how to continue on from here. I'm new to the servlet world.. Thanks!!! Cheers:)

If both web-apps are on the same server, i.e. Tomcat
in its META-INF/context.xml set <Context crossContext="true" />
getServletContext().getContext("/app").getRequestDispatcher("f.jsp").forward(..);,
where app is the name of the other application.
Or what you maybe should do is, Use URLConnection to send request to any URL.
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
About how to set XML in request, you can carry relatively larger amounts of data in POST request. You can also find the max limit of POST data.
just read the bytes that make up the XML file (using FileInputStream)
(if you dont have xml in file, use String to create ur xml)and send
them in the POST body. Make sure to set the content encoding
accordingly.
I am editing this for the 4th time, to add more details.
You can use Apache HTTP Client to post XML easily if its difficult for you to use Java's HTTP client.
String xml = "your xml";
PostMethod post = new PostMethod(strURL);
try {
StringRequestEntity requestEntity = new StringRequestEntity(xml);
post.setRequestEntity(requestEntity); ..
....
...

Because the xml will not be a small body for request,so you have to let the client post the new xml for you. or you can do:
share the same database or cache with remote web service, and forward the key of the data in database or cache.
use HttpClient to post the request for your client, with modified xml, and return the response from remote service to your client.
if you can make sure the xml body is small, you can just using GET method, forward the request to remote server

Let's rule out some possibilities first:
You cannot do response.sendRedirect("/otherapp/servlet.do") since it doesn't let you send POST data to another webapp.
You cannot use session since you're sending data across to a different webapp.
You cannot obviously pass full XML in a query string using GET.
Once those possibilities are ruled out only possible way I can think of is this:
Return to the calling page with modified XML and URL of other webapps's servelt in response
Let calling page immediately POST the modified XML to other webapps's servelt using simple Javascript

Related

As a body HttpServletRequest always returns CoyoteInputStream and not actual body

I'm trying to write a method that checks user credentials and if these are correct parses sent JSON. It is working fine but I cannot access JSON. In my code there is a command InputStream inputStream = request.getInputStream(); that should read JSON but every time it returns org.apache.catalina.connector.CoyoteInputStream#3f1e9348. Please have a look at my code:
#POST
#Path("auth")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_HTML)
public String controller(#Context HttpServletRequest request) {
String authorization = request.getHeader("Authorization");
if (authorization == null) {
authorization = request.getHeader("authorization");
}
String basicHeader = "basic";
if (authorization != null && authorization.toLowerCase().startsWith(basicHeader)) {
String base64Credentials = authorization.substring(basicHeader.length()).trim();
String credentials = new String(Base64.getDecoder().decode(base64Credentials),
Charset.forName("UTF-8"));
String[] values = credentials.split(":", 2);
}
try {
InputStream inputStream = request.getInputStream();
System.out.println(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
When I try to use request.getReader() I get the infamous IllegalStateException: getInputStream() has already been called for this request exception. Please see the relevant piece of code:
if ("POST".equalsIgnoreCase(request.getMethod()))
{
try {
String req = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
} catch (IOException e) {
e.printStackTrace();
}
}
I use curl to send POST:
curl -u myusername:mypasswor -H "Content-Type: application/json"
-X POST -d '{"username":"xyz","password":"xyz"}' localhost
You can obtain your body content by declaring a parameter on your method:
public String controller(String body, #Context HttpServletRequest request)
But you can also get the JAX-RS implementation to deserialize that JSON to your intended type:
public String controller(MyExpectedType body, #Context HttpServletRequest request)
This should work because you've declared your expected content type, assuming you have a provider that's applicable (such as jackson-jaxrs...).
Regarding the input stream error: this is probably because the container JAXRS implementation has already parsed the request.
But if you were to process it in a normal scenario, such as in a servlet, you'd still have to correct the way you read it:
The documentation for getInputStream state:
Retrieves the body of the request as binary data using a ServletInputStream. Either this method or getReader() may be called to read the body, not both.
This means that to get the content sent by your client in the body, you need to read the stream:
String body = request.getReader().lines()
.collect(Collectors.joining("\n"));
You can also use the Stream-based API:
byte[] bytes = new byte[request.getContentLength()];
request.getInputStream().read(bytes);
String body = new String(bytes); //you may need to specify the character set
The actual input stream class is implementation-based (container-supplied), so you shouldn't need to be concerned with CoyoteInputStream

write the file and download the file same as of attachments

i have a requirement where i get byte array (byte[]) data from database, i need to save this data in a file and allow the user to save where ever he want to save, same as downloading the attachments.The file name and extension also i'm retrieving from database. I'm using java,spring-mvc for this.
Below is the code:
spring controller:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
}
Please suggest, i know that using java.io.*, i can write the byte[] data in file and give file name and extension by taking the values declared above, but how can i allow users when clicked on "download file" icon to write the data and save that file where ever he wants same as downloading the attachment.Please suggest. Once user clicks on download file icon control comes to above controller.Thanks.
--EDIT--
Modified code:
#RequestMapping(value="/getFile", method = RequestMethod.GET)
public ModelAndView getFile(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//logic to get the data from database
byte[] documentData = document.getDOCUMENTData();
String documentName = document.getDOCUMENTTITLE();
String documentExt = document.getDocumentExtension();
response.setHeader("Content-Disposition", "attachment;filename="+userDoc.getDOCUMENT_TITLE());
long l = userDoc.getDOCUMENT_SIZE();
int size = (int)l;
response.setContentLength(size);
response.getWriter().write("hello");//i need to write byte[] but for test i kept string.
}
I want user to see save window so that he can save where ever he want same as downloading the attachments from mail.Thanks.
This is a code I'm usign for the same request
HTML page:
<h:commandButton value="Click Here to Download" action="#{reportBean.download}" />
BEAN:
public void download(){
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
response.setHeader("Content-Disposition", "attachment;filename="+file.getName());
response.setContentLength((int) file.length());
ServletOutputStream out = null;
try {
FileInputStream input = new FileInputStream(file);
byte[] buffer = new byte[1024];
out = response.getOutputStream();
int i = 0;
while ((i = input.read(buffer)) != -1) {
out.write(buffer);
out.flush();
}
FacesContext.getCurrentInstance().getResponseComplete();
input.close();
} catch (IOException err) {
err.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException err) {
err.printStackTrace();
}
}
}
Just make sure you have a File object named file
You have two options to achieve this:
One is to write the file in your server's local filesystem in an internet accesible folder. You can configure which of your server's local folders are accesible from internet in your Apache/IIS serttings. Then you update your HTML so your "download file" link points to that file through an URL.
The other option is, like #an3sarmiento did, to return the file as a byte[] stream to the browser. For this option to work, you have to send, along with the file content, a response header in which you tell the browser you are returning a downloadable file as a stream. You do that with the line:
response.setHeader("Content-Disposition", "attachment;filename="+[your file name]);
response.setContentLength([your file's length or bytes count]);
response.getWriter.write([your file's content as byte array]);
In the line above I assume you are working with Java Servlets and you have an HttpServletResponse variable named reponse, which you will respond to the browser's HTTP POST or GET request.

jax-rs returned String

I am programming a jax-rs webservice which I want to contact from a java-program. I defined a #POST method which receives a String-array as input and is supposed to return a boolean value.
But really, how can i access this return value in java? I've been searching the web for several hours now, everybody writes example methods which return Strings or something else, but nobody shows how to access the returned value from another java program.
Here is the code from the program that contacts the #POST method:
ObjectOutputStream oos = null;
String[] login = {"XXXXXX","XXXXXXX"};
try {
login[1] = PasswordGenerator.hashPassword(login[1]);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URL url = new URL("XXXXX/XXXXXXX/XXXXXX/users/login/1");
try {
// creates a HTTP connection
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setUseCaches(false);
httpConn.setDoOutput(true);
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Boolean", "application/xml");
OutputStream outputStream = httpConn.getOutputStream();
oos = new ObjectOutputStream(outputStream);
outputStream.close();
System.out.println();
} finally {
if (oos != null) {
oos.close();
}
}
}
What I want to know is: What happens after I closed my outputStream? I mean, i started the POST method, but it is supposed to return a boolean value. Where is this value? How can I access it???
JAX-RS 2.0 has a Client API that provides you with a fluent API to retrieve the content of the response:
Client client = ClientBuilder.newClient();
Boolean result = client.target("http://localhost:8080/xxx/")
.path("user/login/1")
.request(MediaType.TEXT_PLAIN_TYPE)
.post(Entity.entity(login, MediaType.APPLICATION_XML) , Boolean.class);
But unfortunately, you'll need a custom MessageBodyWriter to convert the String[] into an XML document. Maybe you should change your server-side method (and client) to manipulate a DTO - a POJO with 2 fields, username and password - and annotated with #XmlRootElement ?
something like that:
(client-side)
Credentials credentials = new
credentials.setUsername("foo");
credentials.setUsername("hashedPwd");
Client client = ClientBuilder.newClient();
Boolean result = client.target("http://xxxxx")
.path("/user/login/1")
.request(MediaType.TEXT_PLAIN_TYPE)
.post(Entity.entity(credentials, MediaType.APPLICATION_XML) , Boolean.class);
System.out.println("Result: " + result);
(server-side)
#Path("/login/{id}")
#POST
public Boolean test(#PathParam("id") String login, Credentials credentials) {
...
}

Special characters in SOAP payload not transferred correctly

I have written a SOAP web-service using CXF which is being called by a SAP system, in the payload there is a word with a special character which occurs multiple times. However, I read this word differently in some random cases, i.e. in a one payload I see the word as Kliëntbestuurder and in another as Kli��ntbestuurder.
The SAP system calling my service via SAP PI only have the one word.
UPDATE:
So it seems that it was not the web-service communication that was getting confused but rather the interceptor that I had written to dump the soap envelope for me to be able to scrutinise. The interceptor is as follows:
public class WebServiceMessageInterceptor extends AbstractPhaseInterceptor<Message> {
public WebServiceMessageInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(Message message) throws Fault {
final LoggingMessage buffer = new LoggingMessage("", "");
String encoding = (String) message.get(Message.ENCODING);
if (encoding != null) {
buffer.getEncoding().append(encoding);
}
Object headers = message.get(Message.PROTOCOL_HEADERS);
if (headers != null) {
buffer.getHeader().append(headers);
}
InputStream is = message.getContent(InputStream.class);
if (is != null) {
CachedOutputStream outputStream = new CachedOutputStream();
try {
IOUtils.copy(is, outputStream);
outputStream.flush();
is.close();
message.setContent(InputStream.class, outputStream.getInputStream());
outputStream.writeCacheTo(buffer.getPayload(), "UTF-8", -1);
outputStream.close();
FileUtils.writeStringToFile(new File("/tmp/soap" + System.currentTimeMillis() + ".log"), buffer.toString(), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
throw new Fault(e);
}
}
}
Any further ideas why my interceptor is not using UTF-8?
This might be related to not using encoding consistently across and within the services. I suggest you help yourself by reading this excellent tutorial - Unicode - How to get the characters right? end to end. Then ask follow up questions once you narrowed down the scope of the error.
Check the http headers on the response you are sending back from your web services. You can use the Raw tab in soapUI to view the headers. If you don't see something like
Content-Type: text/xml;charset=UTF-8
then you can force CXF to add it to the response by doing something like this in your WebMethods:
MessageContext ctx = context.getMessageContext();
ctx.put(Message.CONTENT_TYPE, "text/xml;charset=UTF-8");
where context is the javax.xml.ws.WebServiceContext injected into your class.
You should also verify that the client to your web service is also using the correct encoding. You may be sending a valid response to him.

Why is My HttpPost request being broken up into two requests?

Just a little starter information. I am writing an Andorid app that talks to a server written in C#.Net using the MVC platform. Every request is a post and a ActionFilter attribute ensures that. However because of the issue .Net parses the HttpMethod as "ST".
The following is the code I use globally to make web requests from my application:
private String MakeRequest(String action, String params){
try {
HttpPost request = new HttpPost(mProtocol + mSubDomain + mHost + action);
String args;
if (params != null) {
args = params;
} else {
args = "[]";
}
StringEntity requestEntity;
requestEntity = new StringEntity(args);
requestEntity.setContentType("application/json;charset=UTF-8");
requestEntity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
request.setEntity(requestEntity);
HttpResponse response = mHttpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
String jString = EntityUtils.toString(responseEntity);
return jString;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
I only have this problem with one particular method all other methods work just fine.
The following link is to a pcap file that contains the traffic so it is plainly visible. (I have filtered it down to only the applicable lines)
http://dl.dropbox.com/u/315661/defect.pcap
Have you tried disabling the use of 100-Continue in your POST? You typically don't need it as it only adds more overhead to your communication with the server - and it can cause issues if the service (or any piece of kit on the way between your device and the service, such as proxies etc.) you are posting to is not completely conformant.
HttpProtocolParams.setUseExpectContinue(params, false)

Categories