| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.tuscany.sdo.util.resource; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Writer; |
| import java.net.URL; |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.xml.XMLConstants; |
| import javax.xml.namespace.NamespaceContext; |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLOutputFactory; |
| import javax.xml.stream.XMLStreamConstants; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.stream.XMLStreamWriter; |
| |
| import org.apache.tuscany.sdo.AnyTypeDataObject; |
| import org.apache.tuscany.sdo.SDOExtendedMetaData; |
| import org.apache.tuscany.sdo.SDOPackage; |
| import org.apache.tuscany.sdo.helper.HelperContextImpl; |
| import org.apache.tuscany.sdo.helper.SDOExtendedMetaDataImpl; |
| import org.apache.tuscany.sdo.helper.XMLStreamHelper; |
| import org.apache.tuscany.sdo.helper.XSDHelperImpl; |
| import org.apache.tuscany.sdo.impl.AnyTypeDataObjectImpl; |
| import org.apache.tuscany.sdo.impl.SDOPackageImpl; |
| import org.apache.tuscany.sdo.api.SDOHelper; |
| import org.apache.tuscany.sdo.api.SDOUtil; |
| import org.apache.tuscany.sdo.util.StAX2SAXAdapter; |
| import org.apache.tuscany.sdo.model.internal.InternalFactory; |
| import org.apache.tuscany.sdo.model.internal.impl.InternalFactoryImpl; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EDataType; |
| 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.Resource; |
| 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.xmi.XMIException; |
| import org.eclipse.emf.ecore.xmi.XMLHelper; |
| import org.eclipse.emf.ecore.xmi.XMLLoad; |
| import org.eclipse.emf.ecore.xmi.XMLOptions; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecore.xmi.XMLSave; |
| import org.eclipse.emf.ecore.xmi.impl.SAXXMLHandler; |
| import org.eclipse.emf.ecore.xmi.impl.XMLHelperImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLOptionsImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLString; |
| 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.XMLTypePackage; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| import commonj.sdo.ChangeSummary; |
| import commonj.sdo.DataObject; |
| import commonj.sdo.helper.XSDHelper; |
| |
| public class SDOXMLResourceImpl extends XMLResourceImpl { |
| private XMLStreamReader reader; |
| |
| /** |
| * [rfeng] Override the XMLHelperImpl to replace the NamespaceSupport so |
| * that it's aware of the NamespaceContext from the XMLStreamReader |
| */ |
| public static class SDOXMLHelperImpl extends XMLHelperImpl { |
| |
| public EObject createObject(EFactory eFactory, EClassifier type) { |
| // this fix does not work! |
| /* |
| * if ("DataObject".equals(type.getName())) { AnyTypeDataObjectImpl |
| * result = (AnyTypeDataObjectImpl) |
| * EcoreUtil.create(SDOPackage.eINSTANCE.getAnyTypeDataObject()); |
| * return result; } |
| */ |
| |
| // this is the createObject from EMF 2.2 note: it creates the object |
| // ALSO for abstract classes.... |
| EObject newObject = null; |
| if (eFactory != null) { |
| if (extendedMetaData != null) { |
| if (type == null) { |
| return null; |
| } else if (type instanceof EClass) { |
| newObject = eFactory.create((EClass) type); |
| } else { |
| SimpleAnyType result = (SimpleAnyType) EcoreUtil |
| .create(anySimpleType); |
| result.setInstanceType((EDataType) type); |
| newObject = result; |
| } |
| } else { |
| if (type != null) { |
| newObject = eFactory.create((EClass) type); |
| } |
| } |
| } |
| return newObject; |
| // return super.createObject(eFactory, type); |
| } |
| |
| /** |
| * EMF XMLResource (SAX) may be used to load from only a *portion* of a |
| * StAX stream which may reference (global) namespaces bound outside the |
| * (local) portion. This class extends EMF's NamespaceSupport to make |
| * {@link #getPrefix} and {@link #getURI} query these global binding(s) |
| * after first checking the local context(s). |
| */ |
| private static class StreamNamespaceSupport extends |
| XMLHelperImpl.NamespaceSupport { |
| protected NamespaceContext nameSpaceContext; |
| |
| public String getPrefix(String uri) { |
| String prefix = super.getPrefix(uri); |
| if (prefix == null) |
| try { |
| prefix = nameSpaceContext.getPrefix(uri); |
| } catch (Exception e) { |
| // HACK: |
| // java.lang.UnsupportedOperationException |
| // at |
| // org.apache.axiom.om.impl.llom.OMStAXWrapper.getNamespaceContext(OMStAXWrapper.java:984) |
| } |
| return prefix; |
| } |
| |
| public String getURI(String prefix) { |
| String uri = super.getURI(prefix); |
| if (uri == null) |
| try { |
| uri = nameSpaceContext.getNamespaceURI(prefix); |
| } catch (Exception e) { |
| // HACK: |
| // java.lang.UnsupportedOperationException |
| // at |
| // org.apache.axiom.om.impl.llom.OMStAXWrapper.getNamespaceContext(OMStAXWrapper.java:984) |
| } |
| return uri; |
| } |
| |
| public StreamNamespaceSupport(XMLStreamReader reader) { |
| super(); |
| nameSpaceContext = reader.getNamespaceContext(); |
| } |
| |
| } |
| |
| public SDOXMLHelperImpl(XMLResource resource, XMLStreamReader reader) { |
| this(reader); |
| setResource(resource); |
| } |
| |
| public SDOXMLHelperImpl(XMLStreamReader reader) { |
| super(); |
| if (reader instanceof XMLDocumentStreamReader) // Only use |
| // StreamNamespaceSupport |
| // when loading from |
| // a *portion* of a |
| // StAX stream |
| namespaceSupport = new StreamNamespaceSupport(reader); |
| } |
| |
| private class NameSpaceContext implements NamespaceContext { // TODO |
| // Helper# |
| // pushContext() |
| // & |
| // popContext |
| public String getNamespaceURI(String prefix) { |
| return SDOXMLHelperImpl.this.getNamespaceURI(prefix); |
| } |
| |
| public String getPrefix(String namespaceURI) { |
| return SDOXMLHelperImpl.this.getPrefix(namespaceURI); |
| } |
| |
| public Iterator getPrefixes(String namespaceURI) { |
| return ((Collection) urisToPrefixes.get(namespaceURI)) |
| .iterator(); |
| } |
| } |
| |
| NameSpaceContext nameSpaceContext/* = null */; |
| |
| protected final NameSpaceContext nameSpaceContext() { |
| if (nameSpaceContext == null) |
| nameSpaceContext = new NameSpaceContext(); |
| return nameSpaceContext; |
| } |
| |
| private String xsdQName2SDOURI(String xsdQName) { |
| org.eclipse.emf.ecore.xml.type.internal.QName qname = new org.eclipse.emf.ecore.xml.type.internal.QName( |
| xsdQName); |
| try { |
| updateQNameURI(qname); |
| } catch (IllegalArgumentException e) { |
| return xsdQName; |
| } |
| String uri = qname.getNamespaceURI(); |
| if (uri != "") |
| return uri + "#" + qname.getLocalPart(); |
| else |
| return qname.getLocalPart(); |
| } |
| |
| private String getPrefixFromNamespaceURI(String nsURI) { |
| String nsPrefix = null; |
| |
| List prefixes = (List) urisToPrefixes.get(nsURI); |
| if (prefixes != null) { |
| for (Iterator i = prefixes.iterator(); i.hasNext();) { |
| nsPrefix = (String) i.next(); |
| if (nsPrefix.length() >= 0) { |
| // When the length is 0, it's the default namespace |
| return nsPrefix; |
| } |
| } |
| } |
| |
| nsPrefix = namespaceSupport.getPrefix(nsURI); |
| if (nsPrefix != null) { |
| return nsPrefix; |
| } |
| |
| // Demand create a new package |
| EPackage ePackage = extendedMetaData.demandPackage(nsURI); |
| |
| if (ExtendedMetaData.XSI_URI.equals(nsURI)) { |
| ePackage.setNsPrefix(ExtendedMetaData.XSI_PREFIX); |
| } |
| |
| // getPrefix() will make sure all mapping tables are configured |
| // correctly |
| nsPrefix = getPrefix(ePackage, true); |
| |
| return nsPrefix; |
| } |
| |
| private String SDOURI2XsdQName(String sdoURI) { |
| String namespace = null; |
| String localPart = sdoURI; |
| |
| int index = sdoURI.indexOf('#'); |
| if (index == -1) { |
| return localPart; |
| } else { |
| namespace = sdoURI.substring(0, index); |
| localPart = sdoURI.substring(index + 1); |
| |
| String prefix = getPrefixFromNamespaceURI(namespace); |
| |
| if (prefix.length() == 0) |
| return localPart; |
| |
| return prefix + ":" + localPart; |
| } |
| } |
| |
| // / TODO?!?!?! |
| /* |
| * public EObject createObject(EFactory eFactory, EClassifier type) { if |
| * (type instanceof AnyTypeDataObject) { AnyTypeDataObjectImpl result = |
| * (AnyTypeDataObjectImpl) |
| * EcoreUtil.create(SDOPackage.eINSTANCE.getAnyTypeDataObject()); return |
| * result; } return super.createObject(eFactory, type); } |
| */ |
| |
| protected Object createFromString(EFactory eFactory, |
| EDataType eDataType, String value) { |
| Object obj = super.createFromString(eFactory, eDataType, value); |
| if (eDataType == ((InternalFactoryImpl) InternalFactory.INSTANCE) |
| .getQName()) { |
| if (extendedMetaData != null) { |
| if (obj instanceof List) { |
| List list = (List) obj; |
| for (int i = 0; i < list.size(); i++) { |
| String xsdQName = (String) list.get(i); |
| list.set(i, xsdQName2SDOURI(xsdQName)); |
| } |
| } else { |
| obj = xsdQName2SDOURI((String) obj); |
| } |
| } |
| } |
| return obj; |
| } |
| |
| public String convertToString(EFactory factory, EDataType eDataType, |
| Object value) { |
| if (eDataType == ((InternalFactoryImpl) InternalFactory.INSTANCE) |
| .getQName()) { |
| if (extendedMetaData != null) { |
| if (value instanceof List) { |
| List list = (List) value; |
| for (int i = 0; i < list.size(); i++) { |
| String sdoURI = (String) list.get(i); |
| list.set(i, SDOURI2XsdQName(sdoURI)); |
| } |
| } else { |
| value = SDOURI2XsdQName((String) value); |
| } |
| } |
| } |
| |
| return super.convertToString(factory, eDataType, value); |
| } |
| } |
| |
| public EObject root; |
| |
| /** |
| * An EMF XMLLoad that loads a model from a StAX stream |
| */ |
| public class SDOXMLLoadImpl extends XMLLoadImpl { |
| public SDOXMLLoadImpl(XMLHelper helper) { |
| super(helper); |
| } |
| |
| final class XmlHandler extends SAXXMLHandler { |
| XmlHandler() { |
| super(resource, SDOXMLLoadImpl.this.helper, options); |
| } |
| |
| protected void handleTopLocations(String prefix, String name) { |
| processSchemaLocations(prefix, name); |
| if (!processAnyXML) |
| return; |
| String nameSpace = helper.getURI(prefix); |
| if (extendedMetaData.getPackage(nameSpace) == null) |
| if (options.get(XMLStreamHelper.OPTION_DEFAULT_ROOT_TYPE) == null) |
| extendedMetaData.demandFeature(nameSpace, name, true); |
| else |
| extendedMetaData.demandPackage(nameSpace); |
| } |
| |
| EClassifier defaultRootType(String prefix, String name, |
| boolean isElement, EObject peekObject, String value) { |
| Object type = options |
| .get(XMLStreamHelper.OPTION_DEFAULT_ROOT_TYPE); |
| if (type != null) |
| return (EClassifier) type; |
| super.handleUnknownFeature(prefix, name, isElement, peekObject, |
| value); |
| return null; |
| } |
| |
| protected void handleUnknownFeature(String prefix, String name, |
| boolean isElement, EObject peekObject, String value) { |
| |
| if (objects.size() == 1) { |
| EFactory eFactory; |
| EClassifier type; |
| String typeQName = getXSIType(); |
| if (typeQName == null) { |
| type = defaultRootType(prefix, name, isElement, |
| peekObject, value); |
| if (type == null) |
| return; |
| eFactory = type.getEPackage().getEFactoryInstance(); |
| } else {// createObjectFromTypeName |
| String typeName = null; |
| String xsiPrefix = XMLConstants.DEFAULT_NS_PREFIX; |
| int index = typeQName.indexOf(":"); |
| if (index > 0) { |
| xsiPrefix = typeQName.substring(0, index); |
| typeName = typeQName.substring(index + 1); |
| } else |
| typeName = typeQName; |
| eFactory = getFactoryForPrefix(xsiPrefix); |
| if (eFactory != null) |
| type = helper.getType(eFactory, typeName); |
| else if (XMLConstants.DEFAULT_NS_PREFIX |
| .equals(xsiPrefix) |
| && helper.getURI(xsiPrefix) == null) { |
| EPackage ePackage = handleMissingPackage(null); |
| if (ePackage == null) { |
| type = defaultRootType(prefix, name, isElement, |
| peekObject, value); |
| if (type == null) |
| return; |
| eFactory = type.getEPackage() |
| .getEFactoryInstance(); |
| } else |
| type = helper.getType(eFactory = ePackage |
| .getEFactoryInstance(), typeName); |
| } else { |
| type = defaultRootType(prefix, name, isElement, |
| peekObject, value); |
| if (type == null) |
| return; |
| eFactory = type.getEPackage().getEFactoryInstance(); |
| } |
| } |
| root = helper.createObject(eFactory, type); |
| if (root != null) { |
| if (disableNotify) |
| root.eSetDeliver(false); |
| handleObjectAttribs(root); |
| processObject(root); |
| return; |
| } |
| } |
| super.handleUnknownFeature(prefix, name, isElement, peekObject, |
| value); |
| } |
| |
| protected RecordedEventXMLStreamReader.Tag tag/* =null */; |
| |
| protected List nameSpaces/* = null */; |
| |
| public void startPrefixMapping(String prefix, String uri) { |
| if (nameSpaces == null) |
| nameSpaces = new ArrayList(); |
| RecordedEventXMLStreamReader.Tag.bind(prefix, uri, nameSpaces); |
| if (tag == null) |
| super.startPrefixMapping(prefix, uri); |
| } |
| |
| public void startElement(String uri, String localName, |
| String qName, Attributes attributes) throws SAXException { |
| if (tag != null) { |
| tag.start(uri, localName, qName, attributes, locator, |
| nameSpaces); |
| nameSpaces = null; |
| return; |
| } |
| EObject peekObject = objects.peekEObject(); |
| if (peekObject != null) { |
| String prefix = helper.getPrefix(uri.length() == 0 ? null |
| : uri); |
| EStructuralFeature feature = getFeature(peekObject, |
| prefix == null ? XMLConstants.DEFAULT_NS_PREFIX |
| : prefix, localName, true); |
| if (feature != null |
| && feature.getEType() == ChangeSummaryStreamSerializer.ChangeSummary_TYPE) { |
| tag = new RecordedEventXMLStreamReader.Tag(uri, |
| localName, prefix, attributes, locator, |
| ((SDOXMLHelperImpl) helper).nameSpaceContext(), |
| nameSpaces); |
| nameSpaces = null; |
| return; |
| } |
| } |
| if (nameSpaces != null) |
| nameSpaces.clear(); |
| super.startElement(uri, localName, qName, attributes); |
| } |
| |
| public void characters(char[] ch, int start, int length) { |
| if (tag == null) |
| super.characters(ch, start, length); |
| else |
| tag.text(XMLStreamConstants.CHARACTERS, new String(ch, |
| start, length), locator); |
| } |
| |
| protected Collection changeSummaryDeserializers/* = null */; |
| |
| public void endElement(String uri, String localName, String qName) { |
| if (tag == null) |
| super.endElement(uri, localName, qName); |
| else if (tag.end(uri, localName, qName, locator)) { |
| if (changeSummaryDeserializers == null) |
| changeSummaryDeserializers = new ArrayList(); |
| ChangeSummaryStreamDeserializer changeSummaryDeserializer = new ChangeSummaryStreamDeserializer(); |
| try { |
| changeSummaryDeserializer |
| .begin((DataObject) objects.peekEObject(), |
| new HelperContextImpl(extendedMetaData, |
| false), tag.play(xmlResource)); |
| changeSummaryDeserializers |
| .add(changeSummaryDeserializer); |
| } catch (XMLStreamException e) { |
| xmlResource.getErrors().add(new XMIException(e)); |
| } |
| tag = null; |
| } |
| } |
| |
| public void endDocument() { |
| super.endDocument(); |
| if (changeSummaryDeserializers != null) |
| for (Iterator iterator = changeSummaryDeserializers |
| .iterator(); iterator.hasNext();) |
| try { |
| ((ChangeSummaryStreamDeserializer) iterator.next()) |
| .end(); |
| // iterator.remove(); |
| } catch (XMLStreamException e) { |
| xmlResource.getErrors().add(new XMIException(e)); |
| } |
| } |
| } |
| |
| protected DefaultHandler makeDefaultHandler() { |
| return new XmlHandler(); |
| } |
| |
| /** |
| * Start parsing an XMLReader with the default handler. |
| */ |
| public void load(XMLResource resource, final XMLStreamReader reader, |
| Map options) throws IOException { |
| this.resource = resource; |
| Map mergedOptions = new HashMap(defaultLoadOptions); |
| if (options != null) |
| mergedOptions.putAll(options); |
| |
| this.options = mergedOptions; |
| |
| final ContentHandler handler = makeDefaultHandler(); |
| |
| if (errors != null) { |
| errors.clear(); |
| } |
| |
| final StAX2SAXAdapter adapter = new StAX2SAXAdapter(true); |
| // Parse the XMLReader and generate SAX events |
| try { |
| AccessController.doPrivileged(new PrivilegedExceptionAction() { |
| public Object run() throws XMLStreamException, SAXException { |
| adapter.parse(reader, handler); |
| return null; |
| } |
| }); |
| } catch (PrivilegedActionException e) { |
| throw new Resource.IOWrappedException(e.getException()); |
| } |
| |
| helper = null; |
| if (!resource.getErrors().isEmpty()) { |
| Exception error = (Exception) resource.getErrors().get(0); |
| if (error instanceof XMIException) { |
| XMIException exception = (XMIException) error; |
| if (exception.getWrappedException() != null) { |
| throw new Resource.IOWrappedException(exception |
| .getWrappedException()); |
| } |
| } |
| throw new Resource.IOWrappedException(error); |
| } |
| } |
| } |
| |
| public SDOXMLResourceImpl(URI uri) { |
| super(uri); |
| } |
| |
| protected XMLHelper createXMLHelper() { |
| return new SDOXMLHelperImpl(this, reader); |
| } |
| |
| /** |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#createXMLLoad() |
| */ |
| protected XMLLoad createXMLLoad() { |
| return new SDOXMLLoadImpl(createXMLHelper()); |
| } |
| |
| static protected int loadLaxForm; |
| static { |
| int defaultLaxForm = 0x4242; |
| String property = System.getProperty("XML.load.form.lax"); |
| if (property == null) |
| loadLaxForm = defaultLaxForm; |
| else |
| try { |
| loadLaxForm = Integer.decode(property).intValue(); |
| } catch (NumberFormatException eNumberFormat) { |
| loadLaxForm = defaultLaxForm; |
| } |
| } |
| |
| public void doLoad(InputSource inputSource, Map options) throws IOException { |
| if (options != null) { |
| /* |
| * Tolerates element/attribute malform unless indicated not to |
| */ |
| Object option = options.get(SDOHelper.XMLOptions.XML_LOAD_LAX_FORM); |
| int tolerance = option == null ? loadLaxForm : ((Number) option) |
| .intValue(); |
| option = options.get(OPTION_EXTENDED_META_DATA); |
| if (tolerance == 0) { |
| if (option instanceof SDOExtendedMetaData) |
| ((SDOExtendedMetaData) option) |
| .setFeatureNamespaceMatchingLax(false); |
| } else if (option instanceof SDOExtendedMetaData) { |
| ((SDOExtendedMetaData) option) |
| .setFeatureNamespaceMatchingLax(true); |
| } else { |
| options.put(OPTION_EXTENDED_META_DATA, |
| option = new SDOExtendedMetaDataImpl()); // TODO copy |
| // (BasicExtendedMetaData)option |
| } |
| /* |
| * Loads schema if necessary |
| */ |
| if (Boolean.TRUE.equals(options |
| .get(SDOHelper.XMLOptions.XML_LOAD_SCHEMA))) { |
| XMLOptions xmlOptions = (XMLOptions) options |
| .get(OPTION_XML_OPTIONS); |
| if (xmlOptions == null) { |
| xmlOptions = new XMLOptionsImpl(); |
| options.put(OPTION_XML_OPTIONS, xmlOptions); |
| } |
| xmlOptions.setProcessSchemaLocations(true); |
| if (option == null) { |
| option = getDefaultLoadOptions().get( |
| OPTION_EXTENDED_META_DATA); |
| } |
| ExtendedMetaData extendedMetaData; |
| final XSDHelper xsdHelper; |
| if (option == null) { |
| extendedMetaData = ExtendedMetaData.INSTANCE; |
| xsdHelper = XSDHelper.INSTANCE; |
| } else { |
| extendedMetaData = (ExtendedMetaData) option; |
| xsdHelper = (new HelperContextImpl(extendedMetaData, false)) |
| .getXSDHelper(); |
| } |
| xmlOptions.setEcoreBuilder(new DefaultEcoreBuilder( |
| extendedMetaData) { |
| public Collection generate(Map targetNamespaceToURI) |
| throws IOException { |
| for (Iterator iterator = targetNamespaceToURI.values() |
| .iterator(); iterator.hasNext();) { |
| String uri = iterator.next().toString(); |
| xsdHelper.define(uri.indexOf(":/") == -1 ? Thread |
| .currentThread().getContextClassLoader() |
| .getResourceAsStream(uri) : new URL(uri) |
| .openStream(), uri); |
| } |
| return null; // XMLHandler#processSchemaLocations |
| // doesn't take the result |
| } |
| }); |
| } |
| |
| if (Boolean.TRUE.equals(options |
| .get(SDOHelper.XMLOptions.XML_LOAD_UNKNOWN_PROPERTIES))) { |
| options.put(OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE); |
| } |
| } else if (loadLaxForm != 0) { |
| /* |
| * Tolerates element/attribute malform |
| */ |
| options = new HashMap(); |
| options.put(OPTION_EXTENDED_META_DATA, |
| new SDOExtendedMetaDataImpl()); |
| } |
| super.doLoad(inputSource, options); |
| // TODO there is some thinking to be done about the restoration of |
| // options |
| } |
| |
| /** |
| * Loads the resource from a StAX XMLStreamReader. |
| */ |
| public void load(XMLStreamReader reader, Map options) throws IOException { |
| this.reader = reader; |
| SDOXMLLoadImpl xmlLoad = (SDOXMLLoadImpl) createXMLLoad(); |
| Map mergedOptions = new HashMap(defaultLoadOptions); |
| if (options != null) |
| mergedOptions.putAll(options); |
| xmlLoad.load(this, reader, mergedOptions); |
| } |
| |
| ChangeSummaryStreamSerializer changeSummarySerializer/* = null */; |
| |
| static private final class LocalName extends QName { |
| private LocalName(String name) { |
| super(name); |
| } |
| |
| public String getNamespaceURI() { |
| return null; |
| } |
| } |
| |
| static final String INDENT = " ", LINE_SEPARATOR = System |
| .getProperty("line.separator"); |
| |
| static final class XmlString extends XMLString { |
| XmlString(int lineWidth, String temporaryFileName) { |
| super(lineWidth, temporaryFileName); // setLineWidth & |
| // setTemporaryFileName |
| } |
| |
| XmlString(int lineWidth, String publicId, String systemId, |
| String temporaryFileName) { |
| super(lineWidth, publicId, systemId, temporaryFileName); |
| } |
| |
| void setLineBreak(String lineBreak) { |
| lineSeparator = lineBreak; |
| } |
| |
| void margin(String margin) { |
| indents.set(0, margin); |
| } |
| |
| String indent = INDENT; |
| |
| protected String getElementIndent(int extra) { |
| int nesting = depth + extra - 1; |
| for (int i = indents.size() - 1; i < nesting; ++i) { |
| indents.add(indents.get(i) + indent); |
| } |
| return (String) indents.get(nesting); |
| } |
| |
| protected String getAttributeIndent() { |
| return getElementIndent(); |
| } |
| |
| public final boolean mixed() { |
| return isMixed; |
| } |
| |
| public void reset(String publicId, String systemId, int lineWidth, |
| String temporaryFileName) { |
| super.reset(publicId, systemId, lineWidth, temporaryFileName); |
| setLineBreak(LINE_SEPARATOR); |
| indent = INDENT; |
| } |
| } |
| |
| static final char MARK = '\n'; |
| |
| static final String LINE_BREAK = new String(new char[] { MARK }); |
| |
| final class SDOXMLSaveImpl extends XMLSaveImpl { |
| SDOXMLSaveImpl(XMLHelper helper) { |
| super(helper); |
| } |
| |
| XmlString doc(XMLResource resource, Map options) { |
| if (doc instanceof XmlString) |
| return (XmlString) doc; |
| Object lineWidth = options.get(OPTION_LINE_WIDTH); |
| int width = lineWidth == null ? Integer.MAX_VALUE |
| : ((Number) lineWidth).intValue(); |
| XmlString d = resource != null |
| && Boolean.TRUE.equals(options.get(OPTION_SAVE_DOCTYPE)) ? new XmlString( |
| width, resource.getPublicId(), resource.getSystemId(), doc |
| .getTemporaryFileName()) |
| : new XmlString(width, doc.getTemporaryFileName()); |
| doc = d; |
| return d; |
| } |
| |
| Map changeSummaryOptions = new HashMap(); |
| String indent = INDENT, margin; |
| |
| protected void init(XMLResource resource, Map options) { |
| super.init(resource, options); |
| int unformat = 0; |
| String lineBreak = (String) options |
| .get(SDOHelper.XMLOptions.XML_SAVE_LINE_BREAK); |
| if (lineBreak == null) |
| changeSummaryOptions.put( |
| SDOHelper.XMLOptions.XML_SAVE_LINE_BREAK, LINE_BREAK); |
| else if (lineBreak.length() == 0) |
| ++unformat; |
| else { |
| changeSummaryOptions.put( |
| SDOHelper.XMLOptions.XML_SAVE_LINE_BREAK, LINE_BREAK); |
| if (lineBreak.equals(LINE_SEPARATOR)) |
| lineBreak = null; |
| } |
| String indent = (String) options |
| .get(SDOHelper.XMLOptions.XML_SAVE_INDENT); |
| if (indent == null) |
| changeSummaryOptions.put(SDOHelper.XMLOptions.XML_SAVE_INDENT, |
| INDENT); |
| else if (indent.length() == 0) |
| ++unformat; |
| else { |
| changeSummaryOptions.put(SDOHelper.XMLOptions.XML_SAVE_INDENT, |
| this.indent = indent); |
| if (indent.equals(INDENT)) |
| indent = null; |
| } |
| String margin = (String) options |
| .get(SDOHelper.XMLOptions.XML_SAVE_MARGIN); |
| if (margin == null || margin.length() == 0) { |
| if (unformat == 2) |
| doc.setUnformatted(true); |
| else if (lineBreak != null) { |
| XmlString d = doc(resource, options); |
| d.setLineBreak(lineBreak); |
| if (indent != null) |
| d.indent = indent; |
| } else if (indent != null) |
| doc(resource, options).indent = indent; |
| this.margin = this.indent; |
| } else { |
| XmlString d = doc(resource, options); |
| d.margin(margin); |
| if (lineBreak != null) |
| d.setLineBreak(lineBreak); |
| if (indent != null) |
| d.indent = indent; |
| this.margin = margin + this.indent; |
| if (!toDOM && declareXML) |
| d.add(margin); |
| } |
| // changeSummaryOptions.put(ChangeSummaryStreamSerializer.OPTION_RootObject_PATH, |
| // "#"); |
| // changeSummaryOptions.put(ChangeSummaryStreamSerializer.OPTION_OPTIMIZE_LIST, |
| // Boolean.TRUE); |
| changeSummaryOptions.put(OPTION_EXTENDED_META_DATA, |
| extendedMetaData); |
| } |
| |
| QName qName(EStructuralFeature f) { |
| if (extendedMetaData == null) |
| return new LocalName(f.getName()); |
| String nameSpace = extendedMetaData.getNamespace(f), name = extendedMetaData |
| .getName(f); |
| return nameSpace == null ? new LocalName(name) : new QName( |
| nameSpace, name); |
| } |
| |
| XMLStreamWriter xmlStreamWriter/* = null */; |
| |
| void saveChangeSummary(EObject o, EStructuralFeature f, |
| Object changeSummary) { |
| boolean notMixed; |
| if (doc instanceof XmlString) |
| notMixed = !((XmlString) doc).mixed(); |
| else if (extendedMetaData == null) |
| notMixed = true; |
| else |
| switch (extendedMetaData.getContentKind(o.eClass())) { |
| case ExtendedMetaData.MIXED_CONTENT: |
| case ExtendedMetaData.SIMPLE_CONTENT: |
| notMixed = false; |
| break; |
| default: |
| notMixed = true; |
| } |
| if (notMixed) { |
| StringBuffer margin = new StringBuffer(this.margin); |
| for (EObject container = o.eContainer(), grandContainer; (grandContainer = container |
| .eContainer()) != null; container = grandContainer) |
| margin.append(indent); |
| changeSummaryOptions.put(SDOHelper.XMLOptions.XML_SAVE_MARGIN, |
| margin.toString()); |
| } |
| try { |
| if (xmlStreamWriter == null) { |
| xmlStreamWriter = XMLOutputFactory.newInstance() |
| .createXMLStreamWriter(new Writer() { |
| public void close() { |
| } |
| |
| public void flush() { |
| } |
| |
| protected final void add(char[] cbuf, |
| int index, int off) { |
| doc.addText(new String(cbuf, index, off |
| - index)); |
| } |
| |
| public void write(char[] cbuf, int off, int len) { |
| if (len != 0) |
| for (;;) { |
| while (cbuf[off] == MARK) { |
| doc.addLine(); |
| if (--len == 0) |
| return; |
| ++off; |
| } |
| for (int index = off;/* true */;) { |
| ++off; |
| if (--len == 0) |
| add(cbuf, index, off); |
| else { |
| if (cbuf[off] != MARK) |
| continue; |
| add(cbuf, index, off); |
| doc.addLine(); |
| if (--len != 0) |
| break; |
| } |
| return; |
| } |
| ++off; |
| } |
| } |
| }); |
| xmlStreamWriter |
| .setNamespaceContext(((SDOXMLHelperImpl) helper).new NameSpaceContext() { |
| public String getNamespaceURI(String prefix) { |
| return declareXSI |
| && ExtendedMetaData.XSI_PREFIX |
| .equals(prefix) ? ExtendedMetaData.XSI_URI |
| : super.getNamespaceURI(prefix); |
| } |
| |
| public String getPrefix(String namespaceURI) { |
| return declareXSI |
| && ExtendedMetaData.XSI_URI |
| .equals(namespaceURI) ? ExtendedMetaData.XSI_PREFIX |
| : super.getPrefix(namespaceURI); |
| } |
| |
| public Iterator getPrefixes(String namespaceURI) { |
| final Iterator iterator = super |
| .getPrefixes(namespaceURI); |
| return ExtendedMetaData.XSI_URI |
| .equals(namespaceURI) ? new Iterator() { |
| boolean first = true; |
| |
| public boolean hasNext() { |
| if (first) |
| if (declareXSI) // never from |
| // true to false |
| return true; |
| else |
| first = false; |
| return iterator.hasNext(); |
| } |
| |
| public Object next() { |
| if (first) { |
| first = false; |
| if (declareXSI) |
| return ExtendedMetaData.XSI_PREFIX; |
| } |
| return iterator.next(); |
| } |
| |
| public void remove() { |
| if (first) |
| declareXSI = false; |
| else |
| iterator.remove(); |
| } |
| } |
| : iterator; |
| } |
| }); |
| for (Iterator iterator = helper.getPrefixToNamespaceMap() |
| .iterator(); iterator.hasNext();) { |
| Map.Entry entry = (Map.Entry) iterator.next(); |
| xmlStreamWriter.setPrefix((String) entry.getKey(), |
| (String) entry.getValue()); |
| } |
| if (declareXSI) |
| xmlStreamWriter.setPrefix(ExtendedMetaData.XSI_PREFIX, |
| ExtendedMetaData.XSI_URI); |
| if (changeSummarySerializer == null) |
| changeSummarySerializer = new ChangeSummaryStreamSerializer(); |
| } |
| changeSummarySerializer.saveChangeSummary( |
| (ChangeSummary) changeSummary, qName(f), |
| xmlStreamWriter, changeSummaryOptions); |
| if (notMixed) |
| doc.addLine(); |
| } catch (XMLStreamException e) { |
| xmlResource.getErrors().add(new XMIException(e)); |
| } |
| } |
| |
| protected void saveDataTypeElementSingle(EObject o, EStructuralFeature f) { |
| if (f.getEType() == ChangeSummaryStreamSerializer.ChangeSummary_TYPE) |
| saveChangeSummary(o, f, helper.getValue(o, f)); |
| else |
| super.saveDataTypeElementSingle(o, f); |
| } |
| |
| // copied from base class because the shouldSaveType did not consider |
| // the DataObject case... |
| protected void saveElement(EObject o, EStructuralFeature f) { |
| EClass eClass = o.eClass(); |
| EClassifier eType = f.getEType(); |
| |
| if (extendedMetaData != null && eClass != eType) { |
| // Check if it's an anonymous type. |
| // |
| String name = extendedMetaData.getName(eClass); |
| if (name.endsWith("_._type")) { |
| String elementName = name.substring(0, name.indexOf("_._")); |
| String prefix = helper.getPrefix(eClass.getEPackage()); |
| if (!"".equals(prefix)) { |
| elementName = prefix + ":" + elementName; |
| } |
| if (!toDOM) { |
| doc.startElement(elementName); |
| } else { |
| currentNode = currentNode.appendChild(document |
| .createElementNS( |
| helper.getNamespaceURI(prefix), |
| elementName)); |
| handler.recordValues(currentNode, o.eContainer(), f, o); |
| } |
| saveElementID(o); |
| return; |
| } |
| } |
| |
| if (map != null) { |
| XMLResource.XMLInfo info = map.getInfo(eClass); |
| if (info != null |
| && info.getXMLRepresentation() == XMLResource.XMLInfo.ELEMENT) { |
| if (!toDOM) { |
| String elementName = helper.getQName(eClass); |
| doc.startElement(elementName); |
| } else { |
| helper.populateNameInfo(nameInfo, eClass); |
| if (currentNode == null) { |
| currentNode = document.createElementNS(nameInfo |
| .getNamespaceURI(), nameInfo |
| .getQualifiedName()); |
| document.appendChild(currentNode); |
| handler.recordValues(currentNode, o.eContainer(), |
| f, o); |
| } else { |
| currentNode = currentNode.appendChild(document |
| .createElementNS( |
| nameInfo.getNamespaceURI(), |
| nameInfo.getQualifiedName())); |
| handler.recordValues(currentNode, o.eContainer(), |
| f, o); |
| } |
| } |
| saveElementID(o); |
| return; |
| } |
| } |
| boolean isAnyType = false; |
| if (o instanceof AnyType) { |
| isAnyType = true; |
| helper.pushContext(); |
| for (FeatureMap.Entry entry : ((AnyType) o).getAnyAttribute()) { |
| if (ExtendedMetaData.XMLNS_URI.equals(extendedMetaData |
| .getNamespace(entry.getEStructuralFeature()))) { |
| String uri = (String) entry.getValue(); |
| helper.addPrefix(extendedMetaData.getName(entry |
| .getEStructuralFeature()), uri == null ? "" |
| : uri); |
| } |
| } |
| } |
| boolean shouldSaveType = saveTypeInfo ? |
| xmlTypeInfo.shouldSaveType(eClass, eType, f) : eClass != eType |
| && ((eClass != anyType && eClass != SDOPackage.Literals.ANY_TYPE_DATA_OBJECT) |
| || extendedMetaData == null |
| || (eType != EcorePackage.Literals.EOBJECT && eClass != SDOPackage.Literals.ANY_TYPE_DATA_OBJECT) || extendedMetaData |
| .getFeatureKind(f) == ExtendedMetaData.UNSPECIFIED_FEATURE); |
| EDataType eDataType = null; |
| if (shouldSaveType) { |
| EClassifier eClassifier = eClass == anySimpleType ? eDataType = ((SimpleAnyType) o) |
| .getInstanceType() |
| : eClass; |
| if (elementHandler != null) { |
| EStructuralFeature substitutionGroup = featureTable |
| .getSubstitutionGroup(f, eClassifier); |
| if (substitutionGroup != null) { |
| f = substitutionGroup; |
| shouldSaveType = substitutionGroup.getEType() != eClassifier; |
| } |
| } |
| } |
| |
| if (!toDOM) { |
| String featureName = helper.getQName(f); |
| doc.startElement(featureName); |
| } else { |
| helper.populateNameInfo(nameInfo, f); |
| if (currentNode == null) { |
| // this is a root element |
| currentNode = document.createElementNS(nameInfo |
| .getNamespaceURI(), nameInfo.getQualifiedName()); |
| document.appendChild(currentNode); |
| handler.recordValues(currentNode, o.eContainer(), f, o); |
| } else { |
| currentNode = currentNode.appendChild(document |
| .createElementNS(nameInfo.getNamespaceURI(), |
| nameInfo.getQualifiedName())); |
| handler.recordValues(currentNode, o.eContainer(), f, o); |
| } |
| } |
| |
| if (shouldSaveType) { |
| if (eDataType != null) { |
| saveTypeAttribute(eDataType); |
| } else { |
| saveTypeAttribute(eClass); |
| } |
| } |
| |
| saveElementID(o); |
| if (isAnyType) { |
| helper.popContext(); |
| } |
| } |
| |
| /* |
| * TEMPORARILY COPIED FROM BASE CLASS - DO NOT EDIT - WILL BE REMOVED |
| * WHEN WE MOVE TO EMF 2.3 |
| */ |
| protected boolean saveElementFeatureMap(EObject o, EStructuralFeature f) { |
| List values = (List) helper.getValue(o, f); |
| int size = values.size(); |
| for (int i = 0; i < size; i++) { |
| FeatureMap.Entry entry = (FeatureMap.Entry) values.get(i); |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| Object value = entry.getValue(); |
| if (entryFeature instanceof EReference) { |
| if (value == null) { |
| saveNil(o, entryFeature); |
| } else { |
| EReference referenceEntryFeature = (EReference) entryFeature; |
| if (referenceEntryFeature.isContainment()) { |
| saveElement((InternalEObject) value, entryFeature); |
| } else if (referenceEntryFeature.isResolveProxies()) { |
| saveFeatureMapElementReference((EObject) value, |
| referenceEntryFeature); |
| } else { |
| saveElementIDRef(o, (EObject) value, entryFeature); |
| } |
| } |
| } else { |
| if (entryFeature == XMLTypePackage.eINSTANCE |
| .getXMLTypeDocumentRoot_Text()) { |
| String svalue = value.toString(); |
| if (escape != null) { |
| svalue = escape.convertText(svalue); |
| } |
| if (!toDOM) { |
| doc.addText(svalue); |
| } else { |
| Node text = document.createTextNode(svalue); |
| currentNode.appendChild(text); |
| handler.recordValues(text, o, f, entry); |
| } |
| } else if (entryFeature == XMLTypePackage.eINSTANCE |
| .getXMLTypeDocumentRoot_CDATA()) { |
| String stringValue = value.toString(); |
| if (escape != null) { |
| stringValue = escape.convertLines(stringValue); |
| } |
| if (!toDOM) { |
| doc.addCDATA(stringValue); |
| } else { |
| Node cdata = document |
| .createCDATASection(stringValue); |
| currentNode.appendChild(cdata); |
| handler.recordValues(cdata, o, f, entry); |
| } |
| } else if (entryFeature == XMLTypePackage.eINSTANCE |
| .getXMLTypeDocumentRoot_Comment()) { |
| String stringValue = value.toString(); |
| if (escape != null) { |
| stringValue = escape.convertLines(stringValue); |
| } |
| if (!toDOM) { |
| doc.addComment(stringValue); |
| } else { |
| // TODO comments are not sent to recordValues |
| currentNode.appendChild(document |
| .createComment(stringValue)); |
| } |
| } else { |
| saveElement(o, value, entryFeature); |
| } |
| } |
| } |
| return size > 0; |
| } |
| |
| protected final void saveElement(EObject o, Object value, |
| EStructuralFeature f) { |
| if (f.getEType() == ChangeSummaryStreamSerializer.ChangeSummary_TYPE) { |
| saveChangeSummary(o, f, value); |
| return; |
| } |
| /* |
| * super.saveElement(o, value, f); TEMPORARILY COPIED FROM BASE |
| * CLASS - DO NOT EDIT - WILL BE REMOVED WHEN WE MOVE TO EMF 2.3 |
| */ |
| if (value == null) { |
| saveNil(o, f); |
| } else { |
| String svalue = getDatatypeValue(value, f, false); |
| if (!toDOM) { |
| doc.saveDataValueElement(helper.getQName(f), svalue); |
| } else { |
| helper.populateNameInfo(nameInfo, f); |
| Element elem = document.createElementNS(nameInfo |
| .getNamespaceURI(), nameInfo.getQualifiedName()); |
| Node text = document.createTextNode(svalue); |
| elem.appendChild(text); |
| currentNode.appendChild(elem); |
| handler.recordValues(elem, o, f, value); |
| handler.recordValues(text, o, f, value); |
| } |
| } |
| } |
| } |
| |
| protected XMLSave createXMLSave() { |
| return new SDOXMLSaveImpl(createXMLHelper()); |
| } |
| } |