Project

General

Profile

Download (8.1 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2014 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9
package eu.etaxonomy.taxeditor.webapp;
10

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

    
18
import javax.management.InstanceNotFoundException;
19
import javax.management.MBeanException;
20
import javax.management.MBeanServerConnection;
21
import javax.management.MalformedObjectNameException;
22
import javax.management.ObjectName;
23
import javax.management.ReflectionException;
24
import javax.management.remote.JMXConnector;
25
import javax.management.remote.JMXConnectorFactory;
26
import javax.management.remote.JMXServiceURL;
27

    
28
import org.apache.log4j.Logger;
29
import org.eclipse.core.runtime.FileLocator;
30
import org.eclipse.core.runtime.Platform;
31
import org.eclipse.jetty.server.Server;
32
import org.eclipse.jetty.util.StringUtil;
33
import org.eclipse.jetty.util.preventers.AppContextLeakPreventer;
34
import org.eclipse.jetty.webapp.WebAppContext;
35
import org.osgi.framework.Bundle;
36

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

    
51
public class CDMServer {
52

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

    
55

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

    
61
    private File warFile;
62
    private Server server;
63

    
64

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

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

    
77
        try {
78
            URL resolvedWarURL = FileLocator.toFileURL(warURL);
79
            // We need to use the 3-arg constructor of URI in order to properly escape file system chars
80
            URI resolvedURI = new URI(resolvedWarURL.getProtocol(), resolvedWarURL.getPath(), null);
81
            warFile = new File(resolvedURI);
82
            System.out.println("war url : " + warFile.getAbsolutePath());
83

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

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

    
97
        httpPort = findFreePort();
98

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

    
101
        server = new Server(httpPort);
102

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

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

    
110
        server.setHandler(webapp);
111
    }
112

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

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

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

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

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

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

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

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

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

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

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

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

    
178
        Thread serverThread = new Thread() {
179

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

    
197
        serverThread.start();
198

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

    
202
        }
203
    }
204

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

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

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

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

    
223

    
224

    
225

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

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

    
250

    
251
}
(2-2/4)