KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > tomcat > internal > TomcatAppServer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.tomcat.internal;
12
13 import java.io.ByteArrayOutputStream JavaDoc;
14 import java.io.PrintStream JavaDoc;
15 import java.net.InetAddress JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.net.UnknownHostException JavaDoc;
18 import java.util.ArrayList JavaDoc;
19
20 import org.apache.catalina.Connector;
21 import org.apache.catalina.Context;
22 import org.apache.catalina.Engine;
23 import org.apache.catalina.Host;
24 import org.apache.catalina.LifecycleEvent;
25 import org.apache.catalina.LifecycleException;
26 import org.apache.catalina.LifecycleListener;
27 import org.apache.catalina.Realm;
28 import org.apache.catalina.core.StandardContext;
29 import org.apache.catalina.core.StandardHost;
30 import org.apache.catalina.logger.FileLogger;
31 import org.apache.catalina.realm.MemoryRealm;
32 import org.apache.catalina.startup.Embedded;
33 import org.apache.coyote.tomcat4.CoyoteConnector;
34 import org.apache.coyote.tomcat4.CoyoteServerSocketFactory;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.FileLocator;
37 import org.eclipse.core.runtime.IConfigurationElement;
38 import org.eclipse.core.runtime.IExtension;
39 import org.eclipse.core.runtime.IExtensionPoint;
40 import org.eclipse.core.runtime.IExtensionRegistry;
41 import org.eclipse.core.runtime.IPath;
42 import org.eclipse.core.runtime.IStatus;
43 import org.eclipse.core.runtime.Platform;
44 import org.eclipse.core.runtime.Preferences;
45 import org.eclipse.core.runtime.Status;
46 import org.eclipse.help.internal.appserver.IWebappServer;
47 import org.eclipse.osgi.util.NLS;
48 import org.eclipse.tomcat.internal.extensions.IRealmFactory;
49
50 /**
51  * Single engine, single host, single connector Tomcat Application Server.
52  */

53 public class TomcatAppServer implements IWebappServer {
54     /**
55      * Specify this reserved value for the SSL port # to indicate that SSL
56      * should not be used
57      */

58     public final static int SSL_DISABLED = -1;
59
60     private String JavaDoc hostAddress;
61
62     private int port;
63
64     private int sslPort = SSL_DISABLED;
65
66     // false until an attempt to start Tomcat
67
private boolean isStarted = false;
68
69     // true after started without problems
70
private boolean running = false;
71
72     private Embedded embedded = null;
73
74     private Engine engine = null;
75
76     private Host host = null;
77
78     private Connector httpConnector = null;
79     private Connector sslConnector = null;
80     // Con
81
private ArrayList JavaDoc contexts = new ArrayList JavaDoc();
82
83     /**
84      * Constructs this class, but does not instantiates or start Tomcat classes
85      * until webapp are added.
86      */

87     public TomcatAppServer() {
88     }
89
90     /**
91      * @see org.eclipse.help.internal.appserver.IWebappServer#start(int,
92      * java.lang.String)
93      */

94     public synchronized void start(int port, String JavaDoc hostAddress) throws CoreException {
95         this.hostAddress = hostAddress;
96         this.port = port;
97
98         if (isStarted) {
99             return;
100         }
101         isStarted = true;
102         try {
103             FileLogger logger = new FileLogger();
104             logger.setDirectory(TomcatPlugin.getDefault().getStateLocation()
105                     .toOSString());
106             embedded = new Embedded(logger, new MemoryRealm());
107             embedded.setDebug(0);
108             embedded.setLogger(logger);
109             URL JavaDoc installURL = TomcatPlugin.getDefault().getBundle()
110                     .getEntry("/"); //$NON-NLS-1$
111
URL JavaDoc resolvedURL = FileLocator.resolve(installURL);
112             String JavaDoc home = FileLocator.toFileURL(resolvedURL).getFile();
113             System.setProperty("catalina.home", home); //$NON-NLS-1$
114
String JavaDoc base = home;
115             System.setProperty("catalina.base", base); //$NON-NLS-1$
116

117             // Set up realm if one found
118
if (TomcatPlugin.getDefault().getPluginPreferences().getInt(
119                     TomcatPlugin.PREF_SSL_PORT) >= 0) {
120                 Realm realm = getRealm();
121                 embedded.setRealm(realm);
122             }
123
124             // start now, and then add all the contexts..
125
embedded.start();
126
127             // Create a very basic container hierarchy
128
engine = embedded.createEngine();
129
130             host = embedded.createHost("localhost", home + "/webapps"); //$NON-NLS-1$ //$NON-NLS-2$
131

132             // all request go to our only host
133
engine.setDefaultHost(host.getName());
134
135             if (host instanceof StandardHost) {
136                 ((StandardHost) host)
137                         .setErrorReportValveClass("org.eclipse.tomcat.internal.EclipseErrorReportValve"); //$NON-NLS-1$
138
}
139             engine.addChild(host);
140
141             // Install the assembled container hierarchy
142
PrintStream JavaDoc sysOut = System.out;
143             // reassign standard output to prevent Tomcat from writing
144
// its version message there.
145
System.setOut(new PrintStream JavaDoc(new ByteArrayOutputStream JavaDoc()));
146             try {
147                 embedded.addEngine(engine);
148             } finally {
149                 System.setOut(sysOut);
150             }
151
152             // Root context
153
Context root = embedded.createContext("", home + "/webapps/ROOT"); //$NON-NLS-1$ //$NON-NLS-2$
154
// this line should be replaced once tomcat provides support
155
// for setting the working directory
156
if (root instanceof StandardContext) {
157                 ((StandardContext) root)
158                         .setWorkDir(getWorkingDirectory("ROOT")); //$NON-NLS-1$
159
}
160             root.setLoader(embedded.createLoader(this.getClass()
161                     .getClassLoader()));
162             contexts.add(root);
163             host.addChild(root);
164
165             InetAddress JavaDoc iAddress = null;
166             if (this.hostAddress != null) {
167                 try {
168                     iAddress = InetAddress.getByName(this.hostAddress);
169                 } catch (UnknownHostException JavaDoc uhe) {
170                     // will default to all interfaces
171
}
172             }
173             updateSslPort(iAddress);
174             if (this.port == 0) {
175                 this.port = SocketUtil.findUnusedLocalPort(iAddress);
176                 if (this.port == -1) {
177                     throw new CoreException(
178                             new Status(
179                                     IStatus.ERROR,
180                                     TomcatPlugin.PLUGIN_ID,
181                                     IStatus.OK,
182                                     TomcatResources.TomcatAppServer_start_CannotObtainPort,
183                                     null));
184                 }
185             }
186
187             // Create Connector
188
Connector connector = embedded.createConnector(null, this.port,
189                     false);
190             // Override defaults on CoyoteConnector
191
if (connector instanceof CoyoteConnector) {
192                 CoyoteConnector connectorImpl = (CoyoteConnector) connector;
193                 if (iAddress != null) {
194                     // bug in Embedded that incorrectly sets host on connector.
195
// pass null when creating connector, and set host here if
196
// it is specified
197
connectorImpl.setAddress(iAddress.getHostAddress());
198                 }
199                 Preferences pref = TomcatPlugin.getDefault()
200                         .getPluginPreferences();
201                 int acceptCount = pref.getInt(TomcatPlugin.PREF_ACCEPT_COUNT);
202                 if (acceptCount > 0) {
203                     connectorImpl.setAcceptCount(acceptCount);
204                 }
205                 int maxProcessors = pref
206                         .getInt(TomcatPlugin.PREF_MAX_PROCESSORS);
207                 if (maxProcessors > 0) {
208                     connectorImpl.setMaxProcessors(maxProcessors);
209                 }
210                 int minProcessors = pref
211                         .getInt(TomcatPlugin.PREF_MIN_PROCESSORS);
212                 if (minProcessors > 0) {
213                     connectorImpl.setMinProcessors(minProcessors);
214                 }
215                 if (this.sslPort > 0) {
216                     connectorImpl.setRedirectPort(this.sslPort);
217                     connectorImpl.setEnableLookups(true);
218                     connectorImpl.setConnectionTimeout(20000);
219                     connectorImpl.setUseURIValidationHack(false);
220                     connectorImpl.setDisableUploadTimeout(true);
221                 }
222                 // connectorImpl.setDebug(0);
223
// If there is problem in embedded.addConnector()
224
// there is no exception, so add a listener
225
connectorImpl.addLifecycleListener(new LifecycleListener() {
226                     public void lifecycleEvent(LifecycleEvent event) {
227                         if ("start".equals(event.getType())) //$NON-NLS-1$
228
running = true;
229                     }
230                 });
231             }
232
233             // add Connector to Tomcat
234
PrintStream JavaDoc sysErr = System.err;
235             // reassign standard error to prevent Coyote from writing
236
// its version message there.
237
System.setErr(new PrintStream JavaDoc(new ByteArrayOutputStream JavaDoc()));
238             try {
239                 embedded.addConnector(connector);
240                 httpConnector = connector;
241             } finally {
242                 System.setErr(sysErr);
243             }
244
245             if (this.sslPort > 0) {
246                 createSSLConnector(iAddress, this.sslPort);
247             }
248
249             // if null passed for hostAddress, use local host
250
if (this.hostAddress == null) {
251                 this.hostAddress = "127.0.0.1"; //$NON-NLS-1$
252
}
253
254             // running = true;
255
TomcatPlugin.getDefault().setAppserver(this);
256
257         } catch (Exception JavaDoc exc) {
258             TomcatPlugin
259                     .logError(
260                             "Exception occurred starting the embedded application server.", //$NON-NLS-1$
261
exc);
262             if (exc instanceof CoreException) {
263                 throw (CoreException) exc;
264             }
265             throw new CoreException(new Status(IStatus.ERROR,
266                     TomcatPlugin.PLUGIN_ID, IStatus.OK,
267                     TomcatResources.TomcatAppServer_start,
268                     exc));
269         }
270         if (!running) {
271             throw new CoreException(new Status(IStatus.ERROR,
272                     TomcatPlugin.PLUGIN_ID, IStatus.OK,
273                     TomcatResources.TomcatAppServer_start, null));
274         }
275     }
276
277     /**
278      * Update {@link sslPort} to refer an appropriate port. If the user set
279      * sslPort to 0, an arbitrary free port will be used.
280      *
281      * @param iAddress
282      * {@link InetAddress} object representing the machine hosting
283      * the help system
284      * @return port number of use for the SSL connection
285      * @throws CoreException
286      */

287     private int updateSslPort(InetAddress JavaDoc iAddress) throws CoreException {
288         this.sslPort = TomcatPlugin.getDefault().getPluginPreferences().getInt(
289                 TomcatPlugin.PREF_SSL_PORT);
290         if (this.sslPort == 0) {
291             this.sslPort = SocketUtil.findUnusedLocalPort(iAddress);
292             if (this.sslPort == -1) {
293                 throw new CoreException(new Status(IStatus.ERROR,
294                         TomcatPlugin.PLUGIN_ID, IStatus.OK,
295                         TomcatResources.TomcatAppServer_start_CannotObtainPort,
296                         null));
297             }
298         }
299         return this.sslPort;
300     }
301
302     /**
303      * @param iAddress
304      * InetAddress representing the machine hosting the help system.
305      * @param sslport
306      * port # to use for the SSL connection
307      * @throws CoreException
308      */

309     private void createSSLConnector(InetAddress JavaDoc iAddress, int sslport)
310             throws CoreException {
311         // Create Connector
312
this.sslConnector = embedded.createConnector(null, sslport, false);
313         // Override defaults on CoyoteConnector
314
if (this.sslConnector instanceof CoyoteConnector) {
315             CoyoteConnector connectorImpl = (CoyoteConnector) this.sslConnector;
316             if (iAddress != null) {
317                 // bug in Embedded that incorrectly sets host on connector.
318
// pass null when creating connector, and set host here if
319
// it is specified
320
connectorImpl.setAddress(iAddress.getHostAddress());
321             }
322             Preferences pref = TomcatPlugin.getDefault().getPluginPreferences();
323             int acceptCount = pref.getInt(TomcatPlugin.PREF_ACCEPT_COUNT);
324             if (acceptCount > 0) {
325                 connectorImpl.setAcceptCount(acceptCount);
326             }
327             int maxProcessors = pref.getInt(TomcatPlugin.PREF_MAX_PROCESSORS);
328             if (maxProcessors > 0) {
329                 connectorImpl.setMaxProcessors(maxProcessors);
330             }
331             int minProcessors = pref.getInt(TomcatPlugin.PREF_MIN_PROCESSORS);
332             if (minProcessors > 0) {
333                 connectorImpl.setMinProcessors(minProcessors);
334             }
335             connectorImpl.setUseURIValidationHack(false);
336             connectorImpl.setDisableUploadTimeout(true);
337             connectorImpl.setSecure(true);
338             String JavaDoc scheme = pref.getString(TomcatPlugin.PREF_SSL_SCHEME);
339             if ((scheme != null) && (!("".equals(scheme.trim())))) { //$NON-NLS-1$
340
connectorImpl.setScheme(scheme);
341             }
342             connectorImpl.setEnableLookups(true);
343             CoyoteServerSocketFactory factory = new CoyoteServerSocketFactory();
344             factory.setClientAuth(false);
345             String JavaDoc protocol = pref.getString(TomcatPlugin.PREF_SSL_PROTOCOL);
346             if ((protocol != null) && (!("".equals(protocol.trim())))) { //$NON-NLS-1$
347
factory.setProtocol(protocol);
348             }
349             String JavaDoc algorithm = pref.getString(TomcatPlugin.PREF_SSL_ALGORITHM);
350             if ((algorithm != null) && (!("".equals(algorithm.trim())))) { //$NON-NLS-1$
351
factory.setAlgorithm(algorithm);
352             }
353             String JavaDoc keyStoreFile = pref
354                     .getString(TomcatPlugin.PREF_KEY_STORE_FILE);
355             if ((keyStoreFile != null) && (!("".equals(keyStoreFile.trim())))) { //$NON-NLS-1$
356
factory.setKeystoreFile(keyStoreFile);
357             }
358             String JavaDoc keyStorePassword = pref
359                     .getString(TomcatPlugin.PREF_KEY_STORE_PASSWORD);
360             if ((keyStorePassword != null)
361                     && (!("".equals(keyStorePassword.trim())))) { //$NON-NLS-1$
362
factory.setKeystorePass(keyStorePassword);
363             }
364             connectorImpl.setFactory(factory);
365             connectorImpl.setDebug(0);
366             // If there is problem in embedded.addConnector()
367
// there is no exception, so add a listener
368
connectorImpl.addLifecycleListener(new LifecycleListener() {
369                 public void lifecycleEvent(LifecycleEvent event) {
370                     if ("start".equals(event.getType())) //$NON-NLS-1$
371
running = true;
372                 }
373             });
374         }
375
376         // add Connector to Tomcat
377
PrintStream JavaDoc sysErr = System.err;
378         // reassign standard error to prevent Coyote from writing
379
// its version message there.
380
System.setErr(new PrintStream JavaDoc(new ByteArrayOutputStream JavaDoc()));
381         try {
382             embedded.addConnector(this.sslConnector);
383         } finally {
384             System.setErr(sysErr);
385         }
386     }
387
388     /**
389      * Creates a {@link Realm}object using the information contained in
390      * extensions of the type org.eclipse.tomcat.realmfactory in the plugin
391      * registry.
392      *
393      * @return the {@link Realm}object created
394      */

395     private Realm getRealm() {
396         IExtensionRegistry registry = Platform.getExtensionRegistry();
397         IExtensionPoint extensionPoint = registry.getExtensionPoint(
398                 TomcatPlugin.PLUGIN_ID, "realmfactory"); //$NON-NLS-1$
399
Realm realm = null;
400         if (extensionPoint != null) {
401             IExtension[] extensions = extensionPoint.getExtensions();
402             if ((extensions != null) && (extensions.length == 1)) {
403                 IConfigurationElement[] factoryElements = extensions[0]
404                         .getConfigurationElements();
405                 if ((factoryElements != null) && (factoryElements.length == 1)) {
406                     try {
407                         IRealmFactory realmFactory = (IRealmFactory) factoryElements[0]
408                                 .createExecutableExtension("class"); //$NON-NLS-1$
409
realm = realmFactory.createRealm();
410                     } catch (CoreException e) {
411                         logError(
412                                 TomcatResources.TomcatAppServer_getRealmFactoryFailed,
413                                 e);
414                     }
415                 } else {
416                     if ((factoryElements == null)
417                             || (factoryElements.length == 0)) {
418                         logError(TomcatResources.TomcatAppServer_missingFactoryElement);
419                     } else {
420                         logError(TomcatResources.TomcatAppServer_multipleFactoryElements);
421                     }
422                 }
423             } else {
424                 if ((extensions == null) || (extensions.length == 0)) {
425                     logError(TomcatResources.TomcatAppServer_missingRealmExtension);
426                 } else {
427                     logError(TomcatResources.TomcatAppServer_multipleRealmExtensions);
428                 }
429             }
430         } else {
431             logError(TomcatResources.TomcatAppServer_missingRealmExtensionPoint);
432         }
433         return realm;
434     }
435
436     /**
437      * Create an error entry in the log
438      *
439      * @param msg
440      * error message
441      */

442     private void logError(String JavaDoc msg) {
443         logError(msg, null);
444     }
445
446     /**
447      * Create an error entry in the log
448      *
449      * @param msg
450      * error message
451      * @param cause
452      * {@link Throwable} associated with this error message
453      */

454     private void logError(String JavaDoc msg, Throwable JavaDoc cause) {
455         TomcatPlugin.logError(msg, cause);
456     }
457
458     /**
459      * @see org.eclipse.help.internal.appserver.IWebappServer#start(java.lang.String,
460      * org.eclipse.core.runtime.IPath, java.lang.ClassLoader)
461      */

462     public synchronized void start(String JavaDoc webappName, IPath path, ClassLoader JavaDoc customLoader)
463             throws CoreException {
464
465         if (!isStarted) {
466             start(port, hostAddress);
467         }
468         if (!running) {
469             throw new CoreException(new Status(IStatus.ERROR,
470                     TomcatPlugin.PLUGIN_ID, IStatus.OK, NLS.bind(
471                             TomcatResources.TomcatAppServer_addingWebapp,
472                             webappName, path.toOSString()), null));
473         }
474
475         String JavaDoc contextPath = webappName;
476         if (!contextPath.startsWith("/")) { //$NON-NLS-1$
477
contextPath = "/" + contextPath; //$NON-NLS-1$
478
}
479         try {
480             Context context = embedded.createContext(contextPath, path
481                     .toOSString());
482             if (context instanceof StandardContext) {
483                 ((StandardContext) context)
484                         .setWorkDir(getWorkingDirectory(webappName));
485             }
486
487             WebAppClassLoader webappLoader = new WebAppClassLoader(customLoader);
488             context.setLoader(embedded.createLoader(webappLoader));
489
490             host.addChild(context);
491             contexts.add(context);
492         } catch (Exception JavaDoc exc) {
493             throw new CoreException(new Status(IStatus.ERROR,
494                     TomcatPlugin.PLUGIN_ID, IStatus.OK, NLS.bind(
495                             "TomcatAppServer.addingWebapp", webappName, path //$NON-NLS-1$
496
.toOSString()), exc));
497         }
498     }
499
500     /**
501      * @see org.eclipse.help.internal.appserver.IWebappServer#stop(java.lang.String)
502      */

503     public synchronized void stop(String JavaDoc webappName) throws CoreException {
504         if (!running) {
505             return;
506         }
507         Context context = (Context) host.findChild("/" + webappName); //$NON-NLS-1$
508
if (context != null) {
509             contexts.remove(context);
510             embedded.removeContext(context);
511         }
512     }
513
514     /**
515      * @see org.eclipse.help.internal.appserver.IWebappServer#getHost()
516      */

517     public String JavaDoc getHost() {
518         if (!running) {
519             return null;
520         }
521         return hostAddress;
522     }
523
524     /**
525      * @see org.eclipse.help.internal.appserver.IWebappServer#getPort()
526      */

527     public int getPort() {
528         if (!running) {
529             return 0;
530         }
531         return port;
532     }
533
534     /**
535      * @see org.eclipse.help.internal.appserver.IWebappServer#isRunning()
536      */

537     public boolean isRunning() {
538         return running;
539     }
540
541     /**
542      * @see org.eclipse.help.internal.appserver.IWebappServer#stop()
543      */

544     public synchronized void stop() throws CoreException {
545         if (!running) {
546             return;
547         }
548         running = false;
549         // Remove all contexts
550
for(int i = 0; i< contexts.size(); i++){
551             embedded.removeContext((Context)contexts.get(i));
552             contexts.remove(contexts.get(i));
553         }
554
555         // Remove the sslConnector, if present.
556
try {
557             if (sslConnector != null) {
558                 embedded.removeConnector(this.sslConnector);
559             }
560         } catch (Exception JavaDoc exc) {
561             throw new CoreException(new Status(IStatus.ERROR,
562                     TomcatPlugin.PLUGIN_ID, IStatus.OK,
563                     TomcatResources.TomcatAppServer_sslConnectorRemove,
564                     exc));
565         }
566
567         // Remove the HTTP Connector, if present.
568
try {
569             if (httpConnector != null) {
570                 embedded.removeConnector(this.httpConnector);
571             }
572         } catch (Exception JavaDoc exc) {
573             throw new CoreException(new Status(IStatus.ERROR,
574                     TomcatPlugin.PLUGIN_ID, IStatus.OK,
575                     TomcatResources.TomcatAppServer_httpConnectorRemove,
576                     exc));
577         }
578
579         // Remove the engine (which should trigger removing the connector)
580
try {
581             embedded.removeEngine(engine);
582         } catch (Exception JavaDoc exc) {
583             throw new CoreException(new Status(IStatus.ERROR,
584                     TomcatPlugin.PLUGIN_ID, IStatus.OK,
585                     TomcatResources.TomcatAppServer_engineRemove,
586                     exc));
587         }
588         // Shut down this tomcat server (should have nothing left to do)
589
try {
590             embedded.stop();
591         } catch (LifecycleException e) {
592             throw new CoreException(new Status(IStatus.ERROR,
593                     TomcatPlugin.PLUGIN_ID, IStatus.OK,
594                     TomcatResources.TomcatAppServer_embeddedStop,
595                     e));
596         }
597         isStarted = false;
598     }
599
600     private String JavaDoc getWorkingDirectory(String JavaDoc webApp) {
601         return TomcatPlugin.getDefault().getStateLocation().append(webApp)
602                 .toOSString();
603     }
604 }
605
Popular Tags