Project

General

Profile

Download (14.2 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
 * Copyright (C) 2014 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
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.
9
 */
10
package eu.etaxonomy.taxeditor.httpinvoker;
11

    
12
import java.io.BufferedReader;
13
import java.io.File;
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;
20
import java.net.URL;
21
import java.util.Properties;
22

    
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;
33

    
34
import org.apache.log4j.Logger;
35
import org.eclipse.core.runtime.FileLocator;
36
import org.springframework.core.io.ClassPathResource;
37
import org.springframework.core.io.Resource;
38
import org.unitils.database.annotations.TestDataSource;
39

    
40
import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
41
import eu.etaxonomy.cdm.database.ICdmDataSource;
42
import eu.etaxonomy.taxeditor.remoting.server.CDMServerException;
43
import eu.etaxonomy.taxeditor.remoting.source.CdmRemoteSourceBase;
44

    
45
/**
46
 *
47
 * (Singleton) Server instance which manages a compatible cdmlib-webapp-war.
48
 * This is done by launching a jetty instance (using jetty-runner) as an
49
 * executed process. The choice of the external process over a more
50
 * preferable 'embedded jetty' instance is due to problems arising from the
51
 * class loading of classes (e.g. from hibernate core) which are needed
52
 * for both the webapp as well as the remoting client.
53
 *
54
 * @author cmathew
55
 * @date 23 Sep 2014
56
 *
57
 */
58

    
59
public class CDMServer {
60

    
61
    public static final Logger logger = Logger.getLogger(CDMServer.class);
62

    
63
    @TestDataSource
64
    protected DataSource dataSource;
65

    
66
    private final String name = "default";
67
    private final String host = "127.0.0.1";
68
    private int httpPort = 9090;
69
    private int stopPort = 9191;
70
    private String stopKey = "jetty-cdm-server";
71
    private final String contextPath = "";
72

    
73
    public static final Resource DEFAULT_CDM_WEBAPP_RESOURCE =
74
            new ClassPathResource("/etc/jetty/cdmlib-remote-webapp.war");
75

    
76
    public static final Resource DEFAULT_DATASOURCE_FILE =
77
            new ClassPathResource("datasources.xml");
78

    
79
    public static final Resource DEFAULT_JETTY_RUNNER_RESOURCE =
80
            new ClassPathResource("/etc/jetty/jetty-runner-9.2.3.v20140905.jar");
81

    
82
    public static final Resource DEFAULT_JETTY_RESOURCE =
83
            new ClassPathResource("/etc/jetty/start-9.2.3.v20140905.jar");
84

    
85
    private static CDMServer cdmServer = null;
86
    private static CDMServerException cdmse = null;
87

    
88
    private boolean serverAlreadyRunning = false;
89

    
90
    private File dataSourcesFile;
91
    private final String dataSourceName;
92

    
93
    public CDMServer(String dataSourceName, URL serverPropertiesURL) throws CDMServerException {
94
        this.dataSourceName = dataSourceName;
95
        Properties prop = new Properties();
96

    
97
        try {
98
            File serverPropertiesFile = new File(FileLocator.resolve(serverPropertiesURL).toURI());
99
            InputStream inputStream = new FileInputStream(serverPropertiesFile);
100

    
101
            prop.load(inputStream);
102
            inputStream.close();
103

    
104
        } catch (FileNotFoundException e) {
105
            throw new CDMServerException(e);
106
        } catch (URISyntaxException e) {
107
            throw new CDMServerException(e);
108
        } catch (IOException e) {
109
            throw new CDMServerException(e);
110
        }
111

    
112

    
113

    
114
        if(prop.getProperty("httpPort") != null) {
115
            setHttpPort(Integer.valueOf(prop.getProperty("httpPort")));
116
        }
117

    
118
        if(prop.getProperty("stopPort") != null) {
119
            setStopPort(Integer.valueOf(prop.getProperty("stopPort")));
120
        }
121

    
122
        if(prop.getProperty("stopKey") != null) {
123
            setStopKey(prop.getProperty("stopKey"));
124
        }
125

    
126
    }
127

    
128

    
129

    
130
    public String getName() {
131
        return name;
132
    }
133

    
134
    public String getHost() {
135
        return host;
136
    }
137

    
138
    public int getPort() {
139
        return httpPort;
140
    }
141

    
142
    public String getContextPath() {
143
        return contextPath;
144
    }
145

    
146
    public void setHttpPort(int port) {
147
        this.httpPort = port;
148
    }
149

    
150
    public void setStopPort(int stopPort) {
151
        this.stopPort = stopPort;
152
    }
153

    
154
    public void setStopKey(String stopKey) {
155
        this.stopKey = stopKey;
156
    }
157

    
158

    
159
    public static boolean isRunningInEclipse() {
160
        return (System.getProperty("sun.java.command") != null &&
161
                System.getProperty("sun.java.command").startsWith("org.eclipse.jdt.internal.junit.runner.RemoteTestRunner"));
162
    }
163

    
164
    private String getVMArgs() throws IOException {
165
        StringBuilder sb = new StringBuilder();
166
        sb.append(" -Dspring.profiles.active=remoting");
167
        sb.append(" -Dcdm.beanDefinitionFile=" + DEFAULT_DATASOURCE_FILE.getFile().getAbsolutePath());
168
        sb.append(" -Dcdm.datasource=cdmTest");
169
        return sb.toString();
170
    }
171

    
172
    private String getStartServerArgs() throws IOException {
173
        StringBuilder sb = new StringBuilder();
174
        sb.append(" --port " + httpPort);
175
        return sb.toString();
176
    }
177

    
178
    private String getStopServerSettings() {
179
        StringBuilder sb = new StringBuilder();
180
        sb.append(" --stop-port ");
181
        sb.append(stopPort);
182
        sb.append(" --stop-key ");
183
        sb.append(stopKey);
184
        return sb.toString();
185
    }
186

    
187
    private String getStopServerArgs() {
188
        StringBuilder sb = new StringBuilder();
189
        sb.append(" STOP.PORT=");
190
        sb.append(stopPort);
191
        sb.append(" STOP.KEY=");
192
        sb.append(stopKey);
193
        return sb.toString();
194
    }
195

    
196

    
197
    public void start() throws CDMServerException {
198

    
199
        /**
200
         * First check if the CDM server responds to a service request, which implies that
201
         * the server has started properly. If no response is received then check if the
202
         * server is listening on specific host / port, which implies that the server
203
         * has started but incorrectly, in which case we try to force stop it (if we can)
204
         * and start a new server.
205
         */
206
        if(isStarted(1)) {
207
            logger.info("[CDM-Server] Server already running @ " + host + ":" + httpPort );
208
            serverAlreadyRunning = true;
209
            return;
210
        }
211

    
212
        Thread t = new Thread() {
213
            @Override
214
            public void run() {
215

    
216
                StringBuffer output = new StringBuffer();
217
                try{
218
                    Process p;
219
                    String command = "java "
220
                            + getVMArgs()
221
                            + " -jar "
222
                            + DEFAULT_JETTY_RUNNER_RESOURCE.getFile().getAbsolutePath()
223
                            + getStartServerArgs()
224
                            + getStopServerSettings()
225
                            + " "
226
                            + DEFAULT_CDM_WEBAPP_RESOURCE.getFile().getAbsolutePath();
227
                    logger.info("[CDM-Server] Starting server with Command : " + command);
228
                    p = Runtime.getRuntime().exec(command);
229

    
230
                    BufferedReader inpReader =
231
                            new BufferedReader(new InputStreamReader(p.getInputStream()));
232

    
233
                    BufferedReader errReader =
234
                            new BufferedReader(new InputStreamReader(p.getErrorStream()));
235

    
236
                    String line = "";
237
                    while ((line = inpReader.readLine())!= null) {
238
                        logger.info("[CDM-Server Start] : " + line);
239
                    }
240

    
241
                    while ((line = errReader.readLine())!= null) {
242
                        logger.info("[CDM-Server Start] : " + line);
243
                    }
244

    
245
                } catch (Exception e) {
246
                    e.printStackTrace();
247
                    cdmse = new CDMServerException(e);
248
                }
249
            }
250
        };
251

    
252
        t.setDaemon(true);
253
        cdmse = null;
254
        t.start();
255

    
256
        if(isStarted(50)) {
257
            logger.info("[CDM-Server] Server running @ " + host + ":" + httpPort );
258
        } else {
259
            logger.info("[CDM-Server] Server not started within given interval");
260
            // making sure to kill server if it is not started correctly
261
            try {
262
                stop(true);
263
            } catch (Exception e) {
264
                throw new CDMServerException("CDM Server could not be stopped : " + e.getMessage());
265
            }
266
            throw new CDMServerException("CDM Server not started : ");
267
        }
268

    
269
    }
270

    
271

    
272
    public boolean isStarted(int checkingIntervals) throws CDMServerException  {
273
        CdmRemoteSourceBase crsb = new CdmRemoteSourceBase("local-cdm-server",
274
                host,
275
                httpPort,
276
                contextPath,
277
                null);
278
        int intervalsCount = 0;
279
        do {
280
            try {
281
                if(cdmse != null) {
282
                    return false;
283
                }
284
                boolean check = crsb.checkConnection();
285
                if(check) {
286
                    logger.info("[CDM-Server] Running @ " + host + ":" + httpPort );
287
                    return true;
288
                }
289
            } catch (Exception e) {
290

    
291
            }
292
            try {
293
                Thread.sleep(1000);
294
            } catch (InterruptedException ie) {
295
                throw new CDMServerException("Error checking CDM Server status", ie);
296
            }
297
            intervalsCount++;
298
        } while (intervalsCount < checkingIntervals);
299
        return false;
300
    }
301

    
302
    public void stop() throws Exception {
303
        stop(false);
304
    }
305

    
306
    public void stop(boolean force) throws Exception {
307

    
308
        if(!force) {
309
            if(!cdmServer.isStarted(1)) {
310
                logger.info("[CDM-Server] Server already stopped @ " + host + ":" + httpPort );
311
                return;
312
            }
313
        }
314

    
315
        if(serverAlreadyRunning) {
316
            return;
317
        }
318
        Thread t = new Thread() {
319
            @Override
320
            public void run() {
321
                StringBuffer output = new StringBuffer();
322
                try{
323
                    Process p;
324
                    String command = "java -jar " + DEFAULT_JETTY_RESOURCE.getFile().getAbsolutePath()
325
                            + getStopServerArgs() + " --stop ";
326
                    logger.info("[CDM-Server] Stop Command : " + command);
327
                    p = Runtime.getRuntime().exec(command);
328

    
329
                    BufferedReader inpReader =
330
                            new BufferedReader(new InputStreamReader(p.getInputStream()));
331

    
332
                    BufferedReader errReader =
333
                            new BufferedReader(new InputStreamReader(p.getErrorStream()));
334

    
335
                    String line = "";
336
                    while ((line = inpReader.readLine())!= null) {
337
                        logger.info("[CDM-Server Stop] : " + line);
338
                    }
339

    
340
                    while ((line = errReader.readLine())!= null) {
341
                        logger.info("[CDM-Server Stop] : " + line);
342
                    }
343
                    logger.info("CDM-Server Stopped : ");
344
                } catch (Exception e) {
345
                    logger.info("[CDM-Server] Could not stop @ " + host + ":" + httpPort + ". Please kill it manually");
346

    
347
                }
348

    
349
            }
350
        };
351

    
352
        t.setDaemon(true);
353
        t.start();
354

    
355
    }
356

    
357
    public static void stopServerViaJMX(int jmxPort) throws CDMServerException  {
358
        String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:" + jmxPort + "/jmxrmi";
359
        logger.warn("Shutting down Jetty instance ... ");
360

    
361
        try {
362
            JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(JMX_URL), null);
363
            connector.connect(null);
364
            MBeanServerConnection connection = connector.getMBeanServerConnection();
365
            ObjectName objectName = new ObjectName("org.eclipse.jetty.server:type=server,id=0");
366
            connection.invoke(objectName, "stop", null, null);
367
            logger.warn("Shutdown command sent");
368
        } catch (InstanceNotFoundException e) {
369
            throw new CDMServerException(e);
370
        } catch (MBeanException e) {
371
            throw new CDMServerException(e);
372
        } catch (ReflectionException e) {
373
            throw new CDMServerException(e);
374
        } catch (IOException e) {
375
            throw new CDMServerException(e);
376
        } catch (MalformedObjectNameException e) {
377
            throw new CDMServerException(e);
378
        }
379
    }
380

    
381
    public void convertEditorToServerConfig() {
382
        String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + System.lineSeparator() +
383
                "<beans xmlns=\"http://www.springframework.org/schema/beans\"" + System.lineSeparator() +
384
                "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + System.lineSeparator() +
385
                "xmlns:tx=\"http://www.springframework.org/schema/tx\"" + System.lineSeparator() +
386
                "xmlns:context=\"http://www.springframework.org/schema/context\"" + System.lineSeparator() +
387
                "xsi:schemaLocation=\"http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" + System.lineSeparator() +
388
                "http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-2.5.xsd" + System.lineSeparator() +
389
                "http://www.springframework.org/schema/tx   http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" + System.lineSeparator() +
390
                ">" + System.lineSeparator() +
391
                "<bean id=\"dataSourceProperties\" class=\"eu.etaxonomy.cdm.remote.config.DataSourceProperties\">" + System.lineSeparator() +
392
                "   <property name=\"propsMap\">" + System.lineSeparator() +
393
                "       <map/>" + System.lineSeparator() +
394
                "   </property>" + System.lineSeparator() +
395
                "</bean>";
396

    
397
        for(ICdmDataSource dataSource : CdmPersistentDataSource.getAllDataSources()) {
398

    
399
        }
400
    }
401
}
(2-2/7)