KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > archive > crawler > SimpleHttpServer


1 /*
2  * SimpleHttpServer
3  *
4  * $Id: SimpleHttpServer.java,v 1.29.2.1 2007/01/13 01:31:06 stack-sf Exp $
5  *
6  * Created on Jul 11, 2003
7  *
8  * Copyright (C) 2003 Internet Archive.
9  *
10  * This file is part of the Heritrix web crawler (crawler.archive.org).
11  *
12  * Heritrix is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * any later version.
16  *
17  * Heritrix is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser Public License
23  * along with Heritrix; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  */

26 package org.archive.crawler;
27
28 import java.io.File JavaDoc;
29 import java.io.FileNotFoundException JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.net.UnknownHostException JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Arrays JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.NoSuchElementException JavaDoc;
38
39 import org.mortbay.http.HashUserRealm;
40 import org.mortbay.http.HttpListener;
41 import org.mortbay.http.HttpServer;
42 import org.mortbay.http.NCSARequestLog;
43 import org.mortbay.http.RequestLog;
44 import org.mortbay.http.SocketListener;
45 import org.mortbay.jetty.Server;
46 import org.mortbay.jetty.servlet.WebApplicationContext;
47 import org.mortbay.util.InetAddrPort;
48
49
50 /**
51  * Wrapper for embedded Jetty server.
52  *
53  * Loads up all webapps under webapp directory.
54  *
55  */

56 public class SimpleHttpServer
57 {
58     private int port;
59     private Server server = null;
60
61     /**
62      * Default web port.
63      */

64     public static final int DEFAULT_PORT = 8080;
65
66     /**
67      * Webapp contexts returned out of a server start.
68      */

69     private List JavaDoc<WebApplicationContext> contexts
70      = new ArrayList JavaDoc<WebApplicationContext>();
71
72     /**
73      * Name of the root webapp.
74      */

75     private static final String JavaDoc ROOT_WEBAPP = "root";
76
77     /**
78      * Name of the admin webapp.
79      */

80     private static final String JavaDoc ADMIN_WEBAPP = "admin";
81
82     /**
83      * List of webapps to deploy.
84      */

85     private static final List JavaDoc webapps =
86         Arrays.asList(new String JavaDoc [] {ROOT_WEBAPP, ADMIN_WEBAPP});
87
88
89     public SimpleHttpServer() throws Exception JavaDoc {
90         this(DEFAULT_PORT, true);
91     }
92
93     public SimpleHttpServer(int port, boolean expandWebapps)
94     throws Exception JavaDoc {
95         this(SimpleHttpServer.webapps, port, expandWebapps);
96     }
97     
98     /**
99      * @param name Name of webapp to load.
100      * @param context Where to mount the webapp. If passed context is
101      * null or empty string, we'll use '/' + <code>name</code> else if
102      * passed '/' then we'll add the webapp as the root webapp.
103      * @param port Port to run on.
104      * @param expandWebapps True if we're to expand the webapp passed.
105      * @throws Exception
106      * @deprecated Use SimpleHttpServer(name,context,hosts,port,expandWebapps)
107      */

108     public SimpleHttpServer(boolean localhostOnly, String JavaDoc name, String JavaDoc context,
109         int port, boolean expandWebapps)
110     throws Exception JavaDoc {
111         this(name, context, determineHosts(localhostOnly), port, expandWebapps);
112     }
113     
114     
115     /**
116      * Constructor.
117      *
118      * @param name Name of webapp to load
119      * @param context Where to mount the webap. If null or empty string,
120      * we'll use '/' + <code>name</code>; if passed '/'
121      * then we'll add the webapp as the root webapp
122      * @param hosts list of hosts to bind to
123      * @param port port to listen on
124      * @param expandWebapps true to expand webapp passed
125      * @throws Exception
126      */

127     public SimpleHttpServer(String JavaDoc name, String JavaDoc context,
128         Collection JavaDoc<String JavaDoc> hosts, int port, boolean expandWebapps)
129     throws Exception JavaDoc {
130         initialize(hosts, port);
131         addWebapp(name, context, expandWebapps);
132         this.server.setRequestLog(getServerLogging());
133     }
134
135
136     /**
137      * @param webapps List of webapps to load.
138      * @param port Port to run on.
139      * @param expandWebapps True if we're to expand the webapps found.
140      * @throws Exception
141      */

142     public SimpleHttpServer(List JavaDoc webapps, int port, boolean expandWebapps)
143     throws Exception JavaDoc {
144         initialize(null, port);
145         
146         // Add each of the webapps in turn. If we're passed the root webapp,
147
// give it special handling -- assume its meant to be server root and
148
// its meant to be mounted on '/'. The below also favors the war file
149
// if its present.
150
for (Iterator JavaDoc i = webapps.iterator(); i.hasNext();) {
151             addWebapp((String JavaDoc)i.next(), null, expandWebapps);
152         }
153         this.server.setRequestLog(getServerLogging());
154     }
155     
156     /**
157      * Add a webapp.
158      * @param name Name of webapp to add.
159      * @param context Context to add the webapp on.
160      * @param expand True if we should expand the webapps.
161      * @throws IOException
162      */

163     protected void addWebapp(String JavaDoc name, String JavaDoc context, boolean expand)
164     throws IOException JavaDoc {
165         File JavaDoc ptr = new File JavaDoc(getWARSPath(), name + ".war");
166         if (!ptr.exists()) {
167             ptr = new File JavaDoc(getWARSPath(), name);
168             if (!ptr.exists()) {
169                 throw new FileNotFoundException JavaDoc(ptr.getAbsolutePath());
170             }
171         }
172         // If webapp name is for root, mount it on '/', else '/WEBAPP_NAME'.
173
if (context == null || context.length() <= 0) {
174             context = "/" + ((name.equals(ROOT_WEBAPP))? "": name);
175         }
176         WebApplicationContext c =
177             this.server. addWebApplication(context, ptr.getAbsolutePath());
178         if (context.equals("/")) {
179             // If we've just mounted the root webapp, make it the root.
180
this.server.setRootWebApp(name);
181         }
182         // Selftest depends on finding the extracted WARs. TODO: Fix.
183
c.setExtractWAR(expand);
184         // let login sessions last 24 hours
185
c.getServletHandler().getSessionManager().setMaxInactiveInterval(86400);
186         this.contexts.add(c);
187     }
188     
189     /**
190      * Initialize the server.
191      * Called from constructors.
192      * @param port Port to start the server on.
193      * @deprecated Use initialize(Collection<String>, port) instead
194      */

195     protected void initialize(int port, boolean localhostOnly) {
196         Collection JavaDoc<String JavaDoc> hosts = determineHosts(localhostOnly);
197         initialize(hosts, port);
198     }
199     
200     
201     /**
202      * Initialize the server. Called from constructors.
203      *
204      * @param hosts the hostnames to bind to; if empty or null, will bind
205      * to all interfaces
206      * @param port the port to listen on
207      */

208     protected void initialize(Collection JavaDoc<String JavaDoc> hosts, int port) {
209         this.server = new Server();
210         this.port = port;
211         if (hosts.isEmpty()) {
212             SocketListener listener = new SocketListener();
213             listener.setPort(port);
214             this.server.addListener(listener);
215             return;
216         }
217         
218         for (String JavaDoc host: hosts) try {
219             InetAddrPort addr = new InetAddrPort(host, port);
220             SocketListener listener = new SocketListener(addr);
221             this.server.addListener(listener);
222         } catch (UnknownHostException JavaDoc e) {
223             e.printStackTrace();
224         }
225     }
226     
227     
228     private static Collection JavaDoc<String JavaDoc> determineHosts(boolean lho) {
229         Collection JavaDoc<String JavaDoc> hosts = new ArrayList JavaDoc<String JavaDoc>();
230         if (lho) {
231             hosts.add("127.0.0.1");
232         }
233         return hosts;
234     }
235
236
237     /**
238      * Setup log files.
239      * @return RequestLog instance to add to a server.
240      * @throws Exception
241      */

242     protected RequestLog getServerLogging() throws Exception JavaDoc {
243         // Have accesses go into the stdout/stderr log for now. Later, if
244
// demand, we'll have accesses go into their own file.
245
NCSARequestLog a = new NCSARequestLog(Heritrix.getHeritrixOut());
246         a.setRetainDays(90);
247         a.setAppend(true);
248         a.setExtended(false);
249         a.setBuffered(false);
250         a.setLogTimeZone("GMT");
251         a.start();
252         return a;
253     }
254
255     /**
256      * Return the directory that holds the WARs we're to deploy.
257      *
258      * @return Return webapp path (Path returned has a trailing '/').
259      * @throws IOException
260      */

261     private static String JavaDoc getWARSPath() throws IOException JavaDoc {
262         String JavaDoc webappsPath = Heritrix.getWarsdir().getAbsolutePath();
263         if (!webappsPath.endsWith(File.separator))
264         {
265             webappsPath = webappsPath + File.separator;
266         }
267         return webappsPath;
268     }
269
270     /**
271      * Start the server.
272      *
273      * @throws Exception if problem starting server or if server already
274      * started.
275      */

276     public synchronized void startServer()
277         throws Exception JavaDoc {
278
279         this.server.start();
280     }
281
282     /**
283      * Stop the running server.
284      *
285      * @throws InterruptedException
286      */

287     public synchronized void stopServer() throws InterruptedException JavaDoc {
288
289         if (this.server != null)
290         {
291             this.server.stop();
292         }
293     }
294
295     /* (non-Javadoc)
296      * @see java.lang.Object#finalize()
297      */

298     protected void finalize()
299         throws Throwable JavaDoc {
300
301         stopServer();
302         super.finalize();
303     }
304
305     /**
306      * @return Port server is running on.
307      */

308     public int getPort() {
309
310         return this.port;
311     }
312
313     /**
314      * @return Server reference.
315      */

316     public HttpServer getServer() {
317
318         return this.server;
319     }
320
321     /**
322      * @param contextName Name of context to look for. Possible names would be
323      * '/admin', '/', or '/selftest'.
324      *
325      * @return named context.
326      */

327     private WebApplicationContext getContext(String JavaDoc contextName) {
328
329         WebApplicationContext context = null;
330
331         if (this.contexts == null)
332         {
333             throw new NullPointerException JavaDoc("No contexts available.");
334         }
335
336         if (!contextName.startsWith("/")) {
337             contextName = '/' + contextName;
338         }
339         for (Iterator JavaDoc i = this.contexts.iterator(); i.hasNext();)
340         {
341             WebApplicationContext c = (WebApplicationContext)i.next();
342             if (c.getHttpContextName().equals(contextName))
343             {
344                 context = c;
345                 break;
346             }
347         }
348
349         if (context == null)
350         {
351             throw new NoSuchElementException JavaDoc("Unknown webapp: " + contextName);
352         }
353
354         return context;
355     }
356
357     /**
358      * Setup a realm on the server named for the webapp and add to the
359      * passed webapp's context.
360      *
361      * Used by the selftest to check digest authentication is working.
362      * For this all to work, the <code>web.xml</code> needs to set with
363      * a security constraint that points to a realm named for the passed
364      * webapp, <code>webappName</code>.
365      *
366      * @param realmName Name of realm to configure.
367      * @param contextName Name of context we're using with this realm.
368      * If null, we'll use the realm name as context name.
369      * @param authProperties Path to file that holds the auth login and
370      * password.
371      * @return Hash of user realms.
372      *
373      * @throws IOException
374      */

375     public HashUserRealm setAuthentication(String JavaDoc realmName,
376         String JavaDoc contextName, String JavaDoc authProperties)
377     throws IOException JavaDoc {
378         HashUserRealm realm =
379             (authProperties != null && authProperties.length() > 0)?
380                 new HashUserRealm(realmName, authProperties):
381                 new HashUserRealm(realmName);
382         this.server.addRealm(realm);
383         if (contextName == null || contextName.length() <= 0) {
384             contextName = realmName;
385         }
386         WebApplicationContext context = getContext(contextName);
387         context.setRealmName(realmName);
388         return realm;
389     }
390     
391     public void setAuthentication(String JavaDoc realmName, String JavaDoc contextName,
392             String JavaDoc username, String JavaDoc password, String JavaDoc role)
393     throws IOException JavaDoc {
394         HashUserRealm realm = setAuthentication(realmName, contextName,
395             null);
396         realm.put(username, password);
397         realm.addUserToRole(username, role);
398     }
399     
400
401     /**
402      * Reset the administrator login info.
403      *
404      * @param realmAndRoleName for our use, always 'admin'
405      * @param oldUsername previous username to replace/disable
406      * @param newUsername new username (may be same as old)
407      * @param newPassword new password
408      */

409     public void resetAuthentication(String JavaDoc realmAndRoleName,
410         String JavaDoc oldUsername, String JavaDoc newUsername, String JavaDoc newPassword) {
411         HashUserRealm realm = (HashUserRealm)this.server.
412             getRealm(realmAndRoleName);
413         realm.remove(oldUsername);
414         realm.put(newUsername,newPassword);
415         realm.addUserToRole(newUsername, realmAndRoleName);
416     }
417
418     /**
419      * Get path to named webapp.
420      *
421      * @param name Name of webpp. Possible names are 'admin' or 'selftest'.
422      *
423      * @return Path to deployed webapp.
424      */

425     public File JavaDoc getWebappPath(String JavaDoc name) {
426
427         if (this.server == null) {
428             throw new NullPointerException JavaDoc("Server does not exist");
429         }
430         String JavaDoc contextName =
431             (name.equals(this.server.getRootWebApp()))? "/": "/" + name;
432         return new
433             File JavaDoc(getContext(contextName).getServletHandler().getRealPath("/"));
434     }
435
436     /**
437      * @return Returns the root webapp name.
438      */

439     public static String JavaDoc getRootWebappName()
440     {
441         return ROOT_WEBAPP;
442     }
443     
444     
445     /**
446      * Returns the hosts that the server is listening on.
447      *
448      * @return the hosts that the server is listening on.
449      */

450     public Collection JavaDoc<String JavaDoc> getHosts() {
451         ArrayList JavaDoc<String JavaDoc> result = new ArrayList JavaDoc<String JavaDoc>();
452         for (HttpListener listener: server.getListeners()) {
453             result.add(listener.getHost());
454         }
455         return result;
456     }
457 }
458
Popular Tags