diff options
Diffstat (limited to '')
-rw-r--r-- | branches/sdo-1.1.1-incubating/impl/src/main/java/org/apache/tuscany/sdo/helper/XMLDocumentImpl.java | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/branches/sdo-1.1.1-incubating/impl/src/main/java/org/apache/tuscany/sdo/helper/XMLDocumentImpl.java b/branches/sdo-1.1.1-incubating/impl/src/main/java/org/apache/tuscany/sdo/helper/XMLDocumentImpl.java new file mode 100644 index 0000000000..bff8375e44 --- /dev/null +++ b/branches/sdo-1.1.1-incubating/impl/src/main/java/org/apache/tuscany/sdo/helper/XMLDocumentImpl.java @@ -0,0 +1,574 @@ +/** + * + * 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.helper; + + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.sdo.SimpleAnyTypeDataObject; +import org.apache.tuscany.sdo.util.DataObjectUtil; +import org.apache.tuscany.sdo.util.SDOUtil; +import org.apache.tuscany.sdo.util.resource.SDOXMLResourceImpl; +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.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +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.xmi.XMLResource; +import org.eclipse.emf.ecore.xml.type.XMLTypePackage; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; + +import commonj.sdo.DataObject; +import commonj.sdo.Type; +import commonj.sdo.helper.XMLDocument; + + +/** + * Represents an XML Document containing a tree of DataObjects. + * + * An example XMLDocument fragment is: + * <?xml version="1.0"?> + * <purchaseOrder orderDate="1999-10-20"> + * + * created from this XML Schema fragment: + * <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + * <xsd:element name="purchaseOrder" type="PurchaseOrderType"/> + * <xsd:complexType name="PurchaseOrderType"> + * + * Upon loading this XMLDocument: + * DataObject is an instance of Type PurchaseOrderType. + * RootElementURI is null because the XSD has no targetNamespace URI. + * RootElementName is purchaseOrder. + * Encoding is null because the document did not specify an encoding. + * XMLDeclaration is true because the document contained an XML declaration. + * XMLVersion is 1.0 + * SchemaLocation and noNamespaceSchemaLocation are null because they are + * not specified in the document. + * + * When saving the root element, if the type of the root dataObject is not the + * type of global element specified by rootElementURI and rootElementName, + * or if a global element does not exist for rootElementURI and rootElementName, + * then an xsi:type declaration is written to record the root DataObject's Type. + * + * When loading the root element and an xsi:type declaration is found + * it is used as the type of the root DataObject. In this case, + * if validation is not being performed, it is not an error if the + * rootElementName is not a global element. + */ +public class XMLDocumentImpl implements XMLDocument +{ + protected ExtendedMetaData extendedMetaData; + + protected EObject rootObject; + + protected XMLResource resource; + + protected EStructuralFeature rootElement; + + protected EObject documentRoot; + + protected final static String WHITESPACE_REGEX = "\\s"; + + //TODO clean up the options thing + protected XMLDocumentImpl(ExtendedMetaData extendedMetaData, Object options) + { + this.extendedMetaData = extendedMetaData; + ResourceSet resourceSet = DataObjectUtil.createResourceSet(); + + if (options instanceof Map) + { + Class resourceFactoryClass = (Class)((Map)options).get("GENERATED_LOADER"); + if (resourceFactoryClass != null) + { + try + { + Object resourceFactory = resourceFactoryClass.newInstance(); + resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", resourceFactory); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + + resource = (XMLResource)resourceSet.createResource(URI.createURI("http:///temp.xml")); + DataObjectUtil.configureXMLResource(resource, extendedMetaData); + } + + protected XMLDocumentImpl(ExtendedMetaData extendedMetaData) + { + this(extendedMetaData, null); + } + + protected XMLDocumentImpl(ExtendedMetaData extendedMetaData, DataObject dataObject, String rootElementURI, String rootElementName) + { + this(extendedMetaData); + + rootObject = (EObject)dataObject; + + rootElement = extendedMetaData.getElement(rootElementURI, rootElementName); + if (rootElement == null) + { + rootElement = ExtendedMetaData.INSTANCE.demandFeature(rootElementURI, rootElementName, true); + } + + EClass documentRootClass = rootElement.getEContainingClass(); + documentRoot = EcoreUtil.create(documentRootClass); + resource.getContents().add(documentRoot); + } + + protected void save(OutputStream outputStream, Object options) throws IOException + { + save(outputStream, null, options); + } + + protected void save(Writer outputWriter, Object options) throws IOException + { + // TODO temporary brute-force implementation ... to be replaced + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + save(outputStream, options); + outputWriter.write(new String(outputStream.toByteArray())); + } + + protected void save(Node node, Object options) throws IOException + { + save(null, (Document)node, options); + } + + protected void save(OutputStream outputStream, Document document, Object options) throws IOException + { + EObject oldContainer = null; + Resource oldResource = null; + EReference oldContainmentReference = null; + int oldContainmentIndex = -1; + + if (documentRoot != null) + { + oldContainer = rootObject.eContainer(); + if (oldContainer != null) + oldContainmentReference = rootObject.eContainmentFeature(); + else + oldResource = rootObject.eResource(); + if (oldContainer != documentRoot || oldContainmentReference != rootElement) + { + if (oldResource != null) + { + oldContainmentIndex = oldResource.getContents().indexOf(rootObject); + oldResource.getContents().remove(oldContainmentIndex); + } + else if (oldContainmentReference != null && FeatureMapUtil.isMany(oldContainer, oldContainmentReference)) + oldContainmentIndex = ((List)oldContainer.eGet(oldContainmentReference)).indexOf(rootObject); + + Object rootValue = + rootElement instanceof EAttribute && rootObject instanceof SimpleAnyTypeDataObject ? + ((SimpleAnyTypeDataObject)rootObject).getValue() : rootObject; + + documentRoot.eSet(rootElement, rootValue); + } + } + + if (outputStream != null) + resource.save(outputStream, (Map)options); + else // if (document != null) + resource.save(document, (Map)options, null); + + if (oldResource != null) + { + oldResource.getContents().add(oldContainmentIndex, rootObject); + } + if (rootElement instanceof EReference) + { + if (oldContainer != null) + { + if (oldContainer != documentRoot || oldContainmentReference != rootElement) + { + if (FeatureMapUtil.isMany(oldContainer, oldContainmentReference)) + ((List)oldContainer.eGet(oldContainmentReference)).add(oldContainmentIndex, rootObject); + else + oldContainer.eSet(oldContainmentReference, rootObject); + } + } + else if (documentRoot != null) + { + documentRoot.eSet(rootElement, null); + } + } + } + + protected void load(InputStream inputStream, String locationURI, Object options) throws IOException + { + InputSource inputSource = new InputSource(inputStream); + load(inputSource, locationURI, options); + } + + protected void load(Reader inputReader, String locationURI, Object options) throws IOException + { + InputSource inputSource = new InputSource(inputReader); + load(inputSource, locationURI, options); + } + + protected final void load(Node node, Object options) throws IOException { + resource.load(node, (Map)options); + initLoadedRoot(); + } + + protected final void load(XMLStreamReader reader, Map options) throws IOException + { + ((SDOXMLResourceImpl)resource).load(reader, options); + initLoadedRoot(); + } + + protected void load(InputSource inputSource, String locationURI, Object options) throws IOException + { + if (locationURI != null) + { + inputSource.setSystemId(locationURI); + resource.setURI(URI.createURI(locationURI)); + } + resource.load(inputSource, (Map)options); + initLoadedRoot(); + } + + /** + * @return a Map object with key-value pair where key is the DataObject and value contains the info + * about the unknown properties for the DataObject + */ + public Map getUnknownProperties(){ + return resource.getEObjectToExtensionMap(); + } + + private void initLoadedRoot() + { + rootObject = null; + rootElement = null; + documentRoot = null; + + if (!resource.getContents().isEmpty()) + { + documentRoot = (EObject)resource.getContents().get(0); + EClass documentRootClass = documentRoot.eClass(); + if ("".equals(extendedMetaData.getName(documentRootClass))) //TODO efficient way to check this? Maybe DataObject.getContainer should also check this? + { + FeatureMap featureMap = (FeatureMap)documentRoot.eGet(documentRootClass.getEStructuralFeature(0)); // get mixed feature + int size = featureMap.size(); + for (int index = 0; index < size; index++) + { + EStructuralFeature feature = featureMap.getEStructuralFeature(index); + boolean isText = + feature == XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__TEXT || + feature == XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__CDATA || + feature == XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__COMMENT; + if (!isText) + { + if (feature instanceof EReference) + { + rootObject = (EObject)featureMap.getValue(index); + documentRoot.eUnset(feature); + } + else //EAttribute + { + rootObject = (EObject)SDOUtil.createDataTypeWrapper((Type)feature.getEType(), featureMap.getValue(index)); + } + rootElement = feature; + break; + } + } //for + if (rootObject == null) + rootObject = ((SDOXMLResourceImpl) resource).root; + } + else + { + rootObject = documentRoot; + documentRoot = null; + } + } + } + + public DataObject getRootObject() + { + return (DataObject)rootObject; + } + + public String getRootElementURI() + { + if (rootElement != null) + { + return extendedMetaData.getNamespace(rootElement); + } + else if (rootObject != null) + { + return extendedMetaData.getNamespace(rootObject.eClass()); + } + return null; + } + + public String getRootElementName() + { + if (rootElement != null) + { + return extendedMetaData.getName(rootElement); + } + else if (rootObject != null) + { + return extendedMetaData.getName(rootObject.eClass()); + } + return null; + } + + public String getEncoding() + { + return resource.getEncoding(); + } + + public void setEncoding(String encoding) + { + resource.setEncoding(encoding); + } + + public boolean isXMLDeclaration() + { + return Boolean.FALSE.equals(resource.getDefaultSaveOptions().get(XMLResource.OPTION_DECLARE_XML)); + } + + public void setXMLDeclaration(boolean xmlDeclaration) + { + resource.getDefaultSaveOptions().put(XMLResource.OPTION_DECLARE_XML, xmlDeclaration ? Boolean.TRUE : Boolean.FALSE); + } + + public String getXMLVersion() + { + return resource.getXMLVersion(); + } + + public void setXMLVersion(String xmlVersion) + { + resource.setXMLVersion(xmlVersion); + } + + /** + * @return an EMap containing the schema locations or null when no map + */ + protected EMap getSchemaLocationMap() + { + EMap result = null; + if ((documentRoot != null) && (extendedMetaData != null)) + { + EReference xsiSchemaLocationMapFeature = extendedMetaData + .getXSISchemaLocationMapFeature(documentRoot.eClass()); + if (xsiSchemaLocationMapFeature != null) + { + result = (EMap) documentRoot.eGet(xsiSchemaLocationMapFeature); + } + } + return result; + } + + /** + * @param value + * from schema location map. + * @return string form of URI from provided value, deresolved if appropriate. + */ + protected String deresolve(String value) + { + URI location = URI.createURI(value); + URI resourceURI = resource.getURI(); + boolean shouldDeresolve = resourceURI != null && !resourceURI.isRelative() + && resourceURI.isHierarchical(); + if (shouldDeresolve && !location.isRelative()) + { + URI deresolvedURI = location.deresolve(resourceURI, true, true, false); + if (deresolvedURI.hasRelativePath()) + { + location = deresolvedURI; + } + } + return location.toString(); + } + + /** + * @param value + * for schema location from input parameter. + * @return string form of URI from provided value, resolved if appropriate. + */ + protected String resolve(String value) + { + URI location = URI.createURI(value); + URI resourceURI = resource.getURI(); + boolean shouldResolve = resourceURI != null && resourceURI.isHierarchical() + && !resourceURI.isRelative(); + if (shouldResolve && location.isRelative() && location.hasRelativePath()) + { + location = location.resolve(resourceURI, false); + } + return location.toString(); + } + + public String getSchemaLocation() + { + EMap xsiSchemaLocationMap = getSchemaLocationMap(); + if (xsiSchemaLocationMap != null) + { + if (!xsiSchemaLocationMap.isEmpty()) + { + StringBuffer xsiSchemaLocation = new StringBuffer(); + for (Iterator i = xsiSchemaLocationMap.entrySet().iterator(); i + .hasNext();) + { + Map.Entry entry = (Map.Entry) i.next(); + String namespace = (String) entry.getKey(); + if (namespace != null) + { + if (xsiSchemaLocation.length() > 0) + { + xsiSchemaLocation.append(' '); + } + xsiSchemaLocation.append(namespace); + xsiSchemaLocation.append(' '); + String value = entry.getValue().toString(); + xsiSchemaLocation.append(deresolve(value)); + } + } + return xsiSchemaLocation.toString().equals("") ? null + : xsiSchemaLocation.toString(); + } + } + return null; + } + + public void setSchemaLocation(String schemaLocation) + { + EMap xsiSchemaLocationMap = getSchemaLocationMap(); + if (xsiSchemaLocationMap != null) + { + // only remove the entries from xsiSchemaLocationMap that contain a + // non-null key + for (Iterator i = xsiSchemaLocationMap.entrySet().iterator(); i.hasNext();) + { + Map.Entry entry = (Map.Entry) i.next(); + if (entry.getKey() != null) + { + i.remove(); + } + } + if (xsiSchemaLocationMap.size() == 0) + { + resource.getDefaultSaveOptions().put( + XMLResource.OPTION_SCHEMA_LOCATION, Boolean.FALSE); + } + if (schemaLocation != null) + { + String[] values = schemaLocation.split(WHITESPACE_REGEX); + for (int i = 0; i < values.length; i++) // note: also incremented in + // loop + { + String key = values[i++]; + if (i < values.length) + { + xsiSchemaLocationMap.put(key, resolve(values[i])); + } + } + if (xsiSchemaLocationMap.size() != 0) + { + resource.getDefaultSaveOptions().put( + XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); + } + } + } + } + + public String getNoNamespaceSchemaLocation() + { + EMap xsiSchemaLocationMap = getSchemaLocationMap(); + if (xsiSchemaLocationMap != null) + { + StringBuffer xsiSchemaLocation = new StringBuffer(); + if (!xsiSchemaLocationMap.isEmpty()) + { + Object valueObject = xsiSchemaLocationMap.get(null); + if (valueObject != null) + { + String valueString = (String) valueObject; + String[] values = valueString.split(WHITESPACE_REGEX); + for (int i = 0; i < values.length; i++) + { + if (xsiSchemaLocation.length() > 0) + { + xsiSchemaLocation.append(' '); + } + xsiSchemaLocation.append(deresolve(values[i])); + } + } + String result = xsiSchemaLocation.toString(); + return result.equals("") ? null : result; + } + } + return null; + } + + public void setNoNamespaceSchemaLocation(String schemaLocation) + { + EMap xsiSchemaLocationMap = getSchemaLocationMap(); + if (xsiSchemaLocationMap != null) + { + // only remove the entries from xsiSchemaLocationMap that contain a null + // key + xsiSchemaLocationMap.removeKey(null); + if (xsiSchemaLocationMap.size() == 0) + { + resource.getDefaultSaveOptions().put( + XMLResource.OPTION_SCHEMA_LOCATION, Boolean.FALSE); + } + if (schemaLocation != null) + { + String[] values = schemaLocation.split(WHITESPACE_REGEX); + for (int i = 0; i < values.length; i++) + { + xsiSchemaLocationMap.put(null, resolve(values[i])); + } + if (xsiSchemaLocationMap.size() != 0) + { + resource.getDefaultSaveOptions().put( + XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); + } + } + } + } +} |