0001: /**
0002: * Speedo: an implementation of JDO compliant personality on top of JORM generic
0003: * I/O sub-system.
0004: * Copyright (C) 2001-2004 France Telecom R&D
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2 of the License, or (at your option) any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0019: *
0020: * Contact: speedo@objectweb.org
0021: * Authors: S.Chassande-Barrioz.
0022: *
0023: */package org.objectweb.speedo.generation.parser.jdo;
0024:
0025: import java.util.ArrayList;
0026: import java.util.Collections;
0027: import java.util.HashMap;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.Map;
0031:
0032: import org.objectweb.speedo.api.SpeedoException;
0033: import org.objectweb.speedo.generation.api.SpeedoXMLError;
0034: import org.objectweb.speedo.generation.parser.AbstractParser;
0035: import org.objectweb.speedo.lib.Personality;
0036: import org.objectweb.speedo.metadata.SpeedoClass;
0037: import org.objectweb.speedo.metadata.SpeedoCollection;
0038: import org.objectweb.speedo.metadata.SpeedoColumn;
0039: import org.objectweb.speedo.metadata.SpeedoCommonField;
0040: import org.objectweb.speedo.metadata.SpeedoDiscriminator;
0041: import org.objectweb.speedo.metadata.SpeedoElement;
0042: import org.objectweb.speedo.metadata.SpeedoExtension;
0043: import org.objectweb.speedo.metadata.SpeedoFetchGroup;
0044: import org.objectweb.speedo.metadata.SpeedoField;
0045: import org.objectweb.speedo.metadata.SpeedoIdentity;
0046: import org.objectweb.speedo.metadata.SpeedoIndex;
0047: import org.objectweb.speedo.metadata.SpeedoInheritance;
0048: import org.objectweb.speedo.metadata.SpeedoInheritedField;
0049: import org.objectweb.speedo.metadata.SpeedoJoin;
0050: import org.objectweb.speedo.metadata.SpeedoJoinColumn;
0051: import org.objectweb.speedo.metadata.SpeedoMap;
0052: import org.objectweb.speedo.metadata.SpeedoNoFieldColumn;
0053: import org.objectweb.speedo.metadata.SpeedoNullValue;
0054: import org.objectweb.speedo.metadata.SpeedoPackage;
0055: import org.objectweb.speedo.metadata.SpeedoPredefinedQuery;
0056: import org.objectweb.speedo.metadata.SpeedoTable;
0057: import org.objectweb.speedo.metadata.SpeedoVersion;
0058: import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
0059: import org.objectweb.speedo.sequence.jdo.JDOSequence;
0060: import org.objectweb.speedo.sequence.lib.SpeedoSequence;
0061: import org.objectweb.util.monolog.api.BasicLevel;
0062: import org.objectweb.util.monolog.api.Logger;
0063: import org.w3c.dom.Node;
0064: import org.w3c.dom.NodeList;
0065:
0066: /**
0067: * This class is a parser of the JDO2 persistent descriptor. It includes the
0068: * parsing the O/R mapping.
0069: *
0070: * @author S.Chassande-Barrioz
0071: */
0072: public class JDO2Parser extends AbstractParser {
0073:
0074: public JDO2Parser() {
0075: super (Personality.JDO);
0076: }
0077:
0078: public void process() throws SpeedoException {
0079: super .process();
0080: //compute fields number for each class
0081: for (Iterator itDesc = scp.getXmldescriptor().values()
0082: .iterator(); itDesc.hasNext();) {
0083: SpeedoXMLDescriptor desc = (SpeedoXMLDescriptor) itDesc
0084: .next();
0085: for (Iterator itPack = desc.packages.values().iterator(); itPack
0086: .hasNext();) {
0087: SpeedoPackage sp = (SpeedoPackage) itPack.next();
0088: for (Iterator itclass = sp.classes.values().iterator(); itclass
0089: .hasNext();) {
0090: SpeedoClass clazz = (SpeedoClass) itclass.next();
0091: clazz.computeFieldNumbers();
0092: }
0093: }
0094: }
0095: }
0096:
0097: protected String getLoggerName() {
0098: return "jdo2";
0099: }
0100:
0101: protected Object treatDocument(Node node, Object mo)
0102: throws SpeedoException {
0103: SpeedoXMLDescriptor xmlDesc = (SpeedoXMLDescriptor) mo;
0104: Map docChildren = groupChildrenByName(node);
0105: List l = (List) docChildren.remove("jdo");
0106: if (l != null) {
0107: for (int i = 0; i < l.size(); i++) {
0108: treatJdoNode((Node) l.get(i), xmlDesc);
0109: }
0110: }
0111: return mo;
0112: }
0113:
0114: protected Object treatJdoNode(Node jdoNode,
0115: SpeedoXMLDescriptor xmlDesc) throws SpeedoException {
0116: Map jdoChildren = groupChildrenByName(jdoNode);
0117: List packages = (List) jdoChildren.remove("package");
0118: if (packages != null) {
0119: for (int i = 0; i < packages.size(); i++) {
0120: Node packageNode = (Node) packages.get(i);
0121: Node n = packageNode.getAttributes().getNamedItem(
0122: "name");
0123: if (n == null) {
0124: logger
0125: .log(BasicLevel.ERROR,
0126: "Attribute 'name' for tag package required.");
0127: continue;
0128: }
0129: SpeedoPackage p = new SpeedoPackage();
0130: p.name = n.getNodeValue();
0131: xmlDesc.add(p, true, logger);
0132: logger.log(BasicLevel.DEBUG, "Parsing package: name= "
0133: + p.name);
0134: Map packageChildren = groupChildrenByName(packageNode);
0135: treatExtensions((List) packageChildren
0136: .remove("extension"), p);
0137: List l = (List) packageChildren.remove("sequence");
0138: if (l != null) {
0139: for (int j = 0; j < l.size(); j++) {
0140: Node classNode = (Node) l.get(j);
0141: treatSequenceNode(classNode, p);
0142: }
0143: }
0144: l = (List) packageChildren.remove("class");
0145: if (l != null) {
0146: for (int j = 0; j < l.size(); j++) {
0147: Node classNode = (Node) l.get(j);
0148: treatClassNode(classNode, p);
0149: }
0150: }
0151: }
0152: }
0153: List queries = (List) jdoChildren.remove("query");
0154: if (queries != null) {
0155: xmlDesc.queries = new ArrayList(queries.size());
0156: for (int i = 0; i < queries.size(); i++) {
0157: SpeedoPredefinedQuery spq = getQuery((Node) queries
0158: .get(i));
0159: xmlDesc.queries.add(spq);
0160: }
0161: }
0162: return xmlDesc;
0163: }
0164:
0165: private Map groupChildrenByName(Node n) {
0166: NodeList nl = n.getChildNodes();
0167: int size = nl.getLength();
0168: if (size == 0) {
0169: return Collections.EMPTY_MAP;
0170: }
0171: HashMap result = new HashMap(size);
0172: for (int i = 0; i < size; i++) {
0173: Node child = nl.item(i);
0174: String name = child.getNodeName();
0175: List l = (List) result.get(name);
0176: if (l == null) {
0177: l = new ArrayList();
0178: result.put(name, l);
0179: }
0180: l.add(child);
0181: }
0182: return result;
0183: }
0184:
0185: private void unmanaged(Node node, Map unmanagedChildren) {
0186: if (unmanagedChildren != null && unmanagedChildren.size() > 0) {
0187: logger.log(BasicLevel.WARN, "Umanaged sub node of "
0188: + node.getNodeName() + ": "
0189: + unmanagedChildren.keySet());
0190: }
0191: }
0192:
0193: private void treatSequenceNode(Node seqNode, SpeedoPackage p)
0194: throws SpeedoException {
0195: SpeedoSequence s = new JDOSequence();
0196: Node n = null;
0197:
0198: //<!ATTLIST sequence name CDATA #REQUIRED>
0199: n = seqNode.getAttributes().getNamedItem("name");
0200: if (n == null)
0201: throw new SpeedoXMLError(
0202: "Attribute name for tag sequence requested.");
0203: s.name = n.getNodeValue();
0204: p.addSequence(s);
0205:
0206: //<!ATTLIST sequence datastore-sequence CDATA #IMPLIED>
0207: n = seqNode.getAttributes().getNamedItem("datastore-sequence");
0208: if (n != null)
0209: s.datastoreName = n.getNodeValue();
0210:
0211: //<!ATTLIST sequence factory-class CDATA #IMPLIED>
0212: n = seqNode.getAttributes().getNamedItem("factory-class");
0213: if (n != null) {
0214: s.factoryClass = n.getNodeValue();
0215: }
0216:
0217: //<!ATTLIST sequence strategy (nontransactional|contiguous|noncontiguous) #REQUIRED>
0218: n = seqNode.getAttributes().getNamedItem("strategy");
0219: if (n == null) {
0220: throw new SpeedoXMLError(
0221: "Attribute strategy for tag sequence requested.");
0222: }
0223: s.strategy = SpeedoSequence.strategyToByte(n.getNodeValue());
0224:
0225: //<!ELEMENT sequence (extension*)>
0226: Map seqChildren = groupChildrenByName(seqNode);
0227: treatExtensions((List) seqChildren.get("extension"), p);
0228:
0229: if (debug) {
0230: logger.log(BasicLevel.DEBUG, "New sequence: " + "name="
0231: + s.name + " / datastoreName = " + s.datastoreName
0232: + " / factoryClass = " + s.factoryClass
0233: + " / strategy = " + s.strategy);
0234: }
0235: }
0236:
0237: private void treatIndexNode(Node indexNode, SpeedoClass sc)
0238: throws SpeedoException {
0239: SpeedoIndex si = new SpeedoIndex();
0240: Node n = null;
0241:
0242: //attribut name (compulsory)
0243: n = indexNode.getAttributes().getNamedItem("name");
0244: if (n == null)
0245: throw new SpeedoXMLError(
0246: "Attribute name for tag index requested.");
0247: si.name = n.getNodeValue();
0248:
0249: //attribute unique
0250: n = indexNode.getAttributes().getNamedItem("unique");
0251: if (n != null)
0252: si.unique = Boolean.valueOf(n.getNodeValue())
0253: .booleanValue();
0254:
0255: //attribute table (compulsory)
0256: n = indexNode.getAttributes().getNamedItem("table");
0257: if (n == null)
0258: throw new SpeedoXMLError(
0259: "Attribute table for tag index requested.");
0260: si.table = n.getNodeValue();
0261:
0262: //add the SpeedoIndex to the SpeedoTable
0263: boolean linked = false;
0264: //test the main table
0265: if (sc.mainTable != null) {
0266: if (sc.mainTable.name.equals(si.table)) {
0267: sc.mainTable.indexes.add(si);
0268: linked = true;
0269: }
0270: }
0271: //and if no success with the main table try the joined tables
0272: if (!linked && sc.joinToExtTables != null) {
0273: for (int i = 0; i < sc.joinToExtTables.length && !linked; i++) {
0274: if (sc.joinToExtTables[i].extTable.name.equals(si.name)) {
0275: sc.joinToExtTables[i].extTable.indexes.add(si);
0276: linked = true;
0277: }
0278: }
0279: }
0280:
0281: Map classChildren = groupChildrenByName(indexNode);
0282: //extension*, (column|field|property)*
0283: treatExtensions((List) classChildren.get("extension"), si);
0284: List l = (List) classChildren.get("field");
0285: if (l != null) {
0286: for (int j = 0; j < l.size(); j++) {
0287: treatFieldNode((Node) l.get(j), sc, si);
0288: }
0289: }
0290: si.speedoClass = sc;
0291: // TODO: unmanaged stuff of class
0292: unmanaged(null, new String[] { "column", "property" },
0293: indexNode, classChildren);
0294: }
0295:
0296: private void treatClassNode(Node classNode, SpeedoPackage p)
0297: throws SpeedoException {
0298: Node n = null;
0299: //attribute name (compulsory)
0300: n = classNode.getAttributes().getNamedItem("name");
0301: if (n == null) {
0302: logger.log(BasicLevel.ERROR,
0303: "Attribute 'name' for tag class required.");
0304: return;
0305: }
0306: SpeedoClass c = new SpeedoClass();
0307: c.name = n.getNodeValue();
0308: p.addClass(c, true, logger);
0309:
0310: //attribute identity-type
0311: n = classNode.getAttributes().getNamedItem("identity-type");
0312: if (n != null)
0313: c.setIdentityType(SpeedoIdentity.getStrategy(n
0314: .getNodeValue()));
0315:
0316: //attribute object-id
0317: n = classNode.getAttributes().getNamedItem("objectid-class");
0318: if (n != null) {
0319: c.identity.objectidClass = n.getNodeValue();
0320: c.setIdentityType(SpeedoIdentity.USER_ID);
0321: }
0322:
0323: //attribute requires-extent is not taken into account
0324:
0325: //attribute detachable
0326: n = classNode.getAttributes().getNamedItem("detachable");
0327: if (n != null)
0328: c.isDetachable = Boolean.valueOf(n.getNodeValue())
0329: .booleanValue();
0330:
0331: //attribute persistence-capable-superclass
0332: n = classNode.getAttributes().getNamedItem(
0333: "persistence-capable-superclass");
0334: if (n != null) {
0335: if (c.inheritance == null) {
0336: c.inheritance = new SpeedoInheritance(c);
0337: }
0338: c.inheritance.super ClassName = n.getNodeValue();
0339: }
0340: //attribute table
0341: n = classNode.getAttributes().getNamedItem("table");
0342: if (n != null) {
0343: c.mainTable = new SpeedoTable();
0344: c.mainTable.name = n.getNodeValue();
0345: }
0346: if (c.mainTable == null) {
0347: if (c.inheritance == null
0348: || c.inheritance.strategy == SpeedoInheritance.STRATEGY_NEW_TABLE) {
0349: c.mainTable = new SpeedoTable();
0350: c.mainTable.name = c.name.toUpperCase();
0351: }
0352: }
0353:
0354: logger.log(BasicLevel.DEBUG, "New class: " + "name=" + c.name
0355: + " / id = " + c.getIdentityType() + " / idClass = "
0356: + c.identity.objectidClass + " / detachable = "
0357: + c.isDetachable);
0358:
0359: Map classChildren = groupChildrenByName(classNode);
0360: //extension*, implements*, datastore-identity?, inheritance?, version?,
0361: // join*, foreign-key*, index*, unique*, field*, query*, fetch-group*, extension*
0362: treatExtensions((List) classChildren.get("extension"), c);
0363: List l = (List) classChildren.get("datastore-identity");
0364: if (l != null) {
0365: treatDataStoreId((Node) l.get(0), c);
0366: }
0367: l = (List) classChildren.get("inheritance");
0368: if (l != null) {
0369: treatInheritance((Node) l.get(0), c);
0370: }
0371: l = (List) classChildren.get("version");
0372: if (l != null) {
0373: treatVersion((Node) l.get(0), c);
0374: }
0375: l = (List) classChildren.get("join");
0376: if (l != null) {
0377: for (int j = 0; j < l.size(); j++) {
0378: Object[] os = getJoin((Node) l.get(j), null);
0379: SpeedoJoin join = (SpeedoJoin) os[0];
0380: String tableName = (String) os[1];
0381: //define an external/secondary table
0382: c.addJoin(join);
0383: if (c.mainTable != null) {
0384: join.mainTable = c.mainTable;
0385: }
0386: if (tableName != null) {
0387: join.extTable = new SpeedoTable();
0388: join.extTable.name = tableName;
0389: join.extTable.join = join;
0390: }
0391: }
0392: }
0393: l = (List) classChildren.get("field");
0394: if (l != null) {
0395: for (int j = 0; j < l.size(); j++) {
0396: treatFieldNode((Node) l.get(j), c);
0397: }
0398: }
0399: l = (List) classChildren.get("query");
0400: if (l != null) {
0401: for (int j = 0; j < l.size(); j++) {
0402: SpeedoPredefinedQuery spq = getQuery((Node) l.get(j));
0403: c.name2query.put(spq.name, spq);
0404: }
0405: }
0406: l = (List) classChildren.get("index");
0407: if (l != null) {
0408: for (int j = 0; j < l.size(); j++) {
0409: treatIndexNode((Node) l.get(j), c);
0410: }
0411: }
0412: l = (List) classChildren.get("fetch-group");
0413: if (l != null) {
0414: for (int j = 0; j < l.size(); j++) {
0415: treatFetchGroupNode((Node) l.get(j), c);
0416: }
0417: }
0418:
0419: //TODO: unmanaged stuff of class
0420: unmanaged(null, new String[] { "foreign-key", "unique" },
0421: classNode, classChildren);
0422: }
0423:
0424: private void treatDataStoreId(Node dsiNode, SpeedoClass moClass)
0425: throws SpeedoException {
0426: SpeedoIdentity ident = new SpeedoIdentity(); //default strategy is native
0427: //<!ATTLIST datastore-identity strategy CDATA 'native'>
0428: Node n = dsiNode.getAttributes().getNamedItem("strategy");
0429: if (n == null)
0430: throw new SpeedoXMLError(
0431: "Attribute strategy for tag datastore-identity requested.");
0432: ident.strategy = SpeedoIdentity.getStrategy(n.getNodeValue());
0433:
0434: //<!ATTLIST datastore-identity sequence CDATA #IMPLIED>
0435: n = dsiNode.getAttributes().getNamedItem("sequence");
0436: if (n != null)
0437: ident.sequenceName = n.getNodeValue();
0438:
0439: //<!ATTLIST datastore-identity column CDATA #IMPLIED>
0440: List columns = null;
0441: n = dsiNode.getAttributes().getNamedItem("column");
0442: if (n != null) {
0443: columns = new ArrayList();
0444: columns.add(new SpeedoColumn(n.getNodeValue()));
0445:
0446: }
0447: //<!ELEMENT datastore-identity (extension*, column*, extension*)>
0448: //inner element column
0449: Map dsiChildren = groupChildrenByName(dsiNode);
0450: treatExtensions((List) dsiChildren.get("extension"), ident);
0451: //TODO: unmanaged stuff of class
0452: unmanaged(null,
0453: new String[] { "index", "unique", "fetch-group" },
0454: dsiNode, dsiChildren);
0455: List columnNodes = (List) dsiChildren.get("column");
0456: if (columnNodes != null) {
0457: for (int i = 0; i < columnNodes.size(); i++) {
0458: if (columns == null) {
0459: columns = new ArrayList();
0460: }
0461: Node columnNode = (Node) columnNodes.get(i);
0462: columns.add(getColumn(columnNode));
0463: }
0464: }
0465: if (columns != null) {
0466: moClass.identity.setColumns(columns);
0467: }
0468: //bind the identity to the moClass
0469: moClass.identity = ident;
0470: if (debug) {
0471: logger.log(BasicLevel.DEBUG, "New datastore-identity: "
0472: + "identity=" + ident);
0473: }
0474: }
0475:
0476: private void treatInheritance(Node inhNode, SpeedoClass moClass)
0477: throws SpeedoException {
0478: if (moClass.inheritance == null) {
0479: moClass.inheritance = new SpeedoInheritance(moClass);
0480: }
0481: //<!ATTLIST inheritance strategy CDATA #IMPLIED>
0482: Node n = inhNode.getAttributes().getNamedItem("strategy");
0483: if (n != null) {
0484: moClass.inheritance.strategy = SpeedoInheritance
0485: .parseStrategy(n.getNodeValue());
0486: logger
0487: .log(
0488: BasicLevel.DEBUG,
0489: "defines the strategy '"
0490: + SpeedoInheritance
0491: .strategy2str(moClass.inheritance.strategy));
0492: }
0493: //<!ELEMENT inheritance (extension*, join?, discriminator?, extension*)>
0494: Map inhChildren = groupChildrenByName(inhNode);
0495: //inner element extension
0496: treatExtensions((List) inhChildren.get("extension"),
0497: moClass.inheritance);
0498: //inner element join
0499: List l = (List) inhChildren.get("join");
0500: if (l != null) {
0501: //define a join to the super class (vertical mapping)
0502: Object[] os = getJoin((Node) l.get(0), null);
0503: moClass.inheritance.join = (SpeedoJoin) os[1];
0504: }
0505: //inner element discriminator
0506: l = (List) inhChildren.get("discriminator");
0507: if (l != null) {
0508: treatDiscriminator((Node) l.get(0), moClass.inheritance);
0509: }
0510: }
0511:
0512: private void treatDiscriminator(Node discNode, SpeedoInheritance inh)
0513: throws SpeedoException {
0514: if (inh.discriminator == null) {
0515: inh.discriminator = new SpeedoDiscriminator();
0516: }
0517: //<!ATTLIST discriminator strategy CDATA #IMPLIED>
0518: Node n = discNode.getAttributes().getNamedItem("strategy");
0519: if (n != null) {
0520: inh.discriminator.strategy = SpeedoDiscriminator
0521: .parseStrategy(n.getNodeValue());
0522: }
0523: //<!ELEMENT discriminator (extension*, column*, index?, extension*)>
0524: //inner element extension
0525: Map discChildren = groupChildrenByName(discNode);
0526:
0527: //<!ATTLIST discriminator value CDATA #IMPLIED>
0528: n = discNode.getAttributes().getNamedItem("value");
0529: String val = null;
0530: if (n != null) {
0531: val = n.getNodeValue();
0532: }
0533:
0534: //<!ATTLIST discriminator column CDATA #IMPLIED>
0535: n = discNode.getAttributes().getNamedItem("column");
0536: SpeedoColumn col = null;
0537: if (n != null) {
0538: col = new SpeedoColumn(n.getNodeValue());
0539: } else {
0540: //inner element column
0541: List columnNodes = (List) discChildren.get("column");
0542: if (columnNodes != null && columnNodes.size() == 1) {
0543: Node columnNode = (Node) columnNodes.get(0);
0544: col = getColumn(columnNode);
0545: }
0546: }
0547: if (col == null) {
0548: if (val != null) {
0549: //try to use the default column
0550:
0551: }
0552: } else {
0553: if (val != null) {
0554:
0555: } else {
0556: //column definition on abstract class
0557: }
0558: }
0559: SpeedoNoFieldColumn snfc = new SpeedoNoFieldColumn();
0560: snfc.column = col;
0561: inh.discriminator.elements.add(snfc);
0562: if (val != null) {
0563: if (inh.discriminatorValues == null) {
0564: inh.discriminatorValues = new HashMap();
0565: }
0566: inh.discriminator.setDiscriminatorValue(val, inh, snfc);
0567: }
0568:
0569: treatExtensions((List) discChildren.get("extension"),
0570: inh.discriminator);
0571: unmanaged(new String[] { "indexed" }, new String[] { "index" },
0572: discNode, discChildren);
0573: }
0574:
0575: private Object[] getJoin(Node joinNode, SpeedoJoin j)
0576: throws SpeedoException {
0577: Node n = joinNode.getAttributes().getNamedItem("table");
0578: if (j == null) {
0579: j = new SpeedoJoin();
0580: }
0581: n = joinNode.getAttributes().getNamedItem("delete-action");
0582: if (n != null) {
0583: String v = n.getNodeValue();
0584: if ("restrict".equals(v)) {
0585: j.deleteAction = SpeedoJoin.ACTION_RESTRICT;
0586: } else if ("cascade".equals(v)) {
0587: j.deleteAction = SpeedoJoin.ACTION_CASCADE;
0588: } else if ("null".equals(v)) {
0589: j.deleteAction = SpeedoJoin.ACTION_NULL;
0590: } else if ("none".equals(v)) {
0591: j.deleteAction = SpeedoJoin.ACTION_NONE;
0592: } else if ("default".equals(v)) {
0593: j.deleteAction = SpeedoJoin.ACTION_DEFAULT;
0594: } else {
0595: j.deleteAction = SpeedoJoin.ACTION_DEFAULT;
0596: }
0597: }
0598: j.setUnique(getBooleanAttributeValue(joinNode, "unique", j
0599: .getUnique()));
0600: j.setIndexed(getBooleanAttributeValue(joinNode, "indexed", j
0601: .getIndexed()));
0602: j.setOuter(getBooleanAttributeValue(joinNode, "indexed", j
0603: .getOuter()));
0604: n = joinNode.getAttributes().getNamedItem("column");
0605: if (n != null) {
0606: SpeedoJoinColumn sjc = new SpeedoJoinColumn(
0607: new SpeedoColumn(n.getNodeValue()));
0608: j.columns.add(sjc);
0609: }
0610: Map joinChildren = groupChildrenByName(joinNode);
0611: List l = (List) joinChildren.get("column");
0612: if (l != null) {
0613: for (int i = 0; i < l.size(); i++) {
0614: j.columns.add(new SpeedoJoinColumn(getColumn((Node) l
0615: .get(i))));
0616: }
0617: }
0618: n = joinNode.getAttributes().getNamedItem("table");
0619: String tableName = null;
0620: if (n != null) {
0621: tableName = n.getNodeValue();
0622: }
0623: return new Object[] { j, tableName };
0624: }
0625:
0626: private void treatVersion(Node versionNode, SpeedoClass moClass)
0627: throws SpeedoException {
0628: SpeedoVersion v = new SpeedoVersion();
0629: //attribute embedded-element
0630: //<!ATTLIST version strategy CDATA #IMPLIED>
0631: Node n = versionNode.getAttributes().getNamedItem("strategy");
0632: v.strategy = SpeedoVersion.toByte(n.getNodeValue());
0633:
0634: //<!ATTLIST version indexed (true|false|unique) #IMPLIED>
0635: n = versionNode.getAttributes().getNamedItem("strategy");
0636: if (n != null) {
0637: //TODO: Speedo does not support yet the indexed attribute in version tag
0638: logger
0639: .log(BasicLevel.WARN,
0640: "Speedo does not support yet the indexed attribute in version tag");
0641: }
0642:
0643: //<!ATTLIST version column CDATA #IMPLIED>
0644: List columns = null;
0645: n = versionNode.getAttributes().getNamedItem("column");
0646: if (n != null) {
0647: columns = new ArrayList();
0648: columns.add(new SpeedoColumn(n.getNodeValue()));
0649: }
0650: //<!ELEMENT version (extension*, column*, index?, extension*)>
0651: Map versionChildren = groupChildrenByName(versionNode);
0652: unmanaged(new String[] { "column" }, new String[] { "column",
0653: "index" }, versionNode, versionChildren);
0654: moClass.version = v;
0655: logger.log(BasicLevel.DEBUG, "New version: strategy="
0656: + v.strategy);
0657: }
0658:
0659: private void treatExtensions(List nodes, SpeedoElement se)
0660: throws SpeedoException {
0661: if (nodes != null) {
0662: for (int i = 0; i < nodes.size(); i++) {
0663: treatExtension((Node) nodes.get(i), se);
0664: }
0665: }
0666: }
0667:
0668: private void treatExtension(Node node, SpeedoElement se)
0669: throws SpeedoException {
0670: SpeedoExtension e = new SpeedoExtension();
0671: //<!ATTLIST extension vendor-name CDATA #REQUIRED>
0672: Node n = node.getAttributes().getNamedItem("vendor-name");
0673: e.vendorName = n.getNodeValue();
0674: //<!ATTLIST extension key CDATA #IMPLIED>
0675: n = node.getAttributes().getNamedItem("key");
0676: if (n != null) {
0677: e.key = n.getNodeValue();
0678: }
0679: //<!ATTLIST extension value CDATA #IMPLIED>
0680: n = node.getAttributes().getNamedItem("value");
0681: if (n != null) {
0682: e.value = n.getNodeValue();
0683: }
0684: //<!ELEMENT extension ANY>
0685:
0686: logger.log(BasicLevel.DEBUG, "Parse extension name=" + e.key
0687: + ", value=" + e.value);
0688: se.addExtension(e);
0689: e.owner = se;
0690: }
0691:
0692: private SpeedoColumn getColumn(Node node) throws SpeedoException {
0693: SpeedoColumn c = new SpeedoColumn();
0694: Node n = node.getAttributes().getNamedItem("name");
0695: if (n != null) {
0696: c.name = n.getNodeValue();
0697: }
0698: n = node.getAttributes().getNamedItem("target");
0699: if (n != null) {
0700: c.targetColumn = n.getNodeValue();
0701: }
0702: n = node.getAttributes().getNamedItem("target-field");
0703: if (n != null) {
0704: c.targetField = n.getNodeValue();
0705: }
0706: n = node.getAttributes().getNamedItem("jdbc-type");
0707: if (n != null) {
0708: c.jdbcType = n.getNodeValue();
0709: }
0710: n = node.getAttributes().getNamedItem("sql-type");
0711: if (n != null) {
0712: c.sqlType = n.getNodeValue();
0713: }
0714: n = node.getAttributes().getNamedItem("length");
0715: if (n != null) {
0716: c.length = Integer.parseInt(n.getNodeValue());
0717: }
0718: n = node.getAttributes().getNamedItem("scale");
0719: if (n != null) {
0720: c.scale = Integer.parseInt(n.getNodeValue());
0721: }
0722: c.allowNull = getBooleanAttributeValue(node, "allows-null",
0723: c.allowNull);
0724: n = node.getAttributes().getNamedItem("default-value");
0725: if (n != null) {
0726: c.defaultValue = n.getNodeValue();
0727: }
0728: return c;
0729: }
0730:
0731: private SpeedoPredefinedQuery getQuery(Node queryNode)
0732: throws SpeedoException {
0733: //TODO: verify DTD about query
0734: SpeedoPredefinedQuery spq = new SpeedoPredefinedQuery();
0735: //<!ATTLIST query name CDATA #IMPLIED>
0736: spq.name = getStringAttributeValue(queryNode, "name", null);
0737: //<!ATTLIST query language CDATA #IMPLIED>
0738: spq.language = getStringAttributeValue(queryNode, "language",
0739: null);
0740: //<!ELEMENT query (#PCDATA|extension)*>
0741: spq.query = queryNode.getNodeValue();
0742: Map queryChildren = groupChildrenByName(queryNode);
0743: treatExtensions((List) queryChildren.get("extension"), spq);
0744: return spq;
0745: }
0746:
0747: private SpeedoFetchGroup getFetchGroup(Node fgNode,
0748: SpeedoClass fieldOwner) throws SpeedoException {
0749: SpeedoFetchGroup fg = new SpeedoFetchGroup();
0750: //<!ATTLIST fetch-group name CDATA #REQUIRED>
0751: Node n = fgNode.getAttributes().getNamedItem("name");
0752: fg.name = n.getNodeValue();
0753:
0754: //<!ATTLIST fetch-group post-load (true|false) #IMPLIED>
0755: n = fgNode.getAttributes().getNamedItem("post-load");
0756: if (n != null) {
0757: fg.postLoad = Boolean.valueOf(n.getNodeValue())
0758: .booleanValue();
0759: } else {
0760: if (fg.name.equals("default")) {
0761: fg.postLoad = true;
0762: } else {
0763: fg.postLoad = false;
0764: }
0765: }
0766: Map fgChildren = groupChildrenByName(fgNode);
0767: //<!ELEMENT fetch-group (fetch-group|field)*>
0768: List l = (List) fgChildren.get("field");
0769: if (l != null) {
0770: for (int j = 0; j < l.size(); j++) {
0771: Node fieldNode = (Node) l.get(j);
0772: String fieldName = getStringAttributeValue(fieldNode,
0773: "name", null);
0774: if (fieldName != null) {
0775: SpeedoField field = fieldOwner.getField(fieldName);
0776: if (field != null) {
0777: fg.addField(field);
0778: } else {
0779: logger.log(BasicLevel.WARN, "Bad field name '"
0780: + fieldName + "'in the fetch group '"
0781: + fg.name + "' in the class "
0782: + fieldOwner.getSourceDesc() + ".");
0783: }
0784: }
0785: }
0786: }
0787: l = (List) fgChildren.get("fetch-group");
0788: if (l != null) {
0789: for (int j = 0; j < l.size(); j++) {
0790: SpeedoFetchGroup subfg = getFetchGroup((Node) l.get(j),
0791: fieldOwner);
0792: if (logger.isLoggable(BasicLevel.DEBUG)) {
0793: logger.log(BasicLevel.DEBUG, "add fetchgroup '"
0794: + subfg.name + "' into the fetchgroup '"
0795: + fg.name + "'");
0796: }
0797: fg.addFetchGroup(subfg);
0798: }
0799: }
0800: return fg;
0801: }
0802:
0803: private void treatFieldNode(Node fieldNode, SpeedoClass moClass,
0804: SpeedoIndex moIndex) throws SpeedoException {
0805: //at the moment, only support for field with name attribute
0806: //no support for field definition within the index tag
0807: Node n = null;
0808:
0809: //<!ATTLIST field name CDATA #REQUIRED>
0810: n = fieldNode.getAttributes().getNamedItem("name");
0811: if (n == null)
0812: throw new SpeedoXMLError(
0813: "Attribute name for tag field requested.");
0814: String name = n.getNodeValue();
0815: //add the field name to the index
0816: moIndex.fieldNames.add(name);
0817: //try to add the column name(s) to the index
0818: SpeedoField sf = (SpeedoField) moClass.fields.get(name);
0819: if (sf == null)
0820: throw new SpeedoXMLError("The field " + name
0821: + " must be defined for the class " + moClass.name
0822: + ".");
0823: if (sf.columns != null && sf.columns.length != 0) {
0824: for (int i = 0; i < sf.columns.length; i++) {
0825: moIndex.columnNames.add(sf.columns[i].name);
0826: }
0827: } else {
0828: logger.log(BasicLevel.WARN, "The column(s) for the field "
0829: + name + " has not been defined yet.");
0830: }
0831: }
0832:
0833: private void treatFieldNode(Node fieldNode, SpeedoClass moClass)
0834: throws SpeedoException {
0835: Node n = null;
0836:
0837: //<!ATTLIST field name CDATA #REQUIRED>
0838: n = fieldNode.getAttributes().getNamedItem("name");
0839: if (n == null)
0840: throw new SpeedoXMLError(
0841: "Attribute name for tag field requested.");
0842: String name = n.getNodeValue();
0843: int dotIdx = name.lastIndexOf(".");
0844: SpeedoField f = null;
0845: SpeedoCommonField cf;
0846: FieldContext fc = new FieldContext();
0847: fc.fieldNode = fieldNode;
0848: if (dotIdx != -1) {
0849: cf = moClass.inheritance.newSpeedoInheritedField(name);
0850: } else {
0851: f = new SpeedoField();
0852: cf = f;
0853: f.name = n.getNodeValue();
0854: f.moClass = moClass;
0855:
0856: //<!ATTLIST field persistence-modifier (persistent|transactional|none) #IMPLIED>
0857: n = fieldNode.getAttributes().getNamedItem(
0858: "persistence-modifier");
0859: if (n != null)
0860: f.persistenceStatus = SpeedoField
0861: .parsePersistenceStatus(n.getNodeValue());
0862:
0863: //<!ATTLIST field primary-key (true|false) 'false'>
0864: n = fieldNode.getAttributes().getNamedItem("primary-key");
0865: if (n != null)
0866: f.primaryKey = Boolean.valueOf(n.getNodeValue())
0867: .booleanValue();
0868:
0869: //<!ATTLIST field null-value (exception|default|none) 'none'>
0870: n = fieldNode.getAttributes().getNamedItem("null-value");
0871: if (n != null) {
0872: f.nullValue = SpeedoNullValue.toByte(n.getNodeValue());
0873: }
0874:
0875: //<!ATTLIST field default-fetch-group (true|false) #IMPLIED>
0876: n = fieldNode.getAttributes().getNamedItem(
0877: "default-fetch-group");
0878: if (n != null)
0879: f.defaultFetchGroup = Boolean.valueOf(n.getNodeValue())
0880: .booleanValue();
0881:
0882: //attribute fetch-group
0883: n = fieldNode.getAttributes().getNamedItem("fetch-group");
0884: if (n != null)
0885: f.fetchGroup = n.getNodeValue();
0886:
0887: //<!ATTLIST field fetch-depth CDATA #IMPLIED>
0888: n = fieldNode.getAttributes().getNamedItem("fetch-depth");
0889: if (n == null) {
0890: n = fieldNode.getAttributes().getNamedItem("depth");
0891: if (n != null) {
0892: logger
0893: .log(BasicLevel.WARN,
0894: "attribute 'depth' is deprecated, use 'fetch-depth'.");
0895: }
0896: }
0897: if (n != null) {
0898: f.depth = Integer.valueOf(n.getNodeValue()).intValue();
0899: }
0900:
0901: //<!ATTLIST field embedded (true|false) #IMPLIED>
0902: n = fieldNode.getAttributes().getNamedItem("embedded");
0903: if (n != null)
0904: f.embedded = Boolean.valueOf(n.getNodeValue())
0905: .booleanValue();
0906:
0907: //<!ATTLIST field value-strategy CDATA #IMPLIED>
0908: n = fieldNode.getAttributes()
0909: .getNamedItem("value-strategy");
0910: if (n != null)
0911: f.valueStrategy = n.getNodeValue();
0912:
0913: //<!ATTLIST field sequence CDATA #IMPLIED>
0914: n = fieldNode.getAttributes().getNamedItem("sequence");
0915: if (n != null)
0916: f.sequence = n.getNodeValue();
0917:
0918: //<!ATTLIST field mapped-by CDATA #IMPLIED>
0919: n = fieldNode.getAttributes().getNamedItem("mapped-by");
0920: if (n != null) {
0921: f.reverseField = n.getNodeValue();
0922: f.mappedByReversefield = true;
0923: f.isCoherentReverseField = true;
0924: if (logger.isLoggable(BasicLevel.DEBUG)) {
0925: logger.log(BasicLevel.DEBUG, "The field " + f.name
0926: + " is mapped by " + f.reverseField);
0927: }
0928: }
0929: }
0930: fc.field = cf;
0931:
0932: //<!ATTLIST field table CDATA #IMPLIED>
0933: fc.parseTableAttribute(fieldNode, logger);
0934:
0935: //<!ELEMENT field (extension*, (array|collection|map)?, join?,
0936: //embedded?, element?, key?, value?, order?, column*, foreign-key?,
0937: //index?, unique?, extension*)>
0938:
0939: fc.fieldChildren = groupChildrenByName(fieldNode);
0940: List l;
0941: treatExtensions((List) fc.fieldChildren.get("extension"), cf);
0942:
0943: if (fc.parseORM()) {
0944: //Parse the O/R mapping of the [inherited] field
0945: l = (List) fc.fieldChildren.get("join");
0946: if (l != null) {
0947: //define an external/secondary table used by a particular field
0948: Object[] os = getJoin((Node) l.get(0), fc.join);
0949: fc.join = (SpeedoJoin) os[0];
0950: if (f != null) {
0951: logger.log(BasicLevel.DEBUG, "Specify the join "
0952: + fc.join + " to the field " + f.name);
0953: } else if (logger.isLoggable(BasicLevel.DEBUG)) {
0954: logger.log(BasicLevel.DEBUG, "Specify the join "
0955: + fc.join + " to the inherited field "
0956: + cf.name);
0957: }
0958: }
0959: //<!ATTLIST field column CDATA #IMPLIED>
0960: n = fieldNode.getAttributes().getNamedItem("column");
0961: if (n != null) {
0962: fc.addColumn(new SpeedoColumn(n.getNodeValue()));
0963: }
0964: l = (List) fc.fieldChildren.get("column");
0965: if (l != null) {
0966: for (int i = 0; i < l.size(); i++) {
0967: fc.addColumn(getColumn((Node) l.get(i)));
0968: }
0969: }
0970: }
0971: boolean isCollection = fc.fieldChildren.get("collection") != null
0972: || fc.fieldChildren.get("element") != null;
0973: boolean isMap = fc.fieldChildren.get("map") != null
0974: || fc.fieldChildren.get("key") != null
0975: || fc.fieldChildren.get("value") != null;
0976: boolean isArray = fc.fieldChildren.get("array") != null;
0977: if (isMap) {
0978: if (isCollection) {
0979: logger.log(BasicLevel.WARN, "The '" + f.name
0980: + "' from the class '" + moClass.getFQName()
0981: + "' cannot be a map AND a collection !");
0982: }
0983: }
0984: if (isCollection) {
0985: treatCollectionField(fc);
0986: } else if (isMap) {
0987: treatMapField(fc);
0988: } else if (isArray) {
0989:
0990: } else {
0991: treatSimpleField(fc);
0992: }
0993: unmanaged(new String[] { "serialized", "dependent",
0994: "delete-action", "load-fetch-group", "foreign-key",
0995: "indexed", "unique" }, new String[] { "embedded",
0996: "order", "foreign-key", "unique", "index", "array" },
0997: fieldNode, fc.fieldChildren);
0998: if (f != null) {
0999: if (debug) {
1000: logger.log(BasicLevel.DEBUG, "New field: " + "name="
1001: + f.name + " / persistenceModifier = "
1002: + f.persistenceStatus + " / primaryKey = "
1003: + f.primaryKey + " / nullValue = "
1004: + f.nullValue + " / defaultFetchGroup = "
1005: + f.defaultFetchGroup + " / embedded = "
1006: + f.embedded + " / depth = " + f.depth
1007: + " / valueStrategy = " + f.valueStrategy
1008: + " / sequence = " + f.sequence);
1009: }
1010: moClass.add(f, true, logger);
1011: } //else it is an inherited field already attached to moClass.inheritance
1012: }
1013:
1014: private void treatMapField(FieldContext fc) throws SpeedoException {
1015: SpeedoMap m = (SpeedoMap) fc.field.jdoTuple;
1016: if (m == null) {
1017: m = new SpeedoMap();
1018: }
1019: fc.field.jdoTuple = m;
1020: m.moField = (SpeedoField) fc.field;
1021: List l = (List) fc.fieldChildren.get("map");
1022: if (l != null) {
1023: l = (List) fc.fieldChildren.get("map");
1024: Node mapNode = (Node) l.get(0);
1025: //attribut key-type
1026: Node n = mapNode.getAttributes().getNamedItem("key-type");
1027: if (n != null)
1028: m.keyType = n.getNodeValue();
1029: //attribut embedded-key
1030: n = mapNode.getAttributes().getNamedItem("embedded-key");
1031: if (n != null)
1032: m.embeddedKey = Boolean.valueOf(n.getNodeValue())
1033: .booleanValue();
1034: //attribute value-type
1035: n = mapNode.getAttributes().getNamedItem("value-type");
1036: if (n != null)
1037: m.valueType = n.getNodeValue();
1038: //attribute embedded-value
1039: n = mapNode.getAttributes().getNamedItem("embedded-value");
1040: if (n != null)
1041: m.embeddedValue = Boolean.valueOf(n.getNodeValue())
1042: .booleanValue();
1043: }
1044:
1045: l = (List) fc.fieldChildren.get("key");
1046: if (l != null) {
1047: //<!ELEMENT key (extension*, embedded?, column*, foreign-key?, index?, unique?, extension*)>
1048: //<!ATTLIST key table CDATA #IMPLIED>
1049: //<!ATTLIST key serialized (true|false) #IMPLIED>
1050: //<!ATTLIST key delete-action (restrict|cascade|null|default|none) #IMPLIED>
1051: //<!ATTLIST key indexed (true|false|unique) #IMPLIED>
1052: //<!ATTLIST key unique (true|false) #IMPLIED>
1053: Node keyNode = (Node) l.get(0);
1054: Map keyChildren = groupChildrenByName(keyNode);
1055: if (fc.parseORM()) {
1056: //<!ATTLIST key column CDATA #IMPLIED>
1057: Node n = keyNode.getAttributes().getNamedItem("column");
1058: if (n != null) {
1059: SpeedoColumn col = new SpeedoColumn(n
1060: .getNodeValue());
1061: //in the same table than map value
1062: if (fc.field.columns != null
1063: && fc.field.columns.length > 0) {
1064: col.table = fc.field.columns[0].table;
1065: }
1066: m.keyColumns = col;
1067: }
1068: l = (List) keyChildren.get("column");
1069: if (l != null) {
1070: m.keyColumns = getColumn((Node) l.get(0));
1071: }
1072: fc.parseTableAttribute(keyNode, logger);
1073: }
1074: unmanaged(new String[] { "serialized", "delete-action",
1075: "indexed", "unique" }, new String[] { "embedded",
1076: "foreign-key", "unique", "index" }, keyNode,
1077: keyChildren);
1078: }
1079: l = (List) fc.fieldChildren.get("value");
1080: if (l != null) {
1081: //<!ELEMENT value (extension*, embedded?, column*, foreign-key?, index?, unique?, extension*)>
1082: //<!ATTLIST value serialized (true|false) #IMPLIED>
1083: //<!ATTLIST value table CDATA #IMPLIED>
1084: //<!ATTLIST value delete-action (restrict|cascade|null|default|none) #IMPLIED>
1085: //<!ATTLIST value indexed (true|false|unique) #IMPLIED>
1086: //<!ATTLIST value unique (true|false) #IMPLIED>
1087: Node valueNode = (Node) l.get(0);
1088: Map valueChildren = groupChildrenByName(valueNode);
1089: if (fc.parseORM()) {
1090: //<!ATTLIST value column CDATA #IMPLIED>
1091: Node n = valueNode.getAttributes().getNamedItem(
1092: "column");
1093: if (n != null) {
1094: fc.addColumn(new SpeedoColumn(n.getNodeValue()));
1095: }
1096: l = (List) valueChildren.get("column");
1097: if (l != null) {
1098: for (int i = 0; i < l.size(); i++) {
1099: fc.addColumn(getColumn((Node) l.get(i)));
1100: }
1101: }
1102: fc.parseTableAttribute(valueNode, logger);
1103: }
1104: unmanaged(new String[] { "serialized", "delete-action",
1105: "indexed", "unique" }, new String[] { "embedded",
1106: "foreign-key", "unique", "index" }, valueNode,
1107: valueChildren);
1108: }
1109: if (fc.join != null && fc.field.moClass.containsJoin(fc.join)) {
1110: fc.field.moClass.removeJoin(fc.join);
1111: }
1112: logger.log(BasicLevel.DEBUG, "New map: " + "keyType="
1113: + m.keyType + " / embeddedKey = " + m.embeddedKey
1114: + " / valueType = " + m.valueType
1115: + " / embeddedValue = " + m.embeddedValue);
1116: }
1117:
1118: private void treatCollectionField(FieldContext fc)
1119: throws SpeedoException {
1120: List l = (List) fc.fieldChildren.get("collection");
1121: if (l != null) {
1122: Node collectionNode = (Node) l.get(0);
1123: SpeedoCollection co = (SpeedoCollection) fc.field.jdoTuple;
1124: if (co == null) {
1125: co = new SpeedoCollection();
1126: }
1127: fc.field.jdoTuple = co;
1128: co.moField = (SpeedoField) fc.field;
1129: //attribute element-type
1130: Node n = collectionNode.getAttributes().getNamedItem(
1131: "element-type");
1132: if (n != null)
1133: co.elementType = n.getNodeValue();
1134:
1135: //attribute embedded-element
1136: n = collectionNode.getAttributes().getNamedItem(
1137: "embedded-element");
1138: if (n != null) {
1139: co.embeddedElement = Boolean.valueOf(n.getNodeValue())
1140: .booleanValue();
1141: }
1142: if (debug) {
1143: logger
1144: .log(BasicLevel.DEBUG, "New collection: "
1145: + "elementType=" + co.elementType
1146: + " / embeddedElement = "
1147: + co.embeddedElement);
1148: }
1149: }
1150: l = (List) fc.fieldChildren.get("element");
1151: if (l != null) {
1152: //<!ATTLIST element column CDATA #IMPLIED>
1153: Node elementNode = (Node) l.get(0);
1154: //<!ELEMENT element (extension*, embedded?, column*, foreign-key?,
1155: // index?, unique?, extension*)>
1156: Map elementChildren = groupChildrenByName(elementNode);
1157: if (fc.parseORM()) {
1158: Node n = elementNode.getAttributes().getNamedItem(
1159: "column");
1160: if (n != null) {
1161: fc.addColumn(new SpeedoColumn(n.getNodeValue()));
1162: }
1163: l = (List) elementChildren.get("column");
1164: if (l != null) {
1165: for (int i = 0; i < l.size(); i++) {
1166: fc.addColumn(getColumn((Node) l.get(i)));
1167: }
1168: }
1169: //<!ATTLIST element table CDATA #IMPLIED>
1170: n = elementNode.getAttributes().getNamedItem("table");
1171: if (n != null) {
1172: if (fc.table == null) {
1173: fc.table = new SpeedoTable();
1174: } else {
1175: logger.log(BasicLevel.WARN,
1176: "Specify two tables for the "
1177: + fc.field.getSourceDesc()
1178: + ": " + fc.table.name
1179: + " and " + n.getNodeValue());
1180: }
1181: fc.table.name = n.getNodeValue();
1182: }
1183: }
1184:
1185: unmanaged(new String[] { "serialized", "delete-action",
1186: "update-action", "indexed", "unique" },
1187: new String[] { "embedded", "foreign-key", "unique",
1188: "index" }, elementNode, fc.fieldChildren);
1189: }
1190: if (!fc.parseORM()) {
1191: return;
1192: }
1193: if (fc.join != null && fc.field.moClass.containsJoin(fc.join)) {
1194: fc.field.moClass.removeJoin(fc.join);
1195: }
1196: if (fc.table != null || fc.join != null) {
1197: // The collection is stored in a join table
1198: if (fc.join == null) {
1199: // the user specified a table without join. Maybe the join to
1200: // this table is already defined at class level
1201: SpeedoJoin[] js = fc.field.moClass.joinToExtTables;
1202: if (js != null) {
1203: for (int i = 0; i < js.length; i++) {
1204: if (js[i].extTable != null
1205: && fc.table.name
1206: .equals(js[i].extTable.name)) {
1207: //The join to this table is already defined at class level
1208: // use it
1209: fc.field.join = js[i];
1210: i = js.length;
1211: }
1212: }
1213: if (fc.field.join == null) {
1214: //no existing join found, create a new one
1215: fc.join = new SpeedoJoin();
1216: }
1217: }
1218: }
1219: fc.field.join = fc.join;
1220: fc.field.join.extTable = fc.table;
1221: fc.field.join.mainTable = fc.field.moClass.mainTable;
1222: } else {
1223: // The collection is stored in the table of the referenced state
1224: fc.field.join = new SpeedoJoin();
1225: }
1226: fc.field.columns = fc.getColumns();
1227: }
1228:
1229: private void treatSimpleField(FieldContext fc) {
1230: if (!fc.parseORM()) {
1231: return;
1232: }
1233: //The field is a primitive field OR a mono valued reference to
1234: // another persistent class
1235: if (fc.join != null) { //join sub element specified
1236: if (fc.table == null) { //no table name specified in field
1237: fc.table = new SpeedoTable();
1238: //allocate a defaut name for the secondary table
1239: fc.table.name = fc.field.moClass.name.toUpperCase()
1240: + "_" + fc.field.name.toUpperCase();
1241: }
1242: fc.field.join = fc.join;
1243: fc.field.join.extTable = fc.table;
1244: fc.field.join.mainTable = fc.field.moClass.mainTable;
1245: if (!fc.field.moClass.containsJoin(fc.field.join)) {
1246: fc.field.moClass.addJoin(fc.field.join);
1247: }
1248: } else if (fc.table != null) {
1249: if (fc.field.moClass.mainTable != null
1250: && fc.table.name
1251: .equals(fc.field.moClass.mainTable.name)) {
1252: //the user specified the same table than the main table
1253: // without join.
1254: fc.table = null;
1255: }
1256: if (fc.table != null) {
1257: logger
1258: .log(BasicLevel.INFO,
1259: "The user specified a secondary table without join columns");
1260: if (fc.field.moClass.getExtTable(fc.table.name, false) != fc.table) {
1261: logger
1262: .log(BasicLevel.INFO,
1263: "The user specified a secondary table without join columns");
1264: fc.field.join = new SpeedoJoin();
1265: fc.field.join.mainTable = fc.field.moClass.mainTable;
1266: fc.field.join.extTable = fc.table;
1267: fc.field.moClass.addJoin(fc.field.join);
1268: } else {
1269: logger.log(BasicLevel.DEBUG, "Field '"
1270: + fc.field.name
1271: + " is mapped into the table '"
1272: + fc.table.name + "'.");
1273: }
1274: }
1275: }
1276: if (fc.table == null) {
1277: fc.table = fc.field.moClass.mainTable;
1278: }
1279: if (fc.columns != null) {
1280: for (int i = 0; i < fc.columns.size(); i++) {
1281: SpeedoColumn column = (SpeedoColumn) fc.columns.get(i);
1282: if (column.table == null) {
1283: column.table = fc.table;
1284: }
1285: fc.field.addColumn(column);
1286: logger.log(BasicLevel.DEBUG, "specify column "
1287: + column.name + " to the field "
1288: + fc.field.name + ": " + fc.field.columns);
1289: }
1290: } else {
1291: //no column specified, the mapping will be defined later
1292: // when we will have more information about the field type.
1293: }
1294:
1295: }
1296:
1297: private void treatFetchGroupNode(Node fetchNode, SpeedoClass moClass)
1298: throws SpeedoException {
1299: SpeedoFetchGroup fg = treatFetchGroupTree(fetchNode, moClass);
1300: moClass.fetchGroups.put(fg.name, fg);
1301: }
1302:
1303: private SpeedoFetchGroup treatFetchGroupTree(Node fetchNode,
1304: SpeedoClass fieldOwner) throws SpeedoException {
1305: //<!ELEMENT fetch-group (fetch-group|field)*>
1306: SpeedoFetchGroup fg = new SpeedoFetchGroup();
1307: //<!ATTLIST fetch-group name CDATA #REQUIRED>
1308: fg.name = getStringAttributeValue(fetchNode, "name", null);
1309: //<!ATTLIST fetch-group post-load (true|false) #IMPLIED>
1310: fg.postLoad = getBooleanAttributeValue(fetchNode, "post-load",
1311: false);
1312: Map fgChildren = groupChildrenByName(fetchNode);
1313: List fgs = (List) fgChildren.get("fetch-group");
1314: if (fgs != null) {
1315: for (Iterator fgIt = fgs.iterator(); fgIt.hasNext();) {
1316: Node fgNode = (Node) fgIt.next();
1317: fg
1318: .addFetchGroup(treatFetchGroupTree(fgNode,
1319: fieldOwner));
1320: }
1321: }
1322:
1323: List fields = (List) fgChildren.get("field");
1324: if (fields != null) {
1325: for (Iterator fieldIt = fields.iterator(); fieldIt
1326: .hasNext();) {
1327: Node fieldNode = (Node) fieldIt.next();
1328: SpeedoField sf = new SpeedoField();
1329: sf.name = getStringAttributeValue(fieldNode, "name",
1330: null);
1331: fg.addField(sf);
1332: //depth for a field
1333: String depth = getStringAttributeValue(fieldNode,
1334: "fetch-depth", null);
1335: if (depth == null) {
1336: depth = getStringAttributeValue(fieldNode, "depth",
1337: null);
1338: logger
1339: .log(BasicLevel.WARN,
1340: "attribute 'depth' is deprecated, use 'fetch-depth'.");
1341: }
1342: if (depth != null) {
1343: sf.depth = new Integer(depth).intValue();
1344: }
1345: }
1346: }
1347: return fg;
1348: }
1349:
1350: private static String getStringAttributeValue(Node node,
1351: String attribName, String defaultValue) {
1352: Node n = node.getAttributes().getNamedItem(attribName);
1353: if (n != null) {
1354: return n.getNodeValue();
1355: } else {
1356: return defaultValue;
1357: }
1358: }
1359:
1360: private static boolean getBooleanAttributeValue(Node node,
1361: String attribName, boolean defaultValue) {
1362: Node n = node.getAttributes().getNamedItem(attribName);
1363: if (n != null) {
1364: return Boolean.valueOf(n.getNodeValue()).booleanValue();
1365: } else {
1366: return defaultValue;
1367: }
1368: }
1369:
1370: private void unmanaged(String[] attributeNames, String[] nodeTypes,
1371: Node node, Map type2nodes) {
1372: String parent = node.getNodeName();
1373: if (attributeNames != null) {
1374: for (int i = 0; i < attributeNames.length; i++) {
1375: Node n = node.getAttributes().getNamedItem(
1376: attributeNames[i]);
1377: if (n != null) {
1378: logger.log(BasicLevel.WARN,
1379: "Speedo does not support yet the "
1380: + attributeNames[i]
1381: + " attribute in " + parent
1382: + " tag.");
1383: }
1384: }
1385: }
1386: if (nodeTypes != null) {
1387: for (int i = 0; i < nodeTypes.length; i++) {
1388: List l = (List) type2nodes.get(nodeTypes[i]);
1389: if (l != null) {
1390: for (int j = 0; j < l.size(); j++) {
1391: logger.log(BasicLevel.WARN,
1392: "Speedo does not support yet the "
1393: + nodeTypes[i]
1394: + " sub element in " + parent
1395: + " tag.");
1396: }
1397: }
1398: }
1399: }
1400: }
1401:
1402: private static class FieldContext {
1403: /**
1404: * The Speedo meta object representing the field:
1405: * SpeedoField or SpeedoInheritedField
1406: */
1407: public SpeedoCommonField field;
1408: /**
1409: * The join found associated to this field
1410: */
1411: public SpeedoJoin join;
1412: /**
1413: * The table instance
1414: */
1415: public SpeedoTable table;
1416: public List columns;
1417: public List idxColumns;
1418: public Node fieldNode;
1419: public Map fieldChildren;
1420:
1421: public void addColumn(SpeedoColumn col) {
1422: if (columns == null) {
1423: columns = new ArrayList();
1424: }
1425: columns.add(col);
1426: }
1427:
1428: public boolean parseORM() {
1429: return !(field instanceof SpeedoField)
1430: || !((SpeedoField) field).mappedByReversefield;
1431: }
1432:
1433: public void parseTableAttribute(Node node, Logger logger) {
1434: Node n = fieldNode.getAttributes().getNamedItem("table");
1435: if (n != null) {
1436: join = field.moClass.getJoin(n.getNodeValue(), true);
1437: table = join.extTable;
1438: if (logger.isLoggable(BasicLevel.DEBUG)) {
1439: if (field instanceof SpeedoField) {
1440: logger.log(BasicLevel.DEBUG, "specify table "
1441: + table.name + " to the field "
1442: + field.name + ": " + field.columns);
1443: } else {
1444: logger.log(BasicLevel.DEBUG, "specify table "
1445: + table.name
1446: + " to the inherited field "
1447: + field.name + ": " + field.columns);
1448: }
1449: }
1450: }
1451: }
1452:
1453: public SpeedoColumn[] getColumns() {
1454: if (columns == null || columns.size() == 0) {
1455: return null;
1456: } else {
1457: return (SpeedoColumn[]) columns
1458: .toArray(new SpeedoColumn[columns.size()]);
1459: }
1460: }
1461: }
1462: }
|