/**
* Copyright (c) 2002-2006 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 - Initial API and implementation
*/
package org.eclipse.emf.ecore.xmi.impl;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
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.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.XMLResource.XMLInfo;
/**
* This class represents a mapping from Ecore constructs to the
* XML representation of those constructs. It is used by the
* XML serializer and deserializer to load and save XML files.
*/
public class XMLMapImpl implements XMLResource.XMLMap
{
protected static final String XSD2ECORE = "http:///org/eclipse/emf/mapping/xsd2ecore/XSD2Ecore";
protected Map<ENamedElement, XMLResource.XMLInfo> ecoreToXMLInfo;
protected EPackage noNamespacePkg;
protected String idAttributeName;
protected Map<String, Map<String, EClassifier>> urisToNamesToClassifiers;
protected Map<EClass, EList<EStructuralFeature>> eClassToFeatures;
protected Set<EPackage> processedEPackages;
protected EPackage.Registry packageRegistry = EPackage.Registry.INSTANCE;
/**
* Constructor for XMLMap.
*/
public XMLMapImpl()
{
super();
ecoreToXMLInfo = new HashMap<ENamedElement, XMLInfo>();
processedEPackages = new HashSet<EPackage>();
eClassToFeatures = new HashMap<EClass, EList<EStructuralFeature>>();
}
/**
* Add an XMLInfo object for an Ecore construct to
* the map.
*/
public void add(ENamedElement element, XMLResource.XMLInfo info)
{
ecoreToXMLInfo.put(element, info);
}
/**
* Returns the XMLInfo object for the given Ecore
* construct, if there is one.
*/
public XMLResource.XMLInfo getInfo(ENamedElement element)
{
XMLResource.XMLInfo result = ecoreToXMLInfo.get(element);
if (result == null)
{
for (EAnnotation eAnnotation : element.getEAnnotations())
{
if (XSD2ECORE.equals(eAnnotation.getSource()))
{
result = new XMLInfoImpl();
EMap<String, String> details = eAnnotation.getDetails();
result.setName(details.get("name"));
result.setTargetNamespace(details.get("targetNamespace"));
String representation = details.get("representation");
if ("element".equals(representation))
{
result.setXMLRepresentation(XMLResource.XMLInfo.ELEMENT);
}
else if ("attribute".equals(representation))
{
result.setXMLRepresentation(XMLResource.XMLInfo.ATTRIBUTE);
}
else if ("simple-content".equals(representation))
{
result.setXMLRepresentation(XMLResource.XMLInfo.CONTENT);
}
}
}
if (result == null)
{
// result = new XMLResource.XMLInfoImpl();
// result.setXMLRepresentation(XMLResource.XMLInfo.UNSPECIFIED);
}
else
{
ecoreToXMLInfo.put(element, result);
}
}
return result;
}
public void setNoNamespacePackage(EPackage pkg)
{
noNamespacePkg = pkg;
}
public EPackage getNoNamespacePackage()
{
return noNamespacePkg;
}
public void setIDAttributeName(String name)
{
idAttributeName = name;
}
public String getIDAttributeName()
{
return idAttributeName;
}
public void setPackageRegistry(EPackage.Registry packageRegistry)
{
this.packageRegistry = packageRegistry;
}
public EPackage.Registry getPackageRegistry()
{
return packageRegistry;
}
public EClassifier getClassifier(String namespaceURI, String name)
{
EPackage ePackage = packageRegistry.getEPackage(namespaceURI);
if (ePackage != null)
{
if (processedEPackages.add(ePackage))
{
if (urisToNamesToClassifiers == null)
{
urisToNamesToClassifiers = new HashMap<String, Map<String, EClassifier>>();
}
getInfoForClassifiers(ePackage);
for (Map.Entry<ENamedElement, XMLResource.XMLInfo> entry : ecoreToXMLInfo.entrySet())
{
Object key = entry.getKey();
// Only handle classifiers from this package.
//
if (key instanceof EClassifier)
{
EClassifier eClassifier = (EClassifier)key;
if (eClassifier.getEPackage() == ePackage)
{
XMLResource.XMLInfo info = entry.getValue();
String uri = info.getTargetNamespace();
if (uri == null)
{
uri = namespaceURI;
}
if (info.getName() != null)
{
Map<String, EClassifier> namesToClassifiers = urisToNamesToClassifiers.get(uri);
if (namesToClassifiers == null)
{
namesToClassifiers = new HashMap<String, EClassifier>();
urisToNamesToClassifiers.put(uri, namesToClassifiers);
}
namesToClassifiers.put(info.getName(), eClassifier);
}
}
}
}
}
Map<String, EClassifier> namesToClassifiers = urisToNamesToClassifiers.get(namespaceURI);
if (namesToClassifiers != null)
{
return namesToClassifiers.get(name);
}
}
return null;
}
/**
* Get the XMLInfo for all of the classifiers of the
* package with the given name.
*/
private void getInfoForClassifiers(EPackage ePackage)
{
for (EClassifier eClassifier : ePackage.getEClassifiers())
{
getInfo(eClassifier);
}
}
public EStructuralFeature getFeature(EClass eClass, String namespaceURI, String name)
{
for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
{
EStructuralFeature feature = eClass.getEStructuralFeature(i);
XMLResource.XMLInfo info = getInfo(feature);
if (info != null)
{
String infoURI = info.getTargetNamespace();
String infoName = info.getName();
if (namespaceURI == null)
{
// We effectively passed null, "" to look up the general-content feature.
//
if (infoURI == null && (name.equals(infoName) || infoName == null && name.length() == 0))
{
return feature;
}
}
else if (namespaceURI.equals(infoURI) && name.equals(infoName))
{
return feature;
}
}
}
return null;
}
public List<EStructuralFeature> getFeatures(EClass eClass)
{
EList<EStructuralFeature> result = eClassToFeatures.get(eClass);
if (result == null)
{
result = new UniqueEList<EStructuralFeature>();
for (EClass eSuperType : eClass.getESuperTypes())
{
result.addAll(getFeatures(eSuperType));
}
List<EAttribute> eAttributes = eClass.getEAttributes();
result.addAll(eAttributes);
List<EReference> eReferences = eClass.getEReferences();
result.addAll(eReferences);
EAnnotation eAnnotation = eClass.getEAnnotation(XSD2ECORE);
if (eAnnotation != null)
{
String featureOrder = eAnnotation.getDetails().get("feature-order");
if (featureOrder != null)
{
int size = result.size();
int index = size - eReferences.size() - eAttributes.size();
for (StringTokenizer stringTokenizer = new StringTokenizer(featureOrder); stringTokenizer.hasMoreTokens(); ++index)
{
String featureName = stringTokenizer.nextToken();
for (int i = index; i < size; ++i)
{
EStructuralFeature eStructuralFeature = result.get(i);
if (featureName.equals(eStructuralFeature.getName()))
{
result.move(index, eStructuralFeature);
break;
}
}
}
}
}
eClassToFeatures.put(eClass, result);
}
return result;
}
}