001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.metadata.parser;
012:
013: import org.xml.sax.Attributes;
014: import org.xml.sax.helpers.AttributesImpl;
015: import org.xml.sax.helpers.DefaultHandler;
016:
017: import org.xml.sax.InputSource;
018: import org.xml.sax.SAXException;
019: import com.versant.core.common.JaxpUtils;
020:
021: import javax.xml.parsers.SAXParser;
022: import javax.xml.parsers.SAXParserFactory;
023:
024: import com.versant.core.metadata.MDStatics;
025:
026: import java.io.FileInputStream;
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.io.StringReader;
030: import java.util.ArrayList;
031: import java.util.Collection;
032: import java.util.Iterator;
033:
034: import com.versant.core.common.BindingSupportImpl;
035:
036: /**
037: * This produces a tree of JdoXXX objects representing the structure of a
038: * JDO meta data file (.jdo). All of our vendor extensions are valdidated
039: * (correct keys) as part of this process.
040: */
041: public class MetaDataParser extends DefaultHandler {
042:
043: public static final String VENDOR_NAME = "versant";
044: public static final String VENDOR_NAME_JDOGENIE = "jdogenie";
045:
046: private SAXParserFactory parserFactory;
047: private SAXParser parser;
048:
049: private int state;
050: private int extState;
051: private int extSkipState;
052: private String elementName;
053: //private int elementDepth;
054: private int extensionSkipDepth;
055:
056: // these fields form a 'stack' of elements
057: private JdoRoot jdoRoot;
058: private JdoPackage jdoPackage;
059: private JdoClass jdoClass;
060: private JdoField jdoField;
061: private JdoCollection jdoCollection;
062: private JdoMap jdoMap;
063: private JdoArray jdoArray;
064: private JdoQuery jdoQuery;
065: private int extStackTop;
066: private JdoExtension[] extStack = new JdoExtension[32];
067: private ArrayList[] extStackList = new ArrayList[32];
068:
069: private ArrayList packageList = new ArrayList();
070: private ArrayList packageExtList = new ArrayList();
071: private ArrayList packageClassList = new ArrayList();
072: private ArrayList classElementList = new ArrayList();
073: // private ArrayList fieldExtList = new ArrayList();
074: private ArrayList queryExtList = new ArrayList();
075: private ArrayList collectionExtList = new ArrayList();
076:
077: private boolean doneFilter;
078: private boolean doneSql;
079: private boolean doneDeclarations;
080: private boolean doneResult;
081: private StringBuffer text;
082:
083: private static final int START = 1;
084: private static final int JDO = 2;
085: private static final int PACKAGE = 3;
086: private static final int CLASS = 4;
087: private static final int FIELD = 5;
088: private static final int COLLECTION = 6;
089: private static final int EXTENSION = 7;
090: private static final int EXTENSION_SKIP = 8;
091: private static final int QUERY = 9;
092: private static final int EMBEDDED = 10;
093: private static final int EMBEDDED_FIELD = 11;
094:
095: private static String[] STATE_STRING = { "ERROR", "START", "JDO",
096: "PACKAGE", "CLASS", "FIELD", "COLLECTION", "EXTENSION",
097: "EXTENSION_SKIP", "QUERY", "EMBEDDED", "EMBEDDED_FIELD" };
098:
099: public MetaDataParser() {
100:
101: parserFactory = JaxpUtils.getSAXParserFactory();
102: parserFactory.setValidating(false);
103: parserFactory.setNamespaceAware(false);
104:
105: }
106:
107: /**
108: * Load all the jdoNames as resources using loader and return the JdoRoot's.
109: */
110: public JdoRoot[] parse(Collection jdoNames, ClassLoader loader) {
111: int n = jdoNames.size();
112: JdoRoot[] roots = new JdoRoot[n];
113: int c = 0;
114: for (Iterator i = jdoNames.iterator(); i.hasNext();) {
115: String name = (String) i.next();
116: InputStream in = null;
117: try {
118:
119: in = loader
120: .getResourceAsStream(name.startsWith("/") ? name
121: .substring(1)
122: : name);
123: if (in == null) {
124: throw BindingSupportImpl.getInstance().runtime(
125: "Unable to load resource: " + name);
126: }
127:
128: roots[c++] = parse(in, name);
129: } finally {
130: if (in != null) {
131: try {
132: in.close();
133: } catch (IOException x) {
134: // ignore
135: }
136: }
137: }
138: }
139: return roots;
140: }
141:
142: /**
143: * Parse the supplied JDO meta data stream and create a JdoRoot tree.
144: */
145: public JdoRoot parse(InputStream in, String name) {
146: try {
147: init(name);
148:
149: parser = JaxpUtils.createSAXParser(parserFactory);
150: parser.parse(in, this );
151: parser = null;
152:
153: return jdoRoot;
154: } catch (Exception x) {
155: throw BindingSupportImpl.getInstance().runtime(
156: name + ": " + x.getMessage(), x);
157: }
158: }
159:
160: /**
161: * Resolve an external entity.
162: * <p/>
163: * We override this method so we don't go looking on the web for dtd's
164: */
165:
166: public InputSource resolveEntity(String publicId, String systemId) {
167: StringReader reader = new StringReader("");
168: return new InputSource(reader);
169: }
170:
171: /**
172: * Parse the supplied JDO meta data file and create a JdoRoot tree.
173: *
174: * @throws IOException if on errors opening filename
175: */
176: public JdoRoot parse(String filename) throws IOException {
177: FileInputStream in = null;
178: try {
179: return parse(in = new FileInputStream(filename), filename);
180: } finally {
181: if (in != null) {
182: try {
183: in.close();
184: } catch (IOException x) {
185: // ignore
186: }
187: }
188: }
189: }
190:
191: /**
192: * Prepare this parser to receive SAX events. Normally one of the parse
193: * methods should be used. Use this only if you are getting SAX events
194: * from somewhere else.
195: *
196: * @see #parse
197: * @see #getJdoRoot
198: */
199: public void init(String name) {
200: jdoRoot = new JdoRoot();
201: jdoRoot.name = name;
202: state = START;
203: jdoPackage = null;
204: jdoClass = null;
205: jdoField = null;
206: jdoCollection = null;
207: jdoMap = null;
208: jdoArray = null;
209: extStackTop = -1;
210: }
211:
212: /**
213: * Retrieve the last parsed JdoRoot.
214: */
215: public JdoRoot getJdoRoot() {
216: return jdoRoot;
217: }
218:
219: /**
220: * Decide what to do with the element based on its name and our current
221: * state.
222: */
223: public void startElement(String uri, String localName, String name,
224: Attributes attr) throws SAXException {
225: try {
226: startElementImp(uri, localName, name, attr);
227: } catch (RuntimeException x) {
228: throw x;
229: }
230: }
231:
232: /**
233: * Decide what to do with the element based on its name and our current
234: * state.
235: */
236: public void startElementImp(String uri, String localName,
237: String name, Attributes attr) throws SAXException {
238: // if (Debug.DEBUG) {
239: // StringBuffer s = new StringBuffer();
240: // s.append(STATE_STR[state]);
241: // s.append(SPACE.substring(0, elementDepth * 2 + 1));
242: // s.append('<');
243: // s.append(name);
244: // int n = attr.getLength();
245: // for (int i = 0; i < n; i++) {
246: // s.append(' ');
247: // s.append(attr.getQName(i));
248: // s.append("=\"");
249: // s.append(attr.getValue(i));
250: // s.append('"');
251: // }
252: // s.append('>');
253: // cat.debug(s.toString());
254: // elementDepth++;
255: // }
256: elementName = name;
257: switch (state) {
258:
259: case START:
260: if (name.equals("jdo") || name.equals("mapping")) {
261: packageList.clear();
262: state = JDO;
263: } else {
264:
265: throwInvalidElement("<jdo>");
266:
267: }
268: break;
269:
270: case JDO:
271: if (name.equals("package") || name.equals("namespace")) {
272: startPackage(attr);
273: } else {
274:
275: throwInvalidElement("<package>");
276:
277: }
278: break;
279:
280: case PACKAGE:
281: if (name.equals("class")) {
282: startClass(attr);
283: } else if (name.equals("extension")) {
284: startExtension(jdoPackage, packageExtList, attr);
285: } else {
286: throwInvalidElement("<class> or <extension>");
287: }
288: break;
289: case EMBEDDED:
290: if (name.equals("field")) {
291: startEmbeddedField(attr);
292: } else {
293: throwInvalidElement("<field>");
294: }
295: break;
296: case CLASS:
297: if (name.equals("field")) {
298: startField(attr);
299: } else if (name.equals("extension")) {
300: startExtension(jdoClass, classElementList, attr);
301: } else if (name.equals("query")) {
302: startQuery(attr);
303: } else {
304: throwInvalidElement("<field> or <extension>");
305: }
306: break;
307: case EMBEDDED_FIELD:
308: case FIELD:
309: if (name.equals("extension")) {
310: startExtension(jdoField, jdoField.extensionList, attr);
311: } else if (name.equals("collection")) {
312: startCollection(attr);
313: } else if (name.equals("map")) {
314: startMap(attr);
315: } else if (name.equals("array")) {
316: startArray(attr);
317: } else if (name.equals("embedded")) {
318: startEmbedded(attr);
319: } else {
320: throwInvalidElement("<collection>, <map>, <array> or <extension>");
321: }
322: break;
323:
324: case COLLECTION:
325: if (name.equals("extension")) {
326: JdoElement p;
327: if (jdoCollection != null) {
328: p = jdoCollection;
329: } else if (jdoArray != null) {
330: p = jdoArray;
331: } else {
332: p = jdoMap;
333: }
334: startExtension(p, collectionExtList, attr);
335: } else {
336: throwInvalidElement("<extension>");
337: }
338: break;
339:
340: case EXTENSION:
341: if (name.equals("extension")) {
342: startExtension(extStack[extStackTop],
343: extStackList[extStackTop], attr);
344: } else {
345: throwInvalidElement("<extension>");
346: }
347: break;
348:
349: case EXTENSION_SKIP:
350: extensionSkipDepth++;
351: break;
352:
353: case QUERY:
354: if (name.equals("filter")) {
355: if (doneFilter)
356: throwDuplicateElement("filter");
357: if (jdoQuery.filter != null) {
358: throw BindingSupportImpl.getInstance().runtime(
359: "You may not have a filter attribute and "
360: + "element in " + getContext());
361: }
362: doneFilter = true;
363: text = new StringBuffer();
364: // no attributes to read
365: } else if (name.equals("sql")) {
366: if (doneSql)
367: throwDuplicateElement("sql");
368: if (jdoQuery.sql != null) {
369: throw BindingSupportImpl.getInstance().runtime(
370: "You may not have a sql attribute and "
371: + "element in " + getContext());
372: }
373: doneSql = true;
374: text = new StringBuffer();
375: // no attributes to read
376: } else if (name.equals("declare")) {
377: if (doneDeclarations)
378: throwDuplicateElement("declarations");
379: doneDeclarations = true;
380: jdoQuery.imports = attr.getValue("imports");
381: jdoQuery.parameters = attr.getValue("parameters");
382: jdoQuery.variables = attr.getValue("variables");
383: } else if (name.equals("result")) {
384: if (doneResult)
385: throwDuplicateElement("result");
386: doneResult = true;
387: jdoQuery.resultClass = attr.getValue("class");
388: jdoQuery.unique = getTriState(attr, "unique");
389: jdoQuery.grouping = attr.getValue("grouping");
390: text = new StringBuffer();
391: } else if (name.equals("extension")) {
392: startExtension(jdoQuery, queryExtList, attr);
393: } else {
394: throwInvalidElement("<filter>, <declarations>, <result> "
395: + "or <extension>");
396: }
397: break;
398: }
399: }
400:
401: private void startEmbedded(Attributes attr) {
402: jdoField.embedded = JdoField.TRUE;
403: state = EMBEDDED;
404: }
405:
406: public void characters(char ch[], int start, int length)
407: throws SAXException {
408: if (text != null)
409: text.append(ch, start, length);
410: }
411:
412: private void throwDuplicateElement(String name) {
413: throw BindingSupportImpl.getInstance().runtime(
414: "Only one '" + elementName + "' element is allowed in "
415: + getContext());
416: }
417:
418: private void throwInvalidElement(String valid) {
419: throw BindingSupportImpl.getInstance().runtime(
420: "Invalid element '" + elementName + "' in "
421: + getContext() + ", expected " + valid);
422: }
423:
424: private void throwInvalidAttribute(String attrName, String value) {
425: throw BindingSupportImpl.getInstance().runtime(
426: "Invalid " + attrName + " attribute '" + value
427: + "' in " + getContext());
428: }
429:
430: private void startPackage(Attributes attr) {
431: jdoPackage = new JdoPackage();
432: jdoPackage.parent = jdoRoot;
433: packageList.add(jdoPackage);
434: jdoPackage.name = getReqAttr(attr, "name");
435: packageClassList.clear();
436: packageExtList.clear();
437: state = PACKAGE;
438: }
439:
440: private void startClass(Attributes attr) {
441: jdoClass = new JdoClass();
442: jdoClass.parent = jdoPackage;
443: packageClassList.add(jdoClass);
444: jdoClass.name = getReqAttr(attr, "name");
445: String idt = attr.getValue("identity-type");
446: if (idt != null) {
447: if (idt.equals("datastore")) {
448: jdoClass.identityType = JdoClass.IDENTITY_TYPE_DATASTORE;
449: } else if (idt.equals("application")) {
450: jdoClass.identityType = JdoClass.IDENTITY_TYPE_APPLICATION;
451: } else if (idt.equals("nondurable")) {
452: jdoClass.identityType = JdoClass.IDENTITY_TYPE_NONDURABLE;
453: } else {
454: throwInvalidAttribute("indentity-type", idt);
455: }
456: }
457: jdoClass.objectIdClass = attr.getValue("objectid-class");
458: String re = attr.getValue("requires-extent");
459: if (re == null || re.equals("true")) {
460: jdoClass.requiresExtent = true;
461: } else if (re.equals("false")) {
462: jdoClass.requiresExtent = false;
463: } else {
464: throwInvalidAttribute("requires-extent", re);
465: }
466: jdoClass.pcSuperclass = attr
467: .getValue("persistence-capable-superclass");
468: classElementList.clear();
469: state = CLASS;
470: }
471:
472: private void startField(Attributes attr) {
473: jdoField = new JdoField();
474: jdoField.parent = jdoClass;
475: classElementList.add(jdoField);
476: jdoField.name = getReqAttr(attr, "name");
477: String pm = attr.getValue("persistence-modifier");
478: if (pm != null) {
479: if (pm.equals("persistent")) {
480: jdoField.persistenceModifier = JdoField.PERSISTENCE_MODIFIER_PERSISTENT;
481: } else if (pm.equals("transactional")) {
482: jdoField.persistenceModifier = JdoField.PERSISTENCE_MODIFIER_TRANSACTIONAL;
483: } else if (pm.equals("none")) {
484: jdoField.persistenceModifier = JdoField.PERSISTENCE_MODIFIER_NONE;
485: } else {
486: throwInvalidAttribute("persistence-modifier", pm);
487: }
488: }
489: String pk = attr.getValue("primary-key");
490: if (pk == null || pk.equals("false")) {
491: jdoField.primaryKey = false;
492: } else if (pk.equals("true")) {
493: jdoField.primaryKey = true;
494: } else {
495: throwInvalidAttribute("primary-key", pk);
496: }
497: String nv = attr.getValue("null-value");
498: if (nv == null || nv.equals("none")) {
499: jdoField.nullValue = JdoField.NULL_VALUE_NONE;
500: } else if (nv.equals("exception")) {
501: jdoField.nullValue = JdoField.NULL_VALUE_EXCEPTION;
502: } else if (nv.equals("default")) {
503: jdoField.nullValue = JdoField.NULL_VALUE_DEFAULT;
504: } else {
505: throwInvalidAttribute("null-value", nv);
506: }
507: String df = attr.getValue("default-fetch-group");
508: if (df != null) {
509: if (df.equals("true")) {
510: jdoField.defaultFetchGroup = JdoField.TRUE;
511: } else if (df.equals("false")) {
512: jdoField.defaultFetchGroup = JdoField.FALSE;
513: } else {
514: throwInvalidAttribute("default-fetch-group", df);
515: }
516: }
517: String em = attr.getValue("embedded");
518: if (em != null) {
519: if (em.equals("true")) {
520: jdoField.embedded = JdoField.TRUE;
521: } else if (em.equals("false")) {
522: jdoField.embedded = JdoField.FALSE;
523: } else {
524: throwInvalidAttribute("embedded", em);
525: }
526: }
527: state = FIELD;
528: }
529:
530: private void startEmbeddedField(Attributes attr) {
531: jdoField = new JdoField(jdoField);
532: jdoField.parent = jdoClass;
533: jdoField.name = getReqAttr(attr, "name");
534:
535: String pm = attr.getValue("persistence-modifier");
536: if (pm != null) {
537: if (pm.equals("persistent")) {
538: jdoField.persistenceModifier = JdoField.PERSISTENCE_MODIFIER_PERSISTENT;
539: } else if (pm.equals("transactional")) {
540: jdoField.persistenceModifier = JdoField.PERSISTENCE_MODIFIER_TRANSACTIONAL;
541: } else if (pm.equals("none")) {
542: jdoField.persistenceModifier = JdoField.PERSISTENCE_MODIFIER_NONE;
543: } else {
544: throwInvalidAttribute("persistence-modifier", pm);
545: }
546: }
547:
548: String nv = attr.getValue("null-value");
549: if (nv == null || nv.equals("none")) {
550: jdoField.nullValue = JdoField.NULL_VALUE_NONE;
551: } else if (nv.equals("exception")) {
552: jdoField.nullValue = JdoField.NULL_VALUE_EXCEPTION;
553: } else if (nv.equals("default")) {
554: jdoField.nullValue = JdoField.NULL_VALUE_DEFAULT;
555: } else {
556: throwInvalidAttribute("null-value", nv);
557: }
558: String df = attr.getValue("default-fetch-group");
559: if (df != null) {
560: if (df.equals("true")) {
561: jdoField.defaultFetchGroup = JdoField.TRUE;
562: } else if (df.equals("false")) {
563: jdoField.defaultFetchGroup = JdoField.FALSE;
564: } else {
565: throwInvalidAttribute("default-fetch-group", df);
566: }
567: }
568: String em = attr.getValue("embedded");
569: if (em != null) {
570: if (em.equals("true")) {
571: jdoField.embedded = JdoField.TRUE;
572: } else if (em.equals("false")) {
573: jdoField.embedded = JdoField.FALSE;
574: } else {
575: throwInvalidAttribute("embedded", em);
576: }
577: }
578: state = EMBEDDED_FIELD;
579: }
580:
581: private void startCollection(Attributes attr) {
582: jdoCollection = new JdoCollection();
583: jdoCollection.parent = jdoField;
584: jdoField.collection = jdoCollection;
585: jdoCollection.elementType = attr.getValue("element-type");
586: String em = attr.getValue("embedded-element");
587: if (em != null) {
588: if (em.equals("true")) {
589: jdoCollection.embeddedElement = JdoCollection.TRUE;
590: } else if (em.equals("false")) {
591: jdoCollection.embeddedElement = JdoCollection.FALSE;
592: } else {
593: throwInvalidAttribute("embedded-element", em);
594: }
595: }
596: collectionExtList.clear();
597: state = COLLECTION;
598: }
599:
600: private void startMap(Attributes attr) {
601: jdoMap = new JdoMap();
602: jdoMap.parent = jdoField;
603: jdoField.map = jdoMap;
604: jdoMap.keyType = attr.getValue("key-type");
605: jdoMap.valueType = attr.getValue("value-type");
606: String em = attr.getValue("embedded-key");
607: if (em != null) {
608: if (em.equals("true")) {
609: jdoMap.embeddedKey = JdoMap.TRUE;
610: } else if (em.equals("false")) {
611: jdoMap.embeddedKey = JdoMap.FALSE;
612: } else {
613: throwInvalidAttribute("embedded-key", em);
614: }
615: }
616: em = attr.getValue("embedded-value");
617: if (em != null) {
618: if (em.equals("true")) {
619: jdoMap.embeddedValue = JdoMap.TRUE;
620: } else if (em.equals("false")) {
621: jdoMap.embeddedValue = JdoMap.FALSE;
622: } else {
623: throwInvalidAttribute("embedded-value", em);
624: }
625: }
626: collectionExtList.clear();
627: state = COLLECTION;
628: }
629:
630: private void startArray(Attributes attr) {
631: jdoArray = new JdoArray();
632: jdoArray.parent = jdoField;
633: jdoField.array = jdoArray;
634: String em = attr.getValue("embedded-element");
635: if (em != null) {
636: if (em.equals("true")) {
637: jdoArray.embeddedElement = JdoCollection.TRUE;
638: } else if (em.equals("false")) {
639: jdoArray.embeddedElement = JdoCollection.FALSE;
640: } else {
641: throwInvalidAttribute("embedded-element", em);
642: }
643: }
644: collectionExtList.clear();
645: state = COLLECTION;
646: }
647:
648: private void startExtension(JdoElement parent, ArrayList list,
649: Attributes attr) {
650:
651: String vn = getReqAttr(attr, "vendor-name");
652:
653: if (isOurVendorName(vn)) {
654: JdoExtension e = new JdoExtension();
655: e.parent = parent;
656: String key = getReqAttr(attr, "key");
657: int i = JdoExtension.parseKey(key);
658: if (i == Integer.MIN_VALUE) {
659: throw BindingSupportImpl.getInstance().runtime(
660: "Invalid key '" + key + "' in " + getContext());
661: }
662: e.key = i;
663: e.value = attr.getValue("value");
664: extStack[++extStackTop] = e;
665: ArrayList a = extStackList[extStackTop];
666: if (a == null) {
667: extStackList[extStackTop] = new ArrayList();
668: } else {
669: a.clear();
670: }
671: if (state != EXTENSION) {
672: extState = state;
673: state = EXTENSION;
674: }
675: list.add(e);
676: } else {
677: extSkipState = state;
678: state = EXTENSION_SKIP;
679: extensionSkipDepth = 0;
680: }
681: }
682:
683: private void startQuery(Attributes attr) {
684: jdoQuery = new JdoQuery();
685: jdoQuery.parent = jdoClass;
686: jdoClass.addJdoQuery(jdoQuery);
687: jdoQuery.name = getReqAttr(attr, "name");
688: jdoQuery.language = attr.getValue("language");
689: jdoQuery.ignoreCache = getTriState(attr, "ignore-cache");
690: jdoQuery.includeSubclasses = getTriState(attr,
691: "include-subclasses");
692: jdoQuery.ordering = attr.getValue("ordering");
693: jdoQuery.filter = attr.getValue("filter");
694: jdoQuery.sql = attr.getValue("sql");
695: String r = attr.getValue("range");
696: if (r != null) {
697: try {
698: int i = r.indexOf(',');
699: jdoQuery.rangeStart = Integer.parseInt(r
700: .substring(0, i));
701: jdoQuery.rangeEnd = Integer
702: .parseInt(r.substring(i + 1));
703: } catch (Exception e) {
704: throwInvalidAttribute("range", r);
705: }
706: }
707: state = QUERY;
708: doneSql = false;
709: }
710:
711: /**
712: * Decide what to do with the element based on our current state and its
713: * name.
714: */
715: public void endElement(String uri, String localName, String name)
716: throws SAXException {
717: endElementImp(uri, localName, name);
718: }
719:
720: /**
721: * Decide what to do with the element based on our current state and its
722: * name.
723: */
724: public void endElementImp(String uri, String localName, String name)
725: throws SAXException {
726: // if (cat.isDebugEnabled()) {
727: // elementDepth--;
728: // StringBuffer s = new StringBuffer();
729: // s.append(STATE_STR[state]);
730: // s.append(SPACE.substring(0, elementDepth * 2 + 1));
731: // s.append("</");
732: // s.append(name);
733: // s.append('>');
734: // cat.debug(s.toString());
735: // }
736: elementName = name;
737: int n;
738: switch (state) {
739:
740: case JDO:
741: jdoRoot.packages = new JdoPackage[packageList.size()];
742: packageList.toArray(jdoRoot.packages);
743: state = START;
744: break;
745:
746: case PACKAGE:
747: n = packageClassList.size();
748: jdoPackage.classes = new JdoClass[n];
749: packageClassList.toArray(jdoPackage.classes);
750: n = packageExtList.size();
751: if (n > 0) {
752: jdoPackage.extensions = new JdoExtension[n];
753: packageExtList.toArray(jdoPackage.extensions);
754: }
755: jdoPackage = null;
756: state = JDO;
757: break;
758:
759: case CLASS:
760: jdoClass.elements = new JdoElement[classElementList.size()];
761: classElementList.toArray(jdoClass.elements);
762: jdoClass = null;
763: state = PACKAGE;
764: break;
765: case EMBEDDED_FIELD:
766: n = jdoField.extensionList.size();
767: if (n > 0) {
768: jdoField.extensions = new JdoExtension[n];
769: jdoField.extensionList.toArray(jdoField.extensions);
770: }
771: jdoField = jdoField.parentField;
772: state = EMBEDDED;
773: break;
774: case FIELD:
775: n = jdoField.extensionList.size();
776: if (n > 0) {
777: jdoField.extensions = new JdoExtension[n];
778: jdoField.extensionList.toArray(jdoField.extensions);
779: }
780: jdoField = null;
781: jdoCollection = null;
782: jdoArray = null;
783: jdoMap = null;
784: state = CLASS;
785: break;
786:
787: case COLLECTION:
788: n = collectionExtList.size();
789: if (n > 0) {
790: JdoExtension[] e = new JdoExtension[n];
791: collectionExtList.toArray(e);
792: if (jdoCollection != null) {
793: jdoCollection.extensions = e;
794: jdoCollection = null;
795: } else if (jdoArray != null) {
796: jdoArray.extensions = e;
797: jdoArray = null;
798: } else {
799: jdoMap.extensions = e;
800: jdoMap = null;
801: }
802: }
803: state = FIELD;
804: break;
805:
806: case EXTENSION:
807: endExtension();
808: break;
809:
810: case EXTENSION_SKIP:
811: if (extensionSkipDepth == 0) {
812: state = extSkipState;
813: } else {
814: extensionSkipDepth--;
815: }
816: break;
817:
818: case QUERY:
819: if (elementName.equals("query")) {
820: jdoQuery.extensions = new JdoExtension[queryExtList
821: .size()];
822: queryExtList.toArray(jdoQuery.extensions);
823: jdoQuery = null;
824: doneFilter = false;
825: doneDeclarations = false;
826: doneResult = false;
827: state = CLASS;
828: } else if (elementName.equals("filter")) {
829: if (text != null)
830: jdoQuery.filter = text.toString().trim();
831: text = null;
832: } else if (elementName.equals("result")) {
833: if (text != null)
834: jdoQuery.result = text.toString().trim();
835: text = null;
836: } else if (elementName.equals("sql")) {
837: if (text != null)
838: jdoQuery.sql = text.toString().trim();
839: text = null;
840: }
841: break;
842: case EMBEDDED:
843: if (jdoField.parentField == null)
844: state = FIELD;
845: else
846: state = EMBEDDED_FIELD;
847: break;
848: }
849: }
850:
851: private void endExtension() {
852: JdoExtension top = extStack[extStackTop];
853: ArrayList a = extStackList[extStackTop];
854: int n = a.size();
855: if (n > 0) {
856: top.nested = new JdoExtension[n];
857: a.toArray(top.nested);
858: }
859: if (--extStackTop < 0)
860: state = extState;
861: }
862:
863: /**
864: * Get information about the current parser context in a String. This is
865: * used to construct error messages.
866: */
867: private String getContext() {
868: StringBuffer s = new StringBuffer();
869: s.append(jdoRoot.name);
870: if (jdoPackage != null) {
871: s.append(":package[");
872: s.append(jdoPackage.name);
873: s.append(']');
874: if (jdoClass != null) {
875: s.append("/class[");
876: s.append(jdoClass.name);
877: s.append(']');
878: if (jdoField != null) {
879: s.append("/field[");
880: s.append(jdoField.name);
881: s.append(']');
882: if (jdoCollection != null) {
883: s.append("/collection");
884: }
885: if (jdoMap != null) {
886: s.append("/map");
887: }
888: if (jdoArray != null) {
889: s.append("/array");
890: }
891: }
892: if (jdoQuery != null) {
893: s.append("/query");
894: }
895: }
896: }
897: for (int i = 0; i <= extStackTop; i++) {
898: s.append("/extension[");
899: JdoExtension e = extStack[i];
900: s.append(JdoExtension.toKeyString(e.key));
901: s.append('=');
902: s.append(e.value);
903: s.append(']');
904: }
905: return s.toString();
906: }
907:
908: /**
909: * Get the value of the Attribute with name.
910: */
911: private String getReqAttr(Attributes attr, String name)
912: /*throws JDOFatalUserException*/{
913: String v = attr.getValue(name);
914: if (v == null) {
915: StringBuffer s = new StringBuffer();
916: s.append("Expected attribute '");
917: s.append(name);
918: s.append("' in ");
919: s.append(getContext());
920: s.append('.');
921: s.append(elementName);
922: throw BindingSupportImpl.getInstance()
923: .runtime(s.toString());
924: }
925: return v;
926: }
927:
928: /**
929: * Get the value of the int Attribute with name. Returns -1 if not found.
930: */
931: private int getIntAttr(Attributes attr, String name) {
932: String v = attr.getValue(name);
933: if (v == null)
934: return -1;
935: try {
936: return Integer.parseInt(v);
937: } catch (NumberFormatException e) {
938: StringBuffer s = new StringBuffer();
939: s.append("Expected int attribute '");
940: s.append(name);
941: s.append("' found '");
942: s.append(v);
943: s.append("' in ");
944: s.append(getContext());
945: s.append('.');
946: s.append(elementName);
947: throw BindingSupportImpl.getInstance()
948: .runtime(s.toString());
949: }
950: }
951:
952: /**
953: * Get an optional boolean attribute.
954: *
955: * @see MDStatics.NOT_SET
956: * @see MDStatics.FALSE
957: * @see MDStatics.TRUE
958: */
959: private int getTriState(Attributes attr, String name)
960: /*throws JDOFatalUserException*/{
961: String v = attr.getValue(name);
962: if (v == null)
963: return MDStatics.NOT_SET;
964: if ("true".equals(v))
965: return MDStatics.TRUE;
966: if ("false".equals(v))
967: return MDStatics.FALSE;
968: StringBuffer s = new StringBuffer();
969: s.append("Expected 'true' or 'false' for attribute '");
970: s.append(name);
971: s.append("', got '");
972: s.append(v);
973: s.append("' in ");
974: s.append(getContext());
975: s.append('.');
976: s.append(elementName);
977: throw BindingSupportImpl.getInstance().runtime(s.toString());
978: }
979:
980: /**
981: * Does s match our vendor name?
982: */
983: public static boolean isOurVendorName(String s) {
984: return VENDOR_NAME.equals(s) || VENDOR_NAME_JDOGENIE.equals(s);
985: }
986:
987: }
|