001: /*
002: * Enhydra Java Application Server Project
003: *
004: * The contents of this file are subject to the Enhydra Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License on
007: * the Enhydra web site ( http://www.enhydra.org/ ).
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
011: * the License for the specific terms governing rights and limitations
012: * under the License.
013: *
014: * The Developer of the Enhydra Application Server is Together Austria.
015: * All Rights Reserved.
016: *
017: */
018: package org.enhydra.util.jivan;
019:
020: import java.io.File;
021: import java.net.URL;
022: import java.util.HashMap;
023:
024: import org.jivan.apache.xerces.xni.parser.XMLInputSource;
025: import org.jivan.html.document.DocumentFactory;
026: import org.jivan.html.document.DocumentManager;
027:
028: import com.lutris.logging.LogChannel;
029: import com.lutris.logging.Logger;
030:
031: /**
032: * <p>Title: JivanFactory</p>
033: * <p>Description: JivanFactory extends the capabilities of DocumentFactory
034: * class which is originaly supplied by Jivan project. The enhacements are the
035: * possibilites of logging and autoreloading. To invoke autoreloading, in the
036: * application configuration file, the parameter 'Server.Jivan.AutoReload'
037: * should be set to 'true'. Autoreloading parameter force Jivan DocumentFactory
038: * object to read neededy resource again from its source. Note that
039: * autoreloading slows down the performance, and it should be used in testing
040: * purpose. The default value for autoreloading is false.</p>
041: * <p>Copyright: Copyright (c) 2004</p>
042: * <p>Company: Together</p>
043: * @author Vladimir Radisic
044: * @version 1.0
045: */
046: public class JivanFactory extends DocumentFactory {
047:
048: /**
049: * Indicates autoreloading status (true = on, false = off)
050: */
051: private boolean isReload = false;
052:
053: /**
054: * Logging object
055: */
056: private LogChannel logChan;
057:
058: /**
059: * Storage for resource timestamps. The timestamps is used only in autoreload
060: * mode of Jivanfactory work.
061: */
062: private HashMap resourceTimestamps = null;
063:
064: /**
065: * Constructs JivanFactory with autoreloading indicator, and given Log4j
066: * logging object. This constructor initialise DocumentManager singleton
067: * object if it is not initialised yet.
068: * @param reload autoreloading status indicator (true = on, false = off).
069: * @param logChan logging object
070: */
071: public JivanFactory(boolean reload, LogChannel logChan) {
072: super ();
073: this .isReload = reload;
074: this .logChan = logChan;
075: if (reload)
076: this .resourceTimestamps = new HashMap();
077:
078: logChan.write(Logger.DEBUG,
079: "JivanFactory is initialised with AutoReload status: "
080: + reload);
081: }
082:
083: /**
084: * Returns logging object which can be used in applications.
085: * @return logging object
086: */
087: public LogChannel getLogger() {
088: return this .logChan;
089: }
090:
091: /**
092: * Overrides DocumentFactory method in order to implement autoreloading
093: * possibility. It retrieves a DocumentManager for the specific 'resourceId'.
094: * Also, if DocumentManager for the corresponding 'resourceId' does not
095: * exists, it reads given XMLInputSource object and creates DocumentManager.<BR>
096: * <BR>
097: * Other docManFor() methods also call this method. docManFor() with single
098: * argument of String type, calls this method with self created XMLInputSource
099: * object by using its 'systemId' argument, which represents the location of
100: * the resource.<BR>
101: * <BR>
102: * For example the systemId can look like:<BR>
103: * <BR>
104: * file:///C:/projects/testjivan/Welcome.html<BR>
105: * <BR>
106: * @param resourceId unique resource identifier which is used as key for
107: * retrieving corresponding DocumentManager.
108: * @param inp XMLInputSource object which is taken as resource in case when
109: * there is no corresponding DocumentManager for given 'resourceId'.
110: * @return DocumentManager which corresponds to given 'resourceId'.
111: */
112: public DocumentManager docManFor(String resourceId,
113: XMLInputSource inp) {
114: this .logChan
115: .write(Logger.DEBUG,
116: "-------------------------------------------------------");
117: this .logChan.write(Logger.DEBUG,
118: "resourceId: " + resourceId);
119: this .logChan.write(Logger.DEBUG,
120: "XMLInputSource - BaseSystemId: "
121: + inp.getBaseSystemId());
122: this .logChan.write(Logger.DEBUG,
123: "XMLInputSource - Encoding: " + inp.getEncoding());
124: this .logChan.write(Logger.DEBUG,
125: "XMLInputSource - PublicId: " + inp.getPublicId());
126: this .logChan.write(Logger.DEBUG,
127: "XMLInputSource - SystemId: " + inp.getSystemId());
128: resourceId = resourceId.intern();
129: synchronized (resourceId) {
130: if (isReload) {
131: // Object will be removed from HashMaps only if its timestamp is larger than
132: // timestamp for particular resource
133: if (reloadChecking(resourceId, inp)) {
134: super .mapMasterDoc.remove(resourceId);
135: super .mapSysemtId2Thread.remove(resourceId);
136: }
137:
138: }
139: }
140: return super .docManFor(resourceId, inp);
141: }
142:
143: /**
144: * Checks is the resource autoreloading necessery or not. Checking is
145: * performed according to stored resource timestamp.
146: * @param resourceId resourceId unique resource identification
147: * @param inp XMLInputSource object which corresponds to given 'resourceId'.
148: * @return true if stored timestamp is older 'then' resource timestamp, or
149: * 'false' otherwise.
150: */
151: private boolean reloadChecking(String resourceId, XMLInputSource inp) {
152:
153: if (inp.getCharacterStream() != null)
154: return true;
155: else if (inp.getByteStream() != null)
156: return true;
157:
158: String systemId = inp.getSystemId();
159: if (systemId != null) {
160: try {
161: // try with URL if systemId is something like: file:///C:/projects/Welcome.html
162: URL url = new URL(systemId);
163: File fResource = new File(url.getFile());
164: if (fResource.exists())
165: return timestampCheck(resourceId, fResource);
166: else {
167: // try withFile if systemId is something like: C:/projects/Welcome.html
168: fResource = new File(systemId);
169: if (fResource.exists())
170: return timestampCheck(resourceId, fResource);
171: else
172: return true;
173: }
174: } catch (Exception ex) {
175: return true;
176: }
177: } else
178: return true;
179:
180: }
181:
182: /**
183: * Check the timestamp for given File resource. If corresponding timestamp
184: * does not exist it will be added to timestamp storage for later use.
185: * @param resourceId unique resource identification
186: * @param f file resource
187: * @return true if stored timestamp is older 'then' resource timestamp, or
188: * 'false' otherwise.
189: */
190: private boolean timestampCheck(String resourceId, File f) {
191: Long oldTime = (Long) this .resourceTimestamps.get(resourceId);
192: if (oldTime == null) {
193: resourceTimestamps.put(resourceId, new Long(f
194: .lastModified()));
195: return true;
196: } else if (oldTime.longValue() < f.lastModified()) {
197: resourceTimestamps.put(resourceId, new Long(f
198: .lastModified()));
199: return true;
200: } else
201: return false;
202:
203: }
204:
205: }
|