I have a Web Service that receives an image upload by a Multipart POST request. I would like to forward the file to another web service without storing it, as the environment does not have access to a file system, so basically just passing along the information that's being received.
How do I achieve this?
If the other webservice resides on the same server use:
String url = "<relative path>";
request.getRequestDispatcher(url).forward(request, response);
return;
otherwise use:
response.sendRedirect(url);
You could always try chaining the input and output streams from one to the other, but I suspect you won't get very far with this when there's a hiccup on either side of the connection.
Another option you have, depending on how much memory you have access to, is to save it as a variable after you fetch it, and then pass it along to the other webservice. This of course won't work with very large images but it's a starting point.
Related
I am making a simple text-only instant messenger in java. The way that it currently works is that all the messages are put into an online text file by sending a php file a request (I know this is bad for security, but this is just to learn how to do web-connected apps in java.)
Currently, I am continually fetching the entire contents of the messages.txt file and placing them into my JTextPane like this:
while(true) {
URL url = new URL("{path to text file}");
InputStream in = url.openStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String conversation = s.hasNext() ? s.next() : "";
textPane.setText(conversation);
}
But when the conversation becomes long enough, it lags as it is fetching 100kb+ files constantly from a web server.
What I want to happen is to only read the changes to the file so that it doesn't lag and max out my internet connection by requesting enourmous amounts of plain text files. I don't want to just make it run every 2 seconds because it's an instant messenger, no delays.
How would I go around only fetching the changes to the file and adding them to the text pane?
Can you push the file contents to another file once it crosses a certain threshold. This will ensure that you operate upon a smaller file.
Instead of contacting url directly you could place some server side script that would call the file
You could (as a client) provide the server script the last line / message identifier and the server could respond with new messages that have been added after the message id that the client has provided. In addition it could send the new last message id
With this approach the server side script doesnt even need to read itself the whole file and instead can immediately skip to the required line if message id contains the information about the line in the log file
Of course this approach is really far from real scenarios but its ok for learning IMO
I currently have a problem with a REST service: The basic construction is the following: On my Tomcat there are running 2 applications (my new REST service (S1) and another application (S2) which also offers REST calls). The Applications should work together so that S1 can send requests to S2. It works fine if I use hard coded URLs in S1 to call S2. But the problem is that the path of the applications are changing due to different ports or configurations. The changes apply to both applications since they are both on the same Tomcat server.
Basically the 2 Paths look similar, starting e.g. with http://localhost:8080/ or http://sys-example:8034/. So if I call S1 on an specific Path, the application should fetch the URL and build its own basePath to reach S2 on the same Server. How can I create a method which gets me the path where my service is called. IS there a way to use ServletContext or is there a better way?
Currently this is my code in S1 to reach the service in S2
String path = configMap.get("basePath").toString();
//configMap is a HashMap which contains Data from an config file
//the result of get("basePath") looks like this: http://localhost:8080
path = path.concat("/otherService/rest/action/login");
If you are sure that the 2 servlets will run in the same Tomcat installation and, moreover, in the same context, I suggest using the direct interaction.
Please check the link at this URL.
If I got you right, you are saying that you run the services in different environments, e.g. production, development, local etc., which means host and port differ. The relative paths to your services remain the same, though.
Then, it is absolutely ok to hard-code the relative paths since they don't change. The host and port, however, should be configurable. You could load them from the database, in case you have access to your database before you need those data.
Another solution might be to configure host and port within your web container. If you should use Tomcat as your web container, create a properties file and load it when the app is being bootstrapped.
EDIT:
Other answers suggest to resolve the path from the request object. I disadvise doing that for the following reasons:
There might be use cases where you don't have a request. There might be (now or in future) other interfaces to your services than via HTTP
You should not rely on what URL to call depending on the request coming in, since you have no control over that values. Think of Reverse Proxies or Load Balancer.
You can extract the REST call using an URI object. Example:
URI u = URI.create("http://www.example.com:8080/rest/service/call");
String restPath = u.getPath();
System.out.println(restPath);
This way, you can append the REST url easily to S2. I hope that helps :)
You can fetch the required details from HttpServletRequest object.
The below code must give you the required details. I have not tested this, but this should get you started.
StringBuffer url = request.getRequestURL();
String uri = request.getRequestURI();
String host = url.substring(0, url.indexOf(uri));
I think request.getRequestURL() is what you want
I need to find a way of reading GET/POST requests from the WEB browser(Network) and retrieve the information like Status, Domain, Size, IP and the most important Timeline.
The main purpose of this is to measure requests count after each action on the WEB page and their execution time. Also this will help me to know if any requests(AJAX/JavaScript) are executing before I want to perform any actions on the WEB page.
Could you please help me with solution?
Assuming you don't want to tie yourself to a particular browser (via plugins or particular dev toolbars), need to capture responses from interactive user events (i.e. via simulated use of a website in a real browser, not dynamically created HTTP calls), and need to automate this, then a proxy server is the way to go.
Something like Browsermob can be set up as a proxy for all Selenium traffic. It can capture the entire content of all requests and responses, and let you generate you a (cross-browser) HAR file that you can then persist, visualise, or query via an API.
Obviously you could automate this, schedule the Selenium test runs, and either produce your own custom metrics with your own Java code; pipe the HAR into a JSON-savvy database for querying (say Elasticsearch) and visualisation, or just save the HARs for offline querying and diffing.
Some example code from the tests:
[...]
proxy.newHar("Test");
HttpGet get = new HttpGet(getLocalServerHostnameAndPort() + "/a.txt?foo=bar&a=1%262");
client.execute(get);
Har har = proxy.getHar();
HarLog log = har.getLog();
List<HarEntry> entries = log.getEntries();
HarEntry entry = entries.get(0);
HarRequest req = entry.getRequest();
[...]
Alternatively you can visualise the output by obtaining the HAR in string form and pasting into http://www.softwareishard.com/har/viewer/. That should give you something that looks very similar to the Network tab, but in a format that's easier to export, screenshot, and print.
Chrome comes with devtools by itself. Just hit 'F12'.
https://developer.chrome.com/devtools
Postman, it's useful for testing web services and API
https://www.getpostman.com/
Hi
I've done a lot of research on the best way to communicate between a java applet and MySql Database.
I have a tune player which I have students logging onto, it's a java applet with a speed slider. I want to save the speed that they play each tune at so it goes back to the same speed the next time they open that tune.
It seems I have a number of options, none of which seem very neat.
Use a javascript function to
periodically check the speed and
save it to a cookie, then each page
of the site would have to check
cookies relationg to each tune.
Make each link on the page call a
javascript function to check the
speed variable in the applet and add
it to a perameter in the url then
redirect so the next php page can
save the speed to a database. This
way when the user navigates away the
speed will be saved, but this won;t
work if the back button is used.
Is there a better way of doing this?
Use the JNLP API and the problems should be solved.
Since Java 1.6.0_10+, it is possible to use the Java Web Start API services (JNLP API) within an embedded applet. The JNLP API provides the PersistenceService. Here is a small demo. of the PersistenceService.
If the user hits the back button (or otherwise leaves the page), the destroy() method will be called. Override the destroy method and persist the data at that time.
No need to use JavaScript.
The java code below posts variables to a PHP script on the web server then
shows the server response on the console
private void post()
throws MalformedURLException, IOException
{ URL url;
URLConnection con;
OutputStream oStream;
String parametersAsString;
byte[] parameterAsBytes;
String aLine; // only if reading response
parametersAsString = "msg=hi&to=memo";
parameterAsBytes = parametersAsString.getBytes();
// send parameters to server
url = this.getCodeBase();
url = new URL(url + "scriptfile.php");
con = url.openConnection();
con.setDoOutput(true);
// setDoInput(true); // only if reading response
con.setDoInput(false);
con.setRequestProperty("Content=length", String.valueOf(parameterAsBytes.length));
oStream = con.getOutputStream();
oStream.write(parameterAsBytes);
oStream.flush();
// read response from server & show the server response on the Java console or whatever ...
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
aLine = in.readLine();
while (aLine != null)
{ System.out.println(line);
aLine = in.readLine();
}
in.close();
oStream.close();
}
I'd suggest you get the applet to update the database. Whenever the speed slider changes you can fire off an update to the database, or you might need to coalesce multiple changes into one request depending on usage.
When the applet changes tune it can also do its own lookup of the correct speed.
Note that the applet will probably not be able to hit the database directly - browsers should restrict what I/O operations are available to applets - but you should be able to get the applet to hit a URL on the server that will actually perform the update. Signing the applet may let you hit the database but you should read up on the applet security model and the various browser quirks first.
It's not really clear how all of this is set up since you don't have a lot of details. However, assuming that you have an actual Java applet, I'd say the following:
If the Java applet requires a login (that is, it knows who the user is) then it can store the preference on the server. To do this you could have the applet connect to the server using JDBC, which isn't generally a good idea for internet-facing applets, or you could have the applet send a message to a server process such as a web server. That process connects to the mysql server.
The applet can communicate directly with the browser using Javascript. So you can have the applet set the cookie when the slider changes, instead of having the Javascript set it.
I've been writing a little application that will let people upload & download files to me. I've added a web service to this applciation to provide the upload/download functionality that way but I'm not too sure on how well my implementation is going to cope with large files.
At the moment the definitions of the upload & download methods look like this (written using Apache CXF):
boolean uploadFile(#WebParam(name = "username") String username,
#WebParam(name = "password") String password,
#WebParam(name = "filename") String filename,
#WebParam(name = "fileContents") byte[] fileContents)
throws UploadException, LoginException;
byte[] downloadFile(#WebParam(name = "username") String username,
#WebParam(name = "password") String password,
#WebParam(name = "filename") String filename) throws DownloadException,
LoginException;
So the file gets uploaded and downloaded as a byte array. But if I have a file of some stupid size (e.g. 1GB) surely this will try and put all that information into memory and crash my service.
So my question is - is it possible to return some kind of stream instead? I would imagine this isn't going to be terribly OS independent though. Although I know the theory behind web services, the practical side is something that I still need to pick up a bit of information on.
Cheers for any input,
Lee
Yes, it is possible with Metro. See the Large Attachments example, which looks like it does what you want.
JAX-WS RI provides support for sending and receiving large attachments in a streaming fashion.
Use MTOM and DataHandler in the programming model.
Cast the DataHandler to StreamingDataHandler and use its methods.
Make sure you call StreamingDataHandler.close() and also close the StreamingDataHandler.readOnce() stream.
Enable HTTP chunking on the client-side.
Stephen Denne has a Metro implementation that satisfies your requirement. My answer is provided below after a short explination as to why that is the case.
Most Web Service implementations that are built using HTTP as the message protocol are REST compliant, in that they only allow simple send-receive patterns and nothing more. This greatly improves interoperability, as all the various platforms can understand this simple architecture (for instance a Java web service talking to a .NET web service).
If you want to maintain this you could provide chunking.
boolean uploadFile(String username, String password, String fileName, int currentChunk, int totalChunks, byte[] chunk);
This would require some footwork in cases where you don't get the chunks in the right order (Or you can just require the chunks come in the right order), but it would probably be pretty easy to implement.
When you use a standardized web service the sender and reciever do rely on the integrity of the XML data send from the one to the other. This means that a web service request and answer only are complete when the last tag was sent. Having this in mind, a web service cannot be treated as a stream.
This is logical because standardized web services do rely on the http-protocol. That one is "stateless", will say it works like "open connection ... send request ... receive data ... close request". The connection will be closed at the end, anyway. So something like streaming is not intended to be used here. Or he layers above http (like web services).
So sorry, but as far as I can see there is no possibility for streaming in web services. Even worse: depending on the implementation/configuration of a web service, byte[] - data may be translated to Base64 and not the CDATA-tag and the request might get even more bloated.
P.S.: Yup, as others wrote, "chuinking" is possible. But this is no streaming as such ;-) - anyway, it may help you.
I hate to break it to those of you who think a streaming web service is not possible, but in reality, all http requests are stream based. Every browser doing a GET to a web site is stream based. Every call to a web service is stream based. Yes, all. We don't notice this at the level where we are implementing services or pages because lower levels of the architecture are dealing with this for you - but it is being done.
Have you ever noticed in a browser that sometimes it can take a while to fetch a page - the browser just keeps cranking away showing the hourglass? That is because the browser is waiting on a stream.
Streams are the reason mime/types have to be sent before the actual data - it's all just a byte stream to the browser, it wouldn't be able to identify a photo if you didn't tell it what it was first. It's also why you have to pass the size of a binary before sending - the browser won't be able to tell where the image stops and the page picks up again.
It's all just a stream of bytes to the client. If you want to prove this for yourself, just get a hold of the output stream at any point in the processing of a request and close() it. You will blow up everything. The browser will immediately stop showing the hourglass, and will display a "cannot find" or "connection reset at server" or some other such message.
That a lot of people don't know that all of this stuff is stream based shows just how much stuff has been layered on top of it. Some would say too much stuff - I am one of those.
Good luck and happy development - relax those shoulders!
For WCF I think its possible to define a member on a message as stream and set the binding appropriately - I've seen this work with wcf talking to Java web service.
You need to set the transferMode="StreamedResponse" in the httpTransport configuration and use mtomMessageEncoding (need to use a custom binding section in the config).
I think one limitation is that you can only have a single message body member if you want to stream (which kind of makes sense).
Apache CXF supports sending and receiving streams.
One way to do it is to add a uploadFileChunk(byte[] chunkData, int size, int offset, int totalSize) method (or something like that) that uploads parts of the file and the servers writes it the to disk.
Keep in mind that a web service request basically boils down to a single HTTP POST.
If you look at the output of a .ASMX file in .NET , it shows you exactly what the POST request and response will look like.
Chunking, as mentioned by #Guvante, is going to be the closest thing to what you want.
I suppose you could implement your own web client code to handle the TCP/IP and stream things into your application, but that would be complex to say the least.
I think using a simple servlet for this task would be a much easier approach, or is there any reason you can not use a servlet?
For instance you could use the Commons open source library.
The RMIIO library for Java provides for handing a RemoteInputStream across RMI - we only needed RMI, though you should be able to adapt the code to work over other types of RMI . This may be of help to you - especially if you can have a small application on the user side. The library was developed with the express purpose of being able to limit the size of the data pushed to the server to avoid exactly the type of situation you describe - effectively a DOS attack by filling up ram or disk.
With the RMIIO library, the server side gets to decide how much data it is willing to pull, where with HTTP PUT and POSTs, the client gets to make that decision, including the rate at which it pushes.
Yes, a webservice can do streaming. I created a webservice using Apache Axis2 and MTOM to support rendering PDF documents from XML. Since the resulting files could be quite large, streaming was important because we didn't want to keep it all in memory. Take a look at Oracle's documentation on streaming SOAP attachments.
Alternately, you can do it yourself, and tomcat will create the Chunked headers. This is an example of a spring controller function that streams.
#RequestMapping(value = "/stream")
public void hellostreamer(HttpServletRequest request, HttpServletResponse response) throws CopyStreamException, IOException
{
response.setContentType("text/xml");
OutputStreamWriter writer = new OutputStreamWriter (response.getOutputStream());
writer.write("this is streaming");
writer.close();
}
It's actually not that hard to "handle the TCP/IP and stream things into your application". Try this...
class MyServlet extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
response.getOutputStream().println("Hello World!");
}
}
And that is all there is to it. You have, in the above code, responded to an HTTP GET request sent from a browser, and returned to that browser the text "Hello World!".
Keep in mind that "Hello World!" is not valid HTML, so you may end up with an error on the browser, but that really is all there is to it.
Good Luck in your development!
Rodney