/******************************************************************************* * Copyright (c) 2009, 2011 IBM Corporation 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 Corporation - initial API and implementation *******************************************************************************/ package org.openhealthtools.uml.xdw; import java.io.IOException; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; 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.xmi.XMLHelper; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl; import net.ihe.gazelle.xdw.XDWPackage; import xdw.internal.registry.XDWRegistry; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.DefaultHandler; public class XDWLoadImpl extends XMLLoadImpl { private Map partTypes = null; private Map nsPrefixMap = null; private int nsPrefixIndex; public XDWLoadImpl(XMLHelper helper) { super(helper); partTypes = new HashMap(); nsPrefixMap = new HashMap(); nsPrefixIndex = 0; populatePartTypes(); } private void populatePartTypes() { // address part types partTypes.put("delimiter", "DEL"); partTypes.put("country", "CNT"); partTypes.put("state", "STA"); partTypes.put("county", "CPA"); partTypes.put("city", "CTY"); partTypes.put("postalCode", "ZIP"); partTypes.put("streetAddressLine", "SAL"); partTypes.put("houseNumber", "BNR"); partTypes.put("houseNumberNumeric", "BNN"); partTypes.put("direction", "DIR"); partTypes.put("streetName", "STR"); partTypes.put("streetNameBase", "STB"); partTypes.put("streetNameType", "STTYP"); partTypes.put("additionalLocator", "ADL"); partTypes.put("unitID", "UNID"); partTypes.put("unitType", "UNIT"); partTypes.put("careOf", "CAR"); partTypes.put("censusTract", "CEN"); partTypes.put("deliveryAddressLine", "DAL"); partTypes.put("deliveryInstallationType", "DINST"); partTypes.put("deliveryInstallationArea", "DINSTA"); partTypes.put("deliveryInstallationQualifier", "DINSTQ"); partTypes.put("deliveryMode", "DMOD"); partTypes.put("deliveryModeIdentifier", "DMODID"); partTypes.put("buildingNumberSuffix", "BNS"); partTypes.put("postBox", "POB"); partTypes.put("precinct", "PRE"); // entity name part types partTypes.put("delimiter", "DEL"); partTypes.put("family", "FAM"); partTypes.put("given", "GIV"); partTypes.put("prefix", "PFX"); partTypes.put("suffix", "SFX"); } private String getNsPrefix(String namespaceURI) { String prefix = nsPrefixMap.get(namespaceURI); if (prefix == null) { prefix = "ns" + nsPrefixIndex; nsPrefixMap.put(namespaceURI, prefix); nsPrefixIndex++; } return prefix; } @Override protected void traverse(Node node, XMLLoadImpl.AttributesProxy attributesProxy, DefaultHandler handler, LexicalHandler lexicalHandler) throws SAXException { processNode(node); super.traverse(node, attributesProxy, handler, lexicalHandler); } @Override protected void traverseElement(Element element, XMLLoadImpl.AttributesProxy attributesProxy, DefaultHandler handler, LexicalHandler lexicalHandler) throws SAXException { processNode(element); super.traverseElement(element, attributesProxy, handler, lexicalHandler); } private void processNode(Node node) { if (node instanceof Element) { Element element = (Element) node; Element root = element.getOwnerDocument().getDocumentElement(); handlePartType(element); handleDataType(element, root); handleTemplate(element, root); } } private void handlePartType(Element element) { String partType = partTypes.get(element.getLocalName()); if (partType != null) { element.setAttributeNS(null, "partType", partType); } } private void handleDataType(Element element, Element root) { if (element.hasAttributeNS(XMLResource.XSI_URI, "type")) { String type = element.getAttributeNS(XMLResource.XSI_URI, "type"); if (type != null && !type.contains(":")) { String nsPrefix = getNsPrefix(XDWPackage.eNS_URI); if (helper.getPrefix(XDWPackage.eNS_URI) == null) { helper.addPrefix(nsPrefix, XDWPackage.eNS_URI); root.setAttributeNS(ExtendedMetaData.XMLNS_URI, "xmlns:" + nsPrefix, XDWPackage.eNS_URI); } element.setAttributeNS(XMLResource.XSI_URI, "xsi:type", nsPrefix + ":" + type); } } } private void handleTemplate(Element element, Element root) { EClass result = null; int last = 0; NodeList nodeList = element.getChildNodes(); EClass type = getType(element); for (int i = 0; i < nodeList.getLength(); i++) { if (nodeList.item(i) instanceof Element) { Element e = (Element) nodeList.item(i); if ("templateId".equals(e.getLocalName())) { EClass eClass = XDWRegistry.INSTANCE.getEClass(e.getAttributeNS(null, "root"), element); if (eClass != null && !eClass.isAbstract() && conformsTo(eClass, type) && eClass.getEAllSuperTypes().size() > last) { result = eClass; last = eClass.getEAllSuperTypes().size(); } } } } if (result != null) { if (helper.getPrefix(XMLResource.XSI_URI) == null) { helper.addPrefix("xsi", XMLResource.XSI_URI); root.setAttributeNS(ExtendedMetaData.XMLNS_URI, "xmlns:xsi", XMLResource.XSI_URI); } EPackage ePackage = result.getEPackage(); String nsURI = ePackage.getNsURI(); String nsPrefix = getNsPrefix(nsURI); if (helper.getPrefix(nsURI) == null) { helper.addPrefix(nsPrefix, nsURI); root.setAttributeNS(ExtendedMetaData.XMLNS_URI, "xmlns:" + nsPrefix, nsURI); } element.setAttributeNS(XMLResource.XSI_URI, "xsi:type", nsPrefix + ":" + getName(result)); } } private List getPath(Element element) { LinkedList result = new LinkedList(); result.addFirst(element.getLocalName()); Node parent = element.getParentNode(); while (parent instanceof Element) { Element e = (Element) parent; result.addFirst(e.getLocalName()); parent = e.getParentNode(); } return result; } private EClass getType(Element element) { EClass eClass = XDWPackage.Literals.DOCUMENT_ROOT; List path = getPath(element); for (String component : path) { EStructuralFeature feature = getEStructuralFeature(eClass, component); if (feature instanceof EReference) { eClass = (EClass) feature.getEType(); } else { return null; } } return eClass; } private EStructuralFeature getEStructuralFeature(EClass eClass, String name) { for (EStructuralFeature feature : eClass.getEAllStructuralFeatures()) { if (name.equals(getName(feature))) { return feature; } } return null; } private boolean conformsTo(EClass eClass, EClass type) { if (eClass == null || type == null) { return false; } return type.isSuperTypeOf(eClass); } private String getName(ENamedElement eNamedElement) { String result = EcoreUtil.getAnnotation(eNamedElement, ExtendedMetaData.ANNOTATION_URI, "name"); if (result != null) { return result; } return eNamedElement.getName(); } @Override protected void handleErrors() throws IOException { if (!resource.getErrors().isEmpty()) { Resource.Diagnostic error = resource.getErrors().get(0); if (error instanceof Exception) { if (shouldThrow((Exception) error)) { throw new Resource.IOWrappedException((Exception) error); } } else { throw new IOException(error.getMessage()); } } } private boolean shouldThrow(Exception exception) { Throwable cause = exception.getCause(); if (cause != null) { String message = cause.getMessage(); if (message != null && message.contains("is not a valid enumerator of")) { return false; } } return true; } }