Project

General

Profile

Download (8.11 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.webapp;
11

    
12
import java.io.File;
13
import java.io.IOException;
14
import java.net.ServerSocket;
15
import java.net.URI;
16
import java.net.URISyntaxException;
17
import java.net.URL;
18

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

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

    
38
/**
39
 *
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.
46
 *
47
 * @author cmathew
48
 * @date 23 Sep 2014
49
 *
50
 */
51

    
52
public class CDMServer {
53

    
54
    public static final Logger logger = Logger.getLogger(CDMServer.class);
55

    
56

    
57
    private final String dataSourceName;
58
    private final String host = "127.0.0.1";
59
    private int httpPort = 9090;
60
    private final String contextPath = "/";
61

    
62
    private File warFile;
63
    private Server server;
64

    
65

    
66
    public CDMServer(String dataSourceName, File dataSourcesFile) throws CDMEmbeddedServerException {
67
        if(StringUtil.isBlank(dataSourceName)) {
68
            throw new CDMEmbeddedServerException("DataSource name is not valid");
69
        }
70

    
71
        if(dataSourcesFile == null || !dataSourcesFile.exists()) {
72
            throw new CDMEmbeddedServerException("DataSource config file does not exist");
73
        }
74
        this.dataSourceName = dataSourceName;
75
        Bundle bundle = Platform.getBundle("eu.etaxonomy.taxeditor.webapp");
76
        URL warURL = bundle.getEntry("lib/cdmlib-remote-webapp.war");
77

    
78
        try {
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());
84

    
85
            if(warFile == null || !warFile.exists()) {
86
                throw new CDMEmbeddedServerException("Cdmlib War file does not exist");
87
            }
88
        } catch (URISyntaxException use) {
89
            throw new CDMEmbeddedServerException(use);
90
        } catch (IOException ioe) {
91
            throw new CDMEmbeddedServerException(ioe);
92
        }
93

    
94
        System.setProperty("spring.profiles.active", "remoting");
95
        System.setProperty("cdm.beanDefinitionFile", dataSourcesFile.getAbsolutePath());
96
        System.setProperty("cdm.datasource", dataSourceName);
97

    
98
        httpPort = findFreePort();
99

    
100
        logger.warn("Starting server on port : " + httpPort);
101

    
102
        server = new Server(httpPort);
103

    
104
        server.addBean(new AppContextLeakPreventer());
105

    
106
        WebAppContext webapp = new WebAppContext();
107
        webapp.setContextPath(contextPath);
108
        webapp.setWar(warFile.getAbsolutePath());
109
        webapp.setThrowUnavailableOnStartupException(true);
110

    
111
        server.setHandler(webapp);
112
    }
113

    
114
    public String getDataSourceName() {
115
        return dataSourceName;
116
    }
117
    public String getHost() {
118
        return host;
119
    }
120

    
121
    public int getPort() {
122
        return httpPort;
123
    }
124

    
125
    public String getContextPath() {
126
        return contextPath;
127
    }
128

    
129
    private static int findFreePort() throws CDMEmbeddedServerException {
130
        ServerSocket socket = null;
131
        try {
132
            socket = new ServerSocket(0);
133
            socket.setReuseAddress(true);
134
            int port = socket.getLocalPort();
135
            try {
136
                socket.close();
137
            } catch (IOException e) {
138

    
139
            }
140
            return port;
141
        } catch (IOException e) {
142
        } finally {
143
            if (socket != null) {
144
                try {
145
                    socket.close();
146
                } catch (IOException e) {
147
                }
148
            }
149
        }
150
        throw new CDMEmbeddedServerException("Could not find a free TCP/IP port to start embedded Jetty HTTP Server on");
151
    }
152

    
153
    public void start(ICDMServerError cdmServerError) throws CDMEmbeddedServerException {
154
        start(true, cdmServerError);
155
    }
156

    
157
    public void start(boolean wait, final ICDMServerError cdmServerError) throws CDMEmbeddedServerException {
158

    
159
        if(server == null) {
160
            throw new CDMEmbeddedServerException("Server is already disposed");
161
        }
162

    
163
        if(server.isStarting()) {
164
            throw new CDMEmbeddedServerException("Server is starting");
165
        }
166

    
167
        if(server.isStarted()) {
168
            throw new CDMEmbeddedServerException("Server has started");
169
        }
170

    
171
        if(server.isRunning()) {
172
            throw new CDMEmbeddedServerException("Server is running");
173
        }
174

    
175
        if(server.isStopping()) {
176
            throw new CDMEmbeddedServerException("Server is currently stopping. Please re-try in about 10 seconds");
177
        }
178

    
179
        Thread serverThread = new Thread() {
180

    
181
            @Override
182
            public void run() {
183
                try {
184
                    server.start();
185
                    server.join();
186
                } catch (Throwable t) {
187
                    //wait for 1sec to get the right order of login dialog and error
188
                    //message when connection fails
189
                    try {
190
                        Thread.sleep(1000);
191
                    } catch (InterruptedException e) {
192
                    }
193
                    cdmServerError.handleError(new RuntimeException("Error during CDM server startup", t));
194
                }
195
            }
196
        };
197

    
198
        serverThread.start();
199

    
200
        if(wait) {
201
            while(!server.isStarted()) {}
202

    
203
        }
204
    }
205

    
206
    public boolean isAlive()  {
207
        return server.isRunning() || server.isStarting() || server.isStarted();
208
    }
209

    
210
    public boolean isStarted() {
211
        return server.isStarted();
212
    }
213

    
214
    public boolean isFailed() {
215
        return server.isFailed();
216
    }
217

    
218
    public void stop() throws Exception {
219
        server.stop();
220
        server.destroy();
221
        server = null;
222
    }
223

    
224

    
225

    
226

    
227
    public static void stopServerViaJMX(int jmxPort) throws CDMEmbeddedServerException  {
228
        String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:" + jmxPort + "/jmxrmi";
229
        logger.warn("Shutting down Jetty instance ... ");
230

    
231
        try {
232
            JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(JMX_URL), null);
233
            connector.connect(null);
234
            MBeanServerConnection connection = connector.getMBeanServerConnection();
235
            ObjectName objectName = new ObjectName("org.eclipse.jetty.server:type=server,id=0");
236
            connection.invoke(objectName, "stop", null, null);
237
            logger.warn("Shutdown command sent");
238
        } catch (InstanceNotFoundException e) {
239
            throw new CDMEmbeddedServerException(e);
240
        } catch (MBeanException e) {
241
            throw new CDMEmbeddedServerException(e);
242
        } catch (ReflectionException e) {
243
            throw new CDMEmbeddedServerException(e);
244
        } catch (IOException e) {
245
            throw new CDMEmbeddedServerException(e);
246
        } catch (MalformedObjectNameException e) {
247
            throw new CDMEmbeddedServerException(e);
248
        }
249
    }
250

    
251

    
252
}
(2-2/4)