001: /*
002: * ChangedTemplate.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1999-2000 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: cstevens.
018: * Portions created by cstevens are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): cstevens, suhler.
022: *
023: * Version: 1.9
024: * Created by cstevens on 99/10/28
025: * Last modified by suhler on 00/12/11 13:30:35
026: */
027:
028: package sunlabs.brazil.template;
029:
030: import sunlabs.brazil.server.FileHandler;
031: import sunlabs.brazil.session.SessionManager;
032:
033: import java.io.File;
034: import java.io.Serializable;
035: import java.net.URL;
036: import java.util.Hashtable;
037: import java.util.Properties;
038:
039: /**
040: * This <code>Template</code> adds an icon to HREFs to indicate when the
041: * file being referred to is new, changed, or unchanged with respect
042: * to the user's session.
043: * <p>
044: * In order for the <code>ChangedTemplate</code> to work, the following
045: * must happen. <ul>
046: * <li> All files whose HREFs should be rewritten must pass through the
047: * <code>ChangedTemplate</code>. All HREFs seen between
048: * <code><changed></code> and <code></changed></code> tags
049: * will be rewritten so that an appropriate icon appears next to the
050: * HREF.
051: *
052: * <li> All files whose last-accessed time is being tracked must also pass
053: * through this <code>ChangedTemplate</code>. Whenever the
054: * <code>ChangedTemplate</code> sees a file that was named in some
055: * previously seen <code><changed></code> section, that file's
056: * last-accessed time will be updated. Only the files named in a
057: * <code><changed></code> section are tracked.
058: * </ul>
059: * Warning:
060: * The <code>ChangedTemplate</code> may have to keep track of a lot of data
061: * per session, specifically, the names of all the files being tracked and
062: * the last time the user accessed them.
063: * <p>
064: * The <code>ChangedTemplate</code> examines the property "fileName", set
065: * (for example) by the <code>FileHandler</code>, in order to update the
066: * last-accessed time of a file as it passes by. If the "fileName" property
067: * is not set, the last-accessed time will not be updated.
068: * <p>
069: * The <code>ChangedTemplate</code> also assumes that all local HREFs it sees
070: * can be directly translated into the corresponding file name based on the
071: * "root" property and the URL of the current file. Getting that file name
072: * is necessary so its last-modified time (on disk) can be compared to its
073: * last-accessed time (per session).
074: * <p>
075: * The <code>ChangedTemplate</code> uses the following properties: <dl class=props>
076: * <dt> fileName
077: * <dd> A request property containing the full path name of the current file,
078: * used to keep track of the last time that file was accessed by the
079: * current user. A <code>Handler</code> or other code may set this
080: * property if it wishes the file to be tracked.
081: *
082: * <dt> root
083: * <dd> The root of the document hierarchy. An HREF must resolve to a file
084: * in this hierarchy so its last-modified time can be checked. If the
085: * file does not exist, the HREF will not be rewritten.
086: *
087: * <dt> always
088: * <dd> If this property is present, the <code>ChangedTemplate</code> always
089: * rewrites the HREFs, instead of just when they appear within the
090: * <code><changed></code> and <code></changed></code> tags.
091: *
092: * <dt> new
093: * <dd> The HTML to substitute into the document if the HREF refers to a
094: * file that has never been accessed by the user. If absent, the HREF
095: * for new files will not be rewritten.
096: *
097: * <dt> changed
098: * <dd> The HTML to substitute into the document if the HREF refers to a
099: * file that has changed since the last time it was accessed by the
100: * user. If absent, the HREF for changed files will not be rewritten.
101: *
102: * <dt> unchanged
103: * <dd> The HTML to substitute into the document if the HREF refers to a
104: * file that has not changed since the last time it was accessed by
105: * the user. If absent, the HREF for unchanged files will not be
106: * rewritten.
107: * </dl>
108: *
109: * @author Colin Stevens (colin.stevens@sun.com)
110: * @version 1.4, 99/10/21
111: */
112: public class ChangedTemplate extends Template implements Serializable {
113: private static final String NEW = "new";
114: private static final String CHANGED = "changed";
115: private static final String UNCHANGED = "unchanged";
116: private static final String ALWAYS = "always";
117:
118: boolean check;
119: Hashtable changed;
120: URL url;
121:
122: String newToken;
123: String changedToken;
124: String unchangedToken;
125: String always;
126:
127: private void setup(RewriteContext hr) {
128: if (changed == null) {
129: changed = (Hashtable) SessionManager.getSession(
130: hr.sessionId, this .getClass(), Hashtable.class);
131:
132: String prefix = hr.prefix;
133: Properties props = hr.request.props;
134: newToken = props.getProperty(prefix + NEW);
135: changedToken = props.getProperty(prefix + CHANGED);
136: unchangedToken = props.getProperty(prefix + UNCHANGED);
137: always = props.getProperty(prefix + ALWAYS);
138: }
139: }
140:
141: /**
142: * Records that this file has just been accessed.
143: */
144: public boolean init(RewriteContext hr) {
145: Properties props = hr.request.props;
146:
147: String path = props.getProperty("fileName");
148: if (path != null) {
149: setup(hr);
150: if (changed.get(path) != null) {
151: changed.put(path, new Long(System.currentTimeMillis()));
152: }
153: }
154: check = (always != null);
155: try {
156: url = new URL("http://localhost" + hr.request.url);
157: } catch (Exception e) {
158: return false;
159: }
160: return true;
161: }
162:
163: public boolean done(RewriteContext hr) {
164: changed = null;
165: url = null;
166: return true;
167: }
168:
169: public void tag_changed(RewriteContext hr) {
170: hr.killToken();
171: check = true;
172: }
173:
174: public void tag_slash_changed(RewriteContext hr) {
175: hr.killToken();
176: check = false;
177: }
178:
179: public void tag_a(RewriteContext hr) {
180: if (check == false) {
181: return;
182: }
183: String href = hr.get("href");
184: try {
185: /*
186: * Turn href into the referenced file name. Assume that the href
187: * refers to a static file with the same "root" property as was
188: * used to generate this file.
189: */
190:
191: String root = hr.request.props.getProperty(hr.prefix
192: + FileHandler.ROOT, hr.request.props.getProperty(
193: FileHandler.ROOT, "."));
194: File file = new File(root, new URL(url, href).getFile());
195:
196: if (file.exists() == false) {
197: return;
198: }
199:
200: /*
201: * Get the token to display for when the file is new, changed, or
202: * unchanged with respect to the session.
203: */
204:
205: setup(hr);
206: String path = file.getPath();
207: Long seen = (Long) changed.get(path);
208: if (seen == null) {
209: seen = new Long(0);
210: changed.put(path, seen);
211: }
212:
213: String token;
214: if (seen.longValue() == 0) {
215: token = newToken;
216: } else if (seen.longValue() < file.lastModified()) {
217: token = changedToken;
218: } else {
219: token = unchangedToken;
220: }
221: hr.append(token);
222: hr.appendToken();
223: } catch (Exception e) {
224: /*
225: * Ignore all File errors and the href not being set.
226: */
227: }
228: }
229: }
|