001: /*
002: * HighlightTemplate.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 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: suhler.
018: * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): suhler.
022: *
023: * Version: 1.11
024: * Created by suhler on 00/10/16
025: * Last modified by suhler on 00/12/11 20:24:40
026: */
027:
028: package sunlabs.brazil.template;
029:
030: import sunlabs.brazil.server.Server;
031: import sunlabs.brazil.util.regexp.Regexp;
032: import sunlabs.brazil.util.Format;
033: import java.util.Properties;
034: import java.io.Serializable;
035:
036: /**
037: * Template class for highlighting text that matches a regular expression.
038: * All text between html/xml entities is matched against a regular expression.
039: * For each portion of text that matches the expression, a pair of
040: * html/xml tags is added on either side of all matched text.
041: * Highlighting is automatically turned off inside of head, script, style,
042: * and server tags.
043: * <p>
044: * Properties. These are recomputed for every page that <code>
045: * highlight</code> changes.
046: * <dl class=props>
047: * <dt>highlight <dd>A regular expression that with match any text
048: * between entities.
049: * <dt>tag <dd>the html/xml tag pair that will be added before and
050: * after all text maching "highlight", above. The
051: * default is "<font> ..... </font>
052: * <dt>options <dd>the set of name=value options that will be added
053: * to the starting tag of the tag pair, above. The
054: * default is "color=red".
055: * <dt>matchCase <dd>If specifies, matched are case sensitive.
056: * The default is to ignore case when matching.
057: * <dt>substitute <dd>The string to substitute for the matched text.
058: * This is for advanced uses. If specified, the values
059: * for <code>tag</code> and <code>options</code> are
060: * ignored. The default is:
061: * <${tag} ${options}>&</${tag}>
062: * The format of the string is a regular expression
063: * substitution string, which supports ${} style
064: * variable substitutions from the request properties.
065: * <dt>mustHighlight <dd>If not set, the entire document is surrounded
066: * by implicit <code>highlight</code> tags. If set
067: * no highlighting will take place until an actual
068: * <code>highlight</code> tag is present.
069: * <dt>exit <dd>If set, the template "init" method will
070: * return false, and no further processing will
071: * take place. This is useful if this template
072: * is used by itself.
073: * </dl>
074: * <p>
075: * The following html tags are processed:
076: * <dl>
077: * <dt>highlight
078: * <dt>/highlight
079: * <dd> Only text between these tags is considered for highlighting.
080: * <dt>nohighlight
081: * <dt>/nohighlight
082: * <dd>Temporarily undoes the effect of a <code>highlight</code> tag.
083: * In the current implementation, <code>highlight</code> and
084: * <code>nohighlight</code> don't nest.
085: * </dl>
086: *
087: * @author Stephen Uhler
088: * @version 1.11 HighlightTemplate.java %V% 0
089: */
090:
091: public class HighlightTemplate extends Template implements Serializable {
092: static final String HIGHLIGHT = "highlight"; // text to highlight
093: static final String TAG = "tag"; // tag to surround with
094: static final String OPTIONS = "options"; // "tag" attributes
095: static final String MATCHCASE = "matchCase"; // set for case sens.
096: static final String SUBSTITUTE = "substitute"; //
097: static final String MUST = "mustHighlight"; //
098: static final String EXIT = "exit"; //
099:
100: String sub; // what we substitute
101: boolean matchCase; // true to do cases sensitive matching
102: Regexp re = null; // regular expression to match
103: String lastExp = ""; // cached exp string
104: String exp; // exp string
105:
106: int dont; // if > 0, don't highlight
107: boolean inHighlight; // in a highlight tag
108: boolean inNoHighlight; // in a no highlight tag
109:
110: /**
111: * This gets called at every page, at the beginning. If this is our first
112: * time, get the config stuff out of the request properties.
113: */
114:
115: public boolean init(RewriteContext hr) {
116: Properties props = hr.request.props;
117: dont = 0;
118: exp = props.getProperty(hr.prefix + HIGHLIGHT, "");
119: if (exp.equals("")) {
120: re = null;
121: if (props.getProperty(hr.prefix + EXIT) != null) {
122: return false;
123: }
124: } else if (!lastExp.equals(exp)) {
125: lastExp = exp;
126: matchCase = (props.getProperty(hr.prefix + MATCHCASE) != null);
127: re = new Regexp(exp, !matchCase);
128: String tag = props.getProperty(hr.prefix + TAG, "font");
129: String options = props.getProperty(hr.prefix + OPTIONS,
130: "color=red");
131: sub = props.getProperty(hr.prefix + SUBSTITUTE);
132: if (sub == null) {
133: sub = "<" + tag + " " + options + ">&</" + tag + ">";
134: } else {
135: sub = Format.subst(props, sub);
136: }
137: inHighlight = props.getProperty(hr.prefix + MUST) == null;
138: hr.request.log(Server.LOG_DIAGNOSTIC, hr.prefix,
139: "Setting: (" + sub + ") for: " + exp);
140: }
141: return true;
142: }
143:
144: /**
145: * Gets all text between tags - highlighting it appropriately.
146: * To restrict the tag set, define the entities and set the shouldHighlight
147: * flag appropriately.
148: */
149:
150: public void string(RewriteContext hr) {
151: String body = hr.getToken();
152: // System.out.println("Re " + inHighlight + inNoHighlight + dont + re);
153: if (inHighlight && !inNoHighlight && dont == 0 && re != null
154: && re.match(body) != null) {
155: hr.append(re.subAll(body, sub));
156: }
157: }
158:
159: /**
160: * Don't do highlight inside the following sections
161: */
162:
163: public void tag_head(RewriteContext hr) {
164: push();
165: }
166:
167: public void tag_slash_head(RewriteContext hr) {
168: pop();
169: }
170:
171: public void tag_script(RewriteContext hr) {
172: push();
173: }
174:
175: public void tag_slash_script(RewriteContext hr) {
176: pop();
177: }
178:
179: public void tag_style(RewriteContext hr) {
180: push();
181: }
182:
183: public void tag_slash_style(RewriteContext hr) {
184: pop();
185: }
186:
187: public void tag_server(RewriteContext hr) {
188: push();
189: }
190:
191: public void tag_slash_server(RewriteContext hr) {
192: pop();
193: }
194:
195: void push() {
196: dont++;
197: }
198:
199: void pop() {
200: if (dont > 0) {
201: dont--;
202: }
203: }
204:
205: /**
206: * The special entities <code>highlight</code> and
207: * <code>nohighlight</code>
208: * may be used to turn highlighting on or off in certain areas.
209: */
210:
211: public void tag_highlight(RewriteContext hr) {
212: inHighlight = true;
213: }
214:
215: public void tag_slash_highlight(RewriteContext hr) {
216: inHighlight = false;
217: }
218:
219: public void tag_nohighlight(RewriteContext hr) {
220: inNoHighlight = true;
221: }
222:
223: public void tag_slash_nohighlight(RewriteContext hr) {
224: inNoHighlight = false;
225: }
226: }
|