001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/metaobj/tags/sakai_2-4-1/metaobj-impl/api-impl/src/java/org/sakaiproject/metaobj/utils/xml/impl/ComplexSchemaNodeImpl.java $
003: * $Id: ComplexSchemaNodeImpl.java 14225 2006-09-05 17:39:44Z chmaurer@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.metaobj.utils.xml.impl;
021:
022: import java.util.ArrayList;
023: import java.util.Hashtable;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027:
028: import org.jdom.Attribute;
029: import org.jdom.Element;
030: import org.sakaiproject.metaobj.utils.xml.NormalizationException;
031: import org.sakaiproject.metaobj.utils.xml.SchemaInvalidException;
032: import org.sakaiproject.metaobj.utils.xml.SchemaNode;
033: import org.sakaiproject.metaobj.utils.xml.ValidatedNode;
034: import org.sakaiproject.metaobj.utils.xml.ValidationError;
035:
036: /**
037: * Created by IntelliJ IDEA.
038: * User: John Ellis
039: * Date: Apr 15, 2004
040: * Time: 3:47:11 PM
041: * To change this template use File | Settings | File Templates.
042: */
043: public class ComplexSchemaNodeImpl extends SchemaNodeImpl {
044:
045: private String[] childrenElements;
046: private Map childrenMap;
047:
048: private String[] childrenAttributes;
049: private Map childrenAttributeMap;
050:
051: private String[] attributeGroupNames;
052:
053: private boolean orderDependant = false;
054: private boolean attributeGroupsSetup = false;
055:
056: private SchemaNode extensionType;
057:
058: public ComplexSchemaNodeImpl(Element schemaElement,
059: GlobalMaps globalMaps) throws SchemaInvalidException {
060: super (schemaElement, globalMaps);
061: }
062:
063: protected void initSchemaElement() {
064: super .initSchemaElement();
065: childrenMap = new Hashtable();
066: childrenAttributeMap = new Hashtable();
067:
068: Element sequenceElement = null;
069: Element attributeParentElement = null;
070:
071: Element complexTypeElement = getSchemaElement().getChild(
072: "complexType", xsdNamespace);
073:
074: attributeParentElement = complexTypeElement;
075:
076: sequenceElement = complexTypeElement.getChild("sequence",
077: xsdNamespace);
078:
079: if (sequenceElement == null) {
080: sequenceElement = complexTypeElement.getChild("choice",
081: xsdNamespace);
082: }
083:
084: if (sequenceElement == null) {
085: Element content = complexTypeElement.getChild(
086: "complexContent", xsdNamespace);
087:
088: if (content == null) {
089: content = complexTypeElement.getChild("simpleContent",
090: xsdNamespace);
091: }
092:
093: Element extension = content.getChild("extension",
094: xsdNamespace);
095: sequenceElement = extension.getChild("sequence",
096: xsdNamespace);
097: attributeParentElement = extension;
098:
099: String baseType = extension.getAttributeValue("base");
100:
101: if (baseType.startsWith(xsdNamespace.getPrefix())) {
102: extensionType = new SimpleSchemaNodeImpl(
103: complexTypeElement, getGlobalMaps(), false);
104: } else {
105: extensionType = new CustomTypeSchemaNodeImpl(
106: complexTypeElement, getGlobalMaps(), baseType,
107: false);
108: }
109: }
110:
111: if (sequenceElement != null) {
112: processSequence(sequenceElement);
113: } else {
114: childrenElements = new String[0];
115: }
116:
117: processAttributes(attributeParentElement.getChildren(
118: "attribute", xsdNamespace));
119:
120: processAttributeGroups(attributeParentElement.getChildren(
121: "attributeGroup", xsdNamespace));
122: }
123:
124: private void processAttributeGroups(List childList) {
125:
126: attributeGroupNames = new String[childList.size()];
127:
128: for (int i = 0; i < attributeGroupNames.length; i++) {
129: Element currentElement = (Element) childList.get(i);
130:
131: attributeGroupNames[i] = currentElement
132: .getAttributeValue("ref");
133: }
134:
135: }
136:
137: protected void processAttributes(List childList) {
138: childrenAttributes = new String[childList.size()];
139:
140: for (int i = 0; i < childrenAttributes.length; i++) {
141: Element currentElement = (Element) childList.get(i);
142:
143: childrenAttributes[i] = currentElement
144: .getAttributeValue("name");
145:
146: if (childrenAttributes[i] == null) {
147: childrenAttributes[i] = currentElement
148: .getAttributeValue("ref");
149: }
150:
151: childrenAttributeMap.put(childrenAttributes[i], createNode(
152: currentElement, true));
153: }
154: }
155:
156: protected void processSequence(Element sequenceElement) {
157: List childList = sequenceElement.getChildren("element",
158: xsdNamespace);
159:
160: childrenElements = new String[childList.size()];
161:
162: for (int i = 0; i < childrenElements.length; i++) {
163: Element currentElement = (Element) childList.get(i);
164:
165: childrenElements[i] = currentElement
166: .getAttributeValue("name");
167:
168: if (childrenElements[i] == null) {
169: childrenElements[i] = currentElement
170: .getAttributeValue("ref");
171: }
172:
173: childrenMap.put(childrenElements[i],
174: createNode(currentElement));
175: }
176:
177: // looking for sequence or all
178: if (sequenceElement.getName().equals("sequence")) {
179: orderDependant = true;
180: }
181: }
182:
183: /**
184: * Validates the passed in node and all children.
185: * Will also normalize any values.
186: *
187: * @param node a jdom element to validate
188: * @return the validated Element wrapped
189: * in a ValidatedNode class
190: */
191: public ValidatedNode validateAndNormalize(Element node) {
192:
193: setupAttributeGroups();
194:
195: ValidatedNodeImpl validatedNode = new ValidatedNodeImpl(this ,
196: node);
197:
198: if (orderDependant) {
199: // todo add ordering check here
200:
201: }
202:
203: for (int i = 0; i < childrenElements.length; i++) {
204: SchemaNode currentSchemaNode = (SchemaNode) childrenMap
205: .get(childrenElements[i]);
206:
207: int actualNumberOfElements = node.getChildren(
208: childrenElements[i]).size();
209:
210: if (actualNumberOfElements == 0
211: && currentSchemaNode.getMinOccurs() == 1) {
212:
213: ValidatedNodeImpl validatedChildNode = new ValidatedNodeImpl(
214: currentSchemaNode, null);
215:
216: validatedChildNode.getErrors().add(
217: new ValidationError(validatedChildNode,
218: "Required field: {0}",
219: new Object[] { childrenElements[i] }));
220: validatedNode.getChildren().add(validatedChildNode);
221: } else if (actualNumberOfElements > currentSchemaNode
222: .getMaxOccurs()
223: && currentSchemaNode.getMaxOccurs() != -1) {
224:
225: ValidatedNodeImpl validatedChildNode = new ValidatedNodeImpl(
226: currentSchemaNode, null);
227:
228: validatedChildNode.getErrors().add(
229: new ValidationError(validatedChildNode,
230: "Too many elements {0}, {1}",
231: new Object[] { childrenElements[i],
232: new Integer(getMaxOccurs()) }));
233: validatedNode.getChildren().add(validatedChildNode);
234: } else if (actualNumberOfElements < currentSchemaNode
235: .getMinOccurs()) {
236:
237: ValidatedNodeImpl validatedChildNode = new ValidatedNodeImpl(
238: currentSchemaNode, null);
239:
240: validatedChildNode.getErrors().add(
241: new ValidationError(validatedChildNode,
242: "Too few elements {0}, {1}",
243: new Object[] { childrenElements[i],
244: new Integer(getMinOccurs()) }));
245: validatedNode.getChildren().add(validatedChildNode);
246: }
247: }
248:
249: List children = node.getChildren();
250:
251: for (Iterator i = children.iterator(); i.hasNext();) {
252: Element currentElement = (Element) i.next();
253:
254: SchemaNode currentSchemaNode = (SchemaNode) childrenMap
255: .get(currentElement.getName());
256:
257: if (currentSchemaNode == null) {
258: validatedNode.getErrors()
259: .add(
260: new ValidationError("Unkown node {0}",
261: new Object[] { currentElement
262: .getName() }));
263: } else {
264: validatedNode.getChildren().add(
265: currentSchemaNode
266: .validateAndNormalize(currentElement));
267: }
268: }
269:
270: children = node.getAttributes();
271:
272: for (Iterator i = children.iterator(); i.hasNext();) {
273: Attribute currentAttribute = (Attribute) i.next();
274:
275: SchemaNode currentSchemaNode = (SchemaNode) childrenAttributeMap
276: .get(currentAttribute.getName());
277:
278: if (currentSchemaNode == null) {
279: validatedNode.getErrors().add(
280: new ValidationError("Unkown node {0}",
281: new Object[] { currentAttribute
282: .getName() }));
283: } else {
284: validatedNode
285: .getChildren()
286: .add(
287: currentSchemaNode
288: .validateAndNormalize(currentAttribute));
289: }
290: }
291:
292: return validatedNode;
293: }
294:
295: protected synchronized void setupAttributeGroups() {
296: if (attributeGroupsSetup) {
297: return;
298: }
299: attributeGroupsSetup = true;
300: List newAttributes = new ArrayList();
301:
302: for (int i = 0; i < attributeGroupNames.length; i++) {
303: SchemaNode[] nodes = (SchemaNode[]) getGlobalMaps().globalAttributeGroups
304: .get(attributeGroupNames[i]);
305:
306: for (int j = 0; j < nodes.length; j++) {
307: newAttributes.add(nodes[j]);
308: }
309: }
310:
311: String[] newAttributeNames = new String[childrenAttributes.length
312: + newAttributes.size()];
313:
314: System.arraycopy(childrenAttributes, 0, newAttributeNames, 0,
315: childrenAttributes.length);
316:
317: int index = childrenAttributes.length;
318:
319: for (Iterator i = newAttributes.iterator(); i.hasNext();) {
320: SchemaNode node = (SchemaNode) i.next();
321: newAttributeNames[index] = node.getName();
322: childrenAttributeMap.put(node.getName(), node);
323: index++;
324: }
325:
326: childrenAttributes = newAttributeNames;
327: }
328:
329: /**
330: * Gets the schema object for the named child node.
331: *
332: * @param elementName the name of the schema node to retrive.
333: * @return
334: */
335: public SchemaNode getChild(String elementName) {
336: if (childrenMap.get(elementName) != null) {
337: return (SchemaNode) childrenMap.get(elementName);
338: } else if (this .getClass().isInstance(extensionType)) {
339: return extensionType.getChild(elementName);
340: }
341:
342: setupAttributeGroups();
343: return (SchemaNode) childrenAttributeMap.get(elementName);
344: }
345:
346: public String getSchemaNormalizedValue(Object value)
347: throws NormalizationException {
348: if (extensionType != null) {
349: return extensionType.getSchemaNormalizedValue(value);
350: }
351:
352: throw new UnsupportedOperationException(
353: "Cannot call this without this being the document node.");
354: }
355:
356: public Class getObjectType() {
357: if (this .getMaxOccurs() > 1) {
358: return List.class;
359: } else {
360: return Map.class;
361: }
362: }
363:
364: public List getChildren() {
365: setupAttributeGroups();
366:
367: List returnedList = new ArrayList();
368:
369: if (extensionType != null
370: && extensionType.getChildren() != null) {
371: returnedList.addAll(extensionType.getChildren());
372: }
373:
374: for (int i = 0; i < childrenElements.length; i++) {
375: returnedList.add(childrenMap.get(childrenElements[i]));
376: }
377:
378: for (int i = 0; i < childrenAttributes.length; i++) {
379: returnedList.add(childrenAttributeMap
380: .get(childrenAttributes[i]));
381: }
382:
383: return returnedList;
384: }
385:
386: public boolean isDataNode() {
387: if (extensionType != null) {
388: return extensionType.isDataNode();
389: } else {
390: return false;
391: }
392: }
393:
394: public boolean hasEnumerations() {
395: if (extensionType != null) {
396: return extensionType.hasEnumerations();
397: } else {
398: return false;
399: }
400: }
401:
402: public List getEnumeration() {
403: if (extensionType != null) {
404: return extensionType.getEnumeration();
405: } else {
406: return super .getEnumeration();
407: }
408: }
409:
410: public Object getActualNormalizedValue(String value)
411: throws NormalizationException {
412: if (extensionType != null) {
413: return extensionType.getActualNormalizedValue(value);
414: } else {
415: return super.getActualNormalizedValue(value);
416: }
417: }
418:
419: }
|