001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.jsp.java;
030:
031: import com.caucho.jsp.JspParseException;
032: import com.caucho.util.CharBuffer;
033: import com.caucho.util.L10N;
034: import com.caucho.util.LineCompileException;
035: import com.caucho.vfs.WriteStream;
036: import com.caucho.xml.QName;
037: import com.caucho.xml.XmlChar;
038:
039: import java.io.IOException;
040: import java.util.ArrayList;
041:
042: /**
043: * A node which can contain other nodes.
044: */
045: public abstract class JspContainerNode extends JspNode {
046: static final L10N L = new L10N(JspContainerNode.class);
047:
048: protected ArrayList<QName> _attributeNames = new ArrayList<QName>();
049: protected ArrayList<Object> _attributeValues = new ArrayList<Object>();
050:
051: protected ArrayList<JspNode> _children = new ArrayList<JspNode>();
052:
053: protected boolean _hasJspAttribute;
054:
055: /**
056: * Adds an attribute.
057: *
058: * @param name the name of the attribute.
059: * @param value the value of the attribute.
060: */
061: public void addAttribute(QName name, String value)
062: throws JspParseException {
063: if (name == null)
064: throw new NullPointerException();
065:
066: if (_attributeNames.indexOf(name) >= 0)
067: throw error(L
068: .l(
069: "'{0}' is a duplicate attribute name. Attributes must occur only once in a tag.",
070: name.getName()));
071:
072: _attributeNames.add(name);
073: _attributeValues.add(value);
074: }
075:
076: /**
077: * Adds a JspAttribute attribute.
078: *
079: * @param name the name of the attribute.
080: * @param value the value of the attribute.
081: */
082: public void addAttribute(QName name, JspAttribute value)
083: throws JspParseException {
084: if (name == null)
085: throw new NullPointerException();
086:
087: if (_attributeNames.indexOf(name) >= 0)
088: throw error(L
089: .l(
090: "'{0}' is a duplicate attribute name. Attributes must occur only once in a tag.",
091: name.getName()));
092:
093: _attributeNames.add(name);
094: _attributeValues.add(value);
095:
096: _gen.addFragment(value);
097: }
098:
099: /**
100: * Returns the named attribute.
101: */
102: public Object getAttribute(String name) throws JspParseException {
103: for (int i = 0; i < _attributeNames.size(); i++) {
104: if (name.equals(_attributeNames.get(i).getName()))
105: return _attributeValues.get(i);
106: }
107:
108: return null;
109: }
110:
111: /**
112: * Adds a child node.
113: */
114: public void addChild(JspNode node) throws JspParseException {
115: node.setParent(this );
116:
117: if (node instanceof JspAttribute) {
118: JspAttribute attr = (JspAttribute) node;
119:
120: QName name = attr.getName();
121:
122: addAttribute(name, attr);
123:
124: _hasJspAttribute = true;
125:
126: int i = 0;
127: while (_children != null && i < _children.size()) {
128: JspNode child = _children.get(i);
129:
130: if (child instanceof StaticText) {
131: String text = ((StaticText) child).getText();
132:
133: if (isWhitespace(text))
134: _children.remove(i);
135: else
136: throw child
137: .error(L
138: .l("tags using jsp:attribute must put body content in a jsp:body tag"));
139: } else if (child instanceof JspBody)
140: i++;
141: else if (child instanceof JspAttribute)
142: i++;
143: else {
144: throw child
145: .error(L
146: .l("tags using jsp:attribute must put body content in a jsp:body tag"));
147: }
148: }
149: } else if (_hasJspAttribute && !(node instanceof JspBody)) {
150: throw node
151: .error(L
152: .l("tags using jsp:attribute must put body content in a jsp:body tag"));
153: } else if (node instanceof StaticText) {
154: StaticText text = (StaticText) node;
155: String data = text.getText();
156:
157: boolean isXml = _gen.isXml();
158: for (JspNode ptr = this ; ptr != null; ptr = ptr.getParent()) {
159: if (ptr instanceof JspRoot)
160: isXml = true;
161: }
162:
163: if (_children == null)
164: _children = new ArrayList<JspNode>();
165:
166: for (int i = 0; i < data.length(); i++) {
167: if (!XmlChar.isWhitespace(data.charAt(i))) {
168: _children.add(node);
169: return;
170: }
171: }
172:
173: if (!isXml)
174: _children.add(node);
175: } else if (node instanceof JspBody && hasJspBody()) {
176: throw node.error(L
177: .l("tags may only have a single jsp:body tag"));
178: } else {
179: if (_children == null)
180: _children = new ArrayList<JspNode>();
181:
182: _children.add(node);
183: }
184: }
185:
186: private boolean hasJspBody() {
187: if (_children == null)
188: return false;
189:
190: for (int i = _children.size() - 1; i >= 0; i--) {
191: if (_children.get(i) instanceof JspBody)
192: return true;
193: }
194:
195: return false;
196: }
197:
198: /**
199: * Adds a child node after its done initializing.
200: */
201: public void addChildEnd(JspNode node) throws JspParseException {
202: }
203:
204: /**
205: * True if the jsf-parent setting is required.
206: */
207: public boolean isJsfParentRequired() {
208: if (_children == null)
209: return false;
210:
211: for (int i = _children.size() - 1; i >= 0; i--) {
212: if (_children.get(i).isJsfParentRequired())
213: return true;
214: }
215:
216: return false;
217: }
218:
219: /**
220: * Returns true if the node is empty
221: */
222: public boolean isEmpty() {
223: if (_children == null || _children.size() == 0)
224: return true;
225:
226: for (int i = 0; i < _children.size(); i++) {
227: JspNode child = _children.get(i);
228:
229: if (child instanceof JspBody) {
230: JspBody body = (JspBody) child;
231:
232: return body.isEmpty();
233: } else if (child instanceof StaticText) {
234: StaticText text = (StaticText) child;
235:
236: if (!text.isWhitespace())
237: return false;
238: } else
239: return false;
240: }
241:
242: return false;
243: }
244:
245: /**
246: * Returns the static text.
247: */
248: public void getStaticText(CharBuffer cb) {
249: if (_children == null)
250: return;
251:
252: for (int i = 0; i < _children.size(); i++)
253: _children.get(i).getStaticText(cb);
254: }
255:
256: /**
257: * Set true if the node contains a child tag.
258: */
259: public boolean hasCustomTag() {
260: for (int i = 0; _children != null && i < _children.size(); i++) {
261: JspNode child = _children.get(i);
262:
263: if (child instanceof CustomTag)
264: return true;
265:
266: if (child.hasCustomTag())
267: return true;
268: }
269:
270: for (int i = 0; _attributeValues != null
271: && i < _attributeValues.size(); i++) {
272: Object value = _attributeValues.get(i);
273:
274: if (value instanceof CustomTag)
275: return true;
276: else if (value instanceof JspNode
277: && ((JspNode) value).hasCustomTag())
278: return true;
279: }
280:
281: return false;
282: }
283:
284: /**
285: * Set true if the node contains a child tag.
286: */
287: public boolean hasTag() {
288: for (int i = 0; _children != null && i < _children.size(); i++) {
289: JspNode child = _children.get(i);
290:
291: if (child instanceof CustomTag
292: || child instanceof CustomSimpleTag)
293: return true;
294:
295: if (child.hasTag())
296: return true;
297: }
298:
299: for (int i = 0; _attributeValues != null
300: && i < _attributeValues.size(); i++) {
301: Object value = _attributeValues.get(i);
302:
303: if (value instanceof CustomTag
304: || value instanceof CustomSimpleTag)
305: return true;
306:
307: else if (value instanceof JspNode
308: && ((JspNode) value).hasTag())
309: return true;
310: }
311:
312: return false;
313: }
314:
315: /**
316: * Adds a text node.
317: */
318: public JspNode addText(String text) throws JspParseException {
319: if (!_hasJspAttribute) {
320: JspNode node = new StaticText(_gen, text, this );
321:
322: addChild(node);
323:
324: return node;
325: } else if (!isWhitespace(text)) {
326: throw error(L
327: .l("tags using jsp:attribute must put body content in a jsp:body tag"));
328: }
329:
330: return null;
331: }
332:
333: protected boolean isWhitespace(String text) {
334: for (int i = 0; i < text.length(); i++) {
335: if (!Character.isWhitespace(text.charAt(i)))
336: return false;
337: }
338:
339: return true;
340: }
341:
342: /**
343: * Returns the children.
344: */
345: public ArrayList<JspNode> getChildren() {
346: return _children;
347: }
348:
349: /**
350: * Has children.
351: */
352: public boolean hasChildren() {
353: return !isEmpty();
354: }
355:
356: /**
357: * True if the node has scripting
358: */
359: public boolean hasScripting() {
360: for (int i = 0; _children != null && i < _children.size(); i++) {
361: if (_children.get(i).hasScripting()) {
362: return true;
363: }
364: }
365:
366: return false;
367: }
368:
369: /**
370: * True if the node has scripting element (i.e. not counting rtexpr values)
371: */
372: @Override
373: public boolean hasScriptingElement() {
374: for (int i = 0; _children != null && i < _children.size(); i++) {
375: if (_children.get(i).hasScriptingElement()) {
376: return true;
377: }
378: }
379:
380: return false;
381: }
382:
383: /**
384: * Finds the first scripting node
385: */
386: @Override
387: public JspNode findScriptingNode() {
388: for (int i = 0; _children != null && i < _children.size(); i++) {
389: JspNode node = _children.get(i).findScriptingNode();
390:
391: if (node != null)
392: return node;
393: }
394:
395: if (hasScripting())
396: return this ;
397: else
398: return null;
399: }
400:
401: /**
402: * Returns true if the children are static.
403: */
404: public boolean isChildrenStatic() {
405: if (_children == null)
406: return true;
407:
408: for (int i = 0; i < _children.size(); i++) {
409: if (!_children.get(i).isStatic())
410: return false;
411: }
412:
413: return true;
414: }
415:
416: /**
417: * Generates the XML text representation for the tag validation.
418: *
419: * @param os write stream to the generated XML.
420: */
421: public void printXmlChildren(WriteStream os) throws IOException {
422: if (_children == null)
423: return;
424:
425: for (int i = 0; i < _children.size(); i++) {
426: JspNode child = _children.get(i);
427:
428: child.printXml(os);
429: }
430: }
431:
432: /**
433: * generates data for prologue children.
434: */
435: public void generatePrologueChildren(JspJavaWriter out)
436: throws Exception {
437: if (_children == null)
438: return;
439:
440: for (int i = 0; i < _children.size(); i++) {
441: JspNode child = _children.get(i);
442:
443: child.generatePrologue(out);
444: }
445: }
446:
447: /**
448: * generates data for declaration children.
449: */
450: public void generateDeclarationChildren(JspJavaWriter out)
451: throws IOException {
452: if (_children == null)
453: return;
454:
455: for (int i = 0; i < _children.size(); i++) {
456: JspNode child = _children.get(i);
457:
458: child.generateDeclaration(out);
459: }
460: }
461:
462: /**
463: * Generates the code for the children.
464: *
465: * @param out the output writer for the generated java.
466: */
467: public void generateChildren(JspJavaWriter out) throws Exception {
468: if (_children == null)
469: return;
470:
471: for (int i = 0; i < _children.size(); i++) {
472: JspNode child = _children.get(i);
473:
474: child.generateStartLocation(out);
475: try {
476: child.generate(out);
477: } catch (Exception e) {
478: if (e instanceof LineCompileException)
479: throw e;
480: else
481: throw child.error(e);
482: }
483: child.generateEndLocation(out);
484: }
485: }
486:
487: /**
488: * Generates the code for the children.
489: *
490: * @param out the output writer for the generated java.
491: */
492: public void generateChildrenEmpty() throws Exception {
493: if (_children == null)
494: return;
495:
496: for (int i = 0; i < _children.size(); i++) {
497: JspNode child = _children.get(i);
498:
499: child.generateEmpty();
500: }
501: }
502:
503: /**
504: * Generates static text.
505: *
506: * @param out the output writer for the generated java.
507: */
508: public void generateStatic(JspJavaWriter out) throws Exception {
509: if (_children == null)
510: return;
511:
512: for (int i = 0; i < _children.size(); i++) {
513: JspNode child = _children.get(i);
514:
515: out.setLocation(child.getFilename(), child.getStartLine());
516: child.generateStatic(out);
517: // out.setLocation(child.getFilename(), child.getEndLine());
518: }
519: }
520: }
|