001: /*
002: License $Id: JoHost.java,v 1.9 2003/09/13 04:59:57 hendriks73 Exp $
003:
004: Copyright (c) 2001-2005 tagtraum industries.
005:
006: LGPL
007: ====
008:
009: jo! is free software; you can redistribute it and/or
010: modify it under the terms of the GNU Lesser General Public
011: License as published by the Free Software Foundation; either
012: version 2.1 of the License, or (at your option) any later version.
013:
014: jo! is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018:
019: You should have received a copy of the GNU Lesser General Public
020: License along with this library; if not, write to the Free Software
021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022:
023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
024:
025:
026: Sun license
027: ===========
028:
029: This release contains software by Sun Microsystems. Therefore
030: the following conditions have to be met, too. They apply to the
031: files
032:
033: - lib/mail.jar
034: - lib/activation.jar
035: - lib/jsse.jar
036: - lib/jcert.jar
037: - lib/jaxp.jar
038: - lib/crimson.jar
039: - lib/servlet.jar
040: - lib/jnet.jar
041: - lib/jaas.jar
042: - lib/jaasmod.jar
043:
044: contained in this release.
045:
046: a. Licensee may not modify the Java Platform
047: Interface (JPI, identified as classes contained within the javax
048: package or any subpackages of the javax package), by creating additional
049: classes within the JPI or otherwise causing the addition to or modification
050: of the classes in the JPI. In the event that Licensee creates any
051: Java-related API and distribute such API to others for applet or
052: application development, you must promptly publish broadly, an accurate
053: specification for such API for free use by all developers of Java-based
054: software.
055:
056: b. Software is confidential copyrighted information of Sun and
057: title to all copies is retained by Sun and/or its licensors. Licensee
058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
059: reverse engineer Software. Software may not be leased, assigned, or
060: sublicensed, in whole or in part. Software is not designed or intended
061: for use in on-line control of aircraft, air traffic, aircraft navigation
062: or aircraft communications; or in the design, construction, operation or
063: maintenance of any nuclear facility. Licensee warrants that it will not
064: use or redistribute the Software for such purposes.
065:
066: c. Software is provided "AS IS," without a warranty
067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
070:
071: d. This License is effective until terminated. Licensee may
072: terminate this License at any time by destroying all copies of Software.
073: This License will terminate immediately without notice from Sun if Licensee
074: fails to comply with any provision of this License. Upon such termination,
075: Licensee must destroy all copies of Software.
076:
077: e. Software, including technical data, is subject to U.S.
078: export control laws, including the U.S. Export Administration Act and its
079: associated regulations, and may be subject to export or import regulations
080: in other countries. Licensee agrees to comply strictly with all such
081: regulations and acknowledges that it has the responsibility to obtain
082: licenses to export, re-export, or import Software. Software may not be
083: downloaded, or otherwise exported or re-exported (i) into, or to a national
084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
087: Commerce Department's Table of Denial Orders.
088:
089:
090: Feedback
091: ========
092:
093: We encourage your feedback and suggestions and want to use your feedback to
094: improve the Software. Send all such feedback to:
095: <feedback@tagtraum.com>
096:
097: For more information on tagtraum industries and jo!
098: please see <http://www.tagtraum.com/>.
099:
100:
101: */
102: package com.tagtraum.jo;
103:
104: import com.tagtraum.framework.http.StatusCodes;
105: import com.tagtraum.framework.log.C_Log;
106: import com.tagtraum.framework.log.Log;
107: import com.tagtraum.framework.server.ServerException;
108: import com.tagtraum.framework.util.UnSyncStringBuffer;
109: import com.tagtraum.jo.builder.I_JoHostBuilder;
110: import com.tagtraum.jo.event.ChildModificationEvent;
111: import com.tagtraum.jo.event.ChildModificationListener;
112: import com.tagtraum.perf.util.FastReadSyncMap;
113:
114: import java.io.File;
115: import java.io.IOException;
116: import java.util.*;
117:
118: /**
119: * Represents a virtual host. Hosts manage {@link I_JoServletContextPeer}s
120: * and some host specific data.
121: *
122: * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
123: * @version 1.1beta1 $Id: JoHost.java,v 1.9 2003/09/13 04:59:57 hendriks73 Exp $
124: */
125: public class JoHost implements C_Jo, I_JoHost {
126:
127: /**
128: * Source-Version
129: */
130: public static String vcid = "$Id: JoHost.java,v 1.9 2003/09/13 04:59:57 hendriks73 Exp $";
131:
132: /**
133: * Prefix rules.
134: */
135: private Map myPrefixMatchRules;
136:
137: /**
138: * This Host's Peers.
139: */
140: private Map myServletContextPeers;
141:
142: /**
143: * The Service.
144: */
145: private I_JoServletService myService;
146:
147: /**
148: * Server-Info
149: */
150: private String myServerInfo;
151:
152: /**
153: * This host's name.
154: */
155: private String myName;
156:
157: /**
158: * Hostnames for this host.
159: */
160: private String[] myHostnames;
161:
162: /**
163: * Builder.
164: */
165: private I_JoHostBuilder myBuilder;
166:
167: /**
168: * Access log.
169: */
170: private Log accessLog;
171:
172: /**
173: * Log.
174: */
175: private Log log;
176:
177: /**
178: * Directories where the wars reside.
179: */
180: private Set warDirs;
181:
182: /**
183: * Listeners for modification.
184: */
185: private Set childModificationListeners;
186:
187: private static ResourceBundle localStrings = ResourceBundle
188: .getBundle("com.tagtraum.jo.localStrings");
189:
190: /**
191: * Constructor for this host.
192: */
193: public JoHost() {
194: try {
195: myServletContextPeers = new FastReadSyncMap(new HashMap());
196: myPrefixMatchRules = new FastReadSyncMap(new HashMap());
197: } catch (CloneNotSupportedException cnse) {
198: // should not be possible
199: cnse.printStackTrace();
200: Log.getLog().log(cnse, C_Log.ERROR);
201: // FIXME!!! Unspecific RuntimeException is a NONO! (rik)
202: throw new RuntimeException(cnse.toString());
203: }
204: childModificationListeners = new HashSet();
205: warDirs = new HashSet();
206: }
207:
208: /**
209: * Initializes this host.
210: */
211: public void init() throws ServerException {
212: myService = null;
213: myName = null;
214: myHostnames = null;
215: myServerInfo = null;
216:
217: myServletContextPeers.clear();
218: myPrefixMatchRules.clear();
219: childModificationListeners.clear();
220: warDirs.clear();
221: }
222:
223: /**
224: * Sets the Builder for this host.
225: */
226: public void setBuilder(I_JoHostBuilder builder) {
227: myBuilder = builder;
228: }
229:
230: /**
231: * Gets the Builder for this host.
232: */
233: public I_JoHostBuilder getBuilder() {
234: return myBuilder;
235: }
236:
237: /**
238: * Rebuilds the host or its components if necessary.
239: */
240: public void rebuild() {
241: autoDeploy();
242: if (getBuilder().needsRebuild()) {
243: if (getLog().isLog(C_Log.MODULE)) {
244: getLog().log(
245: localStrings.getString("rebuilding_host")
246: + this , C_Log.MODULE);
247: }
248: try {
249: getBuilder().rebuild(this );
250: } catch (Exception e) {
251: if (getLog().isLog(C_Log.ERROR)) {
252: getLog().log(
253: localStrings
254: .getString("host_rebuilt_failed")
255: + this , C_Log.ERROR);
256: getLog().log(e, C_Log.ERROR);
257: }
258: }
259: }
260: // if the host does not need to be rebuilt, maybe some
261: // peers need rebuilding...
262: else {
263: Iterator it = myServletContextPeers.values().iterator();
264: while (it.hasNext()) {
265: I_JoServletContextPeer peer = (I_JoServletContextPeer) it
266: .next();
267: if (peer.needsRebuild())
268: peer.rebuild();
269: }
270: }
271: }
272:
273: public void autoDeploy() {
274: try {
275: getBuilder().buildWebApps(this );
276: } catch (Exception e) {
277: if (getLog().isLog(C_Log.ERROR)) {
278: getLog()
279: .log(
280: localStrings
281: .getString("auto_deploy_error")
282: + e, C_Log.ERROR);
283: getLog().log(e, C_Log.ERROR);
284: }
285: }
286: }
287:
288: /**
289: * Deletes all set hostnames and sets them new.
290: *
291: * @param aHostnames list of hostnames
292: */
293: public void setHostnames(String[] aHostnames) {
294: myHostnames = aHostnames;
295: }
296:
297: /**
298: * Sets the service of this host.
299: *
300: * @param aService the service
301: */
302: public void setService(I_JoServletService aService) {
303: myService = aService;
304: }
305:
306: /**
307: * Returns the service of this host.
308: *
309: * @return the service.
310: */
311: public I_JoServletService getService() {
312: return myService;
313: }
314:
315: /**
316: * Returns the symbolic name of this host.
317: *
318: * @return this host's name
319: */
320: public String getName() {
321: return myName;
322: }
323:
324: /**
325: * Sets the the symbolic name of this host and its accesslog/eventlog.
326: *
327: * @param aName this host's name
328: * @see #setAccessLog
329: * @see #setLog
330: */
331: public void setName(String aName) {
332: myName = aName;
333: setAccessLog(Log.getLog(myName + "_access"));
334: setLog(Log.getLog(myName));
335: }
336:
337: /**
338: * Returns the names of this host
339: *
340: * @return names of this host
341: */
342: public String[] getHostnames() {
343: return myHostnames;
344: }
345:
346: /**
347: * Returns the name of this server. Format: <pre><name>/<majorversion.<minorversion></pre>
348: *
349: * @return server name
350: */
351: public String getServerInfo() {
352: if (myServerInfo == null) {
353: // cache it!
354: myServerInfo = myService.getServerInfo();
355: }
356: return myServerInfo;
357: }
358:
359: /**
360: * Returns an attribute of this service.
361: *
362: * @param aName key for an attribute.
363: * @return the value of this attribute or <code>null</code>.
364: */
365: public Object getAttribute(String aName) {
366: return myService.getAttribute(aName);
367: }
368:
369: /**
370: * Returns an iterator over all registered {@link I_JoServletContextPeer}s.
371: *
372: * @return Iterator
373: */
374: public Iterator servletContextPeers() {
375: HashSet peers = new HashSet();
376: peers.addAll(myServletContextPeers.values());
377: return peers.iterator();
378: }
379:
380: /**
381: * Returns the MIME type of the file or <code>null</code> if
382: * the type is not known.
383: *
384: * @param file Name of the file
385: */
386: public final String getMimeType(String file) {
387: return myService.getMimeType(file);
388: }
389:
390: /**
391: * Adds a {@link I_JoServletContextPeer} to this host.
392: *
393: * @param aPeer a Peer
394: */
395: public void addServletContextPeer(I_JoServletContextPeer aPeer) {
396: myServletContextPeers.put(aPeer.getName(), aPeer);
397: myPrefixMatchRules.put(aPeer.getContextPath(), aPeer);
398: fireChildModificationEvent(new ChildModificationEvent(this ,
399: aPeer, true));
400: }
401:
402: /**
403: * Removes a {@link I_JoServletContextPeer} from this host.
404: *
405: * @param aName Name of the peer
406: */
407: public void removeServletContextPeer(String aName) {
408: I_JoServletContextPeer aPeer = (I_JoServletContextPeer) myServletContextPeers
409: .get(aName);
410: if (aPeer != null) {
411: myPrefixMatchRules.remove(aPeer.getContextPath());
412: myServletContextPeers.remove(aName);
413: // is this the right place for this? (rik)
414: /*
415: try {
416: aPeer.getJspEngine().forceClean();
417: }
418: catch (IOException ioe) {
419: log.log("Force clean failed.", C_Log.ERROR);
420: log.log(ioe, C_Log.ERROR);
421: }
422: */
423: aPeer.destroy();
424: fireChildModificationEvent(new ChildModificationEvent(this ,
425: aPeer, false));
426: }
427: }
428:
429: /**
430: * Returns a {@link I_JoServletContextPeer} for a name.
431: *
432: * @param aKey key for a {@link I_JoServletContextPeer}
433: * @return I_JoServletContextPeer
434: */
435: public I_JoServletContextPeer getNamedServletContextPeer(String aKey) {
436: return (I_JoServletContextPeer) myServletContextPeers.get(aKey);
437: }
438:
439: /**
440: * Returns a {@link I_JoServletContextPeer} for a URI.
441: *
442: * @param aURI URI
443: * @return I_JoServletContextPeer
444: */
445: public I_JoServletContextPeer getServletContextPeer(String aURI) {
446: if (aURI == null)
447: return null;
448: I_JoServletContextPeer theMatchingPeer = (I_JoServletContextPeer) myPrefixMatchRules
449: .get(aURI);
450: int idx;
451: while (theMatchingPeer == null
452: && (idx = aURI.lastIndexOf('/')) != -1) {
453: aURI = aURI.substring(0, idx);
454: theMatchingPeer = (I_JoServletContextPeer) myPrefixMatchRules
455: .get(aURI);
456: }
457: return theMatchingPeer;
458: }
459:
460: /**
461: * Returns a {@link I_JoServletContextPeer} for a request.
462: *
463: * @param aRequest Request
464: * @return I_JoServletContextPeer
465: */
466: public final I_JoServletContextPeer getServletContextPeer(
467: I_JoServletRequest aRequest) {
468: return getServletContextPeer(aRequest.getRequestURI());
469: }
470:
471: /**
472: * Returns an errorpage.
473: *
474: * @param aStatusCode Statuscode
475: * @param aMessage message
476: * @return an errorpage.
477: */
478: public String getErrorPage(int aStatusCode, String aMessage) {
479: // here we could insert a JSP...?! (rik)
480: UnSyncStringBuffer sb = new UnSyncStringBuffer();
481:
482: sb.append("<h2>");
483: sb.append(aStatusCode);
484: sb.append(' ');
485: sb.append(StatusCodes.get(aStatusCode));
486: sb.append("</h2>");
487:
488: if (aMessage != null) {
489: sb.append("<pre>");
490: sb.append(aMessage);
491: sb.append("</pre>");
492: }
493:
494: return sb.toString();
495: }
496:
497: /**
498: * Returns an errorpage.
499: *
500: * @param aStatusCode Statuscode
501: * @param aThrowable Throwable
502: * @return an errorpage.
503: */
504: public String getErrorPage(int aStatusCode, Throwable aThrowable) {
505: return getErrorPage(aStatusCode, Log.getStackTrace(aThrowable));
506: }
507:
508: /**
509: * Returns the eventlog.
510: *
511: * @see #getAccessLog()
512: */
513: public Log getLog() {
514: return log;
515: }
516:
517: /**
518: * Sets the log.
519: *
520: * @see #setName(String)
521: */
522: public void setLog(Log log) {
523: this .log = log;
524: }
525:
526: /**
527: * Returns the accesslog.
528: *
529: * @see #getLog()
530: */
531: public Log getAccessLog() {
532: return accessLog;
533: }
534:
535: /**
536: * Sets the accesslog.
537: *
538: * @see #setName(String)
539: */
540: public void setAccessLog(Log log) {
541: accessLog = log;
542: }
543:
544: /**
545: * Returns the name of the directory where the wars are stored.
546: * JO_HOME/webapp/<hostname>/
547: */
548: public File[] getWARDirs() {
549: return (File[]) warDirs.toArray(new File[warDirs.size()]);
550: }
551:
552: /**
553: * Adds the name of the directory where the wars are stored.
554: */
555: public void addWARDir(File warDir) {
556: warDirs.add(warDir);
557: if (log.isLog(C_Log.MODULE)) {
558: log.log("Added WAR dir = " + warDir, C_Log.MODULE);
559: }
560: }
561:
562: /**
563: * Removes the name of the directory where the wars are stored.
564: */
565: public void removeWARDir(File warDir) {
566: warDirs.remove(warDir);
567: if (log.isLog(C_Log.MODULE)) {
568: log.log("Removed WAR dir = " + warDir, C_Log.MODULE);
569: }
570: }
571:
572: /**
573: * Destroys all {@link I_JoServletContextPeer}s.
574: */
575: public void destroy() {
576: Iterator i = myServletContextPeers.entrySet().iterator();
577:
578: while (i.hasNext()) {
579: ((I_JoServletContextPeer) ((Map.Entry) i.next()).getValue())
580: .destroy();
581: }
582:
583: myServletContextPeers.clear();
584: try {
585: accessLog.flush();
586: log.flush();
587: } catch (IOException ioe) {
588: Log.getLog().log(
589: localStrings.getString("log_flush_failed")
590: + ioe.toString());
591: }
592: }
593:
594: protected synchronized void fireChildModificationEvent(
595: ChildModificationEvent e) {
596: Iterator i = childModificationListeners.iterator();
597: while (i.hasNext()) {
598: ((ChildModificationListener) i.next()).childModification(e);
599: }
600: }
601:
602: public synchronized void addChildModificationListener(
603: ChildModificationListener listener) {
604: childModificationListeners.add(listener);
605: }
606:
607: public synchronized void removeChildModificationListener(
608: ChildModificationListener listener) {
609: childModificationListeners.remove(listener);
610: }
611:
612: }
|