Where to start with a webapp that is not really a webapp

A

Andrew

I have an app that is currently a Junit test but I want to convert it
to a program that will run 24x7, i.e. a server. The dev env that I am
in means the app uses many, many 3rd party jars. Loads of them. We
also use several frameworks including spring and hibernate. There are
many properties and beans that form part of our lengthly
configuration. I have pointed out that ideally this app would be a
standalone server. In the past I designed such apps with a main
entrypoint and wrote a little shellscript to kick them off using the
java VM with appropriate CLASSPATH settings. However, I have been
asked to make it a webapp. I am looking for help.

There are certain advantages to it being a webapp. Deployment is a
snap, the jar issue is neatly taken care of and I don't need to write
a shellscript either since tomcat will run the app for me. But the
question is "how?". I haven't been doing java very long and working in
webspace is very new to me. My server actually has nothing to do with
the web, the webapp route is purely to simplify deployment and the
general runtime env.

The only other webapps I have seen are either using spring MVC or are
a bean that listens to a JMS queue for ever. I can see how these work.
In the first case tomcat starts the app in response to a URL pattern
match and the entrypoint is the http request for the matching URL. In
the second case the bean is a singleton and starts when tomcat starts.
Since it listens to the JMS queue immediately and never shuts down
there is no problem. My app does not fit into either of these
categories. So what kind of entrypoint would I have? Obviously not a
URL-related one. Does that mean it would have to be done as a
singleton referred to in the bean configuration?

Regards,

Andrew Marlow
 
D

Donkey Hottie

Andrew said:
I have an app that is currently a Junit test but I want
to convert it to a program that will run 24x7, i.e. a
server. The dev env that I am in means the app uses many,
many 3rd party jars. Loads of them. We also use several
frameworks including spring and hibernate. There are many
properties and beans that form part of our lengthly
configuration. I have pointed out that ideally this app
would be a standalone server. In the past I designed such
apps with a main entrypoint and wrote a little
shellscript to kick them off using the java VM with
appropriate CLASSPATH settings. However, I have been
asked to make it a webapp. I am looking for help.

There are certain advantages to it being a webapp.
Deployment is a snap, the jar issue is neatly taken care
of and I don't need to write a shellscript either since
tomcat will run the app for me. But the question is
"how?". I haven't been doing java very long and working
in webspace is very new to me. My server actually has
nothing to do with the web, the webapp route is purely to
simplify deployment and the general runtime env.

The only other webapps I have seen are either using
spring MVC or are a bean that listens to a JMS queue for
ever. I can see how these work. In the first case tomcat
starts the app in response to a URL pattern match and the
entrypoint is the http request for the matching URL. In
the second case the bean is a singleton and starts when
tomcat starts. Since it listens to the JMS queue
immediately and never shuts down there is no problem. My
app does not fit into either of these categories. So what
kind of entrypoint would I have? Obviously not a
URL-related one. Does that mean it would have to be done
as a singleton referred to in the bean configuration?

If it does not have much web style services, I might write it into a
HttpServlet, configuring it to load on startup. A servlet does not have to
serve HTTP requests, but it might, along the other stuff it does.

That might require own Threads, which are considered bad juju with J2EE
containers, but doable.
 
L

Lew

Andrew said:
standalone server. In the past I designed such apps with a main
entrypoint and wrote a little shellscript to kick them off using the
java VM with appropriate CLASSPATH settings.

This doesn't answer your question, but there's a better way to deploy a
standalone app, that is, as an executable JAR.

You put the classpath in the JAR manifest and deliver the related libraries in
a subdirectory (e.g., ./ or lib/) of the JAR deployment directory, then
execute the JAR with "java -jar" (which ignores other classpath settings). No
need for a shell script.
 
J

John B. Matthews

Andrew said:
I have an app that is currently a Junit test but I want to convert it
to a program that will run 24x7, i.e. a server.

If your test is simple and you just want to see the result:

<code>
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** @author John B. Matthews */

public class Test extends HttpServlet {

public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Exec";
out.println("<html>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h2>" + title + ": " + new Date() + "</h2>");
doExec("java org.junit.runner.JUnitCore yourTest", out);
out.println("</body>");
out.println("</html>");
}

private void doExec(String cmd, PrintWriter out) {
String s;
try {
Process p = Runtime.getRuntime().exec(cmd);
// read from the process's stdout
BufferedReader stdout = new BufferedReader (
new InputStreamReader(p.getInputStream()));
while ((s = stdout.readLine()) != null) {
out.println(s + "<br>");
}
// read from the process's stderr
BufferedReader stderr = new BufferedReader (
new InputStreamReader(p.getErrorStream()));
while ((s = stderr.readLine()) != null) {
out.println(s + "<br>");
}
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
out.println("Exit value: " + p.waitFor() + "<br>");
}
catch (Exception e) {
e.printStackTrace(out);
}
}
}
</code>

Not tested; assumes correct classpath; meta refresh optional.

[...]
 
T

Tom Anderson

I have an app that is currently a Junit test but I want to convert it
to a program that will run 24x7, i.e. a server. The dev env that I am
in means the app uses many, many 3rd party jars. Loads of them. We
also use several frameworks including spring and hibernate. There are
many properties and beans that form part of our lengthly
configuration. I have pointed out that ideally this app would be a
standalone server. In the past I designed such apps with a main
entrypoint and wrote a little shellscript to kick them off using the
java VM with appropriate CLASSPATH settings. However, I have been
asked to make it a webapp. I am looking for help.

There are certain advantages to it being a webapp. Deployment is a
snap, the jar issue is neatly taken care of and I don't need to write
a shellscript either since tomcat will run the app for me. But the
question is "how?". I haven't been doing java very long and working in
webspace is very new to me. My server actually has nothing to do with
the web, the webapp route is purely to simplify deployment and the
general runtime env.

The only other webapps I have seen are either using spring MVC or are
a bean that listens to a JMS queue for ever. I can see how these work.
In the first case tomcat starts the app in response to a URL pattern
match and the entrypoint is the http request for the matching URL. In
the second case the bean is a singleton and starts when tomcat starts.
Since it listens to the JMS queue immediately and never shuts down
there is no problem. My app does not fit into either of these
categories. So what kind of entrypoint would I have? Obviously not a
URL-related one. Does that mean it would have to be done as a
singleton referred to in the bean configuration?

Your basic problem is that your app is completely unsuited to being a web
app. The fundamental nature of web components is that they sit there and
respond to web requests. A message-driven bean is similar, but it responds
to JMS messages. Web services respond to SOAP calls. EJBs respond to RMI
calls. Your app doesn't do any responding.

I think, in fact, that there's a mistake in your very first sentence -
needing to run all the time doesn't make it a server. It might make it a
daemon, but it's not serving anyone, so it's not a server. All the J2EE
infrastructure is about serving, so it's not really right for you. I think
the original idea of a standalone app is the right one.

However, it sounds like the need to make it a web app is external - it's
not a design decision, it's a requirement. In which case, a web app it
must be. And since you're talking about MDBs, i assume that by "webapp"
you actually mean "J2EE component".

In which case, the problem is finding something to respond to. My
suggestion would be timer events. See:

http://java.sun.com/javaee/5/docs/tutorial/backup/update3/doc/Session4.html

You can create a recurring timer with:

long intervalInMilliseconds;
TimerService ts;
ts.createTimer(0L, intervalInMilliseconds, null);

Annotate your main method (IYSWIM) with @Timeout. Put the timer creation
in a method annotated with @PostCreate. Then, as soon as the bean gets
loaded, it will go into an infinite loop doing whatever it is it needs to
do.

The only problem then is causing it to be loaded. I don't think the
container will create an instance on deployment - i think the bean has to
be referenced first. I'm not aware of anything you can write in the
deployment descriptor which changes this, but i'm pretty ignorant when it
comes to EJB, really. It would be simple enough to create a client which
connects to the EJB and pokes it over RMI to get it loaded. I don't think
it even has to do RMI, actually - i suspect a JNDI lookup will be enough.
You'd then need to run the client after deploying the component.

Alternatively, rather than creating the timer in a @PostCreate method, put
a start() method on the bean, and do it in there. Have the service-starter
client call that method. You could then add a stop() method which cancels
the timer, in case you decide your loop shouldn't be infinite after all.
You could even then add a status() method, which lets the client app check
whether the component is working properly - that triad of operations is a
pretty common in service-control tools. You often see a restart() too.

A related approach would be to look at something like Quartz, which is a
more sophisticated scheduling service (and funnily enough, which pretends
to be, or perhaps even is, a JMS source, so your job would be an MDB,
getting a message whenever it was time to run). With that, there are ways
of configuring scheduled jobs which wouldn't require you to explicitly
start the service - it would be run automatically as long as it was on the
schedule. JBoss comes with Quartz built in; i don't know about other app
servers.

tom
 
M

Michael Justin

Tom said:
The only problem then is causing it to be loaded. I don't think the
container will create an instance on deployment - i think the bean has
to be referenced first. I'm not aware of anything you can write in the
deployment descriptor which changes this, but i'm pretty ignorant when
it comes to EJB, really. It would be simple enough to create a client
which connects to the EJB and pokes it over RMI to get it loaded. I
don't think it even has to do RMI, actually - i suspect a JNDI lookup
will be enough. You'd then need to run the client after deploying the
component.

A servlet can be configured to load on startup in web.xml, and in the
servlet's init method I could call a 'start' method of a stateless
session bean. This start method can get a TimerService instance using
its context.

How can I use the J2EE Timer Service API in the Servlet startup code?
http://stackoverflow.com/questions/1024081/

I have not done it in the actual test or production environment but I
think that the benefit of moving Java services to a J2EE container is
the availability of common services like JMS and datasources, and also
administration.
 
A

Andrew

This doesn't answer your question, but there's a better way to deploy a
standalone app, that is, as an executable JAR.

You put the classpath in the JAR manifest and deliver the related libraries in
a subdirectory (e.g., ./ or lib/) of the JAR deployment directory, then
execute the JAR with "java -jar" (which ignores other classpath settings)..  No
need for a shell script.

Many thanks for this tip. I think that this is just what I need in
this case. We also have other apps that IMO should be deployed in this
way.
 
A

Andrew

Your basic problem is that your app is completely unsuited to being a web
app. The fundamental nature of web components is that they sit there and
respond to web requests. A message-driven bean is similar, but it responds
to JMS messages. Web services respond to SOAP calls. EJBs respond to RMI
calls. Your app doesn't do any responding.
Yes.

I think, in fact, that there's a mistake in your very first sentence -
needing to run all the time doesn't make it a server. It might make it a
daemon, but it's not serving anyone, so it's not a server.

Er said:
However, it sounds like the need to make it a web app is external - it's
not a design decision, it's a requirement.

Right again!
In which case, a web app it
must be. And since you're talking about MDBs, i assume that by "webapp"
you actually mean "J2EE component".

In which case, the problem is finding something to respond to.

Yes, and this a big unknown. AFAIK there are no plans for any other
process to call us as a web service.
My suggestion would be timer events. See:

http://java.sun.com/javaee/5/docs/tutorial/backup/update3/doc/Session...

You can create a recurring timer with:

long intervalInMilliseconds;
TimerService ts;
ts.createTimer(0L, intervalInMilliseconds, null);

Annotate your main method (IYSWIM) with @Timeout. Put the timer creation
in a method annotated with @PostCreate. Then, as soon as the bean gets
loaded, it will go into an infinite loop doing whatever it is it needs to
do.

This sounds very promising. Many thanks for your help :)
The only problem then is causing it to be loaded. I don't think the
container will create an instance on deployment - i think the bean has to
be referenced first. I'm not aware of anything you can write in the
deployment descriptor which changes this, but i'm pretty ignorant when it
comes to EJB, really. It would be simple enough to create a client which
connects to the EJB and pokes it over RMI to get it loaded. I don't think
it even has to do RMI, actually - i suspect a JNDI lookup will be enough.
You'd then need to run the client after deploying the component.

I cannot see anyone doing this. They talk of web services but really,
I think what they mean is a webapp that will visit a particular URL to
available themselves of some 'service' or other. So far these have
been mainly admin screens. That's not really the case for us.

Alternatively, rather than creating the timer in a @PostCreate method, put
a start() method on the bean, and do it in there. Have the service-starter
client call that method. You could then add a stop() method which cancels
the timer, in case you decide your loop shouldn't be infinite after all.
You could even then add a status() method, which lets the client app check
whether the component is working properly - that triad of operations is a
pretty common in service-control tools. You often see a restart() too.

This sounds to me like what we should do until they make their minds
up.
A related approach would be to look at something like Quartz, which is a
more sophisticated scheduling service

IMO that would be overkill. There are quite enough new technologies
and third party jars in the system without us adding to the problem.

Thanks again for your suggestions.

-Andrew Marlow
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top