001: /*
002: * argun 1.0
003: * Web 2.0 delivery framework
004: * Copyright (C) 2007 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.web.analysis;
024:
025: import java.io.StringReader;
026: import java.util.ArrayList;
027: import java.util.Iterator;
028: import java.util.List;
029:
030: import org.apache.log4j.Logger;
031:
032: import antlr.Token;
033: import antlr.TokenStreamException;
034: import biz.hammurapi.web.analysis.sql.AnalysisTerm;
035: import biz.hammurapi.web.util.HTMLLexer;
036: import biz.hammurapi.web.util.HTMLTokenTypes;
037:
038: /**
039: * Helper class to form help topic tree.
040: * @author Pavel Vlasov
041: *
042: */
043: public class AnalysisParser {
044: private static final Logger logger = Logger
045: .getLogger(AnalysisParser.class);
046:
047: private static final String DOUBLE_RIGHT_BRACKET = "drb";
048:
049: private static final String DOUBLE_LEFT_BRACKET = "dlb";
050:
051: private static final String TOOLTIP_END = "tooltip-end";
052:
053: private static final int MIN_TOOLTIP_LENGTH = 100;
054:
055: private static final String TERM_OPEN = "[[";
056:
057: private static final String TERM_CLOSE = "]]";
058:
059: public static final int DEFAULT_MAX_TOOLTIP_LENGTH = 1000;
060:
061: static final String ELLIPSIS = " ...";
062:
063: static final int MAX_TERM_LENGTH = 7000;
064:
065: private TermSource termSource;
066:
067: public AnalysisParser(TermSource termSource) {
068: this .termSource = termSource;
069: }
070:
071: /**
072: * Expands [[...]] terms to values obtained from TermSource.
073: * @param input
074: * @param isTooltip
075: * @return
076: */
077: public String parse(String input, boolean isTooltip) {
078: StringBuffer ret = new StringBuffer();
079:
080: // Go through text and break at [[...]]
081: String txt = input;
082: int oidx = txt.indexOf(TERM_OPEN);
083: while (oidx != -1) {
084: int cidx = txt.indexOf(TERM_CLOSE, oidx);
085: if (cidx == -1) {
086: break;
087: }
088: // Term is too long. Must be a mistake, ignore open tag.
089: if (cidx - oidx > MAX_TERM_LENGTH) {
090: logger.warn("Term is too long at position " + oidx);
091: ret.append(txt.substring(0, oidx + 2));
092: txt = txt.substring(oidx + 2);
093: oidx = txt.indexOf(TERM_OPEN);
094: continue;
095: }
096: if (oidx > 0) {
097: ret.append(txt.substring(0, oidx));
098: }
099: String term = txt.substring(oidx + 2, cidx);
100: int tpidx = term.indexOf("|");
101: int nidx = term.indexOf(":");
102: String namespace = nidx != -1
103: && (tpidx == -1 || nidx < tpidx) ? term.substring(
104: 0, nidx) : null;
105: String alternativeText = tpidx == -1 ? null : term
106: .substring(tpidx + 1);
107: String termName = tpidx == -1 ? term.substring(nidx + 1)
108: : term.substring(nidx + 1, tpidx);
109: if (namespace == null && alternativeText == null) {
110: if (TOOLTIP_END.equals(termName)) {
111: if (isTooltip) {
112: ret.append(ELLIPSIS);
113: return ret.toString();
114: }
115: } else if (DOUBLE_LEFT_BRACKET.equals(termName)) {
116: ret.append("[[");
117: } else if (DOUBLE_RIGHT_BRACKET.equals(termName)) {
118: ret.append("]]");
119: } else {
120: Object trm = termSource.getTerm(namespace, termName
121: .trim(), alternativeText);
122: ret.append(term2text(isTooltip, alternativeText,
123: termName, trm));
124: }
125: } else {
126: Object trm = termSource.getTerm(
127: namespace == null ? namespace : namespace
128: .trim(), termName.trim(),
129: alternativeText);
130: ret.append(term2text(isTooltip, alternativeText,
131: termName, trm));
132: }
133: txt = txt.substring(cidx + 2);
134: oidx = txt.indexOf(TERM_OPEN);
135: }
136: ret.append(txt);
137:
138: int maxTooltipLength = DEFAULT_MAX_TOOLTIP_LENGTH;
139:
140: if (!isTooltip || ret.length() < maxTooltipLength) {
141: return ret.toString();
142: }
143:
144: // Paragraph detection.
145: Token lastPARA = null;
146: List tokenChain = new ArrayList();
147: HTMLLexer lexer = new HTMLLexer(
148: new StringReader(ret.toString()));
149: int textcounter = 0; // To protect against infinite loops.
150: try {
151: for (Token t = lexer.nextToken(); t != null
152: && t.getType() != HTMLTokenTypes.CHTML
153: && t.getType() != HTMLTokenTypes.EOF; t = lexer
154: .nextToken()) {
155: tokenChain.add(t);
156: if (t.getText() != null
157: && ((t.getType() == HTMLTokenTypes.UNDEFINED_TOKEN && t
158: .getText().length() == 1) || t
159: .getType() == HTMLTokenTypes.PCDATA)) {
160: textcounter += t.getText().length();
161: if (textcounter >= maxTooltipLength) {
162: tokenChain.add(new Token(
163: HTMLTokenTypes.UNDEFINED_TOKEN,
164: ELLIPSIS));
165: break;
166: }
167: }
168:
169: switch (t.getType()) {
170: case HTMLTokenTypes.OPARA:
171: case HTMLTokenTypes.CPARA:
172: case HTMLTokenTypes.SAPARA:
173: lastPARA = t;
174: break;
175: }
176: }
177: } catch (TokenStreamException e) {
178: if (ret.length() > maxTooltipLength) {
179: return ret.substring(0, maxTooltipLength) + ELLIPSIS;
180: }
181: }
182:
183: if (lastPARA != null) {
184: StringBuffer rsb = new StringBuffer();
185: Iterator it = tokenChain.iterator();
186: while (it.hasNext()) {
187: Token t = (Token) it.next();
188: if (t == lastPARA) {
189: if (rsb.toString().trim().length() < MIN_TOOLTIP_LENGTH) {
190: break;
191: }
192: rsb.append(ELLIPSIS);
193: return rsb.toString();
194: }
195: rsb.append(t.getText());
196: }
197: }
198:
199: StringBuffer rsb = new StringBuffer();
200: Iterator it = tokenChain.iterator();
201: while (it.hasNext()) {
202: Token t = (Token) it.next();
203: rsb.append(t.getText());
204: }
205: return rsb.toString();
206: }
207:
208: private String term2text(boolean isTooltip, String alternativeText,
209: String termName, Object trm) {
210: String termText;
211: if (trm == null) {
212: if (alternativeText == null) {
213: termText = termName;
214: } else {
215: termText = alternativeText;
216: }
217: } else {
218: if (isTooltip && trm instanceof AnalysisTerm) {
219: String text = AnalysisActions.isBlank(alternativeText) ? ((AnalysisTerm) trm)
220: .getName()
221: : alternativeText;
222: termText = "<B style=\"border-bottom:gray dotted 1px\">"
223: + text + "</B>";
224: } else {
225: termText = trm.toString();
226: }
227: }
228: return termText;
229: }
230: }
|