On Mar 15, 2013, at 2:15 PM, Christopher Schultz wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
> 
> Nick,
> 
> On 3/13/13 2:19 PM, Nicholas Williams wrote:
>> On Wed, Mar 13, 2013 at 12:10 PM, Christopher Schultz 
>> <ch...@christopherschultz.net> wrote:
>>> You mean addWebapp methods? They seem fairly self-explanatory.
>> 
>> Yes. I meant addWebapp methods. That was a typo.
>> 
>> There are three of them. Only one is documented. Unfortunately,
>> the other two are not "self explanatory." I have no idea what the
>> "url," "path," and "name" parameters are (although "host" makes
>> sense). The documentation for the lone method that IS documented
>> only has "contextPath" and "baseDir" ... that doesn't line up with
>> the other two methods.
> 
> Yup, it's ugly.
> 
>>> Tomcat.addWebapp(String,String) says that the first argument is
>>> the context path. The context path for the ROOT webapp is "", not
>>> "/".
>> 
>> I didn't know this. I will change it. By the way, I got this code
>> from the tutorial at 
>> https://devcenter.heroku.com/articles/create-a-java-web-application-using-embedded-tomcat.
> 
> They
>> 
> should probably update their HOWTO: "/" isn't a valid context
> path, though it might actually work since "//" ~= "/" in the URL world.

Yep.

> 
>>> The second argument is a "baseDir" which says (via 
>>> Context.setDocBase) it can be an absolute pathname, a relative 
>>> pathname (to the cwd I suppose, or maybe relative to the hosts's 
>>> appbase), or a URL.
>> 
>> Well there's part of the problem with the documentation. The 
>> documentation for the method says "Add a webapp using normal 
>> WEB-INF/web.xml if found." and the documentation for the "baseDir" 
>> parameter says nothing. There's no information here that would
>> have led me to look at the Context#setDocBase() method. Nada. I
>> will try out making it a URL.
> 
> I was reading the code, not the Javadoc: it makes it a lot easier.
> Since the "baseDir" gets passed into Context.setDocBase, I read the
> javadoc for that method to get the real story.

That's how I ended up getting it running: I starting reading code instead of 
documentation.

> 
>>> You are passing a relative path name which probably won't
>>> resolve to a resource "inside" the JAR file you are using. Try
>>> fetching a resource URL for the "web/" path from the ClassLoader
>>> and pass that instead of just "web/".
>> 
>> I will give this a try.
>> 
>>> You didn't say what actually happens: just stated your
>>> requirements and showed your code. Does Tomcat fail to start?
>>> Does it fail to listen on your port? Does it fail to respond to
>>> requests?
>> 
>> My bad. I'm always seeing y'all tell people to explain the
>> problem, and here I go not explaining the problem just like all the
>> rest of them. :-P ... When I ran the application using the batch
>> file generated by the mojo plugin, almost everything was good
>> (Tomcat started up, started listening on the right port, found all
>> the classes it was supposed to find, etc.). However, I got a
>> "severe" error that the web application directory
>> (webAppDirLocation) did not exist and the application could not be
>> deployed. Understandable, since I didn't know what to use for
>> this.
> 
> The likely problem is that your appBase was just "web" and Tomcat was
> trying to load that from the disk (directly) instead of looking inside
> your JAR file. Using a JAR-URL (which the ClassLoader should give you)
> should work. The URL should look something like /path/to/your.jar!/web
> or something like that.

I tried using a JAR URL. (If I remember correctly, it ended up looking 
something like 
jar:url://C:/Users/Nicholas/Desktop/Project/target/Test.jar!/Test.war.) I tried 
it as both a directory and a WAR file. Tomcat did not like it. It said "Could 
not deploy web application to [temporary webapps directory location]" or 
something like that. I ended up, at runtime, extracting the war file from the 
JAR file to a temporary directory and deploying from there. That worked great, 
and it's how the Tomcat Maven plugin executable war works, too.

> 
>>>> tomcat.start();
>>> 
>>> You should probably call tomcat.init() first, though some of the 
>>> Tomcat test cases don't do it so you're probably okay.
>> 
>> Yea, the tutorial I was using didn't say anything about that. 
>> Interesting that "init" and "start" are separate. If "init" was 
>> required and "start" didn't call "init" I would think that "start" 
>> would throw an IllegalStateException. Since it doesn't, my guess
>> is that calling "start" is sufficient, though I will certainly add 
>> "init." I would love to now the semantic difference between "init"
>> and "start." The documentation just says "Initialize the server"
>> and "Start the server."
> 
> Take a look at the Javadoc for LifecycleListener, one of the
> interfaces that the Tomcat class implements. The Javadoc for any
> implemented yet not documented method from that interface gets
> inherited in the javadoc for the implementation class, but the
> interface-level documentation is, of course, ignored. Go look at the
> javadoc for that interface and you'll see some nice ASCII art that
> describes the full lifecycle.

Yep. Found that. Last time I saw ASCII art was the late 1990s or something. ;-)

> 
>>>> tomcat.getServer().await(); } }
>>> 
>>> I don't think you configured any logging. You might want to set
>>> up something to at least dump to the console, and crank-up the
>>> log level to DEBUG or something like that. Then you might be able
>>> to see what Tomcat is actually doing.
>> 
>> It does seem to automatically dump to the console automatically. I
>> got plenty of messages, most of them good (listening on 8973,
>> etc.). I will look into logging more, of course. This was just a
>> first pass at proof-of-concept.
> 
> Cool. Obviously, you're going to want to log to a log file eventually.
> If you configure commons-logging at the top-level (that is, your own
> code), I think everything will flow through that.

Yep. I used the standard logging.properties that ships with Tomcat and got 
Tomcat logging to a temporary directory I set up. Works great now.

> 
>> Since sending this email, I've discovered the "Executable WAR" [2] 
>> capability of the Tomcat Maven plugin. I'm kind of confused about
>> the difference between Embedded Tomcat and Executable WAR. Which
>> one do I need? Will they both do what I need, but one might be
>> better than the other based on more exact requirements?
> 
> I dunno anything about the Tomcat Maven plugin, but I think that an
> executable WAR file is exactly what you are trying to build.

It is. There are some issues (not bugs) with the Tomcat Maven plugin executable 
war, the first one being that it's not very easy to customize without using 
command-line arguments (makes it kind of hard to "double-click" and run the 
executable war effectively). Also, while there are snapshots for the Tomcat 8.0 
embedded artifacts, there is no Tomcat 8.0 version of the Tomcat Maven plugin 
yet, so I literally can't use it. I ended up using a few maven modules and the 
embedded Tomcat artifacts to create my own executable WAR. Working great now.

> 
>> This may be premature (getting it working is my priority), but I 
>> should mention that performance is important to what I'm doing
>> here. I'd like to enable the native code. Some applications and
>> libraries include native DLLs/SOs/JNILIBs in their JAR files, copy
>> them to a temporary directory at runtime and load them from the
>> temporary location (to avoid having to actually "install" the
>> native libraries in the OS or JVM directory structure). Is there a
>> way to do this with an embedded/executable Tomcat application so
>> that the Tomcat classes can take advantage of the native library?
> 
> I'm almost sure Java won't load a shared library out of a JAR file, so
> you'll have to use this same technique: extract some shared libraries
> out of your JAR file and throw them into java.io.tmpdir/pid/shared/*
> or whatever and then instruct the JVM to load them from there (or
> modify the java.library.path system property to point to that and let
> them load naturally).

Yea. I got that working. Embedded the DLLs in the JAR file and then extracted 
at runtime. Learned a lot about how Tomcat loads the native library and filed 
and created a patch for improvement request #54700 as a result. This is a 
prototype for now, but if we use it for real we'll probably compile and include 
statically-linked Linux .so and Mac .jnilib files as well, and let the other 
platforms just run without APR.

> 
> Just be aware that if you want an executable JAR/WAR that will run
> anywhere, you'll have to bundle all possible combinations of
> architecture, OS, etc. in order to rely on APR (and it will be a
> mess). If you provide a statically-linked tcnative (includes APR and
> OpenSSL), you may be able to survive this process, but if you want to
> support shared libraries, you're in for a world of hurt.

Understood.

> 
> Also, if APR doesn't load for some reason, you'll have to configure
> your SSL Connectors completely differently (using trustStore instead
> of SSLCertificateKeyFile, etc.), which could be a real pain.

Not using SSL, so not concerned here.

> 
> As for performance itself, you may not actually need APR: if you need
> SSL, then APR is probably the way to go. If you don't need SSL, stick
> to the NIO connector which provides comparable performance (from the
> testing I've done). I dunno if APR provides a faster PRNG than
> whatever the JVM provides, but I believe the AprLifecycleListener
> configures Tomcat to use the OpenSSL PRNG which may have some
> advantages -- I don't actually know.

Interesting. My reading on the Tomcat site seemed to indicate APR was better in 
ALL cases, not just OpenSSL. I will keep this in mind.

> 
> If it were me, I'd forget about tcnative entirely.

Thanks. Consider me advised.
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to