| /** |
| * Copyright (c) 2002-2008 IBM Corporation, Embarcadero Technologies, and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| * Kenn Hussey (Embarcadero Technologies) - 218759 |
| */ |
| package org.eclipse.emf.ecore.xmi.impl; |
| |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EFactory; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.InternalEObject; |
| import org.eclipse.emf.ecore.resource.ContentHandler; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl; |
| import org.eclipse.emf.ecore.util.BasicExtendedMetaData; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.util.ExtendedMetaData; |
| import org.eclipse.emf.ecore.util.FeatureMap; |
| import org.eclipse.emf.ecore.util.FeatureMapUtil; |
| import org.eclipse.emf.ecore.util.InternalEList; |
| import org.eclipse.emf.ecore.xmi.ClassNotFoundException; |
| import org.eclipse.emf.ecore.xmi.EcoreBuilder; |
| import org.eclipse.emf.ecore.xmi.FeatureNotFoundException; |
| import org.eclipse.emf.ecore.xmi.IllegalValueException; |
| import org.eclipse.emf.ecore.xmi.PackageNotFoundException; |
| import org.eclipse.emf.ecore.xmi.UnresolvedReferenceException; |
| import org.eclipse.emf.ecore.xmi.XMIException; |
| import org.eclipse.emf.ecore.xmi.XMIPlugin; |
| import org.eclipse.emf.ecore.xmi.XMLDefaultHandler; |
| import org.eclipse.emf.ecore.xmi.XMLHelper; |
| import org.eclipse.emf.ecore.xmi.XMLOptions; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecore.xmi.util.DefaultEcoreBuilder; |
| import org.eclipse.emf.ecore.xml.type.AnyType; |
| import org.eclipse.emf.ecore.xml.type.SimpleAnyType; |
| import org.eclipse.emf.ecore.xml.type.XMLTypeFactory; |
| import org.eclipse.emf.ecore.xml.type.XMLTypePackage; |
| import org.eclipse.emf.ecore.xml.type.util.XMLTypeUtil; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| |
| /** |
| * This class is a generic interface for loading XML files and |
| * creating EObjects from them. Its subclasses include the SAXXMLHandler |
| * class, which wraps this class in a SAX default handler. |
| */ |
| public abstract class XMLHandler extends DefaultHandler implements XMLDefaultHandler |
| { |
| protected static final String ERROR_TYPE = "error"; |
| protected static final String OBJECT_TYPE = "object"; |
| protected static final String UNKNOWN_FEATURE_TYPE = "unknownFeature"; |
| protected static final String DOCUMENT_ROOT_TYPE = "documentRoot"; |
| |
| protected final static String TYPE_ATTRIB = XMLResource.XSI_NS + ":" + XMLResource.TYPE; |
| protected final static String NIL_ATTRIB = XMLResource.XSI_NS + ":" + XMLResource.NIL; |
| protected final static String SCHEMA_LOCATION_ATTRIB = XMLResource.XSI_NS + ":" + XMLResource.SCHEMA_LOCATION; |
| protected final static String NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB = XMLResource.XSI_NS + ":" + XMLResource.NO_NAMESPACE_SCHEMA_LOCATION; |
| |
| protected final static boolean DEBUG_DEMANDED_PACKAGES = false; |
| |
| protected static class MyStack<E> extends BasicEList<E> |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public MyStack() |
| { |
| super(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public final E peek() |
| { |
| return size == 0 ? null : (E)data[size - 1]; |
| } |
| |
| public final void push(E o) |
| { |
| grow(size + 1); |
| data[size++] = o; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public final E pop() |
| { |
| return size == 0 ? null : (E)data[--size]; |
| } |
| } |
| |
| protected static class MyEObjectStack extends MyStack<EObject> |
| { |
| private static final long serialVersionUID = 1L; |
| |
| protected EObject [] eObjectData; |
| |
| public MyEObjectStack() |
| { |
| super(); |
| } |
| |
| @Override |
| protected final Object[] newData(int capacity) |
| { |
| return eObjectData = new EObject[capacity]; |
| } |
| |
| public final EObject peekEObject() |
| { |
| return size == 0 ? null : eObjectData[size - 1]; |
| } |
| |
| public final EObject popEObject() |
| { |
| return size == 0 ? null : eObjectData[--size]; |
| } |
| |
| @Override |
| public void clear() |
| { |
| eObjectData = null; |
| super.clear(); |
| } |
| } |
| |
| /** |
| * For unresolved forward references, the line number where the incorrect id |
| * appeared in an XML resource is needed, so the Value for the forward reference |
| * and the line number where the forward reference occurred must be saved until |
| * the end of the XML resource is encountered. |
| */ |
| protected static class SingleReference |
| { |
| private EObject object; |
| private EStructuralFeature feature; |
| private Object value; |
| private int position; |
| private int lineNumber; |
| private int columnNumber; |
| |
| public SingleReference(EObject object, |
| EStructuralFeature feature, |
| Object value, |
| int position, |
| int lineNumber, |
| int columnNumber) |
| { |
| this.object = object; |
| this.feature = feature; |
| this.value = value; |
| this.position = position; |
| this.lineNumber = lineNumber; |
| this.columnNumber = columnNumber; |
| } |
| |
| public EObject getObject() |
| { |
| return object; |
| } |
| |
| public EStructuralFeature getFeature() |
| { |
| return feature; |
| } |
| |
| public Object getValue() |
| { |
| return value; |
| } |
| |
| public int getPosition() |
| { |
| return position; |
| } |
| |
| public int getLineNumber() |
| { |
| return lineNumber; |
| } |
| |
| public int getColumnNumber() |
| { |
| return columnNumber; |
| } |
| } |
| |
| protected static class ManyReference implements XMLHelper.ManyReference |
| { |
| private EObject object; |
| private EStructuralFeature feature; |
| private Object[] values; |
| private int[] positions; |
| private int lineNumber; |
| private int columnNumber; |
| |
| public ManyReference(EObject object, |
| EStructuralFeature feature, |
| Object[] values, |
| int[] positions, |
| int lineNumber, |
| int columnNumber) |
| { |
| this.object = object; |
| this.feature = feature; |
| this.values = values; |
| this.positions = positions; |
| this.lineNumber = lineNumber; |
| this.columnNumber = columnNumber; |
| } |
| |
| public EObject getObject() |
| { |
| return object; |
| } |
| |
| public EStructuralFeature getFeature() |
| { |
| return feature; |
| } |
| |
| public Object[] getValues() |
| { |
| return values; |
| } |
| |
| public int[] getPositions() |
| { |
| return positions; |
| } |
| |
| public int getLineNumber() |
| { |
| return lineNumber; |
| } |
| |
| public int getColumnNumber() |
| { |
| return columnNumber; |
| } |
| } |
| |
| protected XMLResource xmlResource; |
| protected XMLHelper helper; |
| protected MyStack<String> elements; |
| protected MyEObjectStack objects; |
| protected MyStack<Object> types; |
| protected MyStack<FeatureMap> mixedTargets; |
| protected Map<String, EFactory> prefixesToFactories; |
| protected Map<String, URI> urisToLocations; |
| protected Map<String, URI> externalURIToLocations; |
| protected boolean processSchemaLocations; |
| protected InternalEList<EObject> extent; |
| protected List<EObject> deferredExtent; |
| protected ResourceSet resourceSet; |
| protected EPackage.Registry packageRegistry; |
| protected URI resourceURI; |
| protected boolean resolve; |
| protected boolean oldStyleProxyURIs; |
| protected boolean disableNotify; |
| protected StringBuffer text; |
| protected boolean isIDREF; |
| protected boolean isSimpleFeature; |
| protected List<InternalEObject> sameDocumentProxies; |
| protected List<SingleReference> forwardSingleReferences; |
| protected List<ManyReference> forwardManyReferences; |
| protected Object[] identifiers; |
| protected int[] positions; |
| protected static final int ARRAY_SIZE = 64; |
| protected static final int REFERENCE_THRESHOLD = 5; |
| protected int capacity; |
| protected Set<String> notFeatures; |
| protected String idAttribute; |
| protected String hrefAttribute; |
| protected XMLResource.XMLMap xmlMap; |
| protected ExtendedMetaData extendedMetaData; |
| protected EClass anyType; |
| protected EClass anySimpleType; |
| protected boolean recordUnknownFeature; |
| protected boolean useNewMethods; |
| protected boolean recordAnyTypeNSDecls; |
| protected Map<EObject, AnyType> eObjectToExtensionMap; |
| protected EStructuralFeature contextFeature; |
| protected EPackage xmlSchemaTypePackage = XMLTypePackage.eINSTANCE; |
| protected boolean deferIDREFResolution; |
| protected boolean processAnyXML; |
| protected EcoreBuilder ecoreBuilder; |
| protected boolean isRoot; |
| protected Locator locator; |
| protected Attributes attribs; |
| protected Map<EStructuralFeature, Integer> featuresToKinds; |
| protected boolean useConfigurationCache; |
| protected boolean needsPushContext; |
| protected XMLResource.ResourceEntityHandler resourceEntityHandler; |
| protected XMLResource.URIHandler uriHandler; |
| protected EObject documentRoot; |
| protected boolean usedNullNamespacePackage; |
| protected boolean isNamespaceAware; |
| protected boolean suppressDocumentRoot; |
| protected boolean laxWildcardProcessing; |
| /** |
| * @since 2.9 |
| */ |
| protected boolean usePackageNsURIAsLocation; |
| |
| /** |
| * @since 2.9 |
| */ |
| protected XMLResource.MissingPackageHandler missingPackageHandler; |
| |
| /** |
| */ |
| public XMLHandler(XMLResource xmlResource, XMLHelper helper, Map<?, ?> options) |
| { |
| this.xmlResource = xmlResource; |
| this.helper = helper; |
| elements = new MyStack<String>(); |
| objects = new MyEObjectStack(); |
| mixedTargets = new MyStack<FeatureMap>(); |
| |
| types = new MyStack<Object>(); |
| prefixesToFactories = new HashMap<String, EFactory>(); |
| forwardSingleReferences = new ArrayList<SingleReference>(); |
| forwardManyReferences = new ArrayList<ManyReference>(); |
| sameDocumentProxies = new ArrayList<InternalEObject>(); |
| identifiers = new Object[ARRAY_SIZE]; |
| positions = new int[ARRAY_SIZE]; |
| capacity = ARRAY_SIZE; |
| resourceSet = xmlResource.getResourceSet(); |
| packageRegistry = resourceSet == null ? EPackage.Registry.INSTANCE : resourceSet.getPackageRegistry(); |
| resourceURI = xmlResource.getURI(); |
| extent = (InternalEList<EObject>)xmlResource.getContents(); |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_DEFER_ATTACHMENT))) |
| { |
| deferredExtent = new ArrayList<EObject>(); |
| } |
| resolve = resourceURI != null && resourceURI.isHierarchical() && !resourceURI.isRelative(); |
| |
| eObjectToExtensionMap = xmlResource.getEObjectToExtensionMap(); |
| eObjectToExtensionMap.clear(); |
| |
| helper.setOptions(options); |
| |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_DISABLE_NOTIFY))) |
| disableNotify = true; |
| |
| notFeatures = new HashSet<String>(); |
| notFeatures.add(TYPE_ATTRIB); |
| notFeatures.add(SCHEMA_LOCATION_ATTRIB); |
| notFeatures.add(NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB); |
| |
| xmlMap = (XMLResource.XMLMap) options.get(XMLResource.OPTION_XML_MAP); |
| helper.setXMLMap(xmlMap); |
| if (xmlMap != null) |
| { |
| idAttribute = xmlMap.getIDAttributeName(); |
| } |
| |
| Object extendedMetaDataOption = options.get(XMLResource.OPTION_EXTENDED_META_DATA); |
| setExtendedMetaDataOption(extendedMetaDataOption); |
| |
| recordUnknownFeature = Boolean.TRUE.equals(options.get(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE)); |
| if (recordUnknownFeature && extendedMetaData == null) |
| { |
| setExtendedMetaDataOption(Boolean.TRUE); |
| } |
| |
| useNewMethods = Boolean.FALSE.equals(options.get(XMLResource.OPTION_USE_DEPRECATED_METHODS)); |
| |
| XMLOptions xmlOptions = (XMLOptions)options.get(XMLResource.OPTION_XML_OPTIONS); |
| if (xmlOptions != null) |
| { |
| processSchemaLocations = xmlOptions.isProcessSchemaLocations(); |
| externalURIToLocations = xmlOptions.getExternalSchemaLocations(); |
| |
| if (processSchemaLocations || externalURIToLocations != null) |
| { |
| if (extendedMetaData == null) |
| { |
| setExtendedMetaDataOption(Boolean.TRUE); |
| } |
| ecoreBuilder = xmlOptions.getEcoreBuilder(); |
| if (ecoreBuilder == null) |
| { |
| ecoreBuilder = createEcoreBuilder(options, extendedMetaData); |
| } |
| else |
| { |
| ecoreBuilder.setExtendedMetaData(extendedMetaData); |
| } |
| } |
| processAnyXML = xmlOptions.isProcessAnyXML(); |
| if (processAnyXML && extendedMetaData == null) |
| { |
| setExtendedMetaDataOption(Boolean.TRUE); |
| } |
| } |
| |
| if (extendedMetaData != null) |
| { |
| AnyType anyType = XMLTypeFactory.eINSTANCE.createAnyType(); |
| mixedTargets.push(anyType.getMixed()); |
| text = new StringBuffer(); |
| } |
| |
| anyType = (EClass)options.get(XMLResource.OPTION_ANY_TYPE); |
| anySimpleType = (EClass)options.get(XMLResource.OPTION_ANY_SIMPLE_TYPE); |
| |
| if (anyType == null) |
| { |
| anyType = XMLTypePackage.eINSTANCE.getAnyType(); |
| anySimpleType = XMLTypePackage.eINSTANCE.getSimpleAnyType(); |
| } |
| |
| helper.setAnySimpleType(anySimpleType); |
| |
| @SuppressWarnings("unchecked") Map<EClassFeatureNamePair, EStructuralFeature> newEClassFeatureNamePairToEStructuralFeatureMap = |
| (Map<EClassFeatureNamePair, EStructuralFeature>)options.get(XMLResource.OPTION_USE_XML_NAME_TO_FEATURE_MAP); |
| eClassFeatureNamePairToEStructuralFeatureMap = newEClassFeatureNamePairToEStructuralFeatureMap; |
| if (eClassFeatureNamePairToEStructuralFeatureMap == null) |
| { |
| eClassFeatureNamePairToEStructuralFeatureMap = new HashMap<EClassFeatureNamePair, EStructuralFeature>(); |
| } |
| else |
| { |
| isOptionUseXMLNameToFeatureSet = true; |
| } |
| |
| recordAnyTypeNSDecls = Boolean.TRUE.equals(options.get(XMLResource.OPTION_RECORD_ANY_TYPE_NAMESPACE_DECLARATIONS)); |
| |
| hrefAttribute = XMLResource.HREF; |
| |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE))) |
| { |
| hrefAttribute = null; |
| } |
| |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_DEFER_IDREF_RESOLUTION))) |
| { |
| helper.setCheckForDuplicates(deferIDREFResolution = true); |
| } |
| |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_CONFIGURATION_CACHE))) |
| { |
| useConfigurationCache = true; |
| } |
| |
| // The entity handler is the best place to resolve and deresolve URIs since it can do it there just once to produce the entity. |
| // So most often the entity handler will be a URI handler as well and when used as a URI handler will be an identity handler. |
| // |
| uriHandler = (XMLResource.URIHandler)options.get(XMLResource.OPTION_URI_HANDLER); |
| resourceEntityHandler = (XMLResource.ResourceEntityHandler)options.get(XMLResource.OPTION_RESOURCE_ENTITY_HANDLER); |
| if (resourceEntityHandler != null) |
| { |
| resourceEntityHandler.reset(); |
| if (uriHandler == null && resourceEntityHandler instanceof XMLResource.URIHandler) |
| { |
| uriHandler = (XMLResource.URIHandler)resourceEntityHandler; |
| uriHandler.setBaseURI(resourceURI); |
| } |
| } |
| |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_SUPPRESS_DOCUMENT_ROOT))) |
| { |
| suppressDocumentRoot = true; |
| } |
| |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_LAX_WILDCARD_PROCESSING))) |
| { |
| laxWildcardProcessing = true; |
| } |
| |
| usePackageNsURIAsLocation = !Boolean.FALSE.equals(options.get(XMLResource.OPTION_USE_PACKAGE_NS_URI_AS_LOCATION)); |
| missingPackageHandler = (XMLResource.MissingPackageHandler)options.get(XMLResource.OPTION_MISSING_PACKAGE_HANDLER); |
| } |
| |
| protected void setExtendedMetaDataOption(Object extendedMetaDataOption) |
| { |
| if (extendedMetaDataOption instanceof Boolean) |
| { |
| if (extendedMetaDataOption.equals(Boolean.TRUE)) |
| { |
| extendedMetaData = |
| resourceSet == null ? |
| ExtendedMetaData.INSTANCE : |
| new BasicExtendedMetaData(resourceSet.getPackageRegistry()); |
| if (xmlResource != null) |
| { |
| xmlResource.getDefaultSaveOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData); |
| } |
| } |
| else |
| { |
| extendedMetaData = null; |
| } |
| } |
| else |
| { |
| extendedMetaData = (ExtendedMetaData)extendedMetaDataOption; |
| } |
| |
| helper.setExtendedMetaData(extendedMetaData); |
| } |
| |
| public void prepare(XMLResource resource, XMLHelper helper, Map<?, ?> options) |
| { |
| this.xmlResource = resource; |
| this.helper = helper; |
| resourceSet = xmlResource.getResourceSet(); |
| packageRegistry = resourceSet == null ? EPackage.Registry.INSTANCE : resourceSet.getPackageRegistry(); |
| resourceURI = xmlResource.getURI(); |
| extent = (InternalEList<EObject>)xmlResource.getContents(); |
| if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_DEFER_ATTACHMENT))) |
| { |
| deferredExtent = new ArrayList<EObject>(); |
| } |
| resolve = resourceURI != null && resourceURI.isHierarchical() && !resourceURI.isRelative(); |
| eObjectToExtensionMap = xmlResource.getEObjectToExtensionMap(); |
| eObjectToExtensionMap.clear(); |
| setExtendedMetaDataOption(options.get(XMLResource.OPTION_EXTENDED_META_DATA)); |
| helper.setOptions(options); |
| if (extendedMetaData != null) |
| { |
| if (ecoreBuilder != null) |
| { |
| ecoreBuilder.setExtendedMetaData(extendedMetaData); |
| } |
| AnyType anyType = XMLTypeFactory.eINSTANCE.createAnyType(); |
| mixedTargets.push(anyType.getMixed()); |
| text = new StringBuffer(); |
| } |
| |
| // bug #126072 |
| @SuppressWarnings("unchecked") Map<EClassFeatureNamePair, EStructuralFeature> newEClassFeatureNamePairToEStructuralFeatureMap = |
| (Map<EClassFeatureNamePair, EStructuralFeature>)options.get(XMLResource.OPTION_USE_XML_NAME_TO_FEATURE_MAP); |
| eClassFeatureNamePairToEStructuralFeatureMap = |
| newEClassFeatureNamePairToEStructuralFeatureMap; |
| if (eClassFeatureNamePairToEStructuralFeatureMap == null) |
| { |
| eClassFeatureNamePairToEStructuralFeatureMap = new HashMap<EClassFeatureNamePair, EStructuralFeature>(); |
| isOptionUseXMLNameToFeatureSet = false; |
| } |
| else |
| { |
| isOptionUseXMLNameToFeatureSet = true; |
| if (helper instanceof XMLHelperImpl && featuresToKinds != null) |
| { |
| ((XMLHelperImpl)helper).featuresToKinds = featuresToKinds; |
| } |
| } |
| |
| // The entity handler is the best place to resolve and deresolve URIs since it can do it there just once to produce the entity. |
| // So most often the entity handler will be a URI handler as well and when used as a URI handler will be an identity handler. |
| // |
| uriHandler = (XMLResource.URIHandler)options.get(XMLResource.OPTION_URI_HANDLER); |
| resourceEntityHandler = (XMLResource.ResourceEntityHandler)options.get(XMLResource.OPTION_RESOURCE_ENTITY_HANDLER); |
| if (resourceEntityHandler != null) |
| { |
| resourceEntityHandler.reset(); |
| if (uriHandler == null && resourceEntityHandler instanceof XMLResource.URIHandler) |
| { |
| uriHandler = (XMLResource.URIHandler)resourceEntityHandler; |
| uriHandler.setBaseURI(resourceURI); |
| } |
| } |
| } |
| |
| public void reset() |
| { |
| this.xmlResource = null; |
| this.extendedMetaData = null; |
| // bug #126072 |
| eClassFeatureNamePair.eClass = null; |
| eClassFeatureNamePairToEStructuralFeatureMap = null; |
| if (isOptionUseXMLNameToFeatureSet && helper instanceof XMLHelperImpl) |
| { |
| featuresToKinds = ((XMLHelperImpl)helper).featuresToKinds; |
| } |
| else |
| { |
| featuresToKinds = null; |
| } |
| |
| if (ecoreBuilder != null) |
| { |
| this.ecoreBuilder.setExtendedMetaData(null); |
| } |
| this.helper = null; |
| elements.clear(); |
| objects.clear(); |
| mixedTargets.clear(); |
| contextFeature = null; |
| eObjectToExtensionMap = null; |
| // external schema locations should only be processed once, i.e. in the subsequent parse |
| // there is no need to process those again. |
| externalURIToLocations = null; |
| |
| types.clear(); |
| prefixesToFactories.clear(); |
| forwardSingleReferences.clear(); |
| forwardManyReferences.clear(); |
| sameDocumentProxies.clear(); |
| for (int i = 0; i < identifiers.length; i++) |
| { |
| identifiers[i] = null; |
| } |
| for (int i = 0; i < positions.length; i++) |
| { |
| positions[i] = 0; |
| } |
| capacity = ARRAY_SIZE; |
| resourceSet = null; |
| packageRegistry = null; |
| resourceURI = null; |
| extent = null; |
| deferredExtent = null; |
| attribs = null; |
| locator = null; |
| urisToLocations = null; |
| resourceEntityHandler = null; |
| uriHandler = null; |
| documentRoot = null; |
| usedNullNamespacePackage = false; |
| isNamespaceAware = false; |
| } |
| |
| // |
| // Overwrite DefaultHandler methods |
| // |
| |
| @Override |
| public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException |
| { |
| // Do nothing. |
| } |
| |
| @Override |
| public void skippedEntity(String name) throws SAXException |
| { |
| // Do nothing. |
| } |
| |
| protected XMIException toXMIException(SAXParseException e) |
| { |
| XMIException xmiException = |
| new XMIException |
| (e.getException() == null ? e : e.getException(), |
| e.getSystemId() == null ? getLocation() : e.getSystemId(), |
| e.getLineNumber(), |
| e.getColumnNumber()); |
| return xmiException; |
| } |
| |
| @Override |
| public void warning(SAXParseException e) throws SAXException |
| { |
| warning(toXMIException(e)); |
| } |
| |
| @Override |
| public void error(SAXParseException e) throws SAXException |
| { |
| error(toXMIException(e)); |
| } |
| |
| @Override |
| public void fatalError(SAXParseException e) throws SAXException |
| { |
| fatalError(toXMIException(e)); |
| throw e; |
| } |
| |
| @Override |
| public void setDocumentLocator(Locator locator) |
| { |
| setLocator(locator); |
| } |
| |
| @Override |
| public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException |
| { |
| setAttributes(attributes); |
| startElement(uri, localName, qName); |
| } |
| |
| // |
| // Implement LexicalHandler methods |
| // |
| |
| public void startEntity(java.lang.String name) |
| { |
| if (resourceEntityHandler != null) |
| { |
| text = new StringBuffer(); |
| } |
| } |
| |
| public void endEntity(java.lang.String name) |
| { |
| if (resourceEntityHandler != null) |
| { |
| resourceEntityHandler.handleEntity(name, text.toString()); |
| } |
| } |
| |
| public void comment(char[] ch, int start, int length) // throws SAXException |
| { |
| if (mixedTargets.peek() != null) |
| { |
| if (text != null) |
| { |
| handleMixedText(); |
| } |
| |
| handleComment(new String(ch, start, length)); |
| } |
| } |
| |
| public void startCDATA() |
| { |
| if (mixedTargets.peek() != null) |
| { |
| if (text != null) |
| { |
| handleMixedText(); |
| } |
| text = new StringBuffer(); |
| } |
| } |
| |
| public void endCDATA() |
| { |
| if (mixedTargets.peek() != null && text != null) |
| { |
| handleCDATA(); |
| } |
| } |
| |
| // |
| // Implement DTDHandler methods |
| // |
| public void startDTD(String name, String publicId, String systemId) |
| { |
| xmlResource.setDoctypeInfo(publicId, systemId); |
| } |
| |
| public void endDTD() |
| { |
| // Do nothing. |
| } |
| |
| @Override |
| public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException |
| { |
| // Do nothing. |
| } |
| |
| @Override |
| public void notationDecl(String name, String publicId, String systemId) throws SAXException |
| { |
| // Do nothing. |
| } |
| |
| // |
| // Implement EntityResolver methods |
| // |
| @Override |
| public InputSource resolveEntity(String publicId, String systemId) throws SAXException |
| { |
| try |
| { |
| Map<Object, Object> options = new HashMap<Object, Object>(); |
| options.put("publicId", publicId); |
| options.put("systemId", systemId); |
| options.put("baseLocation", resourceURI == null ? null : resourceURI.toString()); |
| URI uri = URI.createURI(systemId); |
| if (resolve && uri.isRelative() && uri.hasRelativePath()) |
| { |
| uri = helper.resolve(uri, resourceURI); |
| } |
| InputStream inputStream = getURIConverter().createInputStream(uri, options); |
| InputSource result = new InputSource(inputStream); |
| result.setPublicId(publicId); |
| result.setSystemId(systemId); |
| return result; |
| } |
| catch (IOException exception) |
| { |
| throw new SAXException(exception); |
| } |
| } |
| |
| /** |
| * Returns the xsi type attribute's value. |
| */ |
| protected abstract String getXSIType(); |
| |
| /** |
| * Process the XML attributes for the newly created object. |
| */ |
| protected abstract void handleObjectAttribs(EObject obj); |
| |
| /** |
| * Process the XML namespace declarations. |
| * @deprecated since 2.2 |
| */ |
| @Deprecated |
| protected void handleNamespaceAttribs() |
| { |
| for (int i = 0, size = attribs.getLength(); i < size; ++i) |
| { |
| String attrib = attribs.getQName(i); |
| if (attrib.startsWith(XMLResource.XML_NS)) |
| { |
| handleXMLNSAttribute(attrib, attribs.getValue(i)); |
| } |
| else if (SCHEMA_LOCATION_ATTRIB.equals(attrib)) |
| { |
| handleXSISchemaLocation(attribs.getValue(i)); |
| } |
| else if (NO_NAMESPACE_SCHEMA_LOCATION_ATTRIB.equals(attrib)) |
| { |
| handleXSINoNamespaceSchemaLocation(attribs.getValue(i)); |
| } |
| } |
| } |
| |
| protected void handleSchemaLocation() |
| { |
| String xsiSchemLocation = attribs.getValue(ExtendedMetaData.XSI_URI, XMLResource.SCHEMA_LOCATION); |
| if (xsiSchemLocation != null) |
| { |
| handleXSISchemaLocation(xsiSchemLocation); |
| } |
| |
| String xsiNoNamespaceSchemLocation = attribs.getValue(ExtendedMetaData.XSI_URI, XMLResource.NO_NAMESPACE_SCHEMA_LOCATION); |
| if (xsiNoNamespaceSchemLocation != null) |
| { |
| handleXSINoNamespaceSchemaLocation(xsiNoNamespaceSchemLocation); |
| } |
| } |
| |
| /** |
| * Returns true if the xsi:nil attribute is in the list of attributes. |
| */ |
| protected boolean isNull() |
| { |
| String value = isNamespaceAware ? attribs.getValue(ExtendedMetaData.XSI_URI, XMLResource.NIL) : attribs.getValue(NIL_ATTRIB); |
| if (value != null) |
| { |
| try |
| { |
| return XMLTypeFactory.eINSTANCE.createBoolean(value); |
| } |
| catch (RuntimeException exception) |
| { |
| error(new XMIException(exception)); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Sets the current attributes and returns the old ones. |
| */ |
| protected Object setAttributes(Object attributes) |
| { |
| Object oldAttribs = attribs; |
| this.attribs = (Attributes)attributes; |
| return oldAttribs; |
| } |
| |
| /** |
| * Sets the object that might be used for determining the line and |
| * column number. |
| */ |
| protected void setLocator(Object locator) |
| { |
| this.locator = (Locator)locator; |
| } |
| |
| protected void recordHeaderInformation() |
| { |
| if (locator != null) |
| { |
| Class<?> locatorClass = locator.getClass(); |
| try |
| { |
| Method encodingMethod = locatorClass.getMethod("getEncoding"); |
| String encoding = (String)encodingMethod.invoke(locator); |
| if (encoding != null) |
| { |
| this.xmlResource.setEncoding(encoding); |
| } |
| |
| Method versionMethod = locatorClass.getMethod("getXMLVersion"); |
| String version = (String)versionMethod.invoke(locator); |
| if (version != null) |
| { |
| this.xmlResource.setXMLVersion(version); |
| } |
| } |
| catch (NoSuchMethodException e) |
| { |
| // Ignore. |
| } |
| catch (IllegalAccessException e) |
| { |
| // Ignore. |
| } |
| catch (InvocationTargetException e) |
| { |
| // Ignore. |
| } |
| } |
| } |
| |
| @Override |
| public void startDocument() |
| { |
| isRoot = true; |
| helper.pushContext(); |
| needsPushContext = true; |
| } |
| |
| /** |
| * This method determines whether to make an object or not, then makes an |
| * object based on the XML attributes and the metamodel. |
| */ |
| public void startElement(String uri, String localName, String name) |
| { |
| if (needsPushContext) |
| { |
| helper.pushContext(); |
| } |
| needsPushContext = true; |
| if (text != null && text.length() > 0) |
| { |
| if (mixedTargets.peek() != null) |
| { |
| handleMixedText(); |
| } |
| else |
| { |
| text = null; |
| } |
| } |
| |
| elements.push(name); |
| String prefix = ""; |
| |
| if (useNewMethods) |
| { |
| if (isRoot) |
| { |
| handleSchemaLocation(); |
| } |
| prefix = helper.getPrefix((uri.length() == 0) ? null : uri); |
| prefix = (prefix == null) ? "" : prefix; |
| } |
| else |
| { |
| handleNamespaceAttribs(); |
| int index = name.indexOf(':', 0); |
| localName = name; |
| if (index != -1) |
| { |
| prefix = name.substring(0, index); |
| localName = name.substring(index + 1); |
| } |
| } |
| processElement(name, prefix, localName); |
| } |
| |
| protected void processElement(String name, String prefix, String localName) |
| { |
| if (isRoot) |
| { |
| isRoot = false; |
| recordHeaderInformation(); |
| } |
| if (isError()) |
| { |
| types.push(ERROR_TYPE); |
| } |
| else |
| { |
| if (objects.isEmpty()) |
| { |
| createTopObject(prefix, localName); |
| } |
| else |
| { |
| handleFeature(prefix, localName); |
| } |
| } |
| } |
| |
| protected void handleForwardReferences() |
| { |
| handleForwardReferences(false); |
| } |
| |
| /** |
| * Check if the values of the forward references have been set (they may |
| * have been set due to a bidirectional reference being set). If not, set them. |
| * If this is called during end document processing, errors should be diagnosed. |
| * If it is called in the middle of a document, |
| * we need to clean up the forward reference lists to avoid processing resolved references again later. |
| */ |
| protected void handleForwardReferences(boolean isEndDocument) |
| { |
| // Handle the same document proxies, which may have problems resulting from the |
| // other end of a bidirectional reference being handled as an IDREF rather than as a proxy. |
| // When we are done with these, we know that funny proxies are now resolved as if they were handled as IDREFs. |
| // |
| for (Iterator<InternalEObject> i = sameDocumentProxies.iterator(); i.hasNext(); ) |
| { |
| InternalEObject proxy = i.next(); |
| |
| // Look through all the references... |
| // |
| LOOP: |
| for (EReference eReference : proxy.eClass().getEAllReferences()) |
| { |
| // And find the one that holds this proxy. |
| // |
| EReference oppositeEReference = eReference.getEOpposite(); |
| if (oppositeEReference != null && oppositeEReference.isChangeable() && proxy.eIsSet(eReference)) |
| { |
| // Try to resolve the proxy locally. |
| // |
| EObject resolvedEObject = xmlResource.getEObject(proxy.eProxyURI().fragment()); |
| if (resolvedEObject != null) |
| { |
| // We won't need to process this again later. |
| // |
| if (!isEndDocument) |
| { |
| i.remove(); |
| } |
| |
| // Compute the holder of the proxy |
| // |
| EObject proxyHolder = (EObject)(eReference.isMany() ? ((List<?>)proxy.eGet(eReference)).get(0) : proxy.eGet(eReference)); |
| |
| // If the proxy holder can hold many values, |
| // it may contain a duplicate that resulted when the other end was processed as an IDREF |
| // and hence did both sides of the bidirectional relation. |
| // |
| if (oppositeEReference.isMany()) |
| { |
| // So if the resolved object is also present... |
| // |
| InternalEList<?> holderContents = (InternalEList<?>)proxyHolder.eGet(oppositeEReference); |
| int resolvedEObjectIndex = holderContents.basicIndexOf(resolvedEObject); |
| if (resolvedEObjectIndex != -1) |
| { |
| // Move the resolved object to the right place, remove the proxy, and we're done. |
| // |
| int proxyIndex = holderContents.basicIndexOf(proxy); |
| holderContents.move(proxyIndex, resolvedEObjectIndex); |
| holderContents.remove(proxyIndex > resolvedEObjectIndex ? proxyIndex - 1 : proxyIndex + 1); |
| break LOOP; |
| } |
| } |
| |
| if (!oppositeEReference.getEType().isInstance(resolvedEObject)) |
| { |
| error |
| (new IllegalValueException |
| (proxyHolder, |
| oppositeEReference, |
| resolvedEObject, |
| null, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| break LOOP; |
| } |
| |
| // If the resolved object doesn't contain a reference to the proxy holder as it should. |
| // |
| if (eReference.isMany() ? |
| !((InternalEList<?>)resolvedEObject.eGet(eReference)).basicContains(proxyHolder) : |
| resolvedEObject.eGet(eReference) != proxyHolder) |
| { |
| // The proxy needs to be replaced in a way that updates both ends of the reference. |
| // |
| if (oppositeEReference.isMany()) |
| { |
| @SuppressWarnings("unchecked") InternalEList<EObject> proxyHolderList = (InternalEList<EObject>)proxyHolder.eGet(oppositeEReference); |
| proxyHolderList.setUnique(proxyHolderList.basicIndexOf(proxy), resolvedEObject); |
| } |
| else |
| { |
| proxyHolder.eSet(oppositeEReference, resolvedEObject); |
| } |
| } |
| } |
| |
| break; |
| } |
| } |
| } |
| |
| for (Iterator<SingleReference> i = forwardSingleReferences.iterator(); i.hasNext(); ) |
| { |
| SingleReference ref = i.next(); |
| EObject obj = xmlResource.getEObject((String) ref.getValue()); |
| |
| if (obj != null) |
| { |
| // We won't need to process this again later. |
| if (!isEndDocument) |
| { |
| i.remove(); |
| } |
| EStructuralFeature feature = ref.getFeature(); |
| setFeatureValue(ref.getObject(), feature, obj, ref.getPosition()); |
| } |
| else if (isEndDocument) |
| { |
| error |
| (new UnresolvedReferenceException |
| ((String) ref.getValue(), |
| getLocation(), |
| ref.getLineNumber(), |
| ref.getColumnNumber())); |
| } |
| } |
| |
| for (Iterator<ManyReference> i = forwardManyReferences.iterator(); i.hasNext(); ) |
| { |
| ManyReference ref = i.next(); |
| Object[] values = ref.getValues(); |
| |
| boolean failure = false; |
| for (int j = 0, l = values.length; j < l; j++) |
| { |
| String id = (String) values[j]; |
| EObject obj = xmlResource.getEObject(id); |
| values[j] = obj; |
| |
| if (obj == null) |
| { |
| failure = true; |
| if (isEndDocument) |
| { |
| error |
| (new UnresolvedReferenceException |
| (id, |
| getLocation(), |
| ref.getLineNumber(), |
| ref.getColumnNumber())); |
| } |
| } |
| } |
| |
| if (!failure) |
| { |
| if (!isEndDocument) |
| { |
| i.remove(); |
| } |
| setFeatureValues(ref); |
| } |
| else if (isEndDocument) |
| { |
| // At least set the references that we were able to resolve, if any. |
| // |
| setFeatureValues(ref); |
| } |
| } |
| } |
| |
| /** |
| * Check if the values of the forward references have been set (they may |
| * have been set due to a bi-directional reference being set). If not, |
| * set them. |
| */ |
| @Override |
| public void endDocument() |
| { |
| if (deferredExtent != null) |
| { |
| extent.addAll(deferredExtent); |
| } |
| |
| // Pretend there is an xmlns="" because we really need to ensure that the null prefix |
| // isn't used to denote something other than the null namespace. |
| // |
| if (usedNullNamespacePackage) |
| { |
| helper.addPrefix("", ""); |
| } |
| helper.recordPrefixToURIMapping(); |
| helper.popContext(); |
| handleForwardReferences(true); |
| |
| if (disableNotify) |
| { |
| for (Iterator<?> i = EcoreUtil.getAllContents(xmlResource.getContents(), false); i.hasNext(); ) |
| { |
| EObject eObject = (EObject)i.next(); |
| eObject.eSetDeliver(true); |
| } |
| } |
| |
| if (extendedMetaData != null) |
| { |
| if (extent.size() == 1) |
| { |
| EObject root = extent.get(0); |
| recordNamespacesSchemaLocations(root); |
| } |
| |
| if (DEBUG_DEMANDED_PACKAGES) |
| { |
| // EATM temporary for debug purposes only. |
| // |
| Collection<EPackage> demandedPackages = EcoreUtil.copyAll(extendedMetaData.demandedPackages()); |
| for (EPackage ePackage : demandedPackages) |
| { |
| ePackage.setName(ePackage.getNsURI()); |
| } |
| extent.addAll(demandedPackages); |
| } |
| } |
| } |
| |
| protected EMap<String, String> recordNamespacesSchemaLocations(EObject root) |
| { |
| EClass eClass = root.eClass(); |
| EReference xmlnsPrefixMapFeature = extendedMetaData.getXMLNSPrefixMapFeature(eClass); |
| EMap<String, String> xmlnsPrefixMap = null; |
| if (xmlnsPrefixMapFeature != null) |
| { |
| @SuppressWarnings("unchecked") EMap<String, String> newXMLNSPrefixMap = (EMap<String, String>)root.eGet(xmlnsPrefixMapFeature); |
| xmlnsPrefixMap = newXMLNSPrefixMap; |
| xmlnsPrefixMap.putAll(helper.getPrefixToNamespaceMap()); |
| } |
| |
| if (urisToLocations != null) |
| { |
| EReference xsiSchemaLocationMapFeature = extendedMetaData.getXSISchemaLocationMapFeature(eClass); |
| if (xsiSchemaLocationMapFeature != null) |
| { |
| @SuppressWarnings("unchecked") EMap<String, String> newXSISchemaLocationMap = (EMap<String, String>)root.eGet(xsiSchemaLocationMapFeature); |
| EMap<String, String> xsiSchemaLocationMap = newXSISchemaLocationMap; |
| for (Map.Entry<String, URI> entry : urisToLocations.entrySet()) |
| { |
| xsiSchemaLocationMap.put(entry.getKey(), entry.getValue().toString()); |
| } |
| } |
| } |
| return xmlnsPrefixMap; |
| } |
| |
| /** |
| * Create an object based on the prefix and type name. |
| */ |
| protected EObject createObjectByType(String prefix, String name, boolean top) |
| { |
| if (top) |
| { |
| handleTopLocations(prefix, name); |
| } |
| |
| EFactory eFactory = getFactoryForPrefix(prefix); |
| String uri = helper.getURI(prefix); |
| if (eFactory == null && prefix.equals("") && uri == null) |
| { |
| EPackage ePackage = handleMissingPackage(null); |
| if (ePackage == null) |
| { |
| error |
| (new PackageNotFoundException |
| (null, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| } |
| else |
| { |
| eFactory = ePackage.getEFactoryInstance(); |
| } |
| } |
| |
| documentRoot= createDocumentRoot(prefix, uri, name, eFactory, top); |
| |
| if (documentRoot != null) return documentRoot; |
| |
| EObject newObject = null; |
| if (useNewMethods) |
| { |
| newObject = createObject(eFactory, helper.getType(eFactory, name) , false); |
| } |
| else |
| { |
| newObject = createObjectFromFactory(eFactory, name); |
| } |
| newObject = validateCreateObjectFromFactory(eFactory, name, newObject, top); |
| |
| if (top) |
| { |
| processTopObject(newObject); |
| // check for simple feature |
| if (extendedMetaData != null && newObject != null) |
| { |
| EStructuralFeature simpleFeature = extendedMetaData.getSimpleFeature(newObject.eClass()); |
| if (simpleFeature != null) |
| { |
| isSimpleFeature = true; |
| isIDREF = simpleFeature instanceof EReference; |
| objects.push(null); |
| mixedTargets.push(null); |
| types.push(simpleFeature); |
| text = new StringBuffer(); |
| } |
| } |
| } |
| return newObject; |
| } |
| |
| protected EObject createDocumentRoot(String prefix, String uri, String name, EFactory eFactory, boolean top) |
| { |
| if (extendedMetaData != null && eFactory != null) |
| { |
| EPackage ePackage = eFactory.getEPackage(); |
| EClass eClass = null; |
| if (useConfigurationCache) |
| { |
| eClass = ConfigurationCache.INSTANCE.getDocumentRoot(ePackage); |
| if (eClass == null) |
| { |
| eClass = extendedMetaData.getDocumentRoot(ePackage); |
| ConfigurationCache.INSTANCE.putDocumentRoot(ePackage, eClass); |
| } |
| } |
| else |
| { |
| eClass = extendedMetaData.getDocumentRoot(ePackage); |
| } |
| if (eClass != null) |
| { |
| // EATM Kind of hacky. |
| String typeName = extendedMetaData.getName(eClass); |
| @SuppressWarnings("deprecation") EObject newObject = |
| useNewMethods ? |
| createObject(eFactory, eClass, true) : |
| helper.createObject(eFactory, typeName); |
| validateCreateObjectFromFactory(eFactory, typeName, newObject); |
| if (top) |
| { |
| if (suppressDocumentRoot) |
| { |
| // Set up a deferred extent so the document root we create definitely will not be added to the resource. |
| // |
| List<EObject> oldDeferredExtent = deferredExtent; |
| try |
| { |
| deferredExtent = new ArrayList<EObject>(); |
| processTopObject(newObject); |
| } |
| finally |
| { |
| deferredExtent = oldDeferredExtent; |
| } |
| handleFeature(prefix, name); |
| |
| // Remove the document root's information from the top of the stacks. |
| // |
| objects.remove(0); |
| mixedTargets.remove(0); |
| types.remove(0); |
| |
| // Process the new root object if any. |
| // |
| EObject peekObject = objects.peek(); |
| if (peekObject == null) |
| { |
| // There's an EObject on the stack already. |
| // |
| if (objects.size() > 1) |
| { |
| // Excise the new root from the document root. |
| // |
| EcoreUtil.remove(peekObject = objects.get(0)); |
| } |
| else |
| { |
| // If there is no root object, we're dealing with an EAttribute feature instead of an EReference feature. |
| // So create an instance of simple any type and prepare it to handle the text content. |
| // |
| SimpleAnyType simpleAnyType = (SimpleAnyType)EcoreUtil.create(anySimpleType); |
| simpleAnyType.setInstanceType(((EAttribute)types.peek()).getEAttributeType()); |
| objects.set(0, simpleAnyType); |
| types.set(0, XMLTypePackage.Literals.SIMPLE_ANY_TYPE__RAW_VALUE); |
| mixedTargets.set(0, simpleAnyType.getMixed()); |
| peekObject = simpleAnyType; |
| } |
| } |
| else |
| { |
| // Excise the new root from the document root. |
| // |
| EcoreUtil.remove(peekObject); |
| } |
| // Do the extent processing that should have been done for the root but was actualljy done for the document root. |
| // |
| if (deferredExtent != null) |
| { |
| deferredExtent.add(peekObject); |
| } |
| else |
| { |
| extent.addUnique(peekObject); |
| } |
| |
| // The new root object is the actual new object since all sign of the document root will now have disappeared. |
| // |
| newObject = peekObject; |
| } |
| else |
| { |
| processTopObject(newObject); |
| handleFeature(prefix, name); |
| } |
| } |
| return newObject; |
| } |
| } |
| return null; |
| } |
| |
| protected void createTopObject(String prefix, String name) |
| { |
| createObjectByType(prefix, name, true); |
| } |
| |
| /** |
| * Add object to extent and call processObject. |
| */ |
| protected void processTopObject(EObject object) |
| { |
| if (object != null) |
| { |
| if (deferredExtent != null) |
| { |
| deferredExtent.add(object); |
| } |
| else |
| { |
| extent.addUnique(object); |
| } |
| |
| if (extendedMetaData != null && !mixedTargets.isEmpty()) |
| { |
| FeatureMap featureMap = mixedTargets.pop(); |
| EStructuralFeature target = extendedMetaData.getMixedFeature(object.eClass()); |
| if (target != null) |
| { |
| FeatureMap otherFeatureMap = (FeatureMap)object.eGet(target); |
| for (FeatureMap.Entry entry : new ArrayList<FeatureMap.Entry>(featureMap)) |
| { |
| // Ignore a whitespace only text entry at the beginning. |
| // |
| if (entry.getEStructuralFeature() != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__TEXT || |
| !"".equals(XMLTypeUtil.normalize(entry.getValue().toString(), true))) |
| { |
| otherFeatureMap.add(entry.getEStructuralFeature(), entry.getValue()); |
| } |
| } |
| } |
| text = null; |
| } |
| } |
| |
| processObject(object); |
| } |
| |
| /** |
| * Pop the appropriate stacks and set features whose values are in |
| * the content of XML elements. |
| */ |
| @Override |
| public void endElement(String uri, String localName, String name) |
| { |
| elements.pop(); |
| Object type = types.pop(); |
| if (type == OBJECT_TYPE) |
| { |
| if (text == null) |
| { |
| objects.pop(); |
| mixedTargets.pop(); |
| } |
| else |
| { |
| EObject object = objects.popEObject(); |
| if (mixedTargets.peek() != null && |
| (object.eContainer() != null || |
| suppressDocumentRoot || |
| recordUnknownFeature && |
| (eObjectToExtensionMap.containsValue(object) || ((InternalEObject)object).eDirectResource() != null))) |
| { |
| handleMixedText(); |
| mixedTargets.pop(); |
| } |
| else |
| { |
| if (text.length() != 0) |
| { |
| handleProxy((InternalEObject)object, text.toString().trim()); |
| } |
| mixedTargets.pop(); |
| text = null; |
| } |
| } |
| } |
| else if (isIDREF) |
| { |
| objects.pop(); |
| mixedTargets.pop(); |
| if (text != null) |
| { |
| setValueFromId(objects.peekEObject(), (EReference)type, text.toString()); |
| text = null; |
| } |
| isIDREF= false; |
| } |
| else if (isTextFeatureValue(type)) |
| { |
| EObject eObject = objects.popEObject(); |
| mixedTargets.pop(); |
| if (eObject == null) |
| { |
| eObject = objects.peekEObject(); |
| } |
| setFeatureValue(eObject, (EStructuralFeature) type, text == null ? null : text.toString()); |
| text = null; |
| } |
| |
| if (isSimpleFeature) |
| { |
| types.pop(); |
| objects.pop(); |
| mixedTargets.pop(); |
| isSimpleFeature = false; |
| } |
| helper.popContext(prefixesToFactories); |
| } |
| |
| protected boolean isTextFeatureValue(Object type) |
| { |
| return type != ERROR_TYPE; |
| } |
| |
| @Override |
| public void startPrefixMapping(String prefix, String uri) |
| { |
| isNamespaceAware = true; |
| |
| if (needsPushContext) |
| { |
| helper.pushContext(); |
| needsPushContext = false; |
| } |
| |
| //if (useNonDeprecatedMethods) |
| //{ |
| helper.addPrefix(prefix, uri); |
| prefixesToFactories.remove(prefix); |
| //} |
| } |
| |
| @Override |
| public void endPrefixMapping(String prefix) |
| { |
| // Do nothing. |
| } |
| |
| @Override |
| public void characters(char [] ch, int start, int length) |
| { |
| if (text == null && mixedTargets.peek() != null) |
| { |
| text = new StringBuffer(); |
| } |
| |
| if (text != null) |
| { |
| text.append(ch, start, length); |
| } |
| } |
| |
| @Override |
| public void processingInstruction(String target, String data) |
| { |
| if (mixedTargets.peek() != null) |
| { |
| if (text != null) |
| { |
| handleMixedText(); |
| } |
| |
| handleProcessingInstruction(target, data); |
| } |
| } |
| |
| protected void handleXMLNSAttribute(String attrib, String value) |
| { |
| // Handle namespaces |
| int index = attrib.indexOf(':', 0); |
| String prefix = index == -1 ? "" : attrib.substring(index + 1); |
| helper.addPrefix(prefix, value); |
| prefixesToFactories.remove(prefix); |
| } |
| |
| protected void handleXSISchemaLocation(String schemaLocations) |
| { |
| if (urisToLocations == null) |
| { |
| urisToLocations = new HashMap<String, URI>(); |
| xmlResource.getDefaultSaveOptions().put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); |
| } |
| |
| for (StringTokenizer stringTokenizer = new StringTokenizer(schemaLocations, " "); stringTokenizer.hasMoreTokens(); ) |
| { |
| String key = stringTokenizer.nextToken(); |
| if (stringTokenizer.hasMoreTokens()) |
| { |
| String value = stringTokenizer.nextToken(); |
| URI uri = URI.createURI(value); |
| if (uriHandler != null) |
| { |
| uri = uriHandler.resolve(uri); |
| } |
| else if (resolve && uri.isRelative() && uri.hasRelativePath()) |
| { |
| uri = helper.resolve(uri, resourceURI); |
| } |
| urisToLocations.put(key, uri); |
| } |
| } |
| } |
| |
| protected void handleXSINoNamespaceSchemaLocation(String noNamespaceSchemaLocation) |
| { |
| if (urisToLocations == null) |
| { |
| urisToLocations = new HashMap<String, URI>(); |
| xmlResource.getDefaultSaveOptions().put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); |
| } |
| |
| URI uri = URI.createURI(noNamespaceSchemaLocation); |
| if (uriHandler != null) |
| { |
| uri = uriHandler.resolve(uri); |
| } |
| else if (resolve && uri.isRelative() && uri.hasRelativePath()) |
| { |
| uri = helper.resolve(uri, resourceURI); |
| } |
| urisToLocations.put(null, uri); |
| } |
| |
| protected void processSchemaLocations(String prefix, String name) |
| { |
| if (urisToLocations != null) |
| { |
| // If processSchemaLocations is specified, treat these as XML Schema locations |
| if (processSchemaLocations) |
| { |
| try |
| { |
| ecoreBuilder.generate(urisToLocations); |
| } |
| catch (Exception exception) |
| { |
| XMIPlugin.INSTANCE.log(exception); |
| } |
| } |
| // If externalSchemaLocations are specified, process these ones as well |
| try |
| { |
| if (externalURIToLocations != null) |
| { |
| ecoreBuilder.generate(externalURIToLocations); |
| } |
| } |
| catch (Exception exception) |
| { |
| XMIPlugin.INSTANCE.log(exception); |
| } |
| |
| URI locationForNull = urisToLocations.get(null); |
| if (locationForNull != null && helper.getNoNamespacePackage() == null) |
| { |
| helper.setNoNamespacePackage(getPackageForURI(locationForNull.toString())); |
| } |
| } |
| else if (externalURIToLocations != null) |
| { |
| try |
| { |
| ecoreBuilder.generate(externalURIToLocations); |
| } |
| catch (Exception exception) |
| { |
| XMIPlugin.INSTANCE.log(exception); |
| } |
| } |
| } |
| |
| protected void handleTopLocations(String prefix, String name) |
| { |
| processSchemaLocations(prefix, name); |
| if (processAnyXML) |
| { |
| // Ensure that anything can be handled, even if it's not recognized. |
| // |
| String uri = helper.getURI(prefix); |
| if (extendedMetaData.getPackage(uri) == null) |
| { |
| extendedMetaData.demandFeature(uri, name, true); |
| } |
| } |
| } |
| |
| /** |
| * The XML element represents a feature. There are two |
| * cases to handle: |
| * 1. The feature has a type that is a datatype. |
| * 2. The feature has a type that is a class. |
| */ |
| protected void handleFeature(String prefix, String name) |
| { |
| EObject peekObject = objects.peekEObject(); |
| |
| // This happens when processing an element with simple content that has elements content even though it shouldn't. |
| // |
| if (peekObject == null) |
| { |
| types.push(ERROR_TYPE); |
| error |
| (new FeatureNotFoundException |
| (name, |
| null, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| return; |
| } |
| |
| EStructuralFeature feature = getFeature(peekObject, prefix, name, true); |
| if (feature != null) |
| { |
| int kind = helper.getFeatureKind(feature); |
| if (kind == XMLHelper.DATATYPE_SINGLE || kind == XMLHelper.DATATYPE_IS_MANY) |
| { |
| objects.push(null); |
| mixedTargets.push(null); |
| types.push(feature); |
| if (!isNull()) |
| { |
| text = new StringBuffer(); |
| } |
| } |
| else if (extendedMetaData != null) |
| { |
| EReference eReference = (EReference)feature; |
| boolean isContainment = eReference.isContainment(); |
| if (!isContainment && !eReference.isResolveProxies() && extendedMetaData.getFeatureKind(feature) != ExtendedMetaData.UNSPECIFIED_FEATURE) |
| { |
| isIDREF = true; |
| objects.push(null); |
| mixedTargets.push(null); |
| types.push(feature); |
| text = new StringBuffer(); |
| } |
| else |
| { |
| createObject(peekObject, feature); |
| EObject childObject = objects.peekEObject(); |
| if (childObject != null) |
| { |
| if (isContainment) |
| { |
| EStructuralFeature simpleFeature = extendedMetaData.getSimpleFeature(childObject.eClass()); |
| if (simpleFeature != null) |
| { |
| isSimpleFeature = true; |
| isIDREF = simpleFeature instanceof EReference; |
| objects.push(null); |
| mixedTargets.push(null); |
| types.push(simpleFeature); |
| text = new StringBuffer(); |
| } |
| } |
| else if (!childObject.eIsProxy()) |
| { |
| text = new StringBuffer(); |
| } |
| } |
| } |
| } |
| else |
| { |
| createObject(peekObject, feature); |
| } |
| } |
| else |
| { |
| // Try to get a general-content feature. |
| // Use a pattern that's not possible any other way. |
| // |
| if (xmlMap != null && (feature = getFeature(peekObject, null, "", true)) != null) |
| { |
| |
| EFactory eFactory = getFactoryForPrefix(prefix); |
| |
| // This is for the case for a local unqualified element that has been bound. |
| // |
| if (eFactory == null) |
| { |
| eFactory = feature.getEContainingClass().getEPackage().getEFactoryInstance(); |
| } |
| |
| EObject newObject = null; |
| if (useNewMethods) |
| { |
| newObject = createObject(eFactory, helper.getType(eFactory, name), false); |
| } |
| else |
| { |
| newObject = createObjectFromFactory(eFactory, name); |
| } |
| newObject = validateCreateObjectFromFactory(eFactory, name, newObject, feature); |
| if (newObject != null) |
| { |
| setFeatureValue(peekObject, feature, newObject); |
| } |
| processObject(newObject); |
| } |
| else |
| { |
| // This handles the case of a substitution group. |
| // |
| if (xmlMap != null) |
| { |
| EFactory eFactory = getFactoryForPrefix(prefix); |
| EObject newObject = createObjectFromFactory(eFactory, name); |
| validateCreateObjectFromFactory(eFactory, name, newObject); |
| if (newObject != null) |
| { |
| for (EReference eReference : peekObject.eClass().getEAllReferences()) |
| { |
| if (eReference.getEType().isInstance(newObject)) |
| { |
| setFeatureValue(peekObject, eReference, newObject); |
| processObject(newObject); |
| return; |
| } |
| } |
| } |
| } |
| |
| handleUnknownFeature(prefix, name, true, peekObject, null); |
| } |
| } |
| } |
| |
| protected int getLineNumber() |
| { |
| if (locator != null) |
| { |
| return locator.getLineNumber(); |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| protected int getColumnNumber() |
| { |
| if (locator != null) |
| { |
| return locator.getColumnNumber(); |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| protected String getLocation() |
| { |
| return |
| locator != null && locator.getSystemId() != null ? |
| locator.getSystemId() : |
| resourceURI == null ? "" : resourceURI.toString(); |
| } |
| |
| protected AnyType getExtension(EObject peekObject) |
| { |
| AnyType anyType = eObjectToExtensionMap.get(peekObject); |
| if (anyType == null) |
| { |
| anyType = XMLTypeFactory.eINSTANCE.createAnyType(); |
| eObjectToExtensionMap.put(peekObject, anyType); |
| } |
| return anyType; |
| } |
| |
| protected void handleUnknownFeature(String prefix, String name, boolean isElement, EObject peekObject, String value) |
| { |
| if (recordUnknownFeature) |
| { |
| recordUnknownFeature(prefix, name, isElement, peekObject, value); |
| } |
| else |
| { |
| reportUnknownFeature(prefix, name, isElement, peekObject, value); |
| } |
| } |
| |
| protected void recordUnknownFeature(String prefix, String name, boolean isElement, EObject peekObject, String value) |
| { |
| if (isElement) |
| { |
| AnyType anyType = getExtension(peekObject); |
| int objectsIndex = objects.size(); |
| objects.push(anyType); |
| int mixedTargetsIndex = mixedTargets.size(); |
| mixedTargets.push(anyType.getAny()); |
| int typesIndex = types.size(); |
| types.push(UNKNOWN_FEATURE_TYPE); |
| |
| handleFeature(prefix, name); |
| |
| objects.remove(objectsIndex); |
| mixedTargets.remove(mixedTargetsIndex); |
| types.remove(typesIndex); |
| } |
| else |
| { |
| AnyType anyType = getExtension(peekObject); |
| setAttribValue(anyType, prefix == null ? name : prefix + ":" + name, value); |
| } |
| } |
| |
| protected void reportUnknownFeature(String prefix, String name, boolean isElement, EObject peekObject, String value) |
| { |
| if (isElement) |
| { |
| types.push(ERROR_TYPE); |
| } |
| error |
| (new FeatureNotFoundException |
| (name, |
| peekObject, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| } |
| |
| public void error(XMIException e) |
| { |
| xmlResource.getErrors().add(e); |
| } |
| |
| public void warning(XMIException e) |
| { |
| xmlResource.getWarnings().add(e); |
| } |
| |
| public void fatalError(XMIException e) |
| { |
| xmlResource.getErrors().add(e); |
| } |
| |
| /** |
| * Create an object based on the given feature and attributes. |
| */ |
| protected void createObject(EObject peekObject, EStructuralFeature feature) |
| { |
| if (isNull()) |
| { |
| setFeatureValue(peekObject, feature, null); |
| objects.push(null); |
| mixedTargets.push(null); |
| types.push(OBJECT_TYPE); |
| } |
| else |
| { |
| String xsiType = getXSIType(); |
| if (xsiType != null) |
| { |
| createObjectFromTypeName(peekObject, xsiType, feature); |
| } |
| else |
| { |
| createObjectFromFeatureType(peekObject, feature); |
| // This check is redundant -- see handleFeature method (EL) |
| /*if (extendedMetaData != null && !((EReference)feature).isContainment()) |
| { |
| text = new StringBuffer(); |
| }*/ |
| if (xmlMap != null && !((EReference)feature).isContainment()) |
| { |
| XMLResource.XMLInfo info = xmlMap.getInfo(feature); |
| if (info != null && info.getXMLRepresentation() == XMLResource.XMLInfo.ELEMENT) |
| { |
| text = new StringBuffer(); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Create an object from the given qualified type name. |
| */ |
| protected EObject createObjectFromTypeName(EObject peekObject, String typeQName, EStructuralFeature feature) |
| { |
| String typeName = null; |
| String prefix = ""; |
| int index = typeQName.indexOf(':', 0); |
| if (index > 0) |
| { |
| prefix = typeQName.substring(0, index); |
| typeName = typeQName.substring(index + 1); |
| } |
| else |
| { |
| typeName = typeQName; |
| } |
| |
| contextFeature = feature; |
| EFactory eFactory = getFactoryForPrefix(prefix); |
| contextFeature = null; |
| |
| if (eFactory == null && prefix.equals("") && helper.getURI(prefix) == null) |
| { |
| contextFeature = feature; |
| EPackage ePackage = handleMissingPackage(null); |
| contextFeature = null; |
| if (ePackage == null) |
| { |
| error(new PackageNotFoundException(null, getLocation(), getLineNumber(), getColumnNumber())); |
| } |
| else |
| { |
| eFactory = ePackage.getEFactoryInstance(); |
| } |
| } |
| EObject obj = null; |
| if (useNewMethods) |
| { |
| obj = createObject(eFactory, helper.getType(eFactory, typeName), false); |
| } |
| else |
| { |
| obj = createObjectFromFactory(eFactory, typeName); |
| |
| } |
| obj = validateCreateObjectFromFactory(eFactory, typeName, obj, feature); |
| |
| if (obj != null) |
| { |
| if (contextFeature == null) |
| { |
| setFeatureValue(peekObject, feature, obj); |
| } |
| else |
| { |
| contextFeature = null; |
| } |
| } |
| |
| processObject(obj); |
| |
| return obj; |
| } |
| |
| /** |
| * Create an object based on the type of the given feature. |
| */ |
| protected EObject createObjectFromFeatureType(EObject peekObject, EStructuralFeature feature) |
| { |
| String typeName = null; |
| EFactory factory = null; |
| EClassifier eType = null; |
| EObject obj = null; |
| |
| if (feature != null && (eType = feature.getEType()) != null) |
| { |
| if (useNewMethods) |
| { |
| if (extendedMetaData != null && eType == EcorePackage.Literals.EOBJECT && extendedMetaData.getFeatureKind(feature) != ExtendedMetaData.UNSPECIFIED_FEATURE) |
| { |
| eType = anyType; |
| typeName = extendedMetaData.getName(anyType); |
| factory = anyType.getEPackage().getEFactoryInstance(); |
| } |
| else |
| { |
| factory = eType.getEPackage().getEFactoryInstance(); |
| typeName = extendedMetaData == null ? eType.getName() : extendedMetaData.getName(eType); |
| } |
| obj = createObject(factory, eType, false); |
| } |
| else |
| { |
| |
| if (extendedMetaData != null && eType == EcorePackage.Literals.EOBJECT && extendedMetaData.getFeatureKind(feature) != ExtendedMetaData.UNSPECIFIED_FEATURE) |
| { |
| typeName = extendedMetaData.getName(anyType); |
| factory = anyType.getEPackage().getEFactoryInstance(); |
| } |
| else |
| { |
| EClass eClass = (EClass)eType; |
| typeName = extendedMetaData == null ? eClass.getName() : extendedMetaData.getName(eClass); |
| factory = eClass.getEPackage().getEFactoryInstance(); |
| } |
| obj = createObjectFromFactory(factory, typeName); |
| } |
| } |
| |
| obj = validateCreateObjectFromFactory(factory, typeName, obj, feature); |
| |
| if (obj != null) |
| { |
| setFeatureValue(peekObject, feature, obj); |
| } |
| |
| processObject(obj); |
| return obj; |
| } |
| |
| /** |
| * @deprecated since 2.2 |
| * Create an object given a content helper, a factory, and a type name, |
| * and process the XML attributes. |
| */ |
| @Deprecated |
| protected EObject createObjectFromFactory(EFactory factory, String typeName) |
| { |
| EObject newObject = null; |
| |
| if (factory != null) |
| { |
| newObject = helper.createObject(factory, typeName); |
| |
| if (newObject != null) |
| { |
| if (disableNotify) |
| newObject.eSetDeliver(false); |
| |
| handleObjectAttribs(newObject); |
| } |
| } |
| |
| return newObject; |
| } |
| |
| protected EObject createObject(EFactory eFactory, EClassifier type, boolean documentRoot) |
| { |
| EObject newObject = helper.createObject(eFactory, type); |
| if (newObject != null && !documentRoot) |
| { |
| if (disableNotify) |
| { |
| newObject.eSetDeliver(false); |
| } |
| handleObjectAttribs(newObject); |
| } |
| return newObject; |
| } |
| |
| protected EObject validateCreateObjectFromFactory(EFactory factory, String typeName, EObject newObject, boolean top) |
| { |
| if (newObject == null && top && (recordUnknownFeature || processAnyXML) && factory != null && extendedMetaData != null) |
| { |
| String namespace = extendedMetaData.getNamespace(factory.getEPackage()); |
| if (namespace == null) |
| { |
| usedNullNamespacePackage = true; |
| } |
| if (useNewMethods) |
| { |
| EClassifier type = extendedMetaData.demandType(namespace, typeName); |
| newObject = createObject(type.getEPackage().getEFactoryInstance(), type, false); |
| } |
| else |
| { |
| factory = extendedMetaData.demandType(namespace, typeName).getEPackage().getEFactoryInstance(); |
| newObject = createObjectFromFactory(factory, typeName); |
| } |
| } |
| |
| validateCreateObjectFromFactory(factory, typeName, newObject); |
| return newObject; |
| } |
| |
| protected void validateCreateObjectFromFactory(EFactory factory, String typeName, EObject newObject) |
| { |
| if (newObject == null) |
| { |
| error |
| (new ClassNotFoundException |
| (typeName, |
| factory, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| } |
| } |
| |
| protected EObject validateCreateObjectFromFactory(EFactory factory, String typeName, EObject newObject, EStructuralFeature feature) |
| { |
| if (newObject != null) |
| { |
| if (extendedMetaData != null) |
| { |
| Collection<EPackage> demandedPackages = extendedMetaData.demandedPackages(); |
| if (!demandedPackages.isEmpty() && demandedPackages.contains(newObject.eClass().getEPackage())) |
| { |
| if (recordUnknownFeature) |
| { |
| EObject peekObject = objects.peekEObject(); |
| if (!(peekObject instanceof AnyType)) |
| { |
| AnyType anyType = getExtension(objects.peekEObject()); |
| EStructuralFeature entryFeature = |
| extendedMetaData.demandFeature(extendedMetaData.getNamespace(feature), extendedMetaData.getName(feature), true); |
| anyType.getAny().add(entryFeature, newObject); |
| contextFeature = entryFeature; |
| } |
| return newObject; |
| } |
| else |
| { |
| String namespace = extendedMetaData.getNamespace(feature); |
| String name = extendedMetaData.getName(feature); |
| EStructuralFeature wildcardFeature = |
| extendedMetaData.getElementWildcardAffiliation((objects.peekEObject()).eClass(), namespace, name); |
| if (wildcardFeature != null) |
| { |
| int processingKind = laxWildcardProcessing ? ExtendedMetaData.LAX_PROCESSING : extendedMetaData.getProcessingKind(wildcardFeature); |
| switch (processingKind) |
| { |
| case ExtendedMetaData.LAX_PROCESSING: |
| case ExtendedMetaData.SKIP_PROCESSING: |
| { |
| return newObject; |
| } |
| } |
| } |
| } |
| |
| newObject = null; |
| } |
| } |
| } |
| else if (feature != null && factory != null && extendedMetaData != null) |
| { |
| // processing unknown feature with xsi:type (xmi:type) |
| if (recordUnknownFeature || processAnyXML) |
| { |
| |
| EObject result = null; |
| String namespace = extendedMetaData.getNamespace(factory.getEPackage()); |
| if (namespace == null) |
| { |
| usedNullNamespacePackage = true; |
| } |
| if (useNewMethods) |
| { |
| EClassifier type = extendedMetaData.demandType(namespace, typeName); |
| result = createObject(type.getEPackage().getEFactoryInstance(), type, false); |
| } |
| else |
| { |
| factory = extendedMetaData.demandType(namespace, typeName).getEPackage().getEFactoryInstance(); |
| result = createObjectFromFactory(factory, typeName); |
| } |
| EObject peekObject = objects.peekEObject(); |
| if (!(peekObject instanceof AnyType)) |
| { |
| AnyType anyType = getExtension(peekObject); |
| EStructuralFeature entryFeature = |
| extendedMetaData.demandFeature(extendedMetaData.getNamespace(feature), extendedMetaData.getName(feature), true); |
| anyType.getAny().add(entryFeature, result); |
| contextFeature = entryFeature; |
| } |
| return result; |
| } |
| else |
| { |
| String namespace = extendedMetaData.getNamespace(feature); |
| String name = extendedMetaData.getName(feature); |
| EStructuralFeature wildcardFeature = |
| extendedMetaData.getElementWildcardAffiliation((objects.peekEObject()).eClass(), namespace, name); |
| if (wildcardFeature != null) |
| { |
| int processingKind = laxWildcardProcessing ? ExtendedMetaData.LAX_PROCESSING : extendedMetaData.getProcessingKind(wildcardFeature); |
| switch (processingKind) |
| { |
| case ExtendedMetaData.LAX_PROCESSING: |
| case ExtendedMetaData.SKIP_PROCESSING: |
| { |
| // EATM Demand create metadata; needs to depend on processing mode... |
| String factoryNamespace = extendedMetaData.getNamespace(factory.getEPackage()); |
| if (factoryNamespace == null) |
| { |
| usedNullNamespacePackage = true; |
| } |
| if (useNewMethods) |
| { |
| EClassifier type = extendedMetaData.demandType(factoryNamespace, typeName); |
| return createObject(type.getEPackage().getEFactoryInstance(), type, false); |
| } |
| else |
| { |
| factory = extendedMetaData.demandType(factoryNamespace, typeName).getEPackage().getEFactoryInstance(); |
| return createObjectFromFactory(factory, typeName); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| validateCreateObjectFromFactory(factory, typeName, newObject); |
| |
| return newObject; |
| } |
| |
| /** |
| * Add object to appropriate stacks. |
| */ |
| protected void processObject(EObject object) |
| { |
| if (recordAnyTypeNSDecls && object instanceof AnyType) |
| { |
| FeatureMap featureMap = ((AnyType)object).getAnyAttribute(); |
| for (Map.Entry<String, String> entry : helper.getAnyContentPrefixToURIMapping().entrySet()) |
| { |
| Object uri = entry.getValue(); |
| featureMap.add(extendedMetaData.demandFeature(ExtendedMetaData.XMLNS_URI, entry.getKey(), false), uri == null ? "" : uri); |
| } |
| } |
| |
| if (object != null) |
| { |
| objects.push(object); |
| types.push(OBJECT_TYPE); |
| |
| if (extendedMetaData != null) |
| { |
| EStructuralFeature mixedFeature = extendedMetaData.getMixedFeature(object.eClass()); |
| if (mixedFeature != null) |
| { |
| mixedTargets.push((FeatureMap)object.eGet(mixedFeature)); |
| } |
| else |
| { |
| mixedTargets.push(null); |
| } |
| } |
| else |
| { |
| mixedTargets.push(null); |
| } |
| } |
| else |
| { |
| types.push(ERROR_TYPE); |
| } |
| } |
| |
| protected EFactory getFactoryForPrefix(String prefix) |
| { |
| EFactory factory = prefixesToFactories.get(prefix); |
| if (factory == null) |
| { |
| String uri = helper.getURI(prefix); |
| EPackage ePackage = getPackageForURI(uri); |
| |
| if (ePackage == null && uri == null && prefix.equals("")) |
| { |
| ePackage = helper.getNoNamespacePackage(); |
| } |
| |
| |
| if (ePackage != null) |
| { |
| factory = ePackage.getEFactoryInstance(); |
| prefixesToFactories.put(prefix, factory); |
| if (uri == null) |
| { |
| usedNullNamespacePackage = true; |
| } |
| } |
| } |
| |
| return factory; |
| } |
| |
| /** |
| * Attempt to get the namespace for the given prefix, then return |
| * ERegister.getPackage() or null. |
| */ |
| protected EPackage getPackageForURI(String uriString) |
| { |
| if (uriString == null) |
| { |
| return null; |
| } |
| |
| EPackage ePackage = |
| extendedMetaData == null ? |
| packageRegistry.getEPackage(uriString) : |
| extendedMetaData.getPackage(uriString); |
| |
| if (ePackage != null && ePackage.eIsProxy()) |
| { |
| ePackage = null; |
| } |
| |
| if (ePackage == null) |
| { |
| URI uri = URI.createURI(uriString); |
| if (uri.scheme() == null) |
| { |
| // This only works for old globally registered things. |
| for (Map.Entry<String, Object> entry : packageRegistry.entrySet()) |
| { |
| String nsURI = entry.getKey(); |
| if (nsURI != null && |
| nsURI.length() > uriString.length() && |
| nsURI.endsWith(uriString) && |
| nsURI.charAt(nsURI.length() - uriString.length() - 1) == '/') |
| { |
| oldStyleProxyURIs = true; |
| return (EPackage)entry.getValue(); |
| } |
| } |
| } |
| |
| URI nsURI = uri; |
| if (urisToLocations != null) |
| { |
| URI locationURI = urisToLocations.get(uriString); |
| if (locationURI != null) |
| { |
| uri = locationURI; |
| } |
| } |
| |
| String fragment = uri.fragment(); |
| Resource resource = null; |
| |
| if ("java".equalsIgnoreCase(uri.scheme()) && uri.authority() != null) |
| { |
| try |
| { |
| String className = uri.authority(); |
| Class<?> javaClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader()); |
| Field field = javaClass.getField("eINSTANCE"); |
| resource = ((EPackage)field.get(null)).eResource(); |
| } |
| catch (Exception exception) |
| { |
| // Ignore it if we can't find it since we'll fail anyway. |
| } |
| } |
| |
| if (resource == null && resourceSet != null) |
| { |
| URI trimmedURI = uri.trimFragment(); |
| resource = resourceSet.getResource(trimmedURI, false); |
| if (resource != null) |
| { |
| if (!resource.isLoaded()) |
| { |
| try |
| { |
| resource.load(resourceSet.getLoadOptions()); |
| } |
| catch (IOException exception) |
| { |
| // Continue with a different approach. |
| } |
| } |
| } |
| else if (!XMLResource.XML_SCHEMA_URI.equals(uriString) && (usePackageNsURIAsLocation || uri != nsURI)) |
| { |
| try |
| { |
| InputStream inputStream = getURIConverter().createInputStream(trimmedURI, null); |
| resource = resourceSet.createResource(trimmedURI, ContentHandler.UNSPECIFIED_CONTENT_TYPE); |
| if (resource == null) |
| { |
| inputStream.close(); |
| } |
| else |
| { |
| resource.load(inputStream, resourceSet.getLoadOptions()); |
| } |
| } |
| catch (IOException exception) |
| { |
| // Continue with a different approach. |
| } |
| } |
| } |
| |
| if (resource != null) |
| { |
| Object content = null; |
| if (fragment != null) |
| { |
| content = resource.getEObject(fragment); |
| } |
| else |
| { |
| List<EObject> contents = resource.getContents(); |
| if (!contents.isEmpty()) |
| { |
| content = contents.get(0); |
| } |
| } |
| |
| if (content instanceof EPackage) |
| { |
| ePackage = (EPackage)content; |
| if (extendedMetaData != null) |
| { |
| extendedMetaData.putPackage(extendedMetaData.getNamespace(ePackage), ePackage); |
| } |
| else |
| { |
| packageRegistry.put(ePackage.getNsURI(), ePackage); |
| } |
| } |
| } |
| } |
| |
| if (ePackage == null) |
| { |
| ePackage = handleMissingPackage(uriString); |
| } |
| |
| if (ePackage == null) |
| { |
| error |
| (new PackageNotFoundException |
| (uriString, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| } |
| |
| return ePackage; |
| } |
| |
| protected EPackage handleMissingPackage(String uriString) |
| { |
| if (XMLResource.XML_SCHEMA_URI.equals(uriString)) |
| { |
| return xmlSchemaTypePackage; |
| } |
| else if (extendedMetaData != null) |
| { |
| if (recordUnknownFeature) |
| { |
| return extendedMetaData.demandPackage(uriString); |
| } |
| else if (processAnyXML && objects.isEmpty()) |
| { |
| return extendedMetaData.demandPackage(uriString); |
| } |
| else if (contextFeature != null) |
| { |
| String namespace = extendedMetaData.getNamespace(contextFeature); |
| String name = extendedMetaData.getName(contextFeature); |
| EStructuralFeature wildcardFeature = |
| extendedMetaData.getElementWildcardAffiliation((objects.peekEObject()).eClass(), namespace, name); |
| if (wildcardFeature != null) |
| { |
| int processingKind = laxWildcardProcessing ? ExtendedMetaData.LAX_PROCESSING : extendedMetaData.getProcessingKind(wildcardFeature); |
| switch (processingKind) |
| { |
| case ExtendedMetaData.LAX_PROCESSING: |
| case ExtendedMetaData.SKIP_PROCESSING: |
| { |
| return extendedMetaData.demandPackage(uriString); |
| } |
| } |
| } |
| } |
| } |
| |
| return missingPackageHandler != null ? missingPackageHandler.getPackage(uriString) : null; |
| } |
| |
| protected URIConverter getURIConverter() |
| { |
| return resourceSet != null ? resourceSet.getURIConverter() : new ExtensibleURIConverterImpl(); |
| } |
| |
| protected void setFeatureValue(EObject object, EStructuralFeature feature, Object value) |
| { |
| setFeatureValue(object, feature, value, -1); |
| } |
| |
| /** |
| * Set the given feature of the given object to the given value. |
| */ |
| protected void setFeatureValue(EObject object, EStructuralFeature feature, Object value, int position) |
| { |
| try |
| { |
| helper.setValue(object, feature, value, position); |
| } |
| catch (RuntimeException e) |
| { |
| error |
| (new IllegalValueException |
| (object, |
| feature, |
| value, |
| e, |
| getLocation(), |
| getLineNumber(), |
| getColumnNumber())); |
| } |
| } |
| |
| /** |
| * Set the values for the given multi-valued forward reference. |
| */ |
| protected void setFeatureValues(ManyReference reference) |
| { |
| List<XMIException> xmiExceptions = helper.setManyReference(reference, getLocation()); |
| |
| if (xmiExceptions != null) |
| { |
| for (XMIException exception : xmiExceptions) |
| { |
| error(exception); |
| } |
| } |
| } |
| |
| /** |
| * Create a feature with the given name for the given object with the |
| * given values. |
| */ |
| protected void setAttribValue(EObject object, String name, String value) |
| { |
| int index = name.indexOf(':', 0); |
| |
| // We use null here instead of "" because an attribute without a prefix is considered to have the null target namespace... |
| String prefix = null; |
| String localName = name; |
| if (index != -1) |
| { |
| prefix = name.substring(0, index); |
| localName = name.substring(index + 1); |
| } |
| EStructuralFeature feature = getFeature(object, prefix, localName, false); |
| if (feature == null) |
| { |
| handleUnknownFeature(prefix, localName, false, object, value); |
| } |
| else |
| { |
| int kind = helper.getFeatureKind(feature); |
| |
| if (kind == XMLHelper.DATATYPE_SINGLE || kind == XMLHelper.DATATYPE_IS_MANY) |
| { |
| setFeatureValue(object, feature, value, -2); |
| } |
| else |
| { |
| setValueFromId(object, (EReference)feature, value); |
| } |
| } |
| } |
| |
| /** |
| * Create a ValueLine object and put it in the list |
| * of references to resolve at the end of the document. |
| */ |
| protected void setValueFromId(EObject object, EReference eReference, String ids) |
| { |
| StringTokenizer st = new StringTokenizer(ids); |
| |
| boolean isFirstID = true; |
| boolean mustAdd = deferIDREFResolution; |
| boolean mustAddOrNotOppositeIsMany = false; |
| |
| int size = 0; |
| String qName = null; |
| int position = 0; |
| while (st.hasMoreTokens()) |
| { |
| String id = st.nextToken(); |
| int index = id.indexOf('#', 0); |
| if (index != -1) |
| { |
| if (index == 0) |
| { |
| id = id.substring(1); |
| } |
| else |
| { |
| Object oldAttributes = setAttributes(null); |
| // Create a proxy in the correct way and pop it. |
| // |
| InternalEObject proxy = |
| (InternalEObject) |
| (qName == null ? |
| createObjectFromFeatureType(object, eReference) : |
| createObjectFromTypeName(object, qName, eReference)); |
| setAttributes(oldAttributes); |
| if (proxy != null) |
| { |
| handleProxy(proxy, id); |
| } |
| objects.pop(); |
| types.pop(); |
| mixedTargets.pop(); |
| |
| qName = null; |
| ++position; |
| continue; |
| } |
| } |
| else if (id.indexOf(':', 0) != -1) |
| { |
| qName = id; |
| continue; |
| } |
| |
| // Ensure that references corresponding to repeating elements are always deferred and processed in order at the end. |
| // |
| if (isFirstID && extendedMetaData != null && eReference.isMany() && extendedMetaData.getFeatureKind(eReference) == ExtendedMetaData.ELEMENT_FEATURE) |
| { |
| SingleReference ref = new SingleReference |
| (object, |
| eReference, |
| id, |
| -1, |
| getLineNumber(), |
| getColumnNumber()); |
| forwardSingleReferences.add(ref); |
| return; |
| } |
| |
| if (!deferIDREFResolution) |
| { |
| if (isFirstID) |
| { |
| EReference eOpposite = eReference.getEOpposite(); |
| if (eOpposite == null) |
| { |
| mustAdd = true; |
| mustAddOrNotOppositeIsMany = true; |
| } |
| else |
| { |
| mustAdd = eOpposite.isTransient() || eReference.isMany(); |
| mustAddOrNotOppositeIsMany = mustAdd || !eOpposite.isMany(); |
| } |
| isFirstID = false; |
| } |
| |
| if (mustAddOrNotOppositeIsMany) |
| { |
| EObject resolvedEObject = xmlResource.getEObject(id); |
| if (resolvedEObject != null) |
| { |
| setFeatureValue(object, eReference, resolvedEObject); |
| qName = null; |
| ++position; |
| continue; |
| } |
| } |
| } |
| |
| if (mustAdd) |
| { |
| if (size == capacity) |
| growArrays(); |
| |
| identifiers[size] = id; |
| positions[size] = position; |
| ++size; |
| } |
| qName = null; |
| ++position; |
| } |
| |
| if (position == 0) |
| { |
| setFeatureValue(object, eReference, null, -2); |
| } |
| else if (size <= REFERENCE_THRESHOLD) |
| { |
| for (int i = 0; i < size; i++) |
| { |
| SingleReference ref = new SingleReference |
| (object, |
| eReference, |
| identifiers[i], |
| positions[i], |
| getLineNumber(), |
| getColumnNumber()); |
| forwardSingleReferences.add(ref); |
| } |
| } |
| else |
| { |
| Object[] values = new Object[size]; |
| int[] currentPositions = new int[size]; |
| System.arraycopy(identifiers, 0, values, 0, size); |
| System.arraycopy(positions, 0, currentPositions, 0, size); |
| |
| ManyReference ref = new ManyReference |
| (object, |
| eReference, |
| values, |
| currentPositions, |
| getLineNumber(), |
| getColumnNumber()); |
| forwardManyReferences.add(ref); |
| } |
| } |
| |
| protected void handleProxy(InternalEObject proxy, String uriLiteral) |
| { |
| URI proxyURI; |
| if (oldStyleProxyURIs) |
| { |
| proxy.eSetProxyURI(proxyURI = URI.createURI(uriLiteral.startsWith("/") ? uriLiteral : "/" + uriLiteral)); |
| } |
| else |
| { |
| URI uri = URI.createURI(uriLiteral); |
| if (uriHandler != null) |
| { |
| uri = uriHandler.resolve(uri); |
| } |
| else if (resolve && |
| uri.isRelative() && |
| uri.hasRelativePath() && |
| (extendedMetaData == null ? |
| !packageRegistry.containsKey(uri.trimFragment().toString()) : |
| extendedMetaData.getPackage(uri.trimFragment().toString()) == null)) |
| { |
| uri = helper.resolve(uri, resourceURI); |
| } |
| proxy.eSetProxyURI(proxyURI = uri); |
| } |
| |
| // Test for a same document reference that would usually be handled as an IDREF. |
| // |
| if (proxyURI.trimFragment().equals(resourceURI)) |
| { |
| sameDocumentProxies.add(proxy); |
| } |
| } |
| |
| protected void growArrays() { |
| int oldCapacity = capacity; |
| capacity = capacity * 2; |
| Object[] newIdentifiers = new Object[capacity]; |
| int[] newPositions = new int[capacity]; |
| System.arraycopy(identifiers, 0, newIdentifiers, 0, oldCapacity); |
| System.arraycopy(positions, 0, newPositions, 0, oldCapacity); |
| identifiers = newIdentifiers; |
| positions = newPositions; |
| } |
| |
| /** |
| * Returns true if there was an error in the last XML element; false otherwise. |
| */ |
| protected boolean isError() |
| { |
| return types.peek() == ERROR_TYPE; |
| } |
| |
| static class EClassFeatureNamePair |
| { |
| public EClass eClass; |
| public String featureName; |
| public String namespaceURI; |
| public boolean isElement; |
| |
| @Override |
| public boolean equals(Object that) |
| { |
| EClassFeatureNamePair typedThat = (EClassFeatureNamePair)that; |
| return |
| typedThat.eClass == eClass && |
| typedThat.isElement == isElement && |
| typedThat.featureName.equals(featureName) && |
| (typedThat.namespaceURI != null ? typedThat.namespaceURI.equals(namespaceURI): namespaceURI == null); |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| return eClass.hashCode() ^ featureName.hashCode() ^ (namespaceURI == null ? 0 : namespaceURI.hashCode()) + (isElement ? 0 : 1); |
| } |
| } |
| |
| Map<EClassFeatureNamePair, EStructuralFeature> eClassFeatureNamePairToEStructuralFeatureMap; |
| boolean isOptionUseXMLNameToFeatureSet; |
| EClassFeatureNamePair eClassFeatureNamePair = new EClassFeatureNamePair(); |
| |
| /** |
| * @deprecated |
| */ |
| @Deprecated |
| protected EStructuralFeature getFeature(EObject object, String prefix, String name) |
| { |
| EClass eClass = object.eClass(); |
| String uri = helper.getURI(prefix); |
| EStructuralFeature result = helper.getFeature(eClass, uri, name, true); |
| if (result == null) |
| { |
| helper.getFeature(eClass, uri, name, false); |
| } |
| return result; |
| } |
| |
| /** |
| * Get the EStructuralFeature from the metaObject for the given object |
| * and feature name. |
| */ |
| protected EStructuralFeature getFeature(EObject object, String prefix, String name, boolean isElement) |
| { |
| String uri = helper.getURI(prefix); |
| EClass eClass = object.eClass(); |
| eClassFeatureNamePair.eClass = eClass; |
| eClassFeatureNamePair.featureName = name; |
| eClassFeatureNamePair.namespaceURI = uri; |
| eClassFeatureNamePair.isElement = isElement; |
| EStructuralFeature result = eClassFeatureNamePairToEStructuralFeatureMap.get(eClassFeatureNamePair); |
| if (result == null) |
| { |
| result = helper.getFeature(eClass, uri, name, isElement); |
| |
| if (result == null) |
| { |
| if (extendedMetaData != null) |
| { |
| EStructuralFeature wildcardFeature = |
| isElement ? |
| extendedMetaData.getElementWildcardAffiliation(eClass, uri, name) : |
| extendedMetaData.getAttributeWildcardAffiliation(eClass, uri, name); |
| if (wildcardFeature != null) |
| { |
| int processingKind = laxWildcardProcessing ? ExtendedMetaData.LAX_PROCESSING : extendedMetaData.getProcessingKind(wildcardFeature); |
| switch (processingKind) |
| { |
| case ExtendedMetaData.LAX_PROCESSING: |
| case ExtendedMetaData.SKIP_PROCESSING: |
| { |
| // EATM Demand create metadata. |
| result = extendedMetaData.demandFeature(uri, name, isElement); |
| break; |
| } |
| } |
| } |
| } |
| else |
| { |
| // EATM Call the deprecated method which does the same thing |
| // but might have an override in older code. |
| result = getFeature(object, prefix, name); |
| } |
| } |
| |
| EClassFeatureNamePair entry = new EClassFeatureNamePair(); |
| entry.eClass = eClass; |
| entry.featureName = name; |
| entry.namespaceURI = uri; |
| entry.isElement = isElement; |
| eClassFeatureNamePairToEStructuralFeatureMap.put(entry, result); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Searches the array of bytes to determine the XML |
| * encoding. |
| */ |
| public static String getXMLEncoding(byte[] bytes) |
| { |
| String javaEncoding = null; |
| |
| if (bytes.length >= 4) |
| { |
| if (((bytes[0] == -2) && (bytes[1] == -1)) || |
| ((bytes[0] == 0) && (bytes[1] == 60))) |
| javaEncoding = "UnicodeBig"; |
| else if (((bytes[0] == -1) && (bytes[1] == -2)) || |
| ((bytes[0] == 60) && (bytes[1] == 0))) |
| javaEncoding = "UnicodeLittle"; |
| else if ((bytes[0] == -17) && (bytes[1] == -69) && (bytes[2] == -65)) |
| javaEncoding = "UTF8"; |
| } |
| |
| String header = null; |
| |
| try |
| { |
| if (javaEncoding != null) |
| header = new String(bytes, 0, bytes.length, javaEncoding); |
| else |
| header = new String(bytes, 0, bytes.length); |
| } |
| catch (UnsupportedEncodingException e) |
| { |
| return null; |
| } |
| |
| if (!header.startsWith("<?xml")) |
| return "UTF-8"; |
| |
| int endOfXMLPI = header.indexOf("?>"); |
| int encodingIndex = header.indexOf("encoding", 6); |
| |
| if ((encodingIndex == -1) || (encodingIndex > endOfXMLPI)) |
| return "UTF-8"; |
| |
| int firstQuoteIndex = header.indexOf('"', encodingIndex); |
| int lastQuoteIndex; |
| |
| if ((firstQuoteIndex == -1) || (firstQuoteIndex > endOfXMLPI)) |
| { |
| firstQuoteIndex = header.indexOf('\'', encodingIndex); |
| lastQuoteIndex = header.indexOf('\'', firstQuoteIndex + 1); |
| } |
| else |
| lastQuoteIndex = header.indexOf('"', firstQuoteIndex + 1); |
| |
| return header.substring(firstQuoteIndex + 1, lastQuoteIndex); |
| } |
| |
| protected void handleComment(String comment) |
| { |
| FeatureMap featureMap = mixedTargets.peek(); |
| featureMap.add(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__COMMENT, comment); |
| text = null; |
| } |
| protected void handleMixedText() |
| { |
| FeatureMap featureMap = mixedTargets.peek(); |
| featureMap.add(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__TEXT, text.toString()); |
| text = null; |
| } |
| |
| protected void handleCDATA() |
| { |
| FeatureMap featureMap = mixedTargets.peek(); |
| featureMap.add(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__CDATA, text.toString()); |
| text = null; |
| } |
| |
| protected void handleProcessingInstruction(String target, String data) |
| { |
| FeatureMap featureMap = mixedTargets.peek(); |
| FeatureMapUtil.addProcessingInstruction(featureMap, target, data); |
| text = null; |
| } |
| |
| protected EcoreBuilder createEcoreBuilder(Map<?, ?> options, ExtendedMetaData extendedMetaData) |
| { |
| return new DefaultEcoreBuilder(extendedMetaData); |
| } |
| } |