001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019: package de.schlund.pfixxml.targets;
020:
021: import java.io.File;
022: import java.io.IOException;
023: import java.util.TreeMap;
024: import java.util.TreeSet;
025:
026: import javax.xml.transform.TransformerException;
027:
028: import org.apache.log4j.Logger;
029:
030: import de.schlund.pfixxml.XMLException;
031: import de.schlund.pfixxml.resources.FileResource;
032: import de.schlund.pfixxml.resources.ResourceUtil;
033: import de.schlund.pfixxml.targets.cachestat.SPCacheStatistic;
034:
035: /**
036: * TargetImpl.java
037: *
038: *
039: * Created: Mon Jul 23 16:24:53 2001
040: *
041: * @author <a href="mailto: "Jens Lautenbacher</a>
042: *
043: *
044: */
045: public abstract class TargetImpl implements TargetRW,
046: Comparable<Target> {
047:
048: //~ Instance/static variables ..................................................................
049:
050: // set in from constructor
051: protected TargetType type;
052: protected TargetGenerator generator;
053: protected String targetkey;
054: protected Themes themes = null;
055: protected TreeMap<String, Object> params = null;
056: protected Target xmlsource = null;
057: protected Target xslsource = null;
058: protected Logger LOG = Logger.getLogger(this .getClass());
059: protected Logger TREE = Logger.getLogger(this .getClass().getName()
060: + ".TREE");
061: // determine if the target has been generated. This affects production mode only, where
062: // we do not need to handle if the target is really up to date (except make generate!!!)
063: private boolean onceLoaded = false;
064: // store exception occured during transformation here.
065: protected Exception storedException = null;
066:
067: protected AuxDependencyManager auxdepmanager = null;
068:
069: //~ Methods ....................................................................................
070:
071: // Target interface
072: /**
073: * @see de.schlund.pfixxml.targets.Target#getType()
074: */
075: public TargetType getType() {
076: return type;
077: }
078:
079: /**
080: * @see de.schlund.pfixxml.targets.Target#getTargetKey()
081: */
082: public String getTargetKey() {
083: return targetkey;
084: }
085:
086: public String getFullName() {
087: return generator.getName() + "@" + targetkey;
088: }
089:
090: /**
091: * @see de.schlund.pfixxml.targets.Target#getTargetGenerator()
092: */
093: public TargetGenerator getTargetGenerator() {
094: return generator;
095: }
096:
097: public Themes getThemes() {
098: return themes;
099: }
100:
101: /**
102: * @see de.schlund.pfixxml.targets.Target#getXMLSource()
103: */
104: public Target getXMLSource() {
105: return xmlsource;
106: }
107:
108: /**
109: * @see de.schlund.pfixxml.targets.Target#getXSLSource()
110: */
111: public Target getXSLSource() {
112: return xslsource;
113: }
114:
115: /**
116: * @see de.schlund.pfixxml.targets.Target#getParams()
117: */
118: public TreeMap<String, Object> getParams() {
119: if (params == null) {
120: return null;
121: } else {
122: synchronized (params) {
123: return new TreeMap<String, Object>(params);
124: }
125: }
126: }
127:
128: public void resetParams() {
129: if (params != null) {
130: params.clear();
131: }
132: }
133:
134: /**
135: * @see de.schlund.pfixxml.targets.Target#getValue()
136: */
137: public Object getValue() throws TargetGenerationException {
138: // Idea: if skip_getmodtimemaybeupdate is set we do not need to call getModeTimeMaybeUpdate
139: // but: if the target is not in disk-cache (has not been generated) we must call
140: // getModTimeMaybeUpdate once to generate it. After that, it can be loaded in getCurrValue()
141: // which sets onceLoaded to true so we don't have to make this check again.
142: if (generator.isGetModTimeMaybeUpdateSkipped()) {
143: // skip getModTimeMaybeUpdate!
144: LOG
145: .debug("skip_getmodtimemaybeupdate is true. Trying to skip getModTimeMaybeUpdate...");
146: if (!onceLoaded) {
147: // do test for exists here!
148: FileResource thefile = ResourceUtil.getFileResource(
149: getTargetGenerator().getDisccachedir(),
150: getTargetKey());
151: if (!thefile.exists()) { // Target has not been loaded once and it doesn't exist in disk cache
152: LOG
153: .debug("Cant't skip getModTimeMaybeUpdated because it has not been loaded "
154: + "and doesn't even exist in disk cache! Generating now !!");
155: try {
156: getModTimeMaybeUpdate();
157: // FIXME FIXME ! Do we really handle the exception here, if getmodtimemaybeupdate is slipped????
158: } catch (IOException e1) {
159: throw new TargetGenerationException(e1
160: .getClass().getName()
161: + " in getModTimeMaybeUpdate()!", e1);
162: } catch (XMLException e2) {
163: throw new TargetGenerationException(e2
164: .getClass().getName()
165: + " in getModTimeMaybeUpdate()", e2);
166: }
167: } else {
168: LOG
169: .debug("Target exists in disc cache, using it...");
170: }
171: } else { // target generated -> nop
172: LOG
173: .debug("Target has already been loaded, reusing it...");
174: }
175: } else { // do not skip getModTimeMaybeUpdate
176: LOG
177: .debug("Skipping getModTimeMaybeUpdate disabled in TargetGenerator!");
178: try {
179: getModTimeMaybeUpdate();
180: } catch (IOException e1) {
181: TargetGenerationException tex = new TargetGenerationException(
182: e1.getClass().getName()
183: + " in getModTimeMaybeUpdate()", e1);
184: tex.setTargetkey(getTargetKey());
185: throw tex;
186: } catch (XMLException e2) {
187: TargetGenerationException tex = new TargetGenerationException(
188: e2.getClass().getName()
189: + " in getModTimeMayUpdate()", e2);
190: tex.setTargetkey(getTargetKey());
191: throw tex;
192: }
193: }
194: Object obj = null;
195: try {
196: obj = getCurrValue();
197: } catch (TransformerException e) {
198: TargetGenerationException tex = new TargetGenerationException(
199: "Exception in getCurrValue (xml=" + getXMLSource()
200: + ", xsl=" + getXSLSource() + ")!", e);
201: tex.setTargetkey(getTargetKey());
202: throw tex;
203: }
204: return obj;
205: }
206:
207: public abstract void addPageInfo(PageInfo info);
208:
209: public abstract TreeSet<PageInfo> getPageInfos();
210:
211: public abstract void setXMLSource(Target source);
212:
213: public abstract void setXSLSource(Target source);
214:
215: public abstract void addParam(String key, Object val);
216:
217: public abstract void storeValue(Object obj);
218:
219: public abstract boolean needsUpdate() throws Exception;
220:
221: public abstract long getModTime();
222:
223: public abstract String toString();
224:
225: /**
226: * @see de.schlund.pfixxml.targets.TargetRW#getCurrValue()
227: */
228: public Object getCurrValue() throws TransformerException {
229: Object obj = getValueFromSPCache();
230: // add cache access to cache statistic
231: doCacheStatistic(obj);
232: // look if the target exists in memory cache and if the file in disk cache is newer.
233: if (obj == null || isDiskCacheNewerThenMemCache()) {
234: synchronized (this ) { // TODO: double-checked locking is broken ...
235: obj = getValueFromSPCache();
236: if (obj == null || isDiskCacheNewerThenMemCache()) {
237: if (LOG.isDebugEnabled()) {
238: if (LOG.isDebugEnabled()
239: && isDiskCacheNewerThenMemCache()) {
240: LOG
241: .debug("File in disk cache is newer then in memory cache. Rereading target from disk...");
242: }
243: }
244:
245: obj = getValueFromDiscCache();
246: // Caution! setCacheValue is not guaranteed to store anything at all, so it's NOT
247: // guaranteed that the sequence
248: // storeValue(tmp); tmp2 = getValueFromSPCache; return tmp2
249: // will return a tmp2 == tmp.
250: // Example: A NullCache will silently ignore all store requests, so a call to this method
251: // will always trigger getValueFromDiscCache().
252: storeValue(obj);
253:
254: // after the newer file on disk is reread and stored in memory cache it isn't
255: // newer any more, so set the mod time of the target to the mod time of the file
256: // in disk cache
257: if (isDiskCacheNewerThenMemCache()) {
258: setModTime(ResourceUtil.getFileResource(
259: getTargetGenerator().getDisccachedir(),
260: getTargetKey()).lastModified());
261: }
262:
263: // now the target is generated
264: onceLoaded = true;
265: }
266: }
267: }
268: return obj;
269: }
270:
271: /**
272: * @see java.lang.Comparable#compareTo(java.lang.Object)
273: */
274: public int compareTo(Target in) {
275: if (getTargetGenerator().getName().compareTo(
276: in.getTargetGenerator().getName()) != 0) {
277: return getTargetGenerator().getName().compareTo(
278: in.getTargetGenerator().getName());
279: } else {
280: return getTargetKey().compareTo(in.getTargetKey());
281: }
282: }
283:
284: public boolean isDiskCacheNewerThenMemCache() {
285: long target_mod_time = getModTime();
286: FileResource thefile = ResourceUtil.getFileResource(
287: getTargetGenerator().getDisccachedir(), getTargetKey());
288: long disk_mod_time = thefile.lastModified();
289: if (LOG.isDebugEnabled()) {
290: LOG.debug("File in DiskCache "
291: + getTargetGenerator().getDisccachedir()
292: + File.separator
293: + getTargetKey()
294: + " ("
295: + disk_mod_time
296: + ") is "
297: + (disk_mod_time > target_mod_time ? " newer "
298: : "older") + " than target("
299: + target_mod_time + ")");
300: }
301: // return true if file in diskcache newer than target
302: return disk_mod_time > target_mod_time ? true : false;
303: }
304:
305: //
306: // implementation
307: //
308: protected abstract Object getValueFromSPCache();
309:
310: protected abstract Object getValueFromDiscCache()
311: throws TransformerException;
312:
313: protected abstract long getModTimeMaybeUpdate()
314: throws TargetGenerationException, XMLException, IOException;
315:
316: protected abstract void setModTime(long mtime);
317:
318: /**
319: * Sets the storedException.
320: * @param storedException The storedException to set
321: */
322: public void setStoredException(Exception stored) {
323: this .storedException = stored;
324: }
325:
326: private void doCacheStatistic(Object value) {
327: if (value == null) {
328: SPCacheStatistic.getInstance().registerCacheMiss(this );
329: } else {
330: SPCacheStatistic.getInstance().registerCacheHit(this );
331: }
332: }
333:
334: public AuxDependencyManager getAuxDependencyManager() {
335: return auxdepmanager;
336: }
337:
338: } // TargetImpl
|