001: package org.jicengine.builder;
002:
003: import org.jicengine.operation.Context;
004: import org.jicengine.operation.SimpleContext;
005: import org.jicengine.operation.BeanUtils;
006: import org.jicengine.operation.OperationException;
007: import org.xml.sax.*;
008: import org.xml.sax.helpers.DefaultHandler;
009: import java.util.*;
010: import org.jicengine.element.*;
011: import org.jicengine.element.impl.*;
012: import org.jicengine.expression.*;
013: import org.jicengine.Instructions;
014: import org.jicengine.BuildContext;
015:
016: /**
017: *
018: *
019: * <p>
020: * Copyright (C) 2004 Timo Laitinen
021: * </p>
022: *
023: * @author .timo
024: */
025:
026: public class Handler extends DefaultHandler {
027:
028: // public static final String NAMESPACE_URI_JICE_1_0 = "http://www.jicengine.org/jic/1.0";
029: public static final String NAMESPACE_URI_JICE_2_0 = "http://www.jicengine.org/jic/2.0";
030: public static final String NAMESPACE_URI_JICE_2_1 = "http://www.jicengine.org/jic/2.1";
031:
032: private Stack elementCompilers = new Stack();
033: private Element rootElement;
034:
035: private String jiceNameSpace;
036: private String jiceNamespacePrefix = "";
037: boolean syntaxBasedCdataConversionSupport = false;
038: private boolean defaultNamespaceUsed = true;
039:
040: StringBuffer cdataContent = new StringBuffer();
041: Locator locator;
042:
043: public Handler() {
044: }
045:
046: public Element getResult() throws ElementException {
047: if (this .rootElement == null) {
048: throw new IllegalStateException("root element is null.");
049: }
050:
051: return this .rootElement;
052: }
053:
054: public void setDocumentLocator(Locator locator) {
055: this .locator = locator;
056: }
057:
058: public void startDocument() throws org.xml.sax.SAXException {
059: }
060:
061: public void endDocument() throws org.xml.sax.SAXException {
062: }
063:
064: public void startPrefixMapping(String prefix, String uri)
065: throws org.xml.sax.SAXException {
066: if (uri.equals(NAMESPACE_URI_JICE_2_0)
067: || uri.equals(NAMESPACE_URI_JICE_2_1)) {
068: // a valid JICE namespace prefix has been specified.
069: this .jiceNameSpace = uri;
070: this .jiceNamespacePrefix = prefix;
071: if (this .jiceNamespacePrefix == null
072: || this .jiceNamespacePrefix.length() == 0) {
073: this .defaultNamespaceUsed = true;
074: } else {
075: this .defaultNamespaceUsed = false;
076: }
077:
078: if (uri.equals(NAMESPACE_URI_JICE_2_1)) {
079: syntaxBasedCdataConversionSupport = true;
080: }
081: }
082: }
083:
084: public void endPrefixMapping(String prefix)
085: throws org.xml.sax.SAXException {
086: // should we do something if the current org.jicengine-namespace-prefix-mapping ends?
087: // or are we informed with a startPrefixMapping()-call of the future
088: // prefixes?
089: }
090:
091: /**
092: * @param jiceAttributeName the local name of a JICE-attribute e.g. 'action'.
093: */
094: protected String getAttribute(Attributes attributes,
095: String jiceAttributeName) {
096: String value = attributes.getValue(jiceAttributeName);
097: if (value == null) {
098: // ok, lets try to specify the namespace also.
099: value = attributes.getValue(this .jiceNameSpace,
100: jiceAttributeName);
101: }
102: return value;
103: }
104:
105: public void startElement(String nameSpaceUri, String localName,
106: String qName, Attributes attributes)
107: throws org.xml.sax.SAXException {
108: try {
109: doStartElement(nameSpaceUri, localName, qName, attributes);
110: } catch (Exception e) {
111: throw new org.xml.sax.SAXException(e);
112: }
113: }
114:
115: protected void doStartElement(String nameSpaceUri,
116: String localName, String qName, Attributes attributes)
117: throws Exception, org.xml.sax.SAXException {
118: Location location;
119: if (this .locator != null) {
120: location = new Location(this .locator.getLineNumber(),
121: locator.getSystemId(), this .elementCompilers.size());
122: } else {
123: location = new Location(-1, "?", 0);
124: }
125:
126: if (!nameSpaceUri.equals(NAMESPACE_URI_JICE_2_0)
127: && !nameSpaceUri.equals(NAMESPACE_URI_JICE_2_1)) {
128: throw new ElementException("Element '" + localName
129: + "' is in illegal namespace '" + nameSpaceUri
130: + "'. only '" + NAMESPACE_URI_JICE_2_0 + "' and '"
131: + NAMESPACE_URI_JICE_2_1 + "' supported.",
132: localName, location);
133: }
134: final ElementCompiler current;
135:
136: Type type;
137: String typeExpression = getAttribute(attributes,
138: ElementCompiler.ATTR_NAME_TYPE);
139: if (typeExpression != null) {
140: type = Type.parse(typeExpression);
141: } else {
142: type = DefaultJiceTypes.getDefaultType();
143: }
144:
145: current = DefaultJiceTypes.getTypeManager().createCompiler(
146: localName, location, type);
147:
148: // ATTRIBUTE HANDLING
149:
150: for (int i = 0; i < attributes.getLength(); i++) {
151:
152: String attrName = attributes.getLocalName(i);
153: String attrValue = attributes.getValue(i);
154: String attrUri = attributes.getURI(i);
155:
156: if (attrName.length() == 0) {
157: // attribute 'xmlns'. ignore
158: continue;
159: } else if (attrUri.length() == 0
160: && !attributes.getQName(i).startsWith("xmlns:")) {
161: // attribute has no namespace
162: // -> since we are inside a JIC element,
163: // the attribute is a JIC attribute
164: setAttribute(attrName, attrValue, current);
165: } else if (attrUri.equals(NAMESPACE_URI_JICE_2_0)
166: || attrUri.equals(NAMESPACE_URI_JICE_2_1)) {
167: // attribute belongs to JICE namespace
168: // -> definitely a JIC attribute
169: setAttribute(attrName, attrValue, current);
170: } else {
171: //System.out.println("ignored: " + attrName + "=\"" + attrValue + "\"");
172: // attribute belongs to some unknown namespace
173: // -> just ignore it
174: continue;
175: }
176: }
177:
178: // tell the element that it's attributes have been set
179: current.elementInitialized();
180:
181: this .elementCompilers.push(current);
182: }
183:
184: protected void setAttribute(String name, String value,
185: ElementCompiler elementCompiler) throws Exception {
186: if (name.equals(ElementCompiler.ATTR_NAME_CLASS)) {
187: elementCompiler.setInstanceClass(value);
188: } else if (name.equals(ElementCompiler.ATTR_NAME_TYPE)) {
189: // nothing..
190: } else if (name.equals(ElementCompiler.ATTR_NAME_INSTANCE)) {
191: elementCompiler.setConstructor(value);
192: } else if (name.equals(ElementCompiler.ATTR_NAME_ACTION)) {
193: elementCompiler.setAction(value);
194: } else if (name
195: .equals(ElementCompiler.ATTR_NAME_CONSTRUCTOR_ARGUMENTS)) {
196: elementCompiler.setConstructorArguments(value);
197: } else if (name.equals(ElementCompiler.ATTR_NAME_VARIABLES)) {
198: elementCompiler.setVariables(value);
199: } else if (name.equals(ElementCompiler.ATTR_NAME_IF)) {
200: elementCompiler.setIf(value);
201: } else if (name
202: .equals(ElementCompiler.ATTR_NAME_OVERRIDABLE_BY)) {
203: elementCompiler.setOverridableBy(value);
204: } else {
205: throw new ElementException("Unsupported attribute: " + name
206: + "=" + value, elementCompiler.getName(),
207: elementCompiler.getLocation());
208: }
209: }
210:
211: public void endElement(String namespaceUri, String localName,
212: String qName) throws org.xml.sax.SAXException {
213: try {
214: doEndElement(namespaceUri, localName, qName);
215: } catch (ElementException e) {
216: throw new org.xml.sax.SAXException(e);
217: } catch (RuntimeException e2) {
218: throw new org.xml.sax.SAXException(
219: new org.jicengine.JICException(
220: "Unexpected runtime exception at line "
221: + this .locator.getLineNumber(), e2));
222: } catch (Exception e3) {
223: throw new org.xml.sax.SAXException(e3);
224: }
225: }
226:
227: protected void doEndElement(String namespaceUri, String localName,
228: String qName) throws Exception, org.xml.sax.SAXException {
229: ElementCompiler current = (ElementCompiler) this .elementCompilers
230: .pop();
231:
232: // cdata of the element
233: //
234: // NOTE: because we clear the buffer here, there can't be nested
235: // cdata-blocks. Consider the following situation:
236: // --------
237: // <parent>
238: // some text as CData
239: // <child>text of the child-element</child>
240: // </parent>
241: // --------
242: // in that case, the child will receive all the cdata,also
243: // the cdata of the parent, and the parent won't receive any
244: // cdata at all (the child has consumed it all).
245: String cdata = cdataContent.toString().trim();
246: if (cdata.length() > 0) {
247: current.setCData(cdata,
248: this .syntaxBasedCdataConversionSupport);
249: }
250: cdataContent = new StringBuffer();
251:
252: // element processed.. let the compiler create the element.
253:
254: Element element = current.createElement();
255:
256: if (!this .elementCompilers.isEmpty()) {
257: ElementCompiler parent = (ElementCompiler) this .elementCompilers
258: .peek();
259:
260: // let the parent handle the element
261: parent.handleChildElement(element);
262: } else {
263: // no parents: this is the root element?
264: this .rootElement = element;
265: }
266:
267: }
268:
269: public void characters(char[] cdata, int start, int length)
270: throws org.xml.sax.SAXException {
271: this .cdataContent.append(cdata, start, length);
272: }
273:
274: public void ignorableWhitespace(char[] parm1, int parm2, int parm3)
275: throws org.xml.sax.SAXException {
276: }
277:
278: public void processingInstruction(String parm1, String parm2)
279: throws org.xml.sax.SAXException {
280: }
281:
282: public void skippedEntity(String parm1)
283: throws org.xml.sax.SAXException {
284: }
285: }
|