/* * Copyright (c) 2005, 2008 Borland Software Corporation * * 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: * Radek Dvorak (Borland) - initial API and implementation * Artem Tikhomirov (Borland) - refactoring */ package org.eclipse.gmf.internal.validate; import java.util.Collection; import java.util.HashSet; import java.util.Map; import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier; import org.eclipse.emf.codegen.ecore.genmodel.GenPackage; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.DiagnosticChain; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; import org.eclipse.emf.ecore.plugin.EcorePlugin; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.osgi.util.NLS; public class ExternModelImport { private static final String DIAGNOSTIC_SOURCE = "org.eclipse.gmf.validate.imports"; //$NON-NLS-1$ private static final Object ROOT_TARGET_OBJECT_KEY = new Object(); private final ResourceSet importedModels; private final EPackage.Registry registry = new EPackageRegistryImpl(EPackage.Registry.INSTANCE); private final HashSet<URI> myProcessedMetaModels = new HashSet<URI>(); private final HashSet<EPackage> processedPackages; private ExternModelImport(EObject validatedObject) { this.importedModels = new ResourceSetImpl(); Resource targetModel = validatedObject.eResource(); if(targetModel != null) { this.importedModels.setURIConverter(targetModel.getResourceSet().getURIConverter()); } this.importedModels.getURIConverter().getURIMap().putAll(EcorePlugin.computePlatformURIMap()); this.processedPackages = new HashSet<EPackage>(); } public static EValidator newImportValidator() { return new AbstractValidator() { public boolean validate(EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) { ensureRootTargetInitialized(eObject, context); return true; } public boolean validate(EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map<Object, Object> context) { ensureRootTargetInitialized(eObject, context); ExternModelImport importer = getImporter(context); if(eObject instanceof EAnnotation) { return importer.processAnnotation((EAnnotation)eObject, diagnostics); } EPackage ePackage = eObject.eClass().getEPackage(); if(!importer.hasPackageImportsProcessed(ePackage)) { return importer.processAnnotations(eObject.eClass().getEPackage(), diagnostics); } return true; } public boolean validate(EDataType dataType, Object value, DiagnosticChain diagnostics, Map<Object, Object> context) { return true; } }; } public static ExternModelImport getImporter(Map<Object, Object> context) { Object value = context.get(ExternModelImport.class); if(value instanceof ExternModelImport) { return (ExternModelImport)value; } assert value == null; EObject validationTarget = getRootTargetObject(context); ExternModelImport importer = new ExternModelImport(validationTarget); importer.initializeExternPackages(validationTarget); context.put(ExternModelImport.class, importer); return importer; } /** * @return The import package registry associated with the context or <code>null</code> if there is no such registry */ public EPackage.Registry getPackageRegistry() { return registry; } boolean hasPackageImportsProcessed(EPackage importingPackage) { return processedPackages.contains(importingPackage); } private boolean processAnnotations(EPackage importingPackage, DiagnosticChain diagnostics) { boolean result = true; for (EAnnotation next : importingPackage.getEAnnotations()) { result &= processAnnotation(next, diagnostics); } processedPackages.add(importingPackage); return result; } private boolean processAnnotation(EAnnotation annotation, DiagnosticChain diagnostics) { if(Annotations.CONSTRAINTS_URI.equals(annotation.getSource())) { return processImportEAnnotation(annotation, diagnostics); } return true; } public void initializeExternPackages(EObject root) { Resource metaModelResource = root.eClass().getEPackage().eResource(); if (metaModelResource != null && !myProcessedMetaModels.contains(metaModelResource.getURI())) { for (EObject nextResourceElement : metaModelResource.getContents()) { if (nextResourceElement instanceof EPackage) { registerLocally((EPackage) nextResourceElement); } } registerReferencedMetaModels(EcoreUtil.ExternalCrossReferencer.find(metaModelResource)); myProcessedMetaModels.add(metaModelResource.getURI()); } registerReferencedMetaModels(EcoreUtil.ExternalCrossReferencer.find(root)); } static void ensureRootTargetInitialized(EObject target, Map<Object, Object> context) { if(context != null && !context.containsKey(ROOT_TARGET_OBJECT_KEY)) { context.put(ROOT_TARGET_OBJECT_KEY, EcoreUtil.getRootContainer(target, true)); } } private static EObject getRootTargetObject(Map<Object, Object> context) { Object rootObj = context.get(ROOT_TARGET_OBJECT_KEY); assert rootObj == null || rootObj instanceof EObject; return (EObject)rootObj; } private void registerReferencedMetaModels(Map<EObject, Collection<Setting>> externalCrossReferences) { for (EObject next : externalCrossReferences.keySet()) { EPackage nextPackage = null; if (next instanceof EClassifier) { nextPackage = ((EClassifier) next).getEPackage(); } else if(next instanceof EPackage) { nextPackage = (EPackage)next; } else if(next instanceof GenPackage) { nextPackage = ((GenPackage)next).getEcorePackage(); } else if(next instanceof GenClassifier) { GenClassifier genClassifier = (GenClassifier) next; if(genClassifier.getGenPackage() != null) { nextPackage = genClassifier.getGenPackage().getEcorePackage(); } } if(nextPackage != null) { registerLocally(nextPackage); } } } private void registerLocally(EPackage nextPackage) { // force the package to be initialized in registry, in case a package descriptor is registered // Note: this is required for successfull ocl environment lookup of EClassifiers from external meta-models registry.put(nextPackage.getNsURI(), registry.getEPackage(nextPackage.getNsURI())); } private boolean processImportEAnnotation(EAnnotation annotation, DiagnosticChain diagnostics) { boolean result = true; for (Map.Entry<String, String> nextEntry : annotation.getDetails()) { if(!nextEntry.getKey().equals(Annotations.Meta.IMPORT)) { continue; } String importVal = nextEntry.getValue(); if(importVal != null) { importVal = importVal.trim(); EPackage p = registry.getEPackage(importVal); if (p != null) { registerLocally(p); return true; } if (!loadAsResourceURI(importVal, annotation, diagnostics)) { result = false; } } else { result = false; reportInvalidModelURI(importVal, annotation.getEModelElement(), diagnostics); } } return result; } /** * @return false if load failed */ private boolean loadAsResourceURI(String importValue, EAnnotation annotation, DiagnosticChain diagnostics) { try { URI modelURI = URI.createURI(importValue); try { importModelFromResource(modelURI); } catch (RuntimeException e) { reportModelLoadingError(importValue, annotation.getEModelElement(), diagnostics, e); return false; } } catch (IllegalArgumentException e) { reportInvalidModelURI(importValue, annotation.getEModelElement(), diagnostics); return false; } return true; } private static void reportInvalidModelURI(String modelURIValue, EModelElement annotatedElement, DiagnosticChain diagnostics) { Object destObj = DefUtils.findAnnotationDetailEntry(annotatedElement, Annotations.CONSTRAINTS_URI, Annotations.Meta.IMPORT, modelURIValue); assert destObj != null; Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.ERROR, DIAGNOSTIC_SOURCE, StatusCodes.INVALID_MODEL_IMPORT_URI, NLS.bind(Messages.invalidModelImportUri, modelURIValue), new Object[] { destObj }); diagnostics.add(diagnostic); } private static void reportModelLoadingError(String modelURIValue, EModelElement annotatedElement, DiagnosticChain diagnostics, RuntimeException error) { Object destObj = DefUtils.findAnnotationDetailEntry(annotatedElement, Annotations.CONSTRAINTS_URI, Annotations.Meta.IMPORT, modelURIValue); assert destObj != null; String message = NLS.bind(Messages.modelImportResourceLoadingError, modelURIValue, error.getLocalizedMessage()); Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.ERROR, DIAGNOSTIC_SOURCE, StatusCodes.INVALID_MODEL_IMPORT_URI, message, new Object[] { destObj }); diagnostics.add(diagnostic); GMFValidationPlugin.log(diagnostic.getSeverity(), message, error); } private boolean importModelFromResource(URI modelURI) throws RuntimeException { EList<EObject> contents = importedModels.getResource(modelURI, true).getContents(); for (EObject nextObj : contents) { if(nextObj instanceof EPackage) { EPackage ePackage = (EPackage)nextObj; if(ePackage.getNsURI() != null) { registerLocally(ePackage); } return true; } } return false; } }