I added a sample that shows a very simple JSP/HTML5 boilerplate site that works on desktops and phones. Need to expand it.
Just follow the link from the top menu to get to github.
Anyone who wants to contribute, just e-ping me.
"Random Acts" is a blog about things of interest, software, technology, religion (or the lack of it), politics and philosophy
Showing posts with label Jetty. Show all posts
Showing posts with label Jetty. Show all posts
Sunday, 27 May 2012
Wednesday, 11 January 2012
Stopping and/or Restarting an embedded Jetty instance via web call
I had a need to allow a web call to stop and restart an embedded Jetty instance.
So basically, I need to have something like this:
curl -v http://localhost:9103/some/path # Calls a handler and does something RESTful curl -v http://localhost:9103/stop # Stops the Jetty instance curl -v http://localhost:9103/restart # Restarts the Jetty instance
First up create a main class:
package com.company; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.RequestLogHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EmbeddedJetty { private static Logger log = LoggerFactory.getLogger(EmbeddedJetty.class); public static void main(String[] args) throws Exception { while (true) { // Realistically all parameters should be read from some external file... log.info("Starting Jetty on port 9103"); Server server = new Server(9103); HandlerCollection handlers = new HandlerCollection(); ContextHandlerCollection contexts = new ContextHandlerCollection(); // I added this to show how to add access logs to an embedded server. RequestLogHandler requestLogHandler = new RequestLogHandler(); NCSARequestLog requestLog = new NCSARequestLog("/tmp/jetty-yyyy_mm_dd.request.log"); requestLog.setAppend(true); requestLog.setExtended(true); requestLog.setLogTimeZone("UTC"); requestLogHandler.setRequestLog(requestLog); // We want the server to gracefully allow current requests to stop server.setGracefulShutdown(1000); server.setStopAtShutdown(true); // Now add the handlers YourHandler yourHandler = new YourHandler(server); handlers.setHandlers(new Handler[]{contexts, yourHandler, requestLogHandler}); server.setHandler(handlers); // Start the server server.start(); server.join(); // It's stopped. log.info("Jetty stopped"); if (!yourHandler.restartPlease) { break; } log.warn("Restarting Jetty"); } } }
Now the handler:
package com.company; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class YourHandler extends AbstractHandler { private static Logger log = LoggerFactory.getLogger(YourHandler.class); private Server server = null; public Boolean restartPlease = false; public YourHandler(Server server) { this.server = server; } private boolean stopServer(HttpServletResponse response) throws IOException { log.warn("Stopping Jetty"); response.setStatus(202); response.setContentType("text/plain"); ServletOutputStream os = response.getOutputStream(); os.println("Shutting down."); os.close(); response.flushBuffer(); try { // Stop the server. new Thread() { @Override public void run() { try { log.info("Shutting down Jetty..."); server.stop(); log.info("Jetty has stopped."); } catch (Exception ex) { log.error("Error when stopping Jetty: " + ex.getMessage(), ex); } } }.start(); } catch (Exception ex) { log.error("Unable to stop Jetty: " + ex); return false; } return true; } @Override public void handle(String string, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String pathInfo = request.getPathInfo(); // THIS SHOULD OBVIOUSLY BE SECURED!!! if ("/stop".equals(pathInfo)) { stopServer(response); return; } if ("/restart".equals(pathInfo)) { restartPlease = true; stopServer(response); return; } // Go off and do the rest of your RESTful calls... // And close off how you please response.sendRedirect("http://nowhere.com"); } }
And you can now run your main class from your IDE of choice.
Just for reference I added a log4j.properties:
# Site log4j.logger.com.company=DEBUG, SITE_CONSOLE log4j.additivity.com.company=false # Set root logger level log4j.rootLogger=DEBUG, CONSOLE log4j.logger.org.eclipse=INFO, CONSOLE log4j.additivity.org.eclipse=false # --------------------------------------------------------------------------------- # Appenders - Notice I have added a discriminator to the conversion pattern # --------------------------------------------------------------------------------- # For console logging - not in production obviously as you'd use a rolling file appender log4j.appender.SITE_CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.SITE_CONSOLE.layout=org.apache.log4j.EnhancedPatternLayout log4j.appender.SITE_CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS}{UTC} SITE %-5p [%t] %c{1.} %x - %m%n # The baseline CONSOLE logger log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.EnhancedPatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS}{UTC} JETTY %-5p [%t] %c{1.} %x - %m%n
I created a plain Java SE app and added a 'lib' folder with these jars in it:
jetty-continuation-8.0.4.v20111024.jar jetty-http-8.0.4.v20111024.jar jetty-io-8.0.4.v20111024.jar jetty-server-8.0.4.v20111024.jar jetty-servlet-8.0.4.v20111024.jar jetty-servlets-8.0.4.v20111024.jar jetty-util-8.0.4.v20111024.jar jetty-webapp-8.0.4.v20111024.jar log4j-1.2.16.jar servlet-api-3.0.jar slf4j-api-1.6.2.jar slf4j-log4j12-1.6.2.jar
From the Jetty8 release.
I then ensured that the MANIFEST included these jars.
Just for reference the META-INF/MANIFEST.MF looks like this:
cat META-INF/MANIFEST.MF Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.2 Created-By: 1.6.0_29-b11-402-10M3527 (Apple Inc.) Class-Path: lib/jetty-all-8.0.4.v20111024-javadoc.jar lib/jetty-contin uation-8.0.4.v20111024.jar lib/jetty-http-8.0.4.v20111024.jar lib/jet ty-io-8.0.4.v20111024.jar lib/jetty-server-8.0.4.v20111024.jar lib/je tty-servlet-8.0.4.v20111024.jar lib/jetty-servlets-8.0.4.v20111024.ja r lib/jetty-util-8.0.4.v20111024.jar lib/jetty-webapp-8.0.4.v20111024 .jar lib/log4j-1.2.16.jar lib/servlet-api-3.0.jar lib/slf4j-api-1.6.2 .jar lib/slf4j-log4j12-1.6.2.jar X-COMMENT: Main-Class will be added automatically by build Main-Class: com.company.EmbeddedJetty
I know I included the javadoc un-intentionally...
This scheme requires a lib folder alongside the jar with those files in it.
(Need to figure out how to bundle the Jetty8 jars so that the app is self-contained...)
So the jar can be started like this:
java -jar /some/folder/EmbeddedJetty/dist/EmbeddedJetty.jar
K
Thursday, 1 December 2011
Hosting multiple Jetty instances each with multiple ports!
I had a requirement to fulfill.
On the web tier I needed multiple instances of Jetty.
Each of these must have each webapp running on a different port.
And on the app tier the same.
So for example:
web tier: /opt/jetty91xx web-app-1 running on port 9101 web-app-2 running on port 9102 web-app-3 running on port 9103 /opt/jetty92xx web-app-4 running on port 9201 web-app-5 running on port 9202 web-app-6 running on port 9203 app tier: /opt/jetty94xx web-app-7 running on port 9401 web-app-8 running on port 9402 web-app-9 running on port 9403 /opt/jetty95xx web-app-10 running on port 9501 web-app-11 running on port 9502 web-app-12 running on port 9503It's not as fiddly as that in reality, but the reason was to have sets of apps running in the same VM that are 'associated'.
So... How to do it?
Easy.
I'll use the jetty91xx example for the explanation below.
First go get the latest release of jetty and unpack it into /opt/jetty-latest or whatever.
Then create /opt/jetty91xx and copy the entire contents of /opt/jetty-latest into it effectively creating a clone.
So now we switch the /opt/jetty91xx.
(If you're on Mac OS-X you need to do a "mkdir work" in the folder to avoid OS-X /tmp/nasties)
Edit the etc/jetty.xml.
Part the way down is an <call name="addConnector">...</call>.
Comment this out.
Above it add this:
<set name="connectors"> <array type="org.eclipse.jetty.server.Connector"> <item> <new class="org.eclipse.jetty.server.nio.SelectChannelConnector" id="conn9101"> <set name="port">9101</set> <set name="maxIdleTime">30000</set> <set name="Acceptors">1</set> <set name="name">conn9101</set> </new> </item> <item> <new class="org.eclipse.jetty.server.nio.SelectChannelConnector" id="conn9102"> <set name="port">9102</set> <set name="maxIdleTime">30000</set> <set name="Acceptors">1</set> <set name="name">conn9102</set> </new> </item> <item> <new class="org.eclipse.jetty.server.nio.SelectChannelConnector" id="conn9103"> <set name="port">9103</set> <set name="maxIdleTime">30000</set> <set name="Acceptors">1</set> <set name="name">conn9103</set> </new> </item> </array> </set>Ok. Your connectors are in and named.
Now go off and prepare your war files.
For simple example purposes I will assume you have port.9100.war, port.9101.war and port.9102.war.
Create contexts/port.9101.xml and put this in it:
<configure class="org.eclipse.jetty.webapp.WebAppContext"> <set name="contextPath">/port.9101</set> <set name="war"><systemproperty default="." name="jetty.home">/webapps/port.9101.war</systemproperty></set> <set name="extractWAR">true</set> <set name="copyWebDir">false</set> <set name="defaultsDescriptor"><systemproperty default="." name="jetty.home">/etc/webdefault.xml</systemproperty></set> <set name="connectorNames"><array type="String"><item>conn9101</item></array></set> </configure>Create contexts/port.9102.xml and contexts/port.9103.xml in the same manner changing the contextPath, war name and connectorNames.
Now start the instance:
/usr/bin/java -Djetty.home=/opt/jetty91xx -Djava.io.tmpdir=/tmp \ -Xms1024M -Xmx1024M -Xmn640M -Xss128k \ -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC \ -XX:+CMSIncrementalMode -XX:SurvivorRatio=8 \ -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 \ -Dcom.sun.management.jmxremote.port=9876 \ -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.authenticate=false \ -DOPTIONS=server,security,servlet,xml,webapp,deploy,jmx,requestlog \ -jar /opt/jetty91xx/start.jar \ --pre=etc/jetty-logging.xml \ --daemonYou will need to change -Djetty.home and the '-jar' option for each instance.
Also I've given a full path here with a bunch of options.
Normally you would use /etc/init.d/jetty91xx.sh start of course.
Tip: While trying this out, leave of the --daemon and you can stop and start jetty by using ^c.
Ok. You should be able to drop the 3 war files into the webapps folder now.
And then...
http://[whatever]:9101/port.9101 http://[whatever]:9102/port.9102 http://[whatever]:9103/port.9103And they'll all be running in the same VM.
You can then create a new /opt/jetty92xx and start agin.
Tuesday, 18 October 2011
Jetty8 Snow Leopard org.apache.jasper.JasperException: PWC6033: Error in Javac compilation for JSP
Argh!
I have a dinky app with an index.jsp.
Create a war and deploy to Tomcat on Snow Leopord.
No problem.
Create a war and deploy to Tomcat on Ubuntu.
No problem.
Deploy to GF3 on Snow Leopard.
No problem.
Deploy to GF3 on Ubuntu.
No problem.
Deploy to Jetty7 or Jetty8 on Ubuntu.
No problem.
Deploy to Jetty7 or Jetty 8 on Snow Leopard and:
The thing that should ring alarm bells is that /private/var/folders... stuff.
The trick is to:
That's it.
It's that retar... er... *unique* /tmp folder that seems to be causing the problem.
You could set the java.io.tmpdir to something meaningful as well.
See: http://wiki.eclipse.org/Jetty/Reference/Temporary_Directories for more information.
I have a dinky app with an index.jsp.
Create a war and deploy to Tomcat on Snow Leopord.
No problem.
Create a war and deploy to Tomcat on Ubuntu.
No problem.
Deploy to GF3 on Snow Leopard.
No problem.
Deploy to GF3 on Ubuntu.
No problem.
Deploy to Jetty7 or Jetty8 on Ubuntu.
No problem.
Deploy to Jetty7 or Jetty 8 on Snow Leopard and:
Oct 17, 2011 5:37:49 PM org.apache.jasper.compiler.Compiler generateClass
SEVERE: Error compiling file: /private/var/folders/dd/dd3VsetWHLuS+PT+sxCe+k+++TI/-Tmp-/jetty-0.0.0.0-8083-com.myapp.war-_com.myapp-any-/jsp/org/apache/jsp/index_jsp.java
424497 [qtp1681653767-16] WARN org.eclipse.jetty.servlet.ServletHandler - /com.myapp/
org.apache.jasper.JasperException: PWC6033: Error in Javac compilation for JSP
PWC6199: Generated servlet error:
string:///index_jsp.java:6: package com.myapp does not exist
PWC6199: Generated servlet error:
string:///index_jsp.java:7: package com.myapp does not exist
PWC6197: An error occurred at line: 10 in the jsp file: /index.jsp
PWC6199: Generated servlet error:
string:///index_jsp.java:52: cannot find symbol
symbol : class SomeProperties
location: class org.apache.jsp.index_jsp
PWC6197: An error occurred at line: 10 in the jsp file: /index.jsp
PWC6199: Generated servlet error:
string:///index_jsp.java:52: cannot find symbol
symbol : variable AResource
location: class org.apache.jsp.index_jsp
at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:126)
at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:296)
at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:372)
...etc...
The thing that should ring alarm bells is that /private/var/folders... stuff.
The trick is to:
cd [your jetty install]
mkdir work
That's it.
It's that retar... er... *unique* /tmp folder that seems to be causing the problem.
You could set the java.io.tmpdir to something meaningful as well.
See: http://wiki.eclipse.org/Jetty/Reference/Temporary_Directories for more information.
Configuring a context root different from war file name to deploy to Jetty
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/myapp</Set>
<Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/com.mycompany.web.myapp.war</Set>
<Set name="extractWAR">true</Set>
<Set name="copyWebDir">false</Set>
<Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
</Configure>
ant clean dist
cp dist/com.mycompany.web.myapp.war /[your_path_to_jetty_install]/webapps
Subscribe to:
Posts (Atom)