001: /* *****************************************************************************
002: * DependencyTracker.java
003: * ****************************************************************************/
004:
005: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
006: * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
007: * Use is subject to license terms. *
008: * J_LZ_COPYRIGHT_END *********************************************************/
009:
010: package org.openlaszlo.cm;
011:
012: import org.apache.log4j.*;
013: import java.io.*;
014: import java.util.*;
015: import org.openlaszlo.server.LPS;
016: import org.openlaszlo.utils.ChainedException;
017:
018: /** Tracks compilation dependencies, so that it can tell if a file
019: * needs to be recompiled. An instance stores version information
020: * about all the source files that an object file depends on (the
021: * files such that, if one changed, the object file would be out of
022: * date).
023: *
024: * @author Oliver steele
025: */
026: class DependencyTracker implements java.io.Serializable {
027: private static Logger mLogger = Logger
028: .getLogger(DependencyTracker.class);
029:
030: /** Records information about the version of a file.
031: */
032: private static class FileInfo implements java.io.Serializable {
033: /** pathname */
034: private String mPathname;
035: /** last mod time */
036: private long mLastMod;
037: /** can read? */
038: private boolean mCanRead;
039: /** File length */
040: private long mLength;
041:
042: /** Constructs an instance.
043: * @param pathname the name of a file
044: */
045: FileInfo(String pathname) {
046: mPathname = pathname;
047: File file = new File(pathname);
048: // Cope with directory indexes for now
049: // FIXME: [2003-05-09 bloch] is this the right place
050: // for this?
051: if (file.isDirectory()) {
052: file = new File(pathname + File.separator
053: + "library.lzx");
054: }
055: // Truncate to an seconds
056: mLastMod = ((long) (file.lastModified() / 1000L)) * 1000L;
057: mCanRead = file.canRead();
058: //mLogger.debug("lm: " + mLastMod);
059: mLength = file.length();
060: }
061:
062: /** Returns true iff this FileInfo has up to date information
063: * compared to the fileinfo argument.
064: * @param info another FileInfo
065: * @return see documentation
066: */
067: boolean isUpToDate(FileInfo info) {
068: return this .mLastMod == info.mLastMod
069: && this .mCanRead == info.mCanRead
070: && this .mLength == info.mLength;
071: }
072: };
073:
074: /** A list of FileInfo records for files that are depended on. */
075: private final Vector mDependencies = new Vector();
076: private Properties mProperties;
077: private String mWebappPath;
078:
079: DependencyTracker(Properties properties) {
080: this .mProperties = properties;
081: this .mWebappPath = LPS.HOME(); // get it from global
082: }
083:
084: /** Add the specified file to the list of file dependencies.
085: * @param file a file
086: */
087: void addFile(File file) {
088: mLogger.debug("addFile Path is " + file.getPath());
089: FileInfo fi = new FileInfo(file.getPath());
090: try {
091: fi.mPathname = file.getCanonicalPath();
092: } catch (java.io.IOException e) {
093: throw new ChainedException(e);
094: }
095: mDependencies.add(fi);
096: }
097:
098: /**
099: * Copy file info from the given tracker to me, omitting
100: * omitting then given file.
101: */
102: void copyFiles(DependencyTracker t, File omitMe) {
103: try {
104: for (Iterator e = t.mDependencies.iterator(); e.hasNext();) {
105: FileInfo f = (FileInfo) e.next();
106: if (!f.mPathname.equals(omitMe.getCanonicalPath())) {
107: mDependencies.add(f);
108: }
109: }
110: } catch (java.io.IOException e) {
111: throw new ChainedException(e);
112: }
113: }
114:
115: /** This will update the FileInfo object chain to use the (possibly new)
116: * webappPath once the DependencyTracker object has been reconstitutded
117: * from ondisk cache.
118: */
119: void updateWebappPath() {
120: String webappPath = LPS.HOME(); // get it from global
121: if (webappPath.equals(mWebappPath))
122: return;
123: mLogger.debug(
124: /* (non-Javadoc)
125: * @i18n.test
126: * @org-mes="updating webappPath from: " + p[0]
127: */
128: org.openlaszlo.i18n.LaszloMessages.getMessage(
129: DependencyTracker.class.getName(), "051018-128",
130: new Object[] { mWebappPath }));
131: mLogger.debug(
132: /* (non-Javadoc)
133: * @i18n.test
134: * @org-mes="updating webappPath to: " + p[0]
135: */
136: org.openlaszlo.i18n.LaszloMessages.getMessage(
137: DependencyTracker.class.getName(), "051018-136",
138: new Object[] { webappPath }));
139: for (Iterator e = mDependencies.iterator(); e.hasNext();) {
140: FileInfo saved = (FileInfo) e.next();
141: if (saved.mPathname.startsWith(mWebappPath)) {
142: mLogger
143: .debug(
144: /* (non-Javadoc)
145: * @i18n.test
146: * @org-mes="updating dependencies from: " + p[0]
147: */
148: org.openlaszlo.i18n.LaszloMessages.getMessage(
149: DependencyTracker.class.getName(),
150: "051018-147",
151: new Object[] { saved.mPathname }));
152: saved.mPathname = webappPath
153: + saved.mPathname.substring(mWebappPath
154: .length());
155: mLogger
156: .debug(
157: /* (non-Javadoc)
158: * @i18n.test
159: * @org-mes="updating dependencies to : " + p[0]
160: */
161: org.openlaszlo.i18n.LaszloMessages.getMessage(
162: DependencyTracker.class.getName(),
163: "051018-157",
164: new Object[] { saved.mPathname }));
165: }
166: }
167: mWebappPath = webappPath;
168: }
169:
170: /** Returns true iff all the files listed in this tracker's
171: * dependency list exist and are at the same version as when they
172: * were recorded.
173: * @return a boolean
174: */
175: boolean isUpToDate(Properties properties) {
176: Iterator e;
177:
178: // fixes bug 962
179: {
180: if (mProperties.size() != properties.size()) {
181: mLogger.debug(
182: /* (non-Javadoc)
183: * @i18n.test
184: * @org-mes="my size " + p[0]
185: */
186: org.openlaszlo.i18n.LaszloMessages.getMessage(
187: DependencyTracker.class.getName(),
188: "051018-181", new Object[] { new Integer(
189: mProperties.size()) }));
190: mLogger.debug(
191: /* (non-Javadoc)
192: * @i18n.test
193: * @org-mes="new size " + p[0]
194: */
195: org.openlaszlo.i18n.LaszloMessages.getMessage(
196: DependencyTracker.class.getName(),
197: "051018-189", new Object[] { new Integer(
198: properties.size()) }));
199: return false;
200: }
201:
202: for (e = mProperties.keySet().iterator(); e.hasNext();) {
203: String key = (String) e.next();
204: String val0 = mProperties.getProperty(key);
205: String val1 = properties.getProperty(key);
206:
207: // val0 can't be null; properties don't allow that
208: if (val1 == null || !val0.equals(val1)) {
209: mLogger.debug(
210: /* (non-Javadoc)
211: * @i18n.test
212: * @org-mes="Missing or changed property: " + p[0]
213: */
214: org.openlaszlo.i18n.LaszloMessages.getMessage(
215: DependencyTracker.class.getName(),
216: "051018-207", new Object[] { val0 }));
217: return false;
218: }
219: }
220: }
221:
222: for (e = mDependencies.iterator(); e.hasNext();) {
223: FileInfo saved = (FileInfo) e.next();
224: FileInfo current = new FileInfo(saved.mPathname);
225: if (!saved.isUpToDate(current)) {
226: mLogger.debug(saved.mPathname + " has changed");
227: mLogger.debug("was " + saved.mLastMod);
228: mLogger.debug(" is " + current.mLastMod);
229: return false;
230: }
231: }
232: return true;
233: }
234: }
|