I am writing a web app that I want to use to perform FTP tasks (downloads)
I have Apache FTPS server installed in Tomcat and a Java Client ready to initiate the transfers.
The client will be invoked by the Servlet.
For example:
http://laptop:8080/MyServlet?action=download&from=desktop&file=C:/home/fred/file.xml
Would tell the instance on my laptop to download file.xml from my desktop.
EDIT:
Apologies, I never made this very clear.
There will be an FTP server at both ends of this process. 1 on my remote laptop and 1 on my local desktop. So in a nutshell I am submitting an FTP 'get' request to the Servlet on the remote side. The Servlet then kicks off an FTP process to pull the file across.
My Servlet is all set to receive the GET parameters and do the work.
If the file is quite big then each request will take a long time to complete. I want the Servlet resources freed up as quickly as possible.
Ideally I'd like the following things to happen:
User to send URL to Servlet
Servlet to digest the URL and work out what file and where from etc...
Servlet to pass info to a Thread
Servlet to come back with an "In progress" message
Request completes
Thread is still working in the background downloading the file
At this time I'm not too concerned with the Servlet having knowledge of the success of the thread, I just need it to kick one off and forget about it. The FTP process will have separate logging elsewhere for any issues.
I am interested in the concept of creating a Threadpool in the WebApp and fetching a thread from there but again, all examples I've found are old and don't really cater for my level of understanding.
There are a few similar questions on StackOverflow with this being the most similar to what I am asking for but it just hints at something ExecutorService that I have no prior knowledge of. How would I set this up in a WebApp ?
What is recommended way for spawning threads from a servlet in Tomcat
For info,
I have researched this and have found a lot of incomplete examples that require a better understanding than I currently have, or hints towards what is required.
Also a lot of the examples I've read are a few years old, nothing recent. I'm hoping there might be a magical one-liner to do everything I need (doubtful) that has come about in the last year or so :)
I'm new to Threading concepts in Java, I understand Threading in general so appreciate any help you can offer me.
Trevor
I'm not sure I have really understood what you want ...
client server
send request (via HTTP) and wait for
HTTP response
analyse request and find file to send
... (processing)
send HTTP response (1) with ?
opens FTP connection (could not open it before)
receive FTP request (command connection)
send file (data connection)
file is received and saved locally
If the client side is a browser, it should be enough for the response (1) to be a redirect to an URL like ftp://host/path/to/file, because all major browsers know of the FTP protocal and are able to use it to download a file.
The problem is not on server side, you can easily spawn a thread that could acts as a FTP client or (probably harder) as a FTP server, but I cannot imagine better than a redirection on client side : the client has open a HTTP connection than cannot be used for a FTP transfert and it must open a new connection for the FTP request. As it is a new connection, how do you want it to be processed by the thread launched at previous step ? There is no notion of session in FTP and there's no easy way to identify the right request.
Edit per comment:
Ok, I appears that you just want to do defered processing on server after request completion. You have two ways of doing that :
as suggested by you tags, use a worker thread to do the job. Your servlet is plain Java and you can create a thread like you would do in any other Java application. If you are interested in getting later the result of the defered processing, you could give a reference the the session (or simply to a session attribute) to the thread where it will be able to put its advancement and/or completion status. This requires some more boiler plate code but is guaranteed to work (examples below)
you can close the HTTP connection before the servlet returns. It is not explicitely guaranteed per the official servlet specs, but I found it to work at least in tomcat 7. You will find more details on that on this other post Servlet - close connection but not method
Example using simple threads, and storing status in session :
public class ThreadedServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest hsr, HttpServletResponse hsr1) throws ServletException, IOException {
String fileName = null;
// preliminary work ...
Worker worker = new Worker(fileName);
final HttpSession session = hsr.getSession();
synchronized (session) {
List<Status> statuses = (List<Status>) session.getAttribute("statuses");
if (statuses == null) {
statuses = new ArrayList<Status>();
}
statuses.add(new Status(fileName));
}
Thread thr = new Thread(worker);
thr.start();
// write the response either directly or by forwarding to a JSP
}
public static class Status implements Serializable {
private String fileName;
private WStatus status;
public Status(String fileName) {
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public WStatus getStatus() {
return status;
}
public void setStatus(WStatus status) {
this.status = status;
}
}
public enum WStatus {
STARTED,
RUNNING,
COMPLETED
}
private static class Worker implements Runnable {
private String fileName;
private Status status;
public Worker(String fileName) {
this.fileName = fileName;
}
#Override
public void run() {
status.setStatus(WStatus.RUNNING);
// do your stuff ...
status.setStatus(WStatus.COMPLETED);
}
}
}
Related
I have created a JAXRS SERVER for some web services. The server is working just fine, but I need to add a new feature so that I can check the server status at any time. So if the server is up I should return a message like running,and if is down a message like down.
My implementation so far:
public class Server
{
public static void main( final String[] args )
{
final JAXRSServerFactoryBean serverFactory = new JAXRSServerFactoryBean();
final SubscriptionService subscriptionService =
new SubscriptionService( SubscriptionRepo.getRepo() );
final SystemService systemservice = new SystemService();
serverFactory.setResourceProvider(new SingletonResourceProvider(subscriptionService));
serverFactory.setResourceProvider(new SingletonResourceProvider(systemservice));
serverFactory.setAddress( "http://localhost:8888" );
serverFactory.setProvider( JacksonJsonProvider.class );
serverFactory.create();
}
}
I have also created a service class where I want to get the status:
public class SystemService
{
#GET
#Path("/systemstatus")
public Response getSystemStatus()
{
return Response.status( Status.OK.getStatusCode() );
}
}
I really have no idea how can I return a status if the system is running or not.
Can anyone help me with some ideas on how to check the server status?
Your quest kind of collapses on itself when you consider that you're trying to get a response from a web service, that's deployed on a non-responsive web server. How exactly do you envisage your web service getting the word out (by way of a coherent HTTP status, no less), that it's not reachable? How are you even going to get to it in the first place? When the container is down, your service is not in a position to return any meaningful message to the client
Stick to time-tested exception handling in the various flavours of the connection-related SocketException and possibly the HttpRetryException, in some cases. That's all you're going to get when your server is not up: some variety of SocketException. Your REST service has no power here.
I have an android app and a C# web service
I am hosting my web service on IIS Express - nothing fancy just set up the directories.
My android app go to the web service gets the data and then displays it on the screen and repeats this as fast as it can go.
After a while my android app will throw the following exception:
"SoapFault - faultcode: 'soap:Server' faultstring: 'Server was unable to process request. ---> No ports available in the range 10101 to 11100' faultactor: 'null' detail: org.kxml2.kdom.Node#41bdf340"
I have Googled around a bit and have not found anything that will help me.
I ran CurrPorts to watch the ports and it looks like every time the app calls the web service it is using a different port.
They all use port 80 but different remote ports.
The exception is being thrown on the following line of code
"SoapPrimitive response = (SoapPrimitive) _envelope.getResponse();"
If I run IISReset the app will go back to getting data again until sometime thereafter to get the exception mentioned above.
Here is the code for my web service which is just returning a comma separated string (it will do something more interesting just trying to get this working)
Web service code
[WebMethod]
public string GetDefaultResults()
{
return "100,1,0,125.987,124.993,117.904,116.038";
}
Here is the code that my android app uses to call the web service.
I create a new thread and have it call this method then get the string value split it on ',' then put it in a few different TextViews
public class WebService implements Runnable{
private static String NAMESPACE = "http://tempuri.org/";
private static String URL = "http://mymachine/mywebservice/service.asmx";
private static String SOAP_ACTION = "http://tempuri.org/";
private String _soapAndMethod;
private HttpTransportSE _androidHttpTransport;
private SoapSerializationEnvelope _envelope;
private String _methodName;
public WebService(String methodName) {
_methodName = methodName;
_soapAndMethod = SOAP_ACTION + _methodName;
SoapObject request = new SoapObject(NAMESPACE, methodName);
_envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
_envelope.dotNet = true;
_envelope.setOutputSoapObject(request);
_androidHttpTransport = new HttpTransportSE(URL);
}
#Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
}
public String InvokeWebService() {
String resTxt = null;
try {
_androidHttpTransport.call(_soapAndMethod, _envelope);
SoapPrimitive response = (SoapPrimitive) _envelope.getResponse();
resTxt = response.toString();
} catch (Exception e){
e.printStackTrace();
}
return resTxt;
}
}
Any help would be great. Thank you to those who do respond. Is there some setting in IIS I need to change? Is there something I missed in my code?
Additional information:
When the server is responding the webservice request IIS creates a process called w3wp.exe and it this process that is running out of ports.
Doing in a little digging and experimentation the Webservice gets newed up each call to "GetDefaultResults". Which leaves w3wp.exe in a Listening state and they never go away until the iisreset is run.
Some time later it uses the remaining ports available and starts throwing that exception.
Why is it not reusing the same webservice instead of creating a new one each time.
If that is not possible what code do I write in the Webservice to close the connection after it is finished. I put in a hack to cause it close after 5 seconds to see if that would work at least.
It does clean up w3wp.exe but after a short time I start getting this exception on the client.
"expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope (position:START_TAG #2:7 in java.io.InputStreamReader#41beb098) "
so this is not a work around but it helped me understand what the problem is a little better.
protected override void Dispose(bool disposing)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 5000;
timer.Elapsed += timer_Elapsed;
timer.Start();
base.Dispose(disposing);
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Environment.Exit(1);
}
Thanks for your help.
If you failed your first request, you might need to enable IIS Express to allow external connections. In your case, it looks like it only failed after running for a while.
In your question, I see that you
"go to the web service gets the data and then displays it on the screen and repeats this as fast as it can go.
did not call "close" on HttpTransportSE
You might be running out of local ports. Are you reusing the connection on all your requests? If not, try to close it when you are done.
My Webservice was referencing an api to get the values from then pass them over a webservice to the android app.
The problem was that every time the webservice was being called a new reference would be created to the api and after the request was sent it would never close out the port. As soon as I stopped referencing the api everything worked.
A cludge to get this to work is I had the webservice monitor a folder and send the data in the file that was last created. Then created another program to attach to the api and output the data to that folder. Not the most elegant solution but it works as a proof of concept for what I am doing.
Still not entirely sure why the Webservice was never closing the port and I am suspect that the Webservice could not dispose of the reference to the api but I am not really sure.
I'm struggling to wrap my head around what needs to happen here. I'm currently working on an app that runs a service. The service when started opens a webserver that runs in a background thread.
At any point while this service is running the user can send commands to the device from a browser. The current sequence of events is as follows.
User sends request to server
Server sends a message to the service via the msg handler construct, it sends data such as the url parameters
The service does what it wants with the data, and wants to send some feedback message to the user in the browser
?????
The server's response to the request contains a feed back message from the service.
The way my functions are set up I need to pause my serve() function while waiting for a response from the service and then once the message is received resume and send an http response.
WebServer.java
public Response serve( String uri, String method, Properties header, Properties parms, Properties files )
{
Bundle b = Utilities.convertToBundle(parms);
Message msg = new Message();
msg.setData(b);
handler.sendMessage(msg);
//sending a message to the handler in the service
return new NanoHTTPD.Response();
}
CommandService.java
public class CommandService extends Service {
private WebServer webserver;
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
execute_command(msg.getData());//some type of message should be sent back after this executes
};
Any suggestions? Is this structure the best way to go about it, or can you think of a better design that would lead to a cleaner implementation?
I think the lack of answers is because you haven't been very specific in what your question is. In my experience it's easier to get answers to simple or direct questions that general architecture advice on StackOverflow.
I'm no expert on Android but I'll give it a shot. My question is why you have a Webservice running in the background of a Service, why not just have one class, make your Service the Webservice?
Regarding threading and communication and sleeping, the main thing to remember is that a webserver needs to always be available to serve new requests, whilst serving current requests. Other than that, it's normal that a client will wait for a thread to complete its task (i.e. the thread "blocks"). So most webservers spawn new a thread to handle each request that comes in. If you have a background thread but you block the initial thread while you wait for the background thread to complete its task, then you're no better off than just completing everything on the one thread. Actually, the latter would be preferable for the sake of simplicity.
If Android is actually spawning new threads for you when requests come in, then there's no need for a background thread. Just do everything synchronously on one thread and rejoice in the simplicity!
I'm developing a multithreaded web server for an android app and I've some problems with a page that uses an external .css file, and a .js file, but only with Google Chrome! With Firefox and Opera the page is rendered fine, with Google Chrome sometimes the .css is loaded, sometimes the .js, sometime both or neither.
This is my app's structure:
WebServer.java
class WebServer implements Runnable{
protected boolean ON;
public void start(){
if(!ON){
ON=true;
thread=new Thread(this,"WebServer");
thread.start(); }}
public void run(){
while(ON){
listenSocket = new ServerSocket(port);
Socket connectionSocket = listenSocket.accept();
Thread t = new Thread(new Client(connectionSocket));
t.start();
listenSocket.close();}
}}
Client.java
class Client implements Runnable {
public void start(){
thread=new Thread(this,"Client");
thread.start();}
public void run(){
//parse the request and send a file
}
}
myApp.java
public class myApp extends Activity{
onCreate(){
WebServer ws=new WebServer(8080);
}
onClick(){
...
ws.start();
}}
When I click a button on the activity, it call webserver.start(); In my opinion google chrome sends more requests concurrently and there's a problem with threads...
Can you help me?
[EDIT]
I had forgotten to write the loop in the run() method in the question
[EDIT 2]
I just tried with an other pc, and there are problems also with firefox..
There is a general misunderstanding of the thread mechanism in your code.
A runnable has to override run. Not start. The run() method of the runnable will be called when the nesting thread will be started. In other words, the start method of your client will never be used, and hope fully, as it would create a thread inside a thread.. not very usefull.
Redesign your webser so that, :
it's start method starts a new nesting thread as you did
it's run method does the following
your webserver binds to a port
in a loop : accept new connections and start new client thread for each.
the loop could be controlled by a boolean flag that you could rise to stop the server (ON would fit, even if the name of this variable doesn't follow java naming conventions and is rather poor semanticly speaking)
then each client would, in it's run (no more start method) :
read data from socket input stream
reply on socket outputstream
briefly, implement http protocole.
You could find some java code to inspire you on the web, some examples are well documented. Also, you could consider using java.nio package that is maybe less effective for a single request but much more effective at handling massive multiple connections. But code is harder.
You should consider reading more about runnables and also consider reading some stuff about synchronized key word to ensure that your web server doesn't start twice a connection for the same client or get confused in case of simultaneous requests.
Regards,
Stéphane
I first need to apologize for my earlier questions. (You can check my profile for them)They seemed to ask more questions than give answers. Hence, I am laying down the actual question that started all them absurd questions.
I am trying to design a chat applet. Till now, I have coded the applet, servlet and communication between the applet and the servlet. The code in the servlet side is such that I was able to establish chatting between clients using the applets, but the code was more like a broadcast all feature, i.e. all clients would be chatting with each other. That was my first objective when I started designing the chat applet. The second step is chatting between only two specific users, much like any other chat application we have. So this was my idea for it:
I create an instance of the servlet that has the 'broadcast-all' code.
I then pass the address of this instance to the respective clients.
2 client applets use the address to then chat. Technically the code is 'broadcast-all', but since only 2 clients are connected to it, it gives the chatting between two clients feature. Thus, groups of 2 clients have different instances of the same servlet, and each instance handles chatting between two clients at a max.
However, as predicted, the idea didn't materialize!
I tried to create an instance of the servlet but the only solution for that was using sessions on the servlet side, and I don't know how to use this session for later communications.
I now know how to use the request.getSession(). So I set the session for an applet in its param tag and use it for further communications with the servlet. But how do I use this data to establish chatting between two clients? As I wrote earlier, I have the code for broadcast_all chatting as follows:
public class CustomerServlet extends HttpServlet {
public String getNextMessage() {
// Create a message sink to wait for a new message from the
// message source.
return new MessageSink().getNextMessage(source);
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ObjectOutputStream dout = new ObjectOutputStream(response.getOutputStream());
String recMSG = getNextMessage();
dout.writeObject(recMSG);
dout.flush();
}
public void broadcastMessage(String message) {
// Send the message to all the HTTP-connected clients by giving the
// message to the message source
source.sendMessage(message);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
ObjectInputStream din= new ObjectInputStream(request.getInputStream());
String message = (String)din.readObject();
ObjectOutputStream dout = new ObjectOutputStream(response.getOutputStream());
dout.writeObject("1");
dout.flush();
if (message != null) {
broadcastMessage(message);
}
// Set the status code to indicate there will be no response
response.setStatus(response.SC_NO_CONTENT);
} catch (Exception e) {
e.printStackTrace();
}
}
MessageSource source = new MessageSource();
}
class MessageSource extends Observable {
public void sendMessage(String message) {
setChanged();
notifyObservers(message);
}
}
class MessageSink implements Observer {
String message = null; // set by update() and read by getNextMessage()
// Called by the message source when it gets a new message
synchronized public void update(Observable o, Object arg) {
// Get the new message
message = (String)arg;
// Wake up our waiting thread
notify();
}
// Gets the next message sent out from the message source
synchronized public String getNextMessage(MessageSource source) {
// Tell source we want to be told about new messages
source.addObserver(this);
// Wait until our update() method receives a message
while (message == null) {
try {
wait();
} catch (Exception e) {
System.out.println("Exception has occured! ERR ERR ERR");
}
}
// Tell source to stop telling us about new messages
source.deleteObserver(this);
// Now return the message we received
// But first set the message instance variable to null
// so update() and getNextMessage() can be called again.
String messageCopy = message;
message = null;
return messageCopy;
}
}
On the applet side, I have a thread that will connect to the servlet above using GET method to get new messages. It uses a while loop, and blocks until it gets a message from the servlet. The main thread communicates with the servlet using POST method whenever the client has entered the message. Currently all clients chat with everyone. I want to use the same methods used above (or if possible any other way) to establish chatting between two clients and two clients only. I could possibly have another thread in the applet to check if any other user wishes to chat with it and then exchange some data so that only those two user chat...
I then tried to modify my broadcast-all code. In that code, I was using classes that implemented Observer and Observable interfaces. So the next idea that I got was:
Create a new object of the Observable class(say class_1). This object be common to 2 clients.
2 clients that wish to chat will use same object of the class_1.
2 other clients will use a different object of class_1.
But the problem here lies with the class that implements the Observer interface(say class_2). Since this has observers monitoring the same type of class, namely class_1, how do I establish an observer monitoring one object of class_1 and another observer monitoring another object of the same class class_1 (Because notifyObservers() would notify all the observers and I can't assign a particular observer to a particular object)?
I first decided to ask individual problems, like how to create instances of servlets, using objects of observable and observer and so on in stackoverflow... but I got confused even more. Can anyone give me an idea how to establish chatting between two clients only?(I am using Http and not sockets or RMI).
Regards,
Mithun.
P.S. Thanks to all who replied to my previous (absurd) queries. I should have stated the purpose earlier so that you guys could help me better.
You need to store all connected users in a Map<String, User> in the application scope using ServletContext#setAttribute(). The String denotes the unique user identifier (chat nickname?). You need to store the specific chat User as well in the session scope using HttpSession#setAttribute(). You also need to store the other user in individual chats in a Map<String, User> in the session scope of the users in question. You can obtain the attribute by the getAttribute() method.
This way you know which users are all available and which user is in the current session and with which users it is individually chatting.
This is a crude way to do it, but I just couldn't find a feasible solution. What I did was that I made all users connect to the servlet that had the broadcastAll code. Each user would be aware of which other user it is chatting with. Hence, while sending a message, the user would append his name and the name of the user that he is chatting with to the message. Since it is a broadcastAll code, every connected user would receive the message. After receiving the message, the user would parse the message to get the user who sent the message, and the name of the user for whom the message was intended. It would compare these two names with its records - see the statement in bold earlier. If matched it would display the message, else ignore it.
Again, its a crude way to do it and I am sure there are better solution out there.