3 * Copyright (C) 2014 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.taxeditor
.webapp
;
13 import java
.io
.IOException
;
14 import java
.net
.ServerSocket
;
16 import java
.net
.URISyntaxException
;
19 import javax
.management
.InstanceNotFoundException
;
20 import javax
.management
.MBeanException
;
21 import javax
.management
.MBeanServerConnection
;
22 import javax
.management
.MalformedObjectNameException
;
23 import javax
.management
.ObjectName
;
24 import javax
.management
.ReflectionException
;
25 import javax
.management
.remote
.JMXConnector
;
26 import javax
.management
.remote
.JMXConnectorFactory
;
27 import javax
.management
.remote
.JMXServiceURL
;
29 import org
.apache
.log4j
.Logger
;
30 import org
.eclipse
.core
.runtime
.FileLocator
;
31 import org
.eclipse
.core
.runtime
.Platform
;
32 import org
.eclipse
.jetty
.server
.Server
;
33 import org
.eclipse
.jetty
.util
.StringUtil
;
34 import org
.eclipse
.jetty
.util
.preventers
.AppContextLeakPreventer
;
35 import org
.eclipse
.jetty
.webapp
.WebAppContext
;
36 import org
.osgi
.framework
.Bundle
;
40 * (Singleton) Server instance which manages a compatible cdmlib-webapp-war.
41 * This is done by launching a jetty instance (using jetty-runner) as an
42 * executed process. The choice of the external process over a more
43 * preferable 'embedded jetty' instance is due to problems arising from the
44 * class loading of classes (e.g. from hibernate core) which are needed
45 * for both the webapp as well as the remoting client.
52 public class CDMServer
{
54 public static final Logger logger
= Logger
.getLogger(CDMServer
.class);
57 private final String dataSourceName
;
58 private final String host
= "127.0.0.1";
59 private int httpPort
= 9090;
60 private final String contextPath
= "/";
63 private Server server
;
66 public CDMServer(String dataSourceName
, File dataSourcesFile
) throws CDMEmbeddedServerException
{
67 if(StringUtil
.isBlank(dataSourceName
)) {
68 throw new CDMEmbeddedServerException("DataSource name is not valid");
71 if(dataSourcesFile
== null || !dataSourcesFile
.exists()) {
72 throw new CDMEmbeddedServerException("DataSource config file does not exist");
74 this.dataSourceName
= dataSourceName
;
75 Bundle bundle
= Platform
.getBundle("eu.etaxonomy.taxeditor.webapp");
76 URL warURL
= bundle
.getEntry("lib/cdmlib-remote-webapp.war");
79 URL resolvedWarURL
= FileLocator
.toFileURL(warURL
);
80 // We need to use the 3-arg constructor of URI in order to properly escape file system chars
81 URI resolvedURI
= new URI(resolvedWarURL
.getProtocol(), resolvedWarURL
.getPath(), null);
82 warFile
= new File(resolvedURI
);
83 System
.out
.println("war url : " + warFile
.getAbsolutePath());
85 if(warFile
== null || !warFile
.exists()) {
86 throw new CDMEmbeddedServerException("Cdmlib War file does not exist");
88 } catch (URISyntaxException use
) {
89 throw new CDMEmbeddedServerException(use
);
90 } catch (IOException ioe
) {
91 throw new CDMEmbeddedServerException(ioe
);
94 System
.setProperty("spring.profiles.active", "remoting");
95 System
.setProperty("cdm.beanDefinitionFile", dataSourcesFile
.getAbsolutePath());
96 System
.setProperty("cdm.datasource", dataSourceName
);
98 httpPort
= findFreePort();
100 logger
.warn("Starting server on port : " + httpPort
);
102 server
= new Server(httpPort
);
104 server
.addBean(new AppContextLeakPreventer());
106 WebAppContext webapp
= new WebAppContext();
107 webapp
.setContextPath(contextPath
);
108 webapp
.setWar(warFile
.getAbsolutePath());
110 server
.setHandler(webapp
);
113 public String
getDataSourceName() {
114 return dataSourceName
;
116 public String
getHost() {
120 public int getPort() {
124 public String
getContextPath() {
128 private static int findFreePort() throws CDMEmbeddedServerException
{
129 ServerSocket socket
= null;
131 socket
= new ServerSocket(0);
132 socket
.setReuseAddress(true);
133 int port
= socket
.getLocalPort();
136 } catch (IOException e
) {
140 } catch (IOException e
) {
142 if (socket
!= null) {
145 } catch (IOException e
) {
149 throw new CDMEmbeddedServerException("Could not find a free TCP/IP port to start embedded Jetty HTTP Server on");
152 public void start(ICDMServerError cdmServerError
) throws CDMEmbeddedServerException
{
153 start(true, cdmServerError
);
156 public void start(boolean wait
, final ICDMServerError cdmServerError
) throws CDMEmbeddedServerException
{
159 throw new CDMEmbeddedServerException("Server is already disposed");
162 if(server
.isStarting()) {
163 throw new CDMEmbeddedServerException("Server is starting");
166 if(server
.isStarted()) {
167 throw new CDMEmbeddedServerException("Server has started");
170 if(server
.isRunning()) {
171 throw new CDMEmbeddedServerException("Server is running");
174 if(server
.isStopping()) {
175 throw new CDMEmbeddedServerException("Server is currently stopping. Please re-try in about 10 seconds");
178 Thread serverThread
= new Thread() {
185 } catch (Throwable t
) {
186 cdmServerError
.handleError(t
);
191 serverThread
.start();
194 while(!server
.isStarted()) {}
199 public boolean isAlive() {
200 return server
.isRunning() || server
.isStarting() || server
.isStarted();
203 public boolean isStarted() {
204 return server
.isStarted();
207 public void stop() throws Exception
{
216 public static void stopServerViaJMX(int jmxPort
) throws CDMEmbeddedServerException
{
217 String JMX_URL
= "service:jmx:rmi:///jndi/rmi://localhost:" + jmxPort
+ "/jmxrmi";
218 logger
.warn("Shutting down Jetty instance ... ");
221 JMXConnector connector
= JMXConnectorFactory
.connect(new JMXServiceURL(JMX_URL
), null);
222 connector
.connect(null);
223 MBeanServerConnection connection
= connector
.getMBeanServerConnection();
224 ObjectName objectName
= new ObjectName("org.eclipse.jetty.server:type=server,id=0");
225 connection
.invoke(objectName
, "stop", null, null);
226 logger
.warn("Shutdown command sent");
227 } catch (InstanceNotFoundException e
) {
228 throw new CDMEmbeddedServerException(e
);
229 } catch (MBeanException e
) {
230 throw new CDMEmbeddedServerException(e
);
231 } catch (ReflectionException e
) {
232 throw new CDMEmbeddedServerException(e
);
233 } catch (IOException e
) {
234 throw new CDMEmbeddedServerException(e
);
235 } catch (MalformedObjectNameException e
) {
236 throw new CDMEmbeddedServerException(e
);