001: // WebOnSwing - Web Application Framework
002: //Copyright (C) 2003 Fernando Damian Petrola
003: //
004: //This library is free software; you can redistribute it and/or
005: //modify it under the terms of the GNU Lesser General Public
006: //License as published by the Free Software Foundation; either
007: //version 2.1 of the License, or (at your option) any later version.
008: //
009: //This library is distributed in the hope that it will be useful,
010: //but WITHOUT ANY WARRANTY; without even the implied warranty of
011: //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: //Lesser General Public License for more details.
013: //
014: //You should have received a copy of the GNU Lesser General Public
015: //License along with this library; if not, write to the Free Software
016: //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017:
018: package net.ar.webonswing.render.templates.html;
019:
020: import java.util.*;
021:
022: import net.ar.webonswing.helpers.*;
023: import net.ar.webonswing.managers.templates.*;
024: import net.ar.webonswing.render.*;
025: import net.ar.webonswing.render.markup.*;
026: import net.ar.webonswing.render.templates.*;
027: import net.ar.webonswing.visitor.*;
028:
029: import org.apache.commons.logging.*;
030: import org.apache.regexp.*;
031:
032: /**
033: * Plantilla de html que parsea un archivo creando recursivamente otros
034: * HtmlTemplate cuando encuentra algun tag con el atributo "name". Quedando
035: * entonces el tag encontrado como "theFoundTag" en la plantilla y el cuerpo se
036: * separa en los fragmentos de texto que correspondan.
037: *
038: * @author Fernando Damian Petrola
039: */
040: public class HtmlTemplate extends DefaultTemplate {
041: protected StringBuffer theHtmlData;
042: protected Tag theFoundTag;
043: protected int theNumberOfBlocks;
044:
045: public HtmlTemplate() {
046: super (null);
047: }
048:
049: public HtmlTemplate(StringBuffer aBuffer, Tag aFoundTag) {
050: super (new HtmlTemplateBody());
051: theFoundTag = aFoundTag;
052: theNumberOfBlocks = 0;
053: theHtmlData = new StringBuffer(aBuffer.toString());
054: generateSubTemplates();
055: getHtmlTemplateBody().setTemplate(this );
056: }
057:
058: public void generateSubTemplates() {
059: while (theHtmlData.length() > 0)
060: getNextHtmlTemplateElement(theHtmlData);
061: }
062:
063: public HtmlTemplate(StringBuffer aBuffer) {
064: this (aBuffer, null);
065: }
066:
067: public HtmlTemplate(String aBuffer) {
068: this (new StringBuffer(aBuffer));
069: }
070:
071: public HtmlTemplateBody getHtmlTemplateBody() {
072: return (HtmlTemplateBody) theBody;
073: }
074:
075: public void addElement(TemplateElement anElement) {
076: if (anElement != null) {
077: TemplateElement theElement = getElementForId(anElement
078: .getId());
079:
080: if (theElement != null) {
081: theElement.setContent(anElement.getContent());
082:
083: if (theElement instanceof IdTagTemplateElement
084: && anElement instanceof IdTagTemplateElement) {
085: IdTagTemplateElement theIdTagElement = (IdTagTemplateElement) theElement;
086:
087: Tag theTag = ((IdTagTemplateElement) anElement)
088: .getTheIdTag();
089: theIdTagElement.getTheIdTag().removeAttribute(
090: "name");
091:
092: if (theTag != null)
093: theTag.addAllTagAttributes(theIdTagElement
094: .getTheIdTag());
095: }
096: }
097: }
098: }
099:
100: public Tag getFoundTag() {
101: return theFoundTag;
102: }
103:
104: public void setFoundTag(Tag aTag) {
105: theFoundTag = aTag;
106: }
107:
108: public void mergeFoundTag(Tag aTag) {
109: if (theFoundTag != null) {
110: theFoundTag.removeAttribute("name");
111: theFoundTag.addNewTagAttributesAndName(aTag);
112: theFoundTag.copyNewTagContainer(aTag);
113: theFoundTag.setNeedsClosure(aTag.isNeedsClosure());
114: }
115: }
116:
117: public void mergeFoundTagKeepingName(Tag aTag) {
118: if (theFoundTag != null) {
119: theFoundTag.removeAttribute("name");
120: theFoundTag.addNewTagAttributes(aTag);
121: theFoundTag.copyNewTagContainer(aTag);
122: theFoundTag.setNeedsClosure(aTag.isNeedsClosure());
123: }
124: }
125:
126: public void deleteFoundTag() {
127: theFoundTag = null;
128: }
129:
130: public Object clone() throws CloneNotSupportedException {
131: HtmlTemplate theHtmlTemplate = (HtmlTemplate) super .clone();
132:
133: if (theFoundTag != null)
134: theHtmlTemplate.theFoundTag = (Tag) theFoundTag.clone();
135:
136: theHtmlTemplate.theNumberOfBlocks = theNumberOfBlocks;
137: theHtmlTemplate.getHtmlTemplateBody().setTemplate(
138: theHtmlTemplate);
139:
140: return theHtmlTemplate;
141: }
142:
143: public void removeElement(String anElementId) {
144: addElement(new IdTagTemplateElement(anElementId,
145: new TextContent("")));
146: }
147:
148: public String renderToText() {
149: return new TextTemplateRenderer(this ).getResult().toString();
150: }
151:
152: public HtmlTemplate addIdTagTemplateElement(Object anId,
153: Visitable aContent, Tag aTag) {
154: addElement(new IdTagTemplateElement(anId, aContent, aTag));
155: return this ;
156: }
157:
158: public HtmlTemplate addIdTagTemplateElement(Object anId,
159: Visitable aContent) {
160: addElement(new IdTagTemplateElement(anId, aContent));
161: return this ;
162: }
163:
164: public HtmlTemplate addIdTagTemplateElement(Object anId,
165: String aContent) {
166: addElement(new IdTagTemplateElement(anId, new TextContent(
167: aContent)));
168: return this ;
169: }
170:
171: public HtmlTemplate getSubTemplate(String aPath) {
172: return HtmlTemplateManager.getSubTemplate(this , aPath);
173: }
174:
175: public HtmlTemplate getClonedSubTemplate(String aPath) {
176: return HtmlTemplateManager.getClonedSubTemplate(this , aPath);
177: }
178:
179: public HtmlTemplate getClonedSubTemplateAt(int i) {
180: try {
181: TemplateElement theElement = getElementAt(i);
182:
183: return (HtmlTemplate) ((HtmlTemplate) theElement
184: .getContent()).clone();
185: } catch (CloneNotSupportedException e) {
186: throw new WebOnSwingException(e);
187: }
188: }
189:
190: public TemplateElement getElementAt(int i) {
191: return super .getElementAt(i * 2 + 1);
192: }
193:
194: public int getElementCount() {
195: return super .getElementCount() / 2;
196: }
197:
198: public IdTagTemplateElement getNextHtmlTemplateElement(
199: StringBuffer aBuffer) {
200: try {
201: Object[] theTagSpecification = getNextTagSpecification(aBuffer);
202:
203: if (theTagSpecification != null) {
204: Tag foundTag = (Tag) theTagSpecification[0];
205: String aKey = foundTag.getAttributeValueForKey("name");
206: int theStart = ((Integer) theTagSpecification[1])
207: .intValue();
208: int theEnd = ((Integer) theTagSpecification[2])
209: .intValue();
210:
211: if (!foundTag.isNeedsClosure())
212: return createHtmlTemplateElement(aBuffer, aKey,
213: foundTag, theStart, theEnd, theEnd, theEnd,
214: theEnd);
215:
216: int theNextOpen = 0;
217: RE reFindNextOpen = new RE("(<)");
218: if (reFindNextOpen.match(aBuffer.toString(), theEnd))
219: theNextOpen = reFindNextOpen.getParenStart(1);
220:
221: String theTagName = foundTag.getTheName();
222:
223: RE reFindOpenTag = new RE(
224: "(<" + theTagName + "[^<]*>)",
225: RE.MATCH_CASEINDEPENDENT);
226: RE reFindCloseTag = new RE("(</" + theTagName
227: + "[^<]*>)", RE.MATCH_CASEINDEPENDENT);
228:
229: int theOpenTags = 1;
230: boolean finalCloseFound = false;
231: int thePosition = theEnd;
232:
233: while (thePosition <= aBuffer.length()
234: && !finalCloseFound) {
235: boolean openFound = reFindOpenTag.match(aBuffer
236: .toString(), thePosition);
237: while (openFound
238: && aBuffer.charAt(reFindOpenTag
239: .getParenEnd(1) - 2) == '/')
240: openFound = reFindOpenTag.match(aBuffer
241: .toString(), reFindOpenTag
242: .getParenEnd(1));
243:
244: boolean closeFound = finalCloseFound = reFindCloseTag
245: .match(aBuffer.toString(), thePosition);
246: if (closeFound) {
247: thePosition = reFindCloseTag.getParenEnd(1);
248: theOpenTags--;
249: if (openFound)
250: if (reFindOpenTag.getParenStart(1) < reFindCloseTag
251: .getParenStart(1)) {
252: thePosition = reFindOpenTag
253: .getParenEnd(1);
254: theOpenTags += 2;
255: }
256:
257: finalCloseFound = theOpenTags == 0;
258: if (finalCloseFound)
259: return createHtmlTemplateElement(aBuffer,
260: aKey, foundTag, theStart, theEnd,
261: theNextOpen, reFindCloseTag
262: .getParenStart(1),
263: reFindCloseTag.getParenEnd(1));
264: } else {
265: throw new WebOnSwingException(
266: "Cannot find the close tag for block= \""
267: + aKey + "\" (" + theStart
268: + ", " + theEnd + ")");
269: }
270: }
271: }
272:
273: if (theTagSpecification == null) {
274: super .addElement(new DefaultTemplateElement("block"
275: + theNumberOfBlocks++, new TextContent(
276: new StringBuffer(aBuffer.toString()))));
277: aBuffer.setLength(0);
278: }
279: } catch (RESyntaxException e) {
280: LogFactory.getLog(HtmlTemplateBody.class).error("", e);
281: }
282:
283: return null;
284: }
285:
286: protected IdTagTemplateElement createHtmlTemplateElement(
287: StringBuffer aBuffer, String aKey, Tag aFoundTag,
288: int theOpenTagStart, int theOpenTagEnd, int theNextOpen,
289: int theCloseTagStart, int theCloseTagEnd) {
290: super .addElement(new DefaultTemplateElement("block"
291: + theNumberOfBlocks++,
292: new TextContent(new StringBuffer(aBuffer.substring(0,
293: theOpenTagStart)))));
294:
295: IdTagTemplateElement theNewElement = null;
296:
297: if (!aKey.equals("delete-template")) {
298: HtmlTemplate theNewHtmlTemplate = new HtmlTemplate(
299: new StringBuffer(aBuffer.substring(theOpenTagEnd,
300: theCloseTagStart)), aFoundTag);
301: theNewElement = new IdTagTemplateElement(aKey,
302: theNewHtmlTemplate, aFoundTag);
303: super .addElement(theNewElement);
304: }
305:
306: aBuffer.delete(0, theCloseTagEnd);
307:
308: return theNewElement;
309: }
310:
311: public Object[] getNextTagSpecification(StringBuffer aBuffer)
312: throws RESyntaxException {
313: //TODO: optimizar con compiladas
314:
315: RE theIdTagRe = new RE(
316: "(<\\w*\\s*[^<]*\\s+name\\s*=\\s*\"[^\"]+\"[^<]*>)",
317: RE.MATCH_CASEINDEPENDENT);
318: RE theTagNameRe = new RE("<(\\w+)\\s*[^<]*>");
319: RE theTagAttributeRe = new RE(
320: "\\s+(\\w+)\\s*=\\s*\"([^\"]*)\"\\s*");
321:
322: Tag theTag = null;
323: int theStart = 0;
324: int theEnd = 0;
325: if (theIdTagRe.match(aBuffer.toString())) {
326: theStart = theIdTagRe.getParenStart(1);
327: theEnd = theIdTagRe.getParenEnd(1);
328: String theTagString = aBuffer.substring(theStart, theEnd)
329: .toString();
330: if (theTagNameRe.match(theTagString)) {
331: theTag = new Tag(theTagNameRe.getParen(1));
332: int thePosition = 0;
333: while (theTagAttributeRe.match(theTagString.toString(),
334: thePosition)) {
335: theTag.addAttribute(new TagAttribute(
336: theTagAttributeRe.getParen(1),
337: theTagAttributeRe.getParen(2)));
338: thePosition = theTagAttributeRe.getParenEnd(2);
339: }
340: }
341:
342: if (aBuffer.charAt(theEnd - 2) == '/')
343: theTag.setNeedsClosure(false);
344: } else
345: return null;
346: return new Object[] { theTag, new Integer(theStart),
347: new Integer(theEnd) };
348: }
349: }
350:
351: class HtmlTemplateBody implements TemplateBody, Cloneable {
352: protected StringBuffer theReplacedBodyBuffer;
353: protected HtmlTemplate theTemplate;
354:
355: public HtmlTemplateBody() {
356: theReplacedBodyBuffer = new StringBuffer();
357: }
358:
359: public void replace(List theElements) {
360: try {
361: theReplacedBodyBuffer = new StringBuffer();
362:
363: for (Iterator i = theElements.iterator(); i.hasNext();) {
364: TemplateElement theElement = (TemplateElement) i.next();
365: String theRendering = new ContentRenderer((theElement)
366: .getContent()).getResult();
367: theReplacedBodyBuffer.append(theRendering);
368: }
369:
370: if (theTemplate.getFoundTag() != null) {
371: Tag theClonedTag = (Tag) theTemplate.getFoundTag()
372: .clone();
373:
374: theClonedTag.getTheMarkupContainer().addElement(
375: new TagContent(theReplacedBodyBuffer));
376: theReplacedBodyBuffer = new StringBuffer(
377: new TextMarkupRenderer(theClonedTag)
378: .getResult().toString());
379: }
380: } catch (CloneNotSupportedException e) {
381: throw new WebOnSwingException(e);
382: }
383: }
384:
385: public Object getResult() {
386: return theReplacedBodyBuffer;
387: }
388:
389: public Object clone() throws CloneNotSupportedException {
390: HtmlTemplateBody theTemplateBody = (HtmlTemplateBody) super
391: .clone();
392:
393: if (theReplacedBodyBuffer != null)
394: theTemplateBody.theReplacedBodyBuffer = new StringBuffer(
395: theReplacedBodyBuffer.toString());
396:
397: return theTemplateBody;
398: }
399:
400: public HtmlTemplate getTemplate() {
401: return theTemplate;
402: }
403:
404: public void setTemplate(HtmlTemplate aTemplate) {
405: theTemplate = aTemplate;
406: }
407: }
|