001: package com.teamkonzept.lib.templates;
002:
003: import java.io.*;
004: import java.util.*;
005: import com.oroinc.text.regex.*;
006:
007: import com.teamkonzept.lib.*;
008:
009: /**
010: * Der Syntaxbaum eines Templates
011: * @author $Author: alex $
012: * @version $Revision: 1.19 $
013: */
014: public class TKTemplateSyntax {
015:
016: static protected String patListMarker = "LIST";
017: static protected String patTagDefinitionMarker = "TAGDEF";
018: static protected String patAtomTagMarker = "ATAG";
019: static protected String patTagMarker = "TAG";
020: static protected String patNoExpandMarker = "NOEXPAND";
021: static protected String patTrimMarker = "TRIM";
022: static protected String patCaseMarker = "CASE";
023: static protected String patNotMarker = "NOT";
024: static protected String patIfMarker = "IF";
025: static protected String patElseMarker = "ELSE";
026: static protected String patElsIfMarker = "ELSIF";
027: static protected String patIncludeMarker = "INCLUDE";
028: static protected String patSwitchMarker = "SWITCH";
029: static protected String patScopeMarker = "SCOPE";
030: static protected String patIgnoreMarker = "IGNORE";
031: static protected String patSetMarker = "SET";
032: static protected String patSetLocalMarker = "SETLOCAL";
033: static protected String patLocalMarker = "LOCAL";
034: static protected String patEvalMarker = "EVAL";
035: static protected String patExpressionMarker = "EXPRESSION";
036: static protected String patWhileMarker = "WHILE";
037: static protected String patExistsMarker = "EXISTS";
038: static protected String patDateMarker = "DATE";
039: static protected String patLanguageMarker = "LANG";
040:
041: static public final int MAX_TAG_TYPE = 100;
042:
043: public boolean applyConverter = false;
044: public boolean isSubSyntax = false;
045:
046: // public static final String CURR_YEAR = Integer.toString( (new java.util.Date()).getYear()+1900 );
047:
048: private static final int VECTOR_SIZE = 100;
049:
050: /** die einzelnen Textabschnitte im Template */
051: protected TKVector textChunks = new TKVector(VECTOR_SIZE,
052: VECTOR_SIZE);
053:
054: /** die Tags eines Templates */
055: public TKVector tags = new TKVector(VECTOR_SIZE, VECTOR_SIZE); // REDESIGN: Wird von anderen Klassen gebraucht
056:
057: /** Die Quelle aus der das Template stammt - URL Format ? */
058: protected String source = "";
059:
060: private Pattern patTKTag = TKTemplate.patTKTag;
061:
062: public Pattern getTKTag() {
063: return patTKTag;
064: }
065:
066: protected void setTKTag(Pattern pat) {
067: patTKTag = pat;
068: }
069:
070: public final String getSource() {
071: return source;
072: }
073:
074: public TKTemplate getNewTemplate() {
075: return new TKTemplate(this );
076: }
077:
078: public TKTemplateData getNewTemplateData() {
079: return new TKTemplateData();
080: }
081:
082: public String getDefaultEncoding() {
083: return TKAnsiConverter.CONV_ID;
084: }
085:
086: public String getDefaultEncoding(TKTemplateData td) {
087: String encoding = td == null ? null : (String) td
088: .getVariable("TEMPLATE_SYNTAX_DEFAULT_ENCODING");
089:
090: return encoding == null ? getDefaultEncoding() : encoding;
091: }
092:
093: /**
094: */
095: public TKTemplateSyntax() {
096: }
097:
098: /**
099: */
100: public TKTemplateSyntax(Pattern patTKTag) {
101: if (patTKTag != null)
102: this .patTKTag = patTKTag;
103: }
104:
105: /**
106: * Konstruktor1
107: * Konstrukror2 wird aufgerufen
108: *
109: * @param String text, das vollstaendige Template als String
110: */
111: public TKTemplateSyntax(String text, String source)
112: throws TKTemplateSyntaxException {
113: init(text, source);
114: }
115:
116: public TKTemplateSyntax(String text, String source, Pattern patTKTag)
117: throws TKTemplateSyntaxException {
118: this .patTKTag = patTKTag;
119: init(text, source);
120: }
121:
122: public TKTemplateSyntax(String text, String source,
123: boolean applyConverter) throws TKTemplateSyntaxException {
124: this .applyConverter = applyConverter;
125: init(text, source);
126: }
127:
128: /**
129: erzeugt neues TKTemplateSyntax Objekt und läßt es gleich parsen
130: @param text der zu parsende Text
131: @param source Quelle des textes
132: @return ein neues TKTemplateSyntax Objekt
133: */
134: public TKTemplateSyntax newChild(String text, String source)
135: throws TKTemplateSyntaxException {
136: TKTemplateSyntax result = newChild();
137: result.init(text, source);
138: return result;
139: }
140:
141: /**
142: erzeugt eine neues TKTemplateSyntaxObjekt (entsprechend der Hierarchie)
143: und kopiert die entsprechenden Member
144: @return ein neues TKTemplateSyntax Objekt
145: */
146: public TKTemplateSyntax newChild() {
147: try {
148: TKTemplateSyntax syntax = (TKTemplateSyntax) getClass()
149: .newInstance();
150: syntax.applyConverter = this .applyConverter;
151: syntax.isSubSyntax = this .isSubSyntax;
152: syntax.setTKTag(patTKTag);
153: return syntax;
154: } catch (InstantiationException e) {
155: throw new InstantiationError(e.getMessage());
156: } catch (IllegalAccessException e) {
157: throw new IllegalAccessError(e.getMessage());
158: }
159: }
160:
161: /**
162: erzeugt neues TKTemplateSyntax Objekt und läßt es gleich parsen
163: @param text der zu parsende Text
164: @param source Quelle des textes
165: @param hasSubTags
166: @return ein neues TKTemplateSyntax Objekt
167: */
168: public TKTemplateSyntax newChild(String text, String source,
169: boolean hasSubTags) throws TKTemplateSyntaxException {
170: TKTemplateSyntax result = newChild();
171: result.isSubSyntax = hasSubTags;
172: result.init(text, source);
173: return result;
174: }
175:
176: public TKTemplateSyntax newChild(PatternMatcherInput matcherInput,
177: String source) throws TKTemplateSyntaxException {
178: TKTemplateSyntax result = newChild();
179: result.init(matcherInput, source);
180: return result;
181: }
182:
183: /**
184: * Konstruktor2
185: * Der uebergebene String wird Tag fuer Tag bearbeitet. Wird ein Tag gefunden,
186: * so wird das entsprechende Tag-Objekt erzeugt. Dieses Tag kann wiederum Syntaxobjekte
187: * beinhalten, so das auch dieses Syntaxobjekte erzeugen muessen, die dann
188: * die Kinder des zuvorigen Syntaxobjektes bilden. Zu jedem Syntaxobjekt werden
189: * der zugehoerige Text gespeichert.
190: * Hierdurch wird eine rekursive Datenstruktur aufgebaut, welche es ermoeglicht,
191: * ein Template exakt in einer Objekthierachie wiederzuspiegeln.
192: *
193: * DIE PATTERN:
194: * patPreTag = "TK_";
195: * String patRefTag = "(SRC|HREF|ACTION|BACKGROUND)";
196: * patCopyRight = compiler.compile( "<HTML>", Perl5Compiler.CASE_INSENSITIVE_MASK );
197: * patBaseURL = compiler.compile(" "+patRefTag+"\\s*\\=\\s*\"(?!(/|#|\\w+?(:|:)))", Perl5Compiler.CASE_INSENSITIVE_MASK);
198: * patTKTag = compiler.compile("</?"+patPreTag, Perl5Compiler.CASE_INSENSITIVE_MASK);
199: * patCleanEmpty = compiler.compile("\n\\s*\n");
200: *
201: *
202: * @param PatternMatcherInput matcherInput, ist der umgewandelte
203: * String des Templates als Text
204: */
205: public TKTemplateSyntax(PatternMatcherInput matcherInput,
206: String source) throws TKTemplateSyntaxException {
207: init(matcherInput, source);
208: }
209:
210: /**
211: Hier werden ggf. Escape-Zeichen aus Tag-Parametern abgefiltert (im SubSyntax-Context)
212: */
213: public String checkForSubSyntaxChunk(String chunk) {
214:
215: if (!isSubSyntax || (chunk == null))
216: return chunk;
217:
218: StringBuffer buf = new StringBuffer();
219:
220: int pos = 0;
221: while (pos < chunk.length()) {
222:
223: char chr = chunk.charAt(pos++);
224:
225: if (chr == '\\') {
226:
227: if (pos + 1 < chunk.length())
228: buf.append(chunk.charAt(pos++));
229: else
230: buf.append(chr);
231:
232: } else
233: buf.append(chr);
234: }
235:
236: return buf.toString();
237: }
238:
239: public void init(String _text, String source)
240: throws TKTemplateSyntaxException {
241: init(new PatternMatcherInput(_text), source);
242: }
243:
244: /**
245: Parsiert Datenquelle und erzeugt Syntaxbaum
246: @param matcherInput Datenquelle für den Pattern Matcher
247: @param source Name der Datenquelle (URL?)
248: */
249: private void init(PatternMatcherInput matcherInput, String source)
250: throws TKTemplateSyntaxException {
251: this .source = source;
252:
253: PatternMatcher matcher = TKReg.getMatcher();
254:
255: int lastPos = matcherInput.getCurrentOffset();
256: //---- Solange ein <TK_ oder </TK_ vorhanden ist befindet => weiter ----//
257: while (matcher.contains(matcherInput, patTKTag)) {
258:
259: //---- match enthaelt den neachsten Pattern: <TK_ oder </TK_ ----//
260: MatchResult match = matcher.getMatch();
261:
262: //---- Text zwischen letzter Position und naechstem TK_Tag ----//
263: String newText = matcherInput.substring(lastPos, match
264: .beginOffset(0));
265:
266: //---- Text zwischen den TK-Tags ----//
267: textChunks.addElement(checkForSubSyntaxChunk(newText));
268:
269: //---- EIN aktuelles TK-Tag Objekt wird erzeugt, welches wiederum ----//
270: //---- ein Syntax-Objekt erzeugt ----//
271: TKTag currTag = newTag(matcherInput, match);
272: tags.addElement(currTag);
273: lastPos = matcherInput.getCurrentOffset();
274:
275: //---- Abbruchbedingung für rekursive Aufrufe//
276: if (currTag instanceof TKEndTag)
277: return;
278: }
279: textChunks.addElement(matcherInput.substring(lastPos,
280: matcherInput.getEndOffset()));
281: }
282:
283: /**
284: codiert Textchunks
285: @param chunk der zu konvertierende Text
286: @param ed hält das Encoding als Template Variable
287: */
288: private String applyConverter(String chunk, TKTemplateData ed)
289: throws TKTemplateSyntaxException {
290:
291: if (!applyConverter)
292: return chunk;
293:
294: String encoding = getDefaultEncoding(ed);
295:
296: TKConverter encoder = TKConverter.getConverter(encoding);
297: if (encoder == null) {
298: throw new Error("missing converter for encoding "
299: + encoding);
300: }
301:
302: String result = new String(encoder.stringToBytes(chunk), 0);
303:
304: return result;
305: }
306:
307: /**
308: * 1.Schritt zur TemplateGenerierung
309: *
310: * @param TKTemplateData ed
311: * @return das generierte Template als String
312: */
313: public String apply(TKTemplateData ed)
314: throws TKTemplateSyntaxException {
315: int nText = textChunks.size();
316: int nTags = tags.size();
317:
318: StringBuffer result = new StringBuffer();
319: int i = 0;
320:
321: if (tags != null) {
322: for (; i < nTags; i++) {
323:
324: result.append(applyConverter((String) textChunks
325: .elementAt(i), ed));
326:
327: //---- Die apply-Methode des jeweiligen TKTag-Objekts wird aufgerufen ----//
328: //---- welche wiederum diese apply-Methode aufruft ----//
329:
330: String tagSubst = ((TKTag) tags.elementAt(i)).apply(ed);
331: if (tagSubst != null)
332: result.append(tagSubst);
333:
334: }
335: }
336:
337: if (i < nText) {
338: result.append(applyConverter((String) textChunks
339: .elementAt(i), ed));
340: }
341:
342: return result.toString();
343: }
344:
345: /**
346: * Das Template wird generiert.
347: *
348: * @param TKTemplateData ed
349: * @param PrintStream ps
350: */
351: public void apply(TKTemplateData ed, PrintStream ps)
352: throws TKTemplateSyntaxException, IOException {
353: int nText = textChunks.size();
354: int nTags = tags.size();
355:
356: int i = 0;
357: for (; i < nTags; i++) {
358:
359: ps.print(applyConverter((String) textChunks.elementAt(i),
360: ed));
361: ((TKTag) tags.elementAt(i)).apply(ed, ps);
362: }
363: if (i < nText) {
364: ps.print(applyConverter((String) textChunks.elementAt(i),
365: ed));
366: }
367: }
368:
369: /**
370: * Das Template wird generiert.
371: *
372: * @param ed TKTemplateData
373: * @param writer Writer to which the result is written
374: */
375: public void apply(TKTemplateData ed, Writer writer)
376: throws TKTemplateSyntaxException, IOException {
377: int nText = textChunks.size();
378: int nTags = tags.size();
379:
380: int i = 0;
381: for (; i < nTags; i++) {
382:
383: writer.write(applyConverter((String) textChunks
384: .elementAt(i), ed));
385: ((TKTag) tags.elementAt(i)).apply(ed, writer);
386: }
387: if (i < nText) {
388: writer.write(applyConverter((String) textChunks
389: .elementAt(i), ed));
390: }
391: }
392:
393: /**
394: * Wird rekursiv ein Syntaxbaum fuer ein Template aus einem String erzeugt und das Template
395: * enthaelt Tags, so muessen diese als Objekte erzeugt werden. Tags koennen neben
396: * Attribute, die gesetzt werden, wiederum Syntaxobjekte beinhalten,welche erzeugt werden.
397: *
398: * @param PatternMatcherInput matcherInput
399: * @param MatchResult match
400: *
401: * @return ein bearbeitetes TKTag-Objekt
402: */
403: public TKTag newTag(PatternMatcherInput matcherInput,
404: MatchResult match) throws TKTemplateSyntaxException {
405:
406: int nameEnd = 0; // Name der Tagklasse (kein Nametag)
407: int firstPos = match.endOffset(0);
408: int currPos = firstPos;
409: int tagsToClose = 1;
410: boolean found = false;
411: boolean hasSubTags = false;
412: char ch;
413: // Wir befinden uns nach </?TK[:_]
414: do {
415: ch = matcherInput.charAt(currPos++);
416:
417: if ((ch == ':') && (!hasSubTags) && (nameEnd == 0)) {
418:
419: nameEnd = currPos;
420:
421: } else if (ch == '\\') {
422:
423: ch = matcherInput.charAt(currPos++);
424: continue;
425:
426: } else if (ch == '>') {
427:
428: found = ((--tagsToClose) == 0);
429:
430: } else if (ch == '<') {
431:
432: tagsToClose++;
433: hasSubTags = hasSubTags
434: || matcherInput.substring(currPos, currPos + 2)
435: .equalsIgnoreCase("TK");
436: }
437: } while (!found);
438:
439: matcherInput.setCurrentOffset(currPos);
440: if (nameEnd != 0) {
441: String tagType = matcherInput.substring(firstPos,
442: nameEnd - 1).toUpperCase();
443: String tagData = matcherInput.substring(nameEnd,
444: currPos - 1);
445:
446: if (matcherInput.charAt(match.beginOffset(0) + 1) == '/')
447: return new TKEndTag(this , tagType, tagData, hasSubTags);
448: // Starttag
449: return getTag(tagType, tagData, matcherInput, hasSubTags);
450:
451: }
452: // z.B. </TK_IF>
453: if (matcherInput.charAt(match.beginOffset(0) + 1) == '/')
454: return new TKEndTag(this , matcherInput.substring(firstPos,
455: currPos - 1), "", hasSubTags);
456:
457: return new TKNameTag(this , matcherInput.substring(firstPos,
458: currPos - 1), hasSubTags);
459: }
460:
461: public TKTag getTag(String tagType, String tagData,
462: PatternMatcherInput matcherInput, boolean hasSubTags)
463: throws TKTemplateSyntaxException {
464: if (tagType.equals(patIfMarker))
465: return new TKIfTag(this , tagData, matcherInput, hasSubTags);
466: if (tagType.equals(patElseMarker))
467: return new TKEndTag(this , tagType, tagData, hasSubTags);
468: if (tagType.equals(patElsIfMarker))
469: return new TKEndTag(this , tagType, tagData, hasSubTags);
470: if (tagType.equals(patListMarker))
471: return new TKListTag(this , tagData, matcherInput,
472: hasSubTags);
473: if (tagType.equals(patIncludeMarker))
474: return new TKIncludeTag(this , tagData, hasSubTags);
475: if (tagType.equals(patTagDefinitionMarker))
476: return new TKTagDefinitionTag(this , tagData, matcherInput,
477: hasSubTags);
478: if (tagType.equals(patAtomTagMarker))
479: return new TKAtomTagTag(this , tagData, hasSubTags);
480: if (tagType.equals(patTagMarker))
481: return new TKTagTag(this , tagData, matcherInput, hasSubTags);
482: if (tagType.equals(patNoExpandMarker))
483: return new TKNoExpandTag(this , tagData, matcherInput,
484: hasSubTags);
485: if (tagType.equals(patTrimMarker))
486: return new TKTrimTag(this , tagData, matcherInput,
487: hasSubTags);
488: if (tagType.equals(patCaseMarker))
489: return new TKCaseTag(this , tagData, matcherInput,
490: hasSubTags);
491: if (tagType.equals(patNotMarker))
492: return new TKNotTag(this , tagData, matcherInput, hasSubTags);
493: if (tagType.equals(patSwitchMarker))
494: return new TKSwitchTag(this , tagData, hasSubTags);
495: if (tagType.equals(patScopeMarker))
496: return new TKScopeTag(this , tagData, matcherInput,
497: hasSubTags);
498: if (tagType.equals(patIgnoreMarker))
499: return new TKIgnoreTag(this , tagData, matcherInput,
500: hasSubTags);
501: if (tagType.equals(patSetMarker))
502: return new TKSetTag(this , tagData, hasSubTags);
503: if (tagType.equals(patSetLocalMarker))
504: return new TKSetLocalTag(this , tagData, hasSubTags);
505: if (tagType.equals(patLocalMarker))
506: return new TKLocalTag(this , tagData, matcherInput,
507: hasSubTags);
508: if (tagType.equals(patEvalMarker))
509: return new TKEvalTag(this , tagData, hasSubTags);
510: if (tagType.equals(patExpressionMarker))
511: return new TKExpressionTag(this , tagData, hasSubTags);
512: if (tagType.equals(patWhileMarker))
513: return new TKWhileTag(this , tagData, matcherInput,
514: hasSubTags);
515: if (tagType.equals(patExistsMarker))
516: return new TKExistsTag(this , tagData, hasSubTags);
517: if (tagType.equals(patDateMarker))
518: return new TKDateTag(this , tagData, hasSubTags);
519: if (tagType.equals(patLanguageMarker))
520: return new TKLanguageTag(this , tagData, hasSubTags);
521: return null;
522: }
523:
524: public final Enumeration getTags() {
525: return tags.elements();
526: }
527:
528: public final Enumeration getTexts() {
529: return textChunks.elements();
530: }
531: }//end class
|