tags:

views:

110

answers:

4

I have the data for my webapp in a database that is accessed differently from different places. There is no generic code that can just do it for both. So I want to know at run time which env I am in. In fact, the code to run really depends on whether it is run within or without tomcat, so I would like to detect this at runtime. How do I do this?

+2  A: 

This doesn't sound like something that the code should have to detect. Placing the burden of detecting an environment and acting differently within the same class is usually a less-than-ideal idea. If things need to be done differently, you should make a couple of different data access classes (which implement the same interface, and maybe share common code in an abstract class they both extend). Then, your web servlet would instantiate and use one class for its database access, and your non-web code would instantiate the other class for database access.

If for some reason you REALLY need to detect whether or not you're in the web abb within a single class, I suppose a somewhat clean way might be to set a System property when the server runs (I think it's -D command line option), and then look for that being set in your class. If it is, do the web logic, otherwise do the non-web logic.

Kaleb Brasee
+1 There should really be a web-class and a non-web-class
Juergen Hartelt
Whether I am making one class act differently or using two classes is completely beside the point. The decision must be made at run-time regardless and I want to know how to do this. I already guessed there could be a system property, but what is it?
Matt Roberts
You can name the system property whatever you want, and check for that. And running in a web container is not completely beside the point, because you'd be using a servlet class when you're running in the web context, and a regular class when you're not. Unless you're using a servlet class in a non-web context, which doesn't make a lot of sense.
Kaleb Brasee
+2  A: 

I would agree with kbrasee that this isn't a great situation to be in, so if you can I would get out it if possible.

That said, assuming you have no choice and need to do this, they do it in the Liferay implementation. Have a look at the ServerDetector class

You'll notice in the _detect method (near the bottom) that they look for a class that they have determined is present if it is running in the given server. They define the classes at the top in the TOMCAT_BOOTSTRAP_CLASS and TOMCAT_EMBEDDED_CLASS constants.

We had a problem with it detecting the embedded tomcat within glassfish. I'm not sure if that's fixed in the version I linked to, but it may not be a problem for you.

digitaljoel
Thankyou, this is what I needed, and I never would have thought of that myself! I knew it was worth asking :)
Matt Roberts
no problem. glad it helped.
digitaljoel
A: 

If this is not for a quick hack right now, but for a long term solution then please notice that any heuristic you choose to make a decision which has not been put in an API stone, will eventually break. The whole point of OSGi is to hide unrelated parts of the stuff in the JVM from each other.

I think for this particular situation the best way to see if you are inside Tomcat or not, is to see if there is a JNDI environment available. If not, you are in a stand alone environment, if there is then you are inside Tomcat.

Thorbjørn Ravn Andersen
Thankyou, another good suggestion. I wish I could tag two answers :) Always looking for long term solutions but happy enough to drop back to a hack if that is how to make it work.
Matt Roberts
+1  A: 

Well, all the well heeded warning aside, I would like to throw my $0.02 in the discussion.

I think ServerDetector uses the presence of a particular class on the system classpath to determine the type of running server is a little flawed: what if the jar containing the class just happened to be on the classpath but is not used? I propose a different method of detecting the running server by using stack trace elements. It might not be perfect but I think it's better than detecting the presence of some class on the classpath.

Here it is in Scala:

def inTomcat: Boolean = (new Throwable).getStackTrace.exists(_.getClassName.startsWith("org.apache.catalina"))
Walter Chang
You make a good point Walter. The problem you bring up is the problem we encountered with liferay in glassfish (for the record I'm not associated with liferay other than as a user). Glassfish is using tomcat as it's servlet engine, but the server is glassfish, not tomcat. The tomcat specific code was then getting executed because the tomcat check took place before the glassfish check and both classes are in the classpath. I believe your method would also be susceptible to this bug.
digitaljoel
@digitaljoel What you need to do in this case is to throw an arbitrary RuntimeException in your servlet code and pick out a Glassfish class high on the call path and check against that.
Walter Chang
Right. What I'm saying is that the LifeRay code had a problem in that it was checking for the Tomcat class before checking for the Glassfish class. Then, because it found the Tomcat class, it assumed Tomcat as the server and didn't check anything else, so it's important that you get the checks in the right order. In this case, you would need to check for Glassfish before checking for Tomcat, or at least understand the situation so the check is intelligent enough to account for it.
digitaljoel