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
.httpinvoker
;
12 import java
.io
.BufferedReader
;
14 import java
.io
.FileInputStream
;
15 import java
.io
.FileNotFoundException
;
16 import java
.io
.IOException
;
17 import java
.io
.InputStream
;
18 import java
.io
.InputStreamReader
;
19 import java
.net
.URISyntaxException
;
21 import java
.util
.Properties
;
23 import javax
.management
.InstanceNotFoundException
;
24 import javax
.management
.MBeanException
;
25 import javax
.management
.MBeanServerConnection
;
26 import javax
.management
.MalformedObjectNameException
;
27 import javax
.management
.ObjectName
;
28 import javax
.management
.ReflectionException
;
29 import javax
.management
.remote
.JMXConnector
;
30 import javax
.management
.remote
.JMXConnectorFactory
;
31 import javax
.management
.remote
.JMXServiceURL
;
32 import javax
.sql
.DataSource
;
34 import org
.apache
.log4j
.Logger
;
35 import org
.eclipse
.core
.runtime
.FileLocator
;
36 import org
.eclipse
.core
.runtime
.Platform
;
37 import org
.osgi
.framework
.Bundle
;
38 import org
.springframework
.core
.io
.ClassPathResource
;
39 import org
.springframework
.core
.io
.Resource
;
40 import org
.unitils
.database
.annotations
.TestDataSource
;
42 import eu
.etaxonomy
.cdm
.database
.CdmPersistentDataSource
;
43 import eu
.etaxonomy
.cdm
.database
.ICdmDataSource
;
44 import eu
.etaxonomy
.taxeditor
.remoting
.server
.CDMServerException
;
45 import eu
.etaxonomy
.taxeditor
.remoting
.source
.CdmRemoteSourceBase
;
49 * (Singleton) Server instance which manages a compatible cdmlib-webapp-war.
50 * This is done by launching a jetty instance (using jetty-runner) as an
51 * executed process. The choice of the external process over a more
52 * preferable 'embedded jetty' instance is due to problems arising from the
53 * class loading of classes (e.g. from hibernate core) which are needed
54 * for both the webapp as well as the remoting client.
61 public class CDMServer
{
63 public static final Logger logger
= Logger
.getLogger(CDMServer
.class);
66 protected DataSource dataSource
;
68 private final String name
= "default";
69 private final String host
= "127.0.0.1";
70 private int httpPort
= 9090;
71 private int stopPort
= 9191;
72 private String stopKey
= "jetty-cdm-server";
73 private final String contextPath
= "";
75 public static final Resource DEFAULT_CDM_WEBAPP_RESOURCE
=
76 new ClassPathResource("/etc/jetty/cdmlib-remote-webapp.war");
78 public static final Resource DEFAULT_DATASOURCE_FILE
=
79 new ClassPathResource("datasources.xml");
81 public static final Resource DEFAULT_JETTY_RUNNER_RESOURCE
=
82 new ClassPathResource("/etc/jetty/jetty-runner-9.2.3.v20140905.jar");
84 public static final Resource DEFAULT_JETTY_RESOURCE
=
85 new ClassPathResource("/etc/jetty/start-9.2.3.v20140905.jar");
87 private static CDMServer cdmServer
= null;
88 private static CDMServerException cdmse
= null;
90 private boolean serverAlreadyRunning
= false;
92 private File dataSourcesFile
;
93 private final String dataSourceName
;
95 public CDMServer(String dataSourceName
) throws CDMServerException
{
96 this.dataSourceName
= dataSourceName
;
97 Properties prop
= new Properties();
99 Bundle bundle
= Platform
.getBundle("eu.etaxonomy.taxeditor.cdmlib");
100 URL serverPropertiesURL
= bundle
.getEntry("src/test/resources/server.properties");
103 File serverPropertiesFile
= new File(FileLocator
.resolve(serverPropertiesURL
).toURI());
104 InputStream inputStream
= new FileInputStream(serverPropertiesFile
);
106 if (inputStream
!= null) {
107 prop
.load(inputStream
);
110 } catch (FileNotFoundException e
) {
111 throw new CDMServerException(e
);
112 } catch (URISyntaxException e
) {
113 throw new CDMServerException(e
);
114 } catch (IOException e
) {
115 throw new CDMServerException(e
);
120 if(prop
.getProperty("httpPort") != null) {
121 setHttpPort(Integer
.valueOf(prop
.getProperty("httpPort")));
124 if(prop
.getProperty("stopPort") != null) {
125 setStopPort(Integer
.valueOf(prop
.getProperty("stopPort")));
128 if(prop
.getProperty("stopKey") != null) {
129 setStopKey(prop
.getProperty("stopKey"));
136 public String
getName() {
140 public String
getHost() {
144 public int getPort() {
148 public String
getContextPath() {
152 public void setHttpPort(int port
) {
153 this.httpPort
= port
;
156 public void setStopPort(int stopPort
) {
157 this.stopPort
= stopPort
;
160 public void setStopKey(String stopKey
) {
161 this.stopKey
= stopKey
;
165 public static boolean isRunningInEclipse() {
166 return (System
.getProperty("sun.java.command") != null &&
167 System
.getProperty("sun.java.command").startsWith("org.eclipse.jdt.internal.junit.runner.RemoteTestRunner"));
170 private String
getVMArgs() throws IOException
{
171 StringBuilder sb
= new StringBuilder();
172 sb
.append(" -Dspring.profiles.active=remoting");
173 sb
.append(" -Dcdm.beanDefinitionFile=" + DEFAULT_DATASOURCE_FILE
.getFile().getAbsolutePath());
174 sb
.append(" -Dcdm.datasource=cdmTest");
175 return sb
.toString();
178 private String
getStartServerArgs() throws IOException
{
179 StringBuilder sb
= new StringBuilder();
180 sb
.append(" --port " + httpPort
);
181 return sb
.toString();
184 private String
getStopServerSettings() {
185 StringBuilder sb
= new StringBuilder();
186 sb
.append(" --stop-port ");
188 sb
.append(" --stop-key ");
190 return sb
.toString();
193 private String
getStopServerArgs() {
194 StringBuilder sb
= new StringBuilder();
195 sb
.append(" STOP.PORT=");
197 sb
.append(" STOP.KEY=");
199 return sb
.toString();
203 public void start() throws CDMServerException
{
206 * First check if the CDM server responds to a service request, which implies that
207 * the server has started properly. If no response is received then check if the
208 * server is listening on specific host / port, which implies that the server
209 * has started but incorrectly, in which case we try to force stop it (if we can)
210 * and start a new server.
213 logger
.info("[CDM-Server] Server already running @ " + host
+ ":" + httpPort
);
214 serverAlreadyRunning
= true;
218 Thread t
= new Thread() {
222 StringBuffer output
= new StringBuffer();
225 String command
= "java "
228 + DEFAULT_JETTY_RUNNER_RESOURCE
.getFile().getAbsolutePath()
229 + getStartServerArgs()
230 + getStopServerSettings()
232 + DEFAULT_CDM_WEBAPP_RESOURCE
.getFile().getAbsolutePath();
233 logger
.info("[CDM-Server] Starting server with Command : " + command
);
234 p
= Runtime
.getRuntime().exec(command
);
236 BufferedReader inpReader
=
237 new BufferedReader(new InputStreamReader(p
.getInputStream()));
239 BufferedReader errReader
=
240 new BufferedReader(new InputStreamReader(p
.getErrorStream()));
243 while ((line
= inpReader
.readLine())!= null) {
244 logger
.info("[CDM-Server Start] : " + line
);
247 while ((line
= errReader
.readLine())!= null) {
248 logger
.info("[CDM-Server Start] : " + line
);
251 } catch (Exception e
) {
253 cdmse
= new CDMServerException(e
);
263 logger
.info("[CDM-Server] Server running @ " + host
+ ":" + httpPort
);
265 logger
.info("[CDM-Server] Server not started within given interval");
266 // making sure to kill server if it is not started correctly
269 } catch (Exception e
) {
270 throw new CDMServerException("CDM Server could not be stopped : " + e
.getMessage());
272 throw new CDMServerException("CDM Server not started : ");
278 public boolean isStarted(int checkingIntervals
) throws CDMServerException
{
279 CdmRemoteSourceBase crsb
= new CdmRemoteSourceBase("local-cdm-server",
284 int intervalsCount
= 0;
290 boolean check
= crsb
.checkConnection();
292 logger
.info("[CDM-Server] Running @ " + host
+ ":" + httpPort
);
295 } catch (Exception e
) {
300 } catch (InterruptedException ie
) {
301 throw new CDMServerException("Error checking CDM Server status", ie
);
304 } while (intervalsCount
< checkingIntervals
);
308 public void stop() throws Exception
{
312 public void stop(boolean force
) throws Exception
{
315 if(!cdmServer
.isStarted(1)) {
316 logger
.info("[CDM-Server] Server already stopped @ " + host
+ ":" + httpPort
);
321 if(serverAlreadyRunning
) {
324 Thread t
= new Thread() {
327 StringBuffer output
= new StringBuffer();
330 String command
= "java -jar " + DEFAULT_JETTY_RESOURCE
.getFile().getAbsolutePath()
331 + getStopServerArgs() + " --stop ";
332 logger
.info("[CDM-Server] Stop Command : " + command
);
333 p
= Runtime
.getRuntime().exec(command
);
335 BufferedReader inpReader
=
336 new BufferedReader(new InputStreamReader(p
.getInputStream()));
338 BufferedReader errReader
=
339 new BufferedReader(new InputStreamReader(p
.getErrorStream()));
342 while ((line
= inpReader
.readLine())!= null) {
343 logger
.info("[CDM-Server Stop] : " + line
);
346 while ((line
= errReader
.readLine())!= null) {
347 logger
.info("[CDM-Server Stop] : " + line
);
349 logger
.info("CDM-Server Stopped : ");
350 } catch (Exception e
) {
351 logger
.info("[CDM-Server] Could not stop @ " + host
+ ":" + httpPort
+ ". Please kill it manually");
363 public static void stopServerViaJMX(int jmxPort
) throws CDMServerException
{
364 String JMX_URL
= "service:jmx:rmi:///jndi/rmi://localhost:" + jmxPort
+ "/jmxrmi";
365 logger
.warn("Shutting down Jetty instance ... ");
368 JMXConnector connector
= JMXConnectorFactory
.connect(new JMXServiceURL(JMX_URL
), null);
369 connector
.connect(null);
370 MBeanServerConnection connection
= connector
.getMBeanServerConnection();
371 ObjectName objectName
= new ObjectName("org.eclipse.jetty.server:type=server,id=0");
372 connection
.invoke(objectName
, "stop", null, null);
373 logger
.warn("Shutdown command sent");
374 } catch (InstanceNotFoundException e
) {
375 throw new CDMServerException(e
);
376 } catch (MBeanException e
) {
377 throw new CDMServerException(e
);
378 } catch (ReflectionException e
) {
379 throw new CDMServerException(e
);
380 } catch (IOException e
) {
381 throw new CDMServerException(e
);
382 } catch (MalformedObjectNameException e
) {
383 throw new CDMServerException(e
);
387 public void convertEditorToServerConfig() {
388 String xmlString
= "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + System
.lineSeparator() +
389 "<beans xmlns=\"http://www.springframework.org/schema/beans\"" + System
.lineSeparator() +
390 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + System
.lineSeparator() +
391 "xmlns:tx=\"http://www.springframework.org/schema/tx\"" + System
.lineSeparator() +
392 "xmlns:context=\"http://www.springframework.org/schema/context\"" + System
.lineSeparator() +
393 "xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" + System
.lineSeparator() +
394 "http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" + System
.lineSeparator() +
395 "http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" + System
.lineSeparator() +
396 ">" + System
.lineSeparator() +
397 "<bean id=\"dataSourceProperties\" class=\"eu.etaxonomy.cdm.remote.config.DataSourceProperties\">" + System
.lineSeparator() +
398 " <property name=\"propsMap\">" + System
.lineSeparator() +
399 " <map/>" + System
.lineSeparator() +
400 " </property>" + System
.lineSeparator() +
403 for(ICdmDataSource dataSource
: CdmPersistentDataSource
.getAllDataSources()) {