View Javadoc

1   /**
2    * Copyright (c) 2002-2011 "Neo Technology,"
3    * Network Engine for Objects in Lund AB [http://neotechnology.com]
4    *
5    * This file is part of Neo4j.
6    *
7    * Neo4j is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.neo4j.server.web;
21  
22  import com.sun.jersey.api.core.ResourceConfig;
23  import com.sun.jersey.spi.container.servlet.ServletContainer;
24  import org.mortbay.jetty.Server;
25  import org.mortbay.jetty.SessionManager;
26  import org.mortbay.jetty.handler.MovedContextHandler;
27  import org.mortbay.jetty.servlet.Context;
28  import org.mortbay.jetty.servlet.HashSessionManager;
29  import org.mortbay.jetty.servlet.ServletHolder;
30  import org.mortbay.jetty.servlet.SessionHandler;
31  import org.mortbay.jetty.webapp.WebAppContext;
32  import org.mortbay.resource.Resource;
33  import org.mortbay.thread.QueuedThreadPool;
34  import org.neo4j.server.NeoServer;
35  import org.neo4j.server.logging.Logger;
36  import org.neo4j.server.rest.web.AllowAjaxFilter;
37  
38  import java.net.URI;
39  import java.net.URISyntaxException;
40  import java.net.URL;
41  import java.util.HashMap;
42  import java.util.List;
43  
44  import javax.servlet.Servlet;
45  
46  public class Jetty6WebServer implements WebServer
47  {
48      public static final Logger log = Logger.getLogger( Jetty6WebServer.class );
49  
50  
51      private Server jetty;
52      private int jettyPort = 80;
53  
54      private final HashMap<String, String> staticContent = new HashMap<String, String>();
55      private final HashMap<String, ServletHolder> jaxRSPackages = new HashMap<String, ServletHolder>();
56      private NeoServer server;
57  
58  
59      @Override
60      public void setNeoServer( NeoServer server )
61      {
62          this.server = server;
63      }
64  
65      @Override
66      public void start() {
67          jetty = new Server(jettyPort);
68          jetty.setStopAtShutdown(true);
69          MovedContextHandler redirector = new MovedContextHandler();
70  
71          jetty.addHandler( redirector );
72  
73          loadStaticContent();
74          loadJAXRSPackages();
75  
76          try {
77              jetty.start();
78          } catch (Exception e) {
79              throw new RuntimeException(e);
80          }
81      }
82  
83      @Override
84      public void stop()
85      {
86          try
87          {
88              jetty.stop();
89              jetty.join();
90          }
91          catch ( Exception e )
92          {
93              throw new RuntimeException(e);
94          }
95          finally
96          {
97              // Jetty doesn't remove its shutdown hook automatically on stop()
98              jetty.setStopAtShutdown( false );
99          }
100     }
101 
102     @Override
103     public void setPort(int portNo) {
104         jettyPort = portNo;
105     }
106 
107     @Override
108     public void setMaxThreads(int maxThreads) {
109         jetty.setThreadPool(new QueuedThreadPool(maxThreads));
110     }
111 
112     @Override
113     public void addJAXRSPackages(List<String> packageNames, String mountPoint) {
114         // We don't want absolute URIs at this point
115         mountPoint = ensureRelativeUri(mountPoint);
116 
117         // Trim any trailing slash to keep Jetty happy
118         mountPoint = trimTrailingSlash(mountPoint);
119 
120         ServletContainer container = new NeoServletContainer(server, server.getInjectables( packageNames ) );
121         ServletHolder servletHolder = new ServletHolder(container);
122         servletHolder.setInitParameter("com.sun.jersey.config.property.packages", toCommaSeparatedList(packageNames));
123         servletHolder.setInitParameter(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS, AllowAjaxFilter.class.getName());
124         log.info("Adding JAXRS package %s at [%s]", packageNames, mountPoint);
125         jaxRSPackages.put(mountPoint, servletHolder);
126     }
127 
128     @Override
129     public void addServlet( Servlet unmanagedServlet, String mountPoint )
130     {
131         log.info("adding Servlet [%s] at [%s]", unmanagedServlet.getClass().getName(), mountPoint);
132         Context servletContext = new Context(jetty, mountPoint);
133         SessionManager sm = new HashSessionManager();
134         SessionHandler sh = new SessionHandler(sm);
135         ServletHolder servletHolder = new ServletHolder(unmanagedServlet);
136         servletContext.addServlet(servletHolder, "/*");
137         servletContext.setSessionHandler(sh);
138     }
139 
140     private String trimTrailingSlash(String mountPoint) {
141         if(mountPoint.equals("/")) {
142             return mountPoint;
143         }
144 
145         if(mountPoint.endsWith("/")) {
146             mountPoint = mountPoint.substring(0, mountPoint.length() -1);
147         }
148         return mountPoint;
149     }
150 
151     private String ensureRelativeUri(String mountPoint) {
152         try {
153             URI result = new URI(mountPoint);
154             if(result.isAbsolute()) {
155                 return result.getPath();
156             } else {
157                 return result.toString();
158             }
159         } catch (URISyntaxException e) {
160             log.debug("Unable to translate [%s] to a relative URI in ensureRelativeUri(String mountPoint)", mountPoint);
161             return mountPoint;
162         }
163     }
164 
165     @Override
166     public void addStaticContent(String contentLocation, String serverMountPoint) {
167         staticContent.put(serverMountPoint, contentLocation);
168     }
169 
170     private void loadStaticContent() {
171         for (String mountPoint : staticContent.keySet()) {
172             String contentLocation = staticContent.get(mountPoint);
173             log.info("Mounting static content at [%s] from [%s]", mountPoint, contentLocation);
174             try {
175                 final WebAppContext staticContext = new WebAppContext();
176                 staticContext.setServer(jetty);
177                 staticContext.setContextPath(mountPoint);
178                 URL resourceLoc = getClass().getClassLoader().getResource(contentLocation);
179                 if(resourceLoc != null) {
180                     log.info("Found [%s]", resourceLoc);
181                     URL url = resourceLoc.toURI().toURL();
182                     final Resource resource = Resource.newResource(url);
183                     staticContext.setBaseResource(resource);
184                     log.info("Mounting static content from [%s] at [%s]", url, mountPoint);
185                     jetty.addHandler(staticContext);
186                 } else {
187                     log.error("No static content available for Neo Server at port [%d], management console may not be available.", jettyPort);
188                 }
189             } catch (Exception e) {
190                 log.error(e);
191                 e.printStackTrace();
192                 throw new RuntimeException(e);
193             }
194         }
195     }
196 
197     private void loadJAXRSPackages() {
198         for (String mountPoint : jaxRSPackages.keySet()) {
199 
200             ServletHolder servletHolder = jaxRSPackages.get(mountPoint);
201             log.info("Mounting servlet at [%s]", mountPoint);
202             Context jerseyContext = new Context(jetty, mountPoint);
203             SessionManager sm = new HashSessionManager();
204             SessionHandler sh = new SessionHandler(sm);
205             jerseyContext.addServlet(servletHolder, "/*");
206             jerseyContext.setSessionHandler(sh);
207         }
208     }
209 
210     private String toCommaSeparatedList(List<String> packageNames) {
211         StringBuilder sb = new StringBuilder();
212 
213         for (String str : packageNames) {
214             sb.append(str);
215             sb.append(", ");
216         }
217 
218         String result = sb.toString();
219         return result.substring(0, result.length() - 2);
220     }
221 }