/** * Copyright (c) 2007 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.Collection; import java.util.List; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.ExtendedMetaData; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xml.type.XMLTypePackage; /** * An implementation of an element handler that includes support for searching for features in a specified collection of packages * as well as optional support for searching for substitution group features for super types of the specified type. * @see XMLResource#OPTION_ELEMENT_HANDLER */ public class ElementHandlerImpl implements XMLResource.ElementHandler { protected boolean considerSubtypes; protected Collection<? extends EPackage> ePackages; /** * Creates a default instances. * @param considerSubtypes whether to consider {@link ExtendedMetaData#getBaseType(EDataType) base types} or {@link EClass#getESuperTypes() super types} * when finding a substitution group. */ public ElementHandlerImpl(boolean considerSubtypes) { this.considerSubtypes = considerSubtypes; } /** * Creates an instance that will search the given packages for candidate features. * @param considerSubtypes whether to consider {@link ExtendedMetaData#getBaseType(EDataType) base types} or {@link EClass#getESuperTypes() super types} * when finding a substitution group. * @param ePackages the packages to search for candidates. */ public ElementHandlerImpl(boolean considerSubtypes, Collection<? extends EPackage> ePackages) { this.considerSubtypes = considerSubtypes; this.ePackages = ePackages; } public EStructuralFeature getRoot(ExtendedMetaData extendedMetaData, EClassifier eClassifier) { if (extendedMetaData == null) { return null; } else { // Walk up the super types until we reach a root. // while (eClassifier != null) { // Look for a matching element in the classifier's package but don't bother with the XML type package's document root. // EClass eClass = extendedMetaData.getDocumentRoot(eClassifier.getEPackage()); if (eClass != null && eClass != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT) { for (EStructuralFeature element : extendedMetaData.getElements(eClass)) { if (element.getEType() == eClassifier && element.isChangeable()) { return element; } } } // Look for a matching element in the specified packages if there are any. // if (ePackages != null) { for (EPackage ePackage : ePackages) { eClass = extendedMetaData.getDocumentRoot(ePackage); if (eClass != null) { for (EStructuralFeature element : extendedMetaData.getElements(eClass)) { if (element.getEType() == eClassifier && element.isChangeable()) { return element; } } } } } eClassifier = getSuperType(extendedMetaData, eClassifier); } return null; } } /** * Returns the {@link ExtendedMetaData#getBaseType(EDataType) base type} or first {@link EClass#getESuperTypes() super type} of the classifier, * depending on there it is a {@link EDataType data type} or a {@link EClass class}. * @param extendedMetaData the extended meta data in which to look up type information. * @param eClassifier the classifier in question. * @return the {@link ExtendedMetaData#getBaseType(EDataType) base type}, the first {@link EClass#getESuperTypes() super type} of the classifier, or <code>null</code>. */ protected EClassifier getSuperType(ExtendedMetaData extendedMetaData, EClassifier eClassifier) { if (eClassifier instanceof EDataType) { return extendedMetaData.getBaseType((EDataType)eClassifier); } else { List<EClass> eSuperTypes = ((EClass)eClassifier).getESuperTypes(); if (eSuperTypes.isEmpty()) { return null; } else { return eSuperTypes.get(0); } } } public EStructuralFeature getSubstitutionGroup(ExtendedMetaData extendedMetaData, EStructuralFeature eStructuralFeature, EClassifier eClassifier) { if (extendedMetaData == null) { return null; } else { // Look for a substitution group feature in the feature's containing class' containing package. // EClass eContainingClass = eStructuralFeature.getEContainingClass(); while (eClassifier != null) { EStructuralFeature result = getSubstitutionGroup(extendedMetaData, eContainingClass.getEPackage(), eContainingClass, eStructuralFeature, eClassifier); if (result != null) { return result; } else { // Look for a substitution group feature in the classifier's containing package. // result = getSubstitutionGroup(extendedMetaData, eClassifier.getEPackage(), eContainingClass, eStructuralFeature, eClassifier); if (result != null) { return result; } else { // Look for a substitution group feature in the additional packages. // if (ePackages != null) { for (EPackage ePackage : ePackages) { result = getSubstitutionGroup(extendedMetaData, ePackage, eContainingClass, eStructuralFeature, eClassifier); if (result != null) { return result; } } } // Process the super types if that's been specified. // if (considerSubtypes) { eClassifier = getSuperType(extendedMetaData, eClassifier); } else { break; } } } } return null; } } /** * Searches the document root object package for a changeable (non-abstract) element * that is affiliated with the given feature in the given class * and a classifier that exactly matches the given classifier * @param extendedMetaData the extended meta data in which to look up type information. * @param ePackage the package whose document root to search. * @param eContainingClass the containing class of the feature. * @param eStructuralFeature the target feature. * @param eClassifier the type of object being matched. * @return the substitution group feature or <code>null</code>. */ protected EStructuralFeature getSubstitutionGroup (ExtendedMetaData extendedMetaData, EPackage ePackage, EClass eContainingClass, EStructuralFeature eStructuralFeature, EClassifier eClassifier) { EClass eClass = extendedMetaData.getDocumentRoot(ePackage); if (eClass != null) { for (EStructuralFeature element : extendedMetaData.getElements(eClass)) { if (element.getEType() == eClassifier && element.isChangeable() && extendedMetaData.getAffiliation(eContainingClass, element) == eStructuralFeature) { return element; } } } return null; } }