0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.pde.internal.core.schema;
0011:
0012: import java.io.FileNotFoundException;
0013: import java.io.IOException;
0014: import java.io.InputStream;
0015: import java.io.PrintWriter;
0016: import java.net.URL;
0017: import java.util.Collections;
0018: import java.util.Iterator;
0019: import java.util.Locale;
0020: import java.util.Vector;
0021:
0022: import org.eclipse.core.runtime.PlatformObject;
0023: import org.eclipse.pde.core.IModelChangedEvent;
0024: import org.eclipse.pde.core.IModelChangedListener;
0025: import org.eclipse.pde.core.ModelChangedEvent;
0026: import org.eclipse.pde.internal.core.PDECore;
0027: import org.eclipse.pde.internal.core.XMLDefaultHandler;
0028: import org.eclipse.pde.internal.core.ischema.IDocumentSection;
0029: import org.eclipse.pde.internal.core.ischema.IMetaAttribute;
0030: import org.eclipse.pde.internal.core.ischema.ISchema;
0031: import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
0032: import org.eclipse.pde.internal.core.ischema.ISchemaComplexType;
0033: import org.eclipse.pde.internal.core.ischema.ISchemaCompositor;
0034: import org.eclipse.pde.internal.core.ischema.ISchemaDescriptor;
0035: import org.eclipse.pde.internal.core.ischema.ISchemaElement;
0036: import org.eclipse.pde.internal.core.ischema.ISchemaEnumeration;
0037: import org.eclipse.pde.internal.core.ischema.ISchemaInclude;
0038: import org.eclipse.pde.internal.core.ischema.ISchemaObject;
0039: import org.eclipse.pde.internal.core.ischema.ISchemaObjectReference;
0040: import org.eclipse.pde.internal.core.ischema.ISchemaRootElement;
0041: import org.eclipse.pde.internal.core.ischema.ISchemaSimpleType;
0042: import org.eclipse.pde.internal.core.ischema.ISchemaType;
0043: import org.eclipse.pde.internal.core.util.PDEXMLHelper;
0044: import org.eclipse.pde.internal.core.util.SAXParserWrapper;
0045: import org.eclipse.pde.internal.core.util.SchemaUtil;
0046: import org.w3c.dom.NamedNodeMap;
0047: import org.w3c.dom.Node;
0048: import org.w3c.dom.NodeList;
0049: import org.xml.sax.SAXException;
0050:
0051: public class Schema extends PlatformObject implements ISchema {
0052:
0053: private URL fURL;
0054:
0055: private Vector fListeners = new Vector();
0056:
0057: private Vector fElements = new Vector();
0058:
0059: private Vector fDocSections = new Vector();
0060:
0061: private Vector fIncludes;
0062:
0063: private String fPointID;
0064:
0065: private String fPluginID;
0066:
0067: private ISchemaDescriptor fSchemaDescriptor;
0068:
0069: private boolean fLoaded;
0070:
0071: private Vector fReferences;
0072:
0073: private String fDescription;
0074:
0075: private String fName = ""; //$NON-NLS-1$
0076:
0077: private boolean fNotificationEnabled;
0078:
0079: public final static String INDENT = " "; //$NON-NLS-1$
0080:
0081: private boolean fDisposed;
0082:
0083: private boolean fValid;
0084:
0085: private boolean fAbbreviated;
0086:
0087: public Schema(String pluginId, String pointId, String name,
0088: boolean abbreviated) {
0089: fPluginID = pluginId;
0090: fPointID = pointId;
0091: fName = name;
0092: fAbbreviated = abbreviated;
0093: }
0094:
0095: public Schema(ISchemaDescriptor schemaDescriptor, URL url,
0096: boolean abbreviated) {
0097: fSchemaDescriptor = schemaDescriptor;
0098: fURL = url;
0099: fAbbreviated = abbreviated;
0100: }
0101:
0102: public void addDocumentSection(IDocumentSection docSection) {
0103: fDocSections.addElement(docSection);
0104: fireModelChanged(new ModelChangedEvent(this ,
0105: IModelChangedEvent.INSERT, new Object[] { docSection },
0106: null));
0107:
0108: }
0109:
0110: public void addElement(ISchemaElement element) {
0111: addElement(element, null);
0112: }
0113:
0114: public void addElement(ISchemaElement element,
0115: ISchemaElement afterElement) {
0116: int index = -1;
0117: if (afterElement != null) {
0118: index = fElements.indexOf(afterElement);
0119: }
0120: if (index != -1)
0121: fElements.add(index + 1, element);
0122: else
0123: fElements.add(element);
0124: fireModelChanged(new ModelChangedEvent(this ,
0125: IModelChangedEvent.INSERT, new Object[] { element },
0126: null));
0127: }
0128:
0129: public void addInclude(ISchemaInclude include) {
0130: if (fIncludes == null)
0131: fIncludes = new Vector();
0132: fIncludes.add(include);
0133: fireModelChanged(new ModelChangedEvent(this ,
0134: IModelChangedEvent.INSERT, new Object[] { include },
0135: null));
0136: }
0137:
0138: public void removeInclude(ISchemaInclude include) {
0139: if (fIncludes == null)
0140: return;
0141: fIncludes.remove(include);
0142: fireModelChanged(new ModelChangedEvent(this ,
0143: IModelChangedEvent.REMOVE, new Object[] { include },
0144: null));
0145: }
0146:
0147: public void addModelChangedListener(IModelChangedListener listener) {
0148: fListeners.addElement(listener);
0149: }
0150:
0151: private void collectElements(ISchemaCompositor compositor,
0152: Vector result) {
0153: Object[] children = compositor.getChildren();
0154: for (int i = 0; i < children.length; i++) {
0155: Object child = children[i];
0156: if (child instanceof ISchemaCompositor)
0157: collectElements((ISchemaCompositor) child, result);
0158: else if (child instanceof ISchemaObjectReference) {
0159: ISchemaObjectReference ref = (ISchemaObjectReference) child;
0160: Object referenced = ref.getReferencedObject();
0161: if (referenced instanceof ISchemaElement)
0162: result.addElement(referenced);
0163: }
0164: }
0165: }
0166:
0167: public void dispose() {
0168: if (fIncludes != null) {
0169: for (int i = 0; i < fIncludes.size(); i++) {
0170: ISchemaInclude include = (ISchemaInclude) fIncludes
0171: .get(i);
0172: include.dispose();
0173: }
0174: }
0175: reset();
0176: fDisposed = true;
0177: }
0178:
0179: public ISchemaElement findElement(String name) {
0180: if (!isLoaded())
0181: load();
0182: for (int i = 0; i < fElements.size(); i++) {
0183: ISchemaElement element = (ISchemaElement) fElements
0184: .elementAt(i);
0185: if (element.getName().equals(name))
0186: return element;
0187: }
0188: if (fIncludes != null) {
0189: for (int i = 0; i < fIncludes.size(); i++) {
0190: ISchemaInclude include = (ISchemaInclude) fIncludes
0191: .get(i);
0192: ISchema ischema = include.getIncludedSchema();
0193: if (ischema == null)
0194: continue;
0195: ISchemaElement element = ischema.findElement(name);
0196: if (element != null)
0197: return element;
0198: }
0199: }
0200: return null;
0201: }
0202:
0203: public void fireModelChanged(IModelChangedEvent event) {
0204: if (!fNotificationEnabled)
0205: return;
0206: for (Iterator iter = fListeners.iterator(); iter.hasNext();) {
0207: IModelChangedListener listener = (IModelChangedListener) iter
0208: .next();
0209: listener.modelChanged(event);
0210: }
0211: }
0212:
0213: public void fireModelObjectChanged(Object object, String property,
0214: Object oldValue, Object newValue) {
0215: fireModelChanged(new ModelChangedEvent(this , object, property,
0216: oldValue, newValue));
0217: }
0218:
0219: private String getAttribute(Node node, String name) {
0220: NamedNodeMap map = node.getAttributes();
0221: Node attNode = map.getNamedItem(name);
0222: if (attNode != null) {
0223: String value = attNode.getNodeValue();
0224: if (value.length() > 0)
0225: return value;
0226: }
0227: return null;
0228: }
0229:
0230: public ISchemaElement[] getCandidateChildren(ISchemaElement element) {
0231: Vector candidates = new Vector();
0232: ISchemaType type = element.getType();
0233: if (type instanceof ISchemaComplexType) {
0234: ISchemaCompositor compositor = ((ISchemaComplexType) type)
0235: .getCompositor();
0236: if (compositor != null)
0237: collectElements(compositor, candidates);
0238: }
0239: ISchemaElement[] result = new ISchemaElement[candidates.size()];
0240: candidates.copyInto(result);
0241: return result;
0242: }
0243:
0244: public String getDescription() {
0245: return fDescription;
0246: }
0247:
0248: public boolean isValid() {
0249: return fValid;
0250: }
0251:
0252: public IDocumentSection[] getDocumentSections() {
0253: IDocumentSection[] result = new IDocumentSection[fDocSections
0254: .size()];
0255: fDocSections.copyInto(result);
0256: return result;
0257: }
0258:
0259: public int getElementCount() {
0260: return fElements.size();
0261: }
0262:
0263: public int getResolvedElementCount() {
0264: int localCount = getElementCount();
0265: if (fIncludes == null)
0266: return localCount;
0267: int totalCount = localCount;
0268: for (int i = 0; i < fIncludes.size(); i++) {
0269: ISchemaInclude include = (ISchemaInclude) fIncludes.get(i);
0270: ISchema schema = include.getIncludedSchema();
0271: if (schema == null)
0272: continue;
0273: totalCount += schema.getResolvedElementCount();
0274: }
0275: return totalCount;
0276: }
0277:
0278: public ISchemaElement[] getElements() {
0279: if (!isLoaded())
0280: load();
0281: ISchemaElement[] result = new ISchemaElement[fElements.size()];
0282: fElements.copyInto(result);
0283: return result;
0284: }
0285:
0286: public String[] getElementNames() {
0287: ISchemaElement[] elements = getElements();
0288: String[] names = new String[elements.length];
0289: for (int i = 0; i < elements.length; i++)
0290: names[i] = elements[i].getName();
0291: return names;
0292: }
0293:
0294: public ISchemaElement[] getResolvedElements() {
0295: if (fIncludes == null)
0296: return getElements();
0297: if (!isLoaded())
0298: load();
0299: Vector result = (Vector) fElements.clone();
0300: for (int i = 0; i < fIncludes.size(); i++) {
0301: ISchemaInclude include = (ISchemaInclude) fIncludes.get(i);
0302: ISchema schema = include.getIncludedSchema();
0303: if (schema == null)
0304: continue;
0305: ISchemaElement[] ielements = schema.getElements();
0306: for (int j = 0; j < ielements.length; j++)
0307: result.add(ielements[j]);
0308: }
0309: return (ISchemaElement[]) result
0310: .toArray(new ISchemaElement[result.size()]);
0311: }
0312:
0313: public ISchemaInclude[] getIncludes() {
0314: if (fIncludes == null)
0315: return new ISchemaInclude[0];
0316: return (ISchemaInclude[]) fIncludes
0317: .toArray(new ISchemaInclude[fIncludes.size()]);
0318: }
0319:
0320: public String getName() {
0321: return fName;
0322: }
0323:
0324: private String getNormalizedText(String source) {
0325: if (source == null)
0326: return ""; //$NON-NLS-1$
0327:
0328: String result = source.replace('\t', ' ');
0329: result = result.trim();
0330: return result;
0331: }
0332:
0333: public ISchemaObject getParent() {
0334: return null;
0335: }
0336:
0337: public void setParent(ISchemaObject obj) {
0338: }
0339:
0340: public ISchemaElement getElementAt(int index) {
0341: return (ISchemaElement) fElements.get(index);
0342: }
0343:
0344: public String getQualifiedPointId() {
0345: return fPluginID + "." + fPointID; //$NON-NLS-1$
0346: }
0347:
0348: public String getPluginId() {
0349: return fPluginID;
0350: }
0351:
0352: public String getPointId() {
0353: return fPointID;
0354: }
0355:
0356: public ISchema getSchema() {
0357: return this ;
0358: }
0359:
0360: public ISchemaDescriptor getSchemaDescriptor() {
0361: return fSchemaDescriptor;
0362: }
0363:
0364: public URL getURL() {
0365: return fURL;
0366: }
0367:
0368: public int indexOf(Object obj) {
0369: return fElements.indexOf(obj);
0370: }
0371:
0372: public boolean isDisposed() {
0373: return fDisposed;
0374: }
0375:
0376: public boolean isEditable() {
0377: return false;
0378: }
0379:
0380: public boolean isLoaded() {
0381: return fLoaded;
0382: }
0383:
0384: public boolean isNotificationEnabled() {
0385: return fNotificationEnabled;
0386: }
0387:
0388: public void load() {
0389: InputStream input = null;
0390: try {
0391: input = SchemaUtil.getInputStream(fURL);
0392: load(input);
0393: } catch (FileNotFoundException e) {
0394: fLoaded = false;
0395: } catch (IOException e) {
0396: PDECore.logException(e);
0397: } finally {
0398: try {
0399: if (input != null)
0400: input.close();
0401: } catch (IOException e1) {
0402: }
0403: }
0404: }
0405:
0406: public void load(InputStream stream) {
0407: try {
0408: SAXParserWrapper parser = new SAXParserWrapper();
0409: XMLDefaultHandler handler = new XMLDefaultHandler(
0410: fAbbreviated);
0411: parser.parse(stream, handler);
0412: traverseDocumentTree(handler.getDocumentElement());
0413: } catch (SAXException e) {
0414: // ignore parse errors - 'loaded' will be false anyway
0415: } catch (Exception e) {
0416: PDECore.logException(e);
0417: }
0418: }
0419:
0420: private ISchemaAttribute processAttribute(ISchemaElement element,
0421: Node elementNode) {
0422: String aname = getAttribute(elementNode, "name"); //$NON-NLS-1$
0423: if (aname == null)
0424: return null;
0425: String atype = getAttribute(elementNode, "type"); //$NON-NLS-1$
0426: String ause = getAttribute(elementNode, "use"); //$NON-NLS-1$
0427: String avalue = getAttribute(elementNode, "value"); //$NON-NLS-1$
0428: ISchemaSimpleType type = null;
0429: if (atype != null) {
0430: type = (ISchemaSimpleType) resolveTypeReference(atype);
0431: }
0432: SchemaAttribute attribute = new SchemaAttribute(element, aname);
0433: //attribute.bindSourceLocation(elementNode, lineTable);
0434: if (ause != null) {
0435: int use = ISchemaAttribute.OPTIONAL;
0436: if (ause.equals("required")) //$NON-NLS-1$
0437: use = ISchemaAttribute.REQUIRED;
0438: else if (ause.equals("optional")) //$NON-NLS-1$
0439: use = ISchemaAttribute.OPTIONAL;
0440: else if (ause.equals("default")) //$NON-NLS-1$
0441: use = ISchemaAttribute.DEFAULT;
0442: attribute.setUse(use);
0443: }
0444: if (avalue != null)
0445: attribute.setValue(avalue);
0446: NodeList children = elementNode.getChildNodes();
0447: for (int i = 0; i < children.getLength(); i++) {
0448: Node child = children.item(i);
0449: if (child.getNodeType() == Node.ELEMENT_NODE) {
0450: String tag = child.getNodeName();
0451: if (tag.equals("annotation")) { //$NON-NLS-1$
0452: processAttributeAnnotation(attribute, child);
0453: } else if (tag.equals("simpleType")) { //$NON-NLS-1$
0454: processAttributeSimpleType(attribute, child);
0455: }
0456: }
0457: }
0458: if (type != null && attribute.getType() == null)
0459: attribute.setType(type);
0460: return attribute;
0461: }
0462:
0463: private void processAttributeAnnotation(SchemaAttribute element,
0464: Node node) {
0465: NodeList children = node.getChildNodes();
0466: for (int i = 0; i < children.getLength(); i++) {
0467: Node child = children.item(i);
0468: if (child.getNodeType() == Node.ELEMENT_NODE) {
0469: if (child.getNodeName().equals("documentation")) { //$NON-NLS-1$
0470: Node doc = child.getFirstChild();
0471: if (doc != null)
0472: element.setDescription(getNormalizedText(doc
0473: .getNodeValue()));
0474: } else if (child.getNodeName().equals("appInfo")) { //$NON-NLS-1$
0475: NodeList infos = child.getChildNodes();
0476: for (int j = 0; j < infos.getLength(); j++) {
0477: Node meta = infos.item(j);
0478: if (meta.getNodeType() == Node.ELEMENT_NODE) {
0479: if (meta.getNodeName().equals(
0480: "meta.attribute")) { //$NON-NLS-1$
0481: element
0482: .setKind(processKind(getAttribute(
0483: meta, "kind"))); //$NON-NLS-1$
0484: element.setBasedOn(getAttribute(meta,
0485: "basedOn")); //$NON-NLS-1$
0486: element
0487: .setTranslatableProperty(processTranslatable(getAttribute(
0488: meta, "translatable"))); //$NON-NLS-1$
0489: element
0490: .setDeprecatedProperty(processDeprecated(getAttribute(
0491: meta, "deprecated"))); //$NON-NLS-1$
0492: }
0493: }
0494: }
0495: }
0496: }
0497: }
0498: }
0499:
0500: private boolean processTranslatable(String value) {
0501: return (value != null && "true".equals(value)); //$NON-NLS-1$
0502: }
0503:
0504: private boolean processDeprecated(String value) {
0505: return value != null && "true".equals(value); //$NON-NLS-1$
0506: }
0507:
0508: private SchemaSimpleType processAttributeRestriction(
0509: SchemaAttribute attribute, Node node) {
0510: NodeList children = node.getChildNodes();
0511: if (children.getLength() == 0)
0512: return null;
0513: String baseName = getAttribute(node, "base"); //$NON-NLS-1$
0514: if (baseName.equals("string") == false) { //$NON-NLS-1$
0515: return new SchemaSimpleType(attribute.getSchema(), "string"); //$NON-NLS-1$
0516: }
0517: SchemaSimpleType type = new SchemaSimpleType(attribute
0518: .getSchema(), baseName);
0519: Vector items = new Vector();
0520: for (int i = 0; i < children.getLength(); i++) {
0521: Node child = children.item(i);
0522: if (child.getNodeType() == Node.ELEMENT_NODE) {
0523: if (child.getNodeName().equals("enumeration")) { //$NON-NLS-1$
0524: ISchemaEnumeration enumeration = processEnumeration(
0525: attribute.getSchema(), child);
0526: if (enumeration != null)
0527: items.addElement(enumeration);
0528: }
0529: }
0530: }
0531: ChoiceRestriction restriction = new ChoiceRestriction(attribute
0532: .getSchema());
0533: restriction.setChildren(items);
0534: type.setRestriction(restriction);
0535: return type;
0536: }
0537:
0538: private void processAttributeSimpleType(SchemaAttribute attribute,
0539: Node node) {
0540: NodeList children = node.getChildNodes();
0541: if (children.getLength() == 0)
0542: return;
0543: SchemaSimpleType type = null;
0544: for (int i = 0; i < children.getLength(); i++) {
0545: Node child = children.item(i);
0546: if (child.getNodeType() == Node.ELEMENT_NODE) {
0547: if (child.getNodeName().equals("restriction")) { //$NON-NLS-1$
0548: type = processAttributeRestriction(attribute, child);
0549: }
0550: }
0551: }
0552: if (type != null)
0553: attribute.setType(type);
0554: }
0555:
0556: private SchemaComplexType processComplexType(ISchemaElement owner,
0557: Node typeNode) {
0558: String aname = getAttribute(typeNode, "name"); //$NON-NLS-1$
0559: String amixed = getAttribute(typeNode, "mixed"); //$NON-NLS-1$
0560: SchemaComplexType complexType = new SchemaComplexType(this ,
0561: aname);
0562: if (amixed != null && amixed.equals("true")) //$NON-NLS-1$
0563: complexType.setMixed(true);
0564: NodeList children = typeNode.getChildNodes();
0565: ISchemaCompositor compositor = null;
0566: for (int i = 0; i < children.getLength(); i++) {
0567: Node child = children.item(i);
0568: if (child.getNodeType() == Node.ELEMENT_NODE) {
0569: if (child.getNodeName().equals("attribute")) { //$NON-NLS-1$
0570: complexType.addAttribute(processAttribute(owner,
0571: child));
0572: } else {
0573: ISchemaObject object = processCompositorChild(
0574: owner, child, ISchemaCompositor.ROOT);
0575: if (object instanceof ISchemaCompositor
0576: && compositor == null) {
0577: compositor = (ISchemaCompositor) object;
0578: }
0579: }
0580: }
0581: }
0582: complexType.setCompositor(compositor);
0583: return complexType;
0584: }
0585:
0586: private ISchemaCompositor processCompositor(ISchemaObject parent,
0587: Node node, int type) {
0588: SchemaCompositor compositor = new SchemaCompositor(parent, type);
0589: NodeList children = node.getChildNodes();
0590: int minOccurs = 1;
0591: int maxOccurs = 1;
0592: String aminOccurs = getAttribute(node, "minOccurs"); //$NON-NLS-1$
0593: String amaxOccurs = getAttribute(node, "maxOccurs"); //$NON-NLS-1$
0594: if (aminOccurs != null)
0595: minOccurs = Integer.valueOf(aminOccurs).intValue();
0596: if (amaxOccurs != null) {
0597: if (amaxOccurs.equals("unbounded")) //$NON-NLS-1$
0598: maxOccurs = Integer.MAX_VALUE;
0599: else {
0600: maxOccurs = Integer.valueOf(amaxOccurs).intValue();
0601: }
0602: }
0603: compositor.setMinOccurs(minOccurs);
0604: compositor.setMaxOccurs(maxOccurs);
0605: for (int i = 0; i < children.getLength(); i++) {
0606: Node child = children.item(i);
0607: ISchemaObject object = processCompositorChild(compositor,
0608: child, type);
0609: if (object != null)
0610: compositor.addChild(object);
0611: }
0612: return compositor;
0613: }
0614:
0615: private ISchemaObject processCompositorChild(ISchemaObject parent,
0616: Node child, int parentKind) {
0617: String tag = child.getNodeName();
0618: if (tag.equals("element") && parentKind != ISchemaCompositor.ROOT) { //$NON-NLS-1$
0619: return processElement(parent, child);
0620: }
0621: // sequence: element | group | choice | sequence
0622: if (tag.equals("sequence") && parentKind != ISchemaCompositor.ALL) { //$NON-NLS-1$
0623: return processCompositor(parent, child,
0624: ISchemaCompositor.SEQUENCE);
0625: }
0626: // choice: element | group | choice | sequence
0627: if (tag.equals("choice") && parentKind != ISchemaCompositor.ALL) { //$NON-NLS-1$
0628: return processCompositor(parent, child,
0629: ISchemaCompositor.CHOICE);
0630: }
0631: // all: element
0632: if (tag.equals("all") //$NON-NLS-1$
0633: && (parentKind == ISchemaCompositor.ROOT || parentKind == ISchemaCompositor.GROUP)) {
0634: return processCompositor(parent, child,
0635: ISchemaCompositor.SEQUENCE);
0636: }
0637: // group: all | choice | sequence
0638: if (tag.equals("group") //$NON-NLS-1$
0639: && (parentKind == ISchemaCompositor.CHOICE || parentKind == ISchemaCompositor.SEQUENCE)) {
0640: return processCompositor(parent, child,
0641: ISchemaCompositor.SEQUENCE);
0642: }
0643: return null;
0644: }
0645:
0646: private ISchemaElement processElement(ISchemaObject parent,
0647: Node elementNode) {
0648: if (parent instanceof ISchemaCompositor)
0649: return processElementReference((ISchemaCompositor) parent,
0650: elementNode);
0651: return processElementDeclaration(parent, elementNode);
0652: }
0653:
0654: private ISchemaElement processElementDeclaration(
0655: ISchemaObject parent, Node elementNode) {
0656: String aname = getAttribute(elementNode, "name"); //$NON-NLS-1$
0657: if (aname == null)
0658: return null;
0659: String atype = getAttribute(elementNode, "type"); //$NON-NLS-1$
0660: int minOccurs = getMinOccurs(elementNode);
0661: int maxOccurs = getMaxOccurs(elementNode);
0662:
0663: ISchemaType type = null;
0664: if (atype != null) {
0665: type = resolveTypeReference(atype);
0666: }
0667: SchemaElement element;
0668: if (aname.equals("extension")) //$NON-NLS-1$
0669: element = new SchemaRootElement(parent, aname);
0670: else
0671: element = new SchemaElement(parent, aname);
0672: //element.bindSourceLocation(elementNode, lineTable);
0673: element.setMinOccurs(minOccurs);
0674: element.setMaxOccurs(maxOccurs);
0675: NodeList children = elementNode.getChildNodes();
0676: for (int i = 0; i < children.getLength(); i++) {
0677: Node child = children.item(i);
0678: if (child.getNodeType() == Node.ELEMENT_NODE) {
0679: String tag = child.getNodeName();
0680: if (type == null && tag.equals("complexType")) { //$NON-NLS-1$
0681: type = processComplexType(element, child);
0682: }
0683: if (tag.equals("annotation")) { //$NON-NLS-1$
0684: processElementAnnotation(element, child);
0685: }
0686: }
0687: }
0688: element.setType(type);
0689: return element;
0690: }
0691:
0692: private ISchemaElement processElementReference(
0693: ISchemaCompositor compositor, Node elementNode) {
0694: String aref = getAttribute(elementNode, "ref"); //$NON-NLS-1$
0695: if (aref == null) {
0696: return null;
0697: }
0698: int minOccurs = getMinOccurs(elementNode);
0699: int maxOccurs = getMaxOccurs(elementNode);
0700:
0701: SchemaElementReference reference = new SchemaElementReference(
0702: compositor, aref);
0703: reference.addComments(elementNode);
0704: reference.setMinOccurs(minOccurs);
0705: reference.setMaxOccurs(maxOccurs);
0706: fReferences.addElement(reference);
0707: //reference.bindSourceLocation(elementNode, lineTable);
0708: return reference;
0709: }
0710:
0711: private int getMinOccurs(Node elementNode) {
0712: String aminOccurs = getAttribute(elementNode, "minOccurs"); //$NON-NLS-1$
0713: if (aminOccurs != null)
0714: return Integer.valueOf(aminOccurs).intValue();
0715: return 1;
0716:
0717: }
0718:
0719: private int getMaxOccurs(Node elementNode) {
0720: String amaxOccurs = getAttribute(elementNode, "maxOccurs"); //$NON-NLS-1$
0721: if (amaxOccurs != null) {
0722: if (amaxOccurs.equals("unbounded")) //$NON-NLS-1$
0723: return Integer.MAX_VALUE;
0724: return Integer.valueOf(amaxOccurs).intValue();
0725: }
0726: return 1;
0727: }
0728:
0729: private void processElementAnnotation(SchemaElement element,
0730: Node node) {
0731: NodeList children = node.getChildNodes();
0732: for (int i = 0; i < children.getLength(); i++) {
0733: Node child = children.item(i);
0734: if (child.getNodeType() == Node.ELEMENT_NODE) {
0735: if (child.getNodeName().equals("documentation") && !fAbbreviated) { //$NON-NLS-1$
0736: element.setDescription(getNormalizedText(child
0737: .getFirstChild().getNodeValue()));
0738: } else if (child.getNodeName().equals("appInfo")) { //$NON-NLS-1$
0739: NodeList infos = child.getChildNodes();
0740: for (int j = 0; j < infos.getLength(); j++) {
0741: Node meta = infos.item(j);
0742: if (meta.getNodeType() == Node.ELEMENT_NODE) {
0743: if (meta.getNodeName().equals(
0744: "meta.element")) { //$NON-NLS-1$
0745: element.setLabelProperty(getAttribute(
0746: meta, "labelAttribute")); //$NON-NLS-1$
0747: element.setIconProperty(getAttribute(
0748: meta, "icon")); //$NON-NLS-1$
0749: if (element.getIconProperty() == null)
0750: element
0751: .setIconProperty(getAttribute(
0752: meta, "iconName")); //$NON-NLS-1$
0753: element
0754: .setTranslatableProperty(processTranslatable(getAttribute(
0755: meta, "translatable"))); //$NON-NLS-1$
0756: element
0757: .setDeprecatedProperty(processDeprecated(getAttribute(
0758: meta, "deprecated"))); //$NON-NLS-1$
0759: if (element instanceof ISchemaRootElement) {
0760: String depSug = getAttribute(
0761: meta,
0762: SchemaRootElement.P_DEP_REPLACEMENT);
0763: ((ISchemaRootElement) element)
0764: .setDeprecatedSuggestion(depSug);
0765: }
0766: }
0767: }
0768: }
0769: }
0770: }
0771: }
0772: }
0773:
0774: private ISchemaEnumeration processEnumeration(ISchema schema,
0775: Node node) {
0776: String name = getAttribute(node, "value"); //$NON-NLS-1$
0777: return new SchemaEnumeration(schema, name);
0778: }
0779:
0780: private int processKind(String name) {
0781: if (name != null) {
0782: if (name.equals("java")) //$NON-NLS-1$
0783: return IMetaAttribute.JAVA;
0784: if (name.equals("resource")) //$NON-NLS-1$
0785: return IMetaAttribute.RESOURCE;
0786: }
0787: return IMetaAttribute.STRING;
0788: }
0789:
0790: private void processSchemaAnnotation(Node node) {
0791: NodeList children = node.getChildNodes();
0792: String section = "overview"; //$NON-NLS-1$
0793: String sectionName = "Overview"; //$NON-NLS-1$
0794: for (int i = 0; i < children.getLength(); i++) {
0795: Node child = children.item(i);
0796: if (child.getNodeType() == Node.ELEMENT_NODE) {
0797: if (child.getNodeName().equals("documentation") && !fAbbreviated) { //$NON-NLS-1$
0798: String text = getNormalizedText(child
0799: .getFirstChild().getNodeValue());
0800: if (section != null) {
0801: if (section.equals("overview")) { //$NON-NLS-1$
0802: setDescription(text);
0803: } else {
0804: DocumentSection sec = new DocumentSection(
0805: this , section, sectionName);
0806: sec.setDescription(text);
0807: fDocSections.addElement(sec);
0808: }
0809: }
0810: } else if (child.getNodeName().equals("appInfo")) { //$NON-NLS-1$
0811: NodeList infos = child.getChildNodes();
0812: for (int j = 0; j < infos.getLength(); j++) {
0813: Node meta = infos.item(j);
0814: if (meta.getNodeType() == Node.ELEMENT_NODE) {
0815: if (meta.getNodeName()
0816: .equals("meta.schema")) { //$NON-NLS-1$
0817: section = "overview"; //$NON-NLS-1$
0818: setName(getAttribute(meta, "name")); //$NON-NLS-1$
0819: fPluginID = getAttribute(meta, "plugin"); //$NON-NLS-1$
0820: fPointID = getAttribute(meta, "id"); //$NON-NLS-1$
0821: fValid = true;
0822: } else if (meta.getNodeName().equals(
0823: "meta.section")) { //$NON-NLS-1$
0824: section = getAttribute(meta, "type"); //$NON-NLS-1$
0825: sectionName = getAttribute(meta, "name"); //$NON-NLS-1$
0826: if (sectionName == null)
0827: sectionName = section;
0828: }
0829: }
0830: }
0831: }
0832: }
0833: }
0834: }
0835:
0836: private void processInclude(Node node) {
0837: String location = getAttribute(node, "schemaLocation"); //$NON-NLS-1$
0838: SchemaInclude include = new SchemaInclude(this , location,
0839: fAbbreviated);
0840: if (fIncludes == null)
0841: fIncludes = new Vector();
0842: fIncludes.add(include);
0843: }
0844:
0845: public void reload() {
0846: reload(null);
0847: }
0848:
0849: public void reload(InputStream is) {
0850: setNotificationEnabled(false);
0851: reset();
0852: if (is != null)
0853: load(is);
0854: else
0855: load();
0856: setNotificationEnabled(true);
0857: if (isLoaded())
0858: fireModelChanged(new ModelChangedEvent(this ,
0859: IModelChangedEvent.WORLD_CHANGED, new Object[0],
0860: null));
0861: }
0862:
0863: public void removeDocumentSection(IDocumentSection docSection) {
0864: fDocSections.removeElement(docSection);
0865: fireModelChanged(new ModelChangedEvent(this ,
0866: IModelChangedEvent.REMOVE, new Object[] { docSection },
0867: null));
0868: }
0869:
0870: public void moveElementToSibling(ISchemaElement element,
0871: ISchemaObject sibling) {
0872: if (!isLoaded())
0873: load();
0874: int index = fElements.indexOf(element);
0875: int newIndex;
0876: if (sibling != null && fElements.contains(sibling))
0877: newIndex = fElements.indexOf(sibling);
0878: else
0879: newIndex = fElements.size() - 1;
0880:
0881: if (index > newIndex) {
0882: for (int i = index; i > newIndex; i--) {
0883: fElements.set(i, fElements.elementAt(i - 1));
0884: }
0885: } else if (index < newIndex) {
0886: for (int i = index; i < newIndex; i++) {
0887: fElements.set(i, fElements.elementAt(i + 1));
0888: }
0889: } else
0890: // don't need to move
0891: return;
0892: fElements.set(newIndex, element);
0893: fireModelChanged(new ModelChangedEvent(this ,
0894: IModelChangedEvent.CHANGE, new Object[] { this }, null));
0895: }
0896:
0897: public void removeElement(ISchemaElement element) {
0898: fElements.removeElement(element);
0899: fireModelChanged(new ModelChangedEvent(this ,
0900: IModelChangedEvent.REMOVE, new Object[] { element },
0901: null));
0902: }
0903:
0904: public void removeModelChangedListener(
0905: IModelChangedListener listener) {
0906: fListeners.removeElement(listener);
0907: }
0908:
0909: private void reset() {
0910: fElements = new Vector();
0911: fDocSections = new Vector();
0912: fIncludes = null;
0913: fPointID = null;
0914: fPluginID = null;
0915: fReferences = null;
0916: fDescription = null;
0917: fName = null;
0918: fValid = false;
0919: fLoaded = false;
0920: }
0921:
0922: private void resolveElementReference(
0923: ISchemaObjectReference reference) {
0924: ISchemaElement[] elementList = getResolvedElements();
0925: for (int i = 0; i < elementList.length; i++) {
0926: ISchemaElement element = elementList[i];
0927: if (!(element instanceof ISchemaObjectReference)
0928: && element.getName().equals(reference.getName())) {
0929: // Link
0930: reference.setReferencedObject(element);
0931: break;
0932: }
0933: }
0934: }
0935:
0936: private void resolveReference(ISchemaObjectReference reference) {
0937: Class clazz = reference.getReferencedObjectClass();
0938: if (clazz.equals(ISchemaElement.class)) {
0939: resolveElementReference(reference);
0940: }
0941: }
0942:
0943: private void resolveReferences(Vector references) {
0944: for (int i = 0; i < references.size(); i++) {
0945: ISchemaObjectReference reference = (ISchemaObjectReference) references
0946: .elementAt(i);
0947: resolveReference(reference);
0948: }
0949: }
0950:
0951: private SchemaType resolveTypeReference(String typeName) {
0952: // for now, create a simple type
0953: return new SchemaSimpleType(this , typeName);
0954: }
0955:
0956: public void setDescription(String newDescription) {
0957: String oldValue = fDescription;
0958: fDescription = newDescription;
0959: fireModelObjectChanged(this , P_DESCRIPTION, oldValue,
0960: fDescription);
0961: }
0962:
0963: public void setName(String newName) {
0964: if (newName == null)
0965: newName = ""; //$NON-NLS-1$
0966: String oldValue = fName;
0967: fName = newName;
0968: fireModelObjectChanged(this , P_NAME, oldValue, fName);
0969: }
0970:
0971: public void setPluginId(String newId) {
0972: String oldValue = fPluginID;
0973: fPluginID = newId;
0974: fireModelObjectChanged(this , P_PLUGIN, oldValue, newId);
0975: }
0976:
0977: public void setPointId(String newId) {
0978: String oldValue = fPointID;
0979: fPointID = newId;
0980: fireModelObjectChanged(this , P_POINT, oldValue, newId);
0981: }
0982:
0983: public void setNotificationEnabled(boolean newNotificationEnabled) {
0984: fNotificationEnabled = newNotificationEnabled;
0985: }
0986:
0987: public String toString() {
0988: return fName;
0989: }
0990:
0991: public void traverseDocumentTree(Node root) {
0992: if (root == null)
0993: return;
0994: NodeList children = root.getChildNodes();
0995: fReferences = new Vector();
0996: for (int i = 0; i < children.getLength(); i++) {
0997: Node child = children.item(i);
0998: if (child.getNodeType() == Node.ELEMENT_NODE) {
0999: String nodeName = child.getNodeName().toLowerCase(
1000: Locale.ENGLISH);
1001: if (nodeName.equals("element")) { //$NON-NLS-1$
1002: ISchemaElement element = processElement(this , child);
1003: if (element == null) {
1004: fValid = false;
1005: return;
1006: }
1007: ISchemaAttribute[] attributes = element
1008: .getAttributes();
1009: for (int j = 0; j < attributes.length; j++)
1010: if (attributes[j] == null) {
1011: fValid = false;
1012: return;
1013: }
1014: fElements.addElement(element);
1015: } else if (nodeName.equals("annotation")) { //$NON-NLS-1$
1016: processSchemaAnnotation(child);
1017: } else if (nodeName.equals("include")) { //$NON-NLS-1$
1018: processInclude(child);
1019: }
1020: }
1021: }
1022: addOmittedDocumentSections();
1023: fLoaded = true;
1024: if (fReferences.size() > 0)
1025: resolveReferences(fReferences);
1026: fReferences = null;
1027: }
1028:
1029: private void addOmittedDocumentSections() {
1030: for (int i = 0; i < DocumentSection.DOC_SECTIONS.length; i++) {
1031: DocumentSection section = new DocumentSection(this ,
1032: DocumentSection.DOC_SECTIONS[i], null);
1033: if (!fDocSections.contains(section)) {
1034: addDocumentSection(section);
1035: }
1036: }
1037: Collections.sort(fDocSections);
1038: }
1039:
1040: public void updateReferencesFor(ISchemaElement element) {
1041: updateReferencesFor(element, ISchema.REFRESH_RENAME);
1042: }
1043:
1044: public void updateReferencesFor(ISchemaElement element, int kind) {
1045: for (int i = 0; i < fElements.size(); i++) {
1046: ISchemaElement el = (ISchemaElement) fElements.elementAt(i);
1047: if (el.equals(element))
1048: continue;
1049: ISchemaType type = el.getType();
1050: if (type instanceof ISchemaComplexType) {
1051: SchemaCompositor compositor = (SchemaCompositor) ((ISchemaComplexType) type)
1052: .getCompositor();
1053: if (compositor != null)
1054: compositor.updateReferencesFor(element, kind);
1055: }
1056: }
1057: }
1058:
1059: public void write(String indent, PrintWriter writer) {
1060: writer.println("<?xml version='1.0' encoding='UTF-8'?>"); //$NON-NLS-1$
1061: writer.println("<!-- Schema file written by PDE -->"); //$NON-NLS-1$
1062: writer
1063: .println("<schema targetNamespace=\"" + fPluginID + "\">"); //$NON-NLS-1$ //$NON-NLS-2$
1064: String indent2 = INDENT + INDENT;
1065: String indent3 = indent2 + INDENT;
1066: writer.println(indent + "<annotation>"); //$NON-NLS-1$
1067: writer.println(indent2 + "<appInfo>"); //$NON-NLS-1$
1068: writer.print(indent3
1069: + "<meta.schema plugin=\"" + fPluginID + "\""); //$NON-NLS-1$ //$NON-NLS-2$
1070: writer.print(" id=\"" + fPointID + "\""); //$NON-NLS-1$ //$NON-NLS-2$
1071: writer.println(" name=\"" + getName() + "\"/>"); //$NON-NLS-1$ //$NON-NLS-2$
1072: writer.println(indent2 + "</appInfo>"); //$NON-NLS-1$
1073: writer.println(indent2 + "<documentation>"); //$NON-NLS-1$
1074: writer.println(indent3 + getWritableDescription());
1075: writer.println(indent2 + "</documentation>"); //$NON-NLS-1$
1076: writer.println(INDENT + "</annotation>"); //$NON-NLS-1$
1077: writer.println();
1078: // add includes, if defined
1079: if (fIncludes != null) {
1080: for (int i = 0; i < fIncludes.size(); i++) {
1081: ISchemaInclude include = (ISchemaInclude) fIncludes
1082: .get(i);
1083: include.write(INDENT, writer);
1084: writer.println();
1085: }
1086: }
1087: // add elements
1088: for (int i = 0; i < fElements.size(); i++) {
1089: ISchemaElement element = (ISchemaElement) fElements
1090: .elementAt(i);
1091: element.write(INDENT, writer);
1092: writer.println();
1093: }
1094: // add document sections
1095: for (int i = 0; i < fDocSections.size(); i++) {
1096: IDocumentSection section = (IDocumentSection) fDocSections
1097: .elementAt(i);
1098: section.write(INDENT, writer);
1099: writer.println();
1100: }
1101: writer.println("</schema>"); //$NON-NLS-1$
1102: }
1103:
1104: private String getWritableDescription() {
1105: String lineDelimiter = System.getProperty("line.separator"); //$NON-NLS-1$
1106: String description = PDEXMLHelper
1107: .getWritableString(getDescription());
1108: String platformDescription = description.replaceAll(
1109: "\\r\\n|\\r|\\n", lineDelimiter); //$NON-NLS-1$
1110:
1111: return platformDescription;
1112: }
1113:
1114: public boolean isDeperecated() {
1115: Iterator it = fElements.iterator();
1116: while (it.hasNext()) {
1117: Object next = it.next();
1118: if (next instanceof SchemaRootElement)
1119: return ((SchemaRootElement) next).isDeprecated();
1120: }
1121: return false;
1122: }
1123:
1124: public String getDeprecatedSuggestion() {
1125: Iterator it = fElements.iterator();
1126: while (it.hasNext()) {
1127: Object next = it.next();
1128: if (next instanceof SchemaRootElement)
1129: return ((SchemaRootElement) next)
1130: .getDeprecatedSuggestion();
1131: }
1132: return null;
1133: }
1134:
1135: }
|