001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.wikitext;
004:
005: import fitnesse.wikitext.widgets.*;
006: import java.lang.reflect.*;
007: import java.util.regex.*;
008: import java.util.List;
009: import java.util.LinkedList;
010: import java.util.concurrent.locks.ReentrantLock;
011:
012: public class WidgetBuilder {
013: public static final Class[] htmlWidgetClasses = new Class[] {
014: CommentWidget.class, LiteralWidget.class,
015: WikiWordWidget.class, BoldWidget.class, ItalicWidget.class,
016: PreformattedWidget.class, HruleWidget.class,
017: HeaderWidget.class, CenterWidget.class, NoteWidget.class,
018: TableWidget.class, ListWidget.class, ClasspathWidget.class,
019: LineBreakWidget.class, ImageWidget.class, LinkWidget.class,
020: TOCWidget.class, AliasLinkWidget.class,
021: VirtualWikiWidget.class, StrikeWidget.class,
022: LastModifiedWidget.class, FixtureWidget.class,
023: XRefWidget.class, MetaWidget.class, EmailWidget.class,
024: AnchorDeclarationWidget.class, AnchorMarkerWidget.class,
025: CollapsableWidget.class, IncludeWidget.class,
026: VariableDefinitionWidget.class, VariableWidget.class };
027:
028: public static WidgetBuilder htmlWidgetBuilder = new WidgetBuilder(
029: htmlWidgetClasses);
030: public static WidgetBuilder literalAndVariableWidgetBuilder = new WidgetBuilder(
031: new Class[] { LiteralWidget.class, VariableWidget.class });
032: public static WidgetBuilder variableWidgetBuilder = new WidgetBuilder(
033: new Class[] { VariableWidget.class });
034:
035: private Class[] widgetClasses;
036: private Pattern widgetPattern;
037: private WidgetData[] widgetDataArray;
038:
039: private List<WidgetInterceptor> interceptors = new LinkedList<WidgetInterceptor>();
040: private final ReentrantLock widgetDataArraylock = new ReentrantLock();
041:
042: public WidgetBuilder(Class[] widgetClasses) {
043: this .widgetClasses = widgetClasses;
044: widgetPattern = buildCompositeWidgetPattern();
045:
046: widgetDataArray = buildWidgetDataArray();
047: }
048:
049: private Pattern buildCompositeWidgetPattern() {
050: StringBuffer pattern = new StringBuffer();
051: for (int i = 0; i < widgetClasses.length; i++) {
052: Class widgetClass = widgetClasses[i];
053: String regexp = getRegexpFromWidgetClass(widgetClass);
054: pattern.append("(").append(regexp).append(")");
055: if (i != (widgetClasses.length - 1))
056: pattern.append("|");
057: }
058: return Pattern.compile(pattern.toString(), Pattern.DOTALL
059: | Pattern.MULTILINE);
060: }
061:
062: private static String getRegexpFromWidgetClass(Class widgetClass) {
063: String regexp = null;
064: try {
065: Field f = widgetClass.getField("REGEXP");
066: regexp = (String) f.get(widgetClass);
067: } catch (Exception e) {
068: e.printStackTrace();
069: }
070: return regexp;
071: }
072:
073: public void addChildWidgets2(String value, ParentWidget parent)
074: throws Exception {
075: Matcher matcher = getWidgetPattern().matcher(value);
076:
077: if (matcher.find()) {
078: String preString = value.substring(0, matcher.start());
079: if (!"".equals(preString))
080: new TextWidget(parent, preString);
081: makeWidget(parent, matcher);
082: String postString = value.substring(matcher.end());
083: if (!postString.equals(""))
084: addChildWidgets(postString, parent);
085: } else
086: new TextWidget(parent, value);
087: }
088:
089: public WikiWidget makeWidget(ParentWidget parent, Matcher matcher)
090: throws Exception {
091: int group = getGroupMatched(matcher);
092: Class widgetClass = widgetClasses[group - 1];
093: return constructWidget(widgetClass, parent, matcher.group());
094: }
095:
096: private WikiWidget constructWidget(Class widgetClass,
097: ParentWidget parent, String text) throws Exception {
098: try {
099: Constructor widgetConstructor = widgetClass
100: .getConstructor(new Class[] { ParentWidget.class,
101: String.class });
102: WikiWidget widget = (WikiWidget) widgetConstructor
103: .newInstance(new Object[] { parent, text });
104: for (WidgetInterceptor i : interceptors) {
105: i.intercept(widget);
106: }
107: return widget;
108: } catch (Exception e) {
109: e.printStackTrace();
110: Exception exception = new Exception(
111: "Widget Construction failed for "
112: + widgetClass.getName() + "\n"
113: + e.getMessage());
114: exception.setStackTrace(e.getStackTrace());
115: throw exception;
116: }
117: }
118:
119: public int getGroupMatched(Matcher matcher) {
120: for (int i = 1; i <= matcher.groupCount(); i++) {
121: if (matcher.group(i) != null)
122: return i;
123: }
124: return -1;
125: }
126:
127: public Pattern getWidgetPattern() {
128: return widgetPattern;
129: }
130:
131: private WidgetData[] buildWidgetDataArray() {
132: WidgetData[] widgetDataArray = new WidgetData[widgetClasses.length];
133: for (int i = 0; i < widgetClasses.length; i++) {
134: Class widgetClass = widgetClasses[i];
135: widgetDataArray[i] = new WidgetData(widgetClass);
136: }
137: return widgetDataArray;
138: }
139:
140: public void addChildWidgets(String value, ParentWidget parent)
141: throws Exception {
142: widgetDataArraylock.lock();
143: WidgetData firstMatch = findFirstMatch(value);
144: try {
145: if (firstMatch != null) {
146: Matcher match = firstMatch.match;
147: String preString = value.substring(0, match.start());
148: if (!"".equals(preString))
149: new TextWidget(parent, preString);
150: constructWidget(firstMatch.widgetClass, parent, match
151: .group());
152: String postString = value.substring(match.end());
153: if (!postString.equals(""))
154: addChildWidgets(postString, parent);
155: } else
156: new TextWidget(parent, value);
157: } finally {
158: widgetDataArraylock.unlock();
159: }
160: }
161:
162: private WidgetData findFirstMatch(String value) {
163: resetWidgetDataList();
164:
165: WidgetData firstMatch = null;
166: for (int i = 0; i < widgetDataArray.length; i++) {
167: WidgetData widgetData = widgetDataArray[i];
168: Matcher match = widgetData.pattern.matcher(value);
169: if (match.find()) {
170: widgetData.match = match;
171: if (firstMatch == null)
172: firstMatch = widgetData;
173: else if (match.start() < firstMatch.match.start())
174: firstMatch = widgetData;
175: }
176: }
177: return firstMatch;
178: }
179:
180: private void resetWidgetDataList() {
181: for (int i = 0; i < widgetDataArray.length; i++)
182: widgetDataArray[i].match = null;
183: }
184:
185: public void addInterceptor(WidgetInterceptor interceptor) {
186: interceptors.add(interceptor);
187: }
188:
189: static class WidgetData {
190: public Class widgetClass;
191: public Pattern pattern;
192: public Matcher match;
193:
194: public WidgetData(Class widgetClass) {
195: this.widgetClass = widgetClass;
196: pattern = Pattern.compile(
197: getRegexpFromWidgetClass(widgetClass),
198: Pattern.DOTALL | Pattern.MULTILINE);
199: }
200: }
201: }
|