| /* |
| * Copyright (c) 2015 Eike Stepper (Berlin, Germany) 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: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.oomph.setup.internal.core.util; |
| |
| import org.eclipse.oomph.base.Annotation; |
| import org.eclipse.oomph.base.BaseAnnotationConstants; |
| import org.eclipse.oomph.base.BaseFactory; |
| import org.eclipse.oomph.base.BasePackage; |
| import org.eclipse.oomph.base.ModelElement; |
| import org.eclipse.oomph.base.util.BaseResourceFactoryImpl; |
| import org.eclipse.oomph.base.util.BaseUtil; |
| import org.eclipse.oomph.internal.setup.SetupProperties; |
| import org.eclipse.oomph.preferences.impl.PreferencesURIHandlerImpl; |
| import org.eclipse.oomph.preferences.util.PreferencesUtil; |
| import org.eclipse.oomph.setup.AnnotationConstants; |
| import org.eclipse.oomph.setup.Scope; |
| import org.eclipse.oomph.setup.internal.core.SetupContext; |
| import org.eclipse.oomph.setup.internal.core.SetupCorePlugin; |
| import org.eclipse.oomph.setup.internal.core.util.ECFURIHandlerImpl.AuthorizationHandler; |
| import org.eclipse.oomph.setup.internal.core.util.ECFURIHandlerImpl.AuthorizationHandlerImpl; |
| import org.eclipse.oomph.util.IOUtil; |
| import org.eclipse.oomph.util.OS; |
| import org.eclipse.oomph.util.PropertiesUtil; |
| import org.eclipse.oomph.util.ReflectUtil; |
| import org.eclipse.oomph.util.ReflectUtil.ReflectionException; |
| import org.eclipse.oomph.util.StringUtil; |
| |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EAttribute; |
| 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.ENamedElement; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EStructuralFeature.Setting; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.InternalEObject; |
| import org.eclipse.emf.ecore.impl.EPackageImpl; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.resource.URIHandler; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.equinox.p2.core.IProvisioningAgent; |
| import org.eclipse.equinox.p2.core.UIServices; |
| import org.eclipse.equinox.security.storage.ISecurePreferences; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipInputStream; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public final class SetupCoreUtil |
| { |
| public static final String OOMPH_NAMESPACE = "org.eclipse.oomph"; |
| |
| public static final String STATS_URI = "http://download.eclipse.org/stats/oomph"; |
| |
| public static final AuthorizationHandler AUTHORIZATION_HANDLER; |
| |
| private static final boolean SKIP_STATS = PropertiesUtil.isProperty(SetupProperties.PROP_SETUP_STATS_SKIP); |
| |
| private static volatile Map<URI, URI> archiveRedirections; |
| |
| private static volatile String archiveExpectedETag; |
| |
| static |
| { |
| IProvisioningAgent agent = (IProvisioningAgent)org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper |
| .getService(org.eclipse.equinox.internal.p2.repository.Activator.getContext(), IProvisioningAgent.SERVICE_NAME); |
| UIServices uiServices = (UIServices)agent.getService(UIServices.SERVICE_NAME); |
| |
| ISecurePreferences root = PreferencesUtil.getSecurePreferences(); |
| ISecurePreferences securePreferences = root.node(OOMPH_NAMESPACE).node("hosts"); |
| |
| AUTHORIZATION_HANDLER = new AuthorizationHandlerImpl(uiServices, securePreferences); |
| } |
| |
| private SetupCoreUtil() |
| { |
| } |
| |
| public static String getLabel(Scope scope) |
| { |
| if (scope == null) |
| { |
| return ""; |
| } |
| |
| String label = scope.getLabel(); |
| if (StringUtil.isEmpty(label)) |
| { |
| label = StringUtil.safe(scope.getName()); |
| } |
| |
| return label; |
| } |
| |
| public static ResourceSet createResourceSet() |
| { |
| ResourceSet resourceSet = new ResourceSetImpl(); |
| configureResourceSet(resourceSet); |
| return resourceSet; |
| } |
| |
| public static void configureResourceSet(final ResourceSet resourceSet) |
| { |
| Resource.Factory factory = new BaseResourceFactoryImpl(); |
| |
| Map<String, Object> extensionToFactoryMap = resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(); |
| extensionToFactoryMap.put("setup", factory); |
| extensionToFactoryMap.put("targlet", factory); |
| extensionToFactoryMap.put("def", factory); |
| extensionToFactoryMap.put("ext", factory); |
| |
| URIConverter uriConverter = resourceSet.getURIConverter(); |
| Map<URI, URI> uriMap = uriConverter.getURIMap(); |
| |
| EList<URIHandler> uriHandlers = uriConverter.getURIHandlers(); |
| uriHandlers.add(4, new UserURIHandlerImpl()); |
| uriHandlers.add(5, new SelfProductCatalogURIHandlerImpl()); |
| uriHandlers.add(6, new PreferencesURIHandlerImpl()); |
| uriHandlers.add(7, new ECFURIHandlerImpl(AUTHORIZATION_HANDLER)); |
| |
| class ModelResourceSet extends ResourceSetImpl |
| { |
| private Map<Resource, Resource> redirectedResources = new HashMap<Resource, Resource>(); |
| |
| public ModelResourceSet() |
| { |
| uriConverter = resourceSet.getURIConverter(); |
| packageRegistry = resourceSet.getPackageRegistry(); |
| resourceFactoryRegistry = resourceSet.getResourceFactoryRegistry(); |
| loadOptions = resourceSet.getLoadOptions(); |
| } |
| |
| @Override |
| protected Resource delegatedGetResource(URI uri, boolean loadOnDemand) |
| { |
| Resource result = super.delegatedGetResource(uri, loadOnDemand); |
| if (result == null) |
| { |
| result = super.delegatedGetResource(uriConverter.normalize(uri), loadOnDemand); |
| } |
| |
| return result; |
| } |
| |
| @Override |
| public Resource getResource(URI uri, boolean loadOnDemand) |
| { |
| try |
| { |
| Resource resource = super.getResource(uri, true); |
| Resource redirectedResource = redirectedResources.get(resource); |
| if (redirectedResource != null) |
| { |
| return redirectedResource; |
| } |
| |
| if (resource.getResourceSet() == this) |
| { |
| synchronized (resourceSet) |
| { |
| resourceSet.getResources().add(resource); |
| } |
| } |
| |
| return resource; |
| } |
| catch (RuntimeException throwable) |
| { |
| Resource resource = super.getResource(uri, false); |
| if (resource.getResourceSet() == this) |
| { |
| synchronized (resourceSet) |
| { |
| resourceSet.getResources().add(resource); |
| } |
| } |
| |
| if (loadOnDemand) |
| { |
| throw throwable; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| } |
| |
| @Override |
| protected void demandLoad(Resource resource) throws IOException |
| { |
| super.demandLoad(resource); |
| |
| EPackage ePackage = (EPackage)EcoreUtil.getObjectByType(resource.getContents(), EcorePackage.Literals.EPACKAGE); |
| if (ePackage != null) |
| { |
| String nsURI = ePackage.getNsURI(); |
| EPackage redirectedEPackage = packageRegistry.getEPackage(nsURI); |
| |
| for (EClassifier eClassifier : ePackage.getEClassifiers()) |
| { |
| String instanceClassName = eClassifier.getInstanceClassName(); |
| if (instanceClassName != null) |
| { |
| if (eClassifier instanceof EDataType) |
| { |
| eClassifier.setInstanceClass(String.class); |
| } |
| else |
| { |
| eClassifier.setInstanceClassName(null); |
| eClassifier.setInstanceClass(null); |
| } |
| } |
| } |
| |
| if (redirectedEPackage != null) |
| { |
| redirectedResources.put(resource, redirectedEPackage.eResource()); |
| |
| packageRegistry.put(resource.getURI().toString(), redirectedEPackage); |
| packageRegistry.put(uriConverter.normalize(resource.getURI()).toString(), redirectedEPackage); |
| } |
| else |
| { |
| packageRegistry.put(resource.getURI().toString(), ePackage); |
| packageRegistry.put(uriConverter.normalize(resource.getURI()).toString(), ePackage); |
| |
| ((EPackageImpl)ePackage).freeze(); |
| } |
| } |
| } |
| } |
| |
| final ModelResourceSet modelResourceSet = new ModelResourceSet(); |
| |
| new ResourceSetImpl.MappedResourceLocator((ResourceSetImpl)resourceSet) |
| { |
| @Override |
| public Resource getResource(URI uri, boolean loadOnDemand) |
| { |
| if ("ecore".equals(uri.fileExtension())) |
| { |
| Resource resource = null; |
| synchronized (resourceSet) |
| { |
| resource = super.getResource(uri, false); |
| if (resource != null) |
| { |
| if (!resource.isLoaded()) |
| { |
| demandLoadHelper(resource); |
| } |
| |
| return resource; |
| } |
| |
| resource = modelResourceSet.getResource(uri, loadOnDemand); |
| if (resource != null) |
| { |
| return resource; |
| } |
| } |
| } |
| |
| return super.getResource(uri, loadOnDemand); |
| } |
| }; |
| |
| uriMap.put(SetupContext.INDEX_SETUP_URI.trimSegments(1), SetupContext.INDEX_SETUP_LOCATION_URI.trimSegments(1).appendSegment("")); |
| |
| Properties properties = System.getProperties(); |
| Map<Object, Object> safeProperties; |
| synchronized (properties) |
| { |
| safeProperties = new HashMap<Object, Object>(properties); |
| } |
| |
| for (Map.Entry<Object, Object> entry : safeProperties.entrySet()) |
| { |
| Object key = entry.getKey(); |
| if (key instanceof String) |
| { |
| if (((String)key).startsWith(SetupProperties.PROP_REDIRECTION_BASE)) |
| { |
| String[] mapping = ((String)entry.getValue()).split("->"); |
| if (mapping.length == 1) |
| { |
| URI sourceURI = URI.createURI(mapping[0]); |
| uriMap.remove(sourceURI); |
| } |
| else if (mapping.length == 2) |
| { |
| URI sourceURI = URI.createURI(mapping[0]); |
| URI targetURI = URI.createURI(mapping[1].replace("\\", "/")); |
| |
| // Only include the mapping if the target exists. |
| // For example, we often include a redirection of the remote setup to the local git clone in an installed IDE, |
| // but if that clone hasn't been cloned yet, we want to continue to use the remote version. |
| // |
| if (targetURI.isFile()) |
| { |
| // If the file is a relative path, interpret it as relative to the root folder of the installation. |
| if (targetURI.isRelative()) |
| { |
| targetURI = targetURI.resolve(SetupContext.PRODUCT_LOCATION.trimSegments(OS.INSTANCE.isMac() ? 2 : 0).appendSegment("")); |
| } |
| |
| File file = new File(targetURI.toFileString()); |
| if (!file.exists()) |
| { |
| continue; |
| } |
| } |
| |
| uriMap.put(sourceURI, targetURI); |
| } |
| } |
| } |
| } |
| |
| if (SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI != null && !PropertiesUtil.isProperty(SetupProperties.PROP_REDIRECTION_BASE + "mirror.nothing") |
| && SetupContext.INDEX_SETUP_LOCATION_URI.equals(uriConverter.normalize(SetupContext.INDEX_SETUP_LOCATION_URI))) |
| { |
| handleArchiveRedirection(uriConverter); |
| } |
| } |
| |
| private static void handleArchiveRedirection(URIConverter uriConverter) |
| { |
| if (archiveExpectedETag == null || !archiveExpectedETag.equals(ECFURIHandlerImpl.getExpectedETag(SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI))) |
| { |
| // long start = System.currentTimeMillis(); |
| |
| Map<Object, Object> options = new HashMap<Object, Object>(); |
| options.put(ECFURIHandlerImpl.OPTION_CACHE_HANDLING, ECFURIHandlerImpl.CacheHandling.CACHE_WITH_ETAG_CHECKING); |
| InputStream inputStream = null; |
| ZipInputStream zipInputStream = null; |
| |
| Map<URI, URI> redirections = new HashMap<URI, URI>(); |
| try |
| { |
| inputStream = uriConverter.createInputStream(SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI, options); |
| zipInputStream = new ZipInputStream(inputStream); |
| for (ZipEntry zipEntry = zipInputStream.getNextEntry(); zipEntry != null; zipEntry = zipInputStream.getNextEntry()) |
| { |
| String name = zipEntry.getName(); |
| URI path = URI.createURI(name); |
| int segmentCount = path.segmentCount(); |
| if (segmentCount > 2) |
| { |
| URI uri = URI.createURI(path.segment(0) + "://" + path.segment(1)); |
| for (int i = 2, length = path.segmentCount(); i < length; ++i) |
| { |
| uri = uri.appendSegment(path.segment(i)); |
| } |
| |
| if (uri.equals(uriConverter.normalize(uri))) |
| { |
| URI archiveEntry = URI.createURI("archive:" + SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI + "!/" + path); |
| redirections.put(uri, archiveEntry); |
| } |
| } |
| } |
| } |
| catch (IOException ex) |
| { |
| SetupCorePlugin.INSTANCE.log(ex, IStatus.WARNING); |
| } |
| finally |
| { |
| IOUtil.closeSilent(inputStream); |
| IOUtil.closeSilent(zipInputStream); |
| } |
| |
| archiveRedirections = redirections; |
| archiveExpectedETag = ECFURIHandlerImpl.getExpectedETag(SetupContext.INDEX_SETUP_ARCHIVE_LOCATION_URI); |
| |
| // long finish = System.currentTimeMillis(); |
| // System.err.println("processing mirror archive " + (finish - start) / 1000.0); |
| } |
| |
| uriConverter.getURIMap().putAll(archiveRedirections); |
| } |
| |
| public static <T> void reorder(EList<T> values, DependencyProvider<T> dependencyProvider) |
| { |
| for (int i = 0, size = values.size(), count = 0; i < size; ++i) |
| { |
| T value = values.get(i); |
| if (count == size) |
| { |
| SetupCorePlugin.INSTANCE.log("Circular dependencies " + value, IStatus.WARNING); |
| return; |
| } |
| |
| boolean changed = false; |
| |
| // TODO Consider basing this on a provider that just returns a boolean based on "does v1 depend on v2". |
| for (T dependency : dependencyProvider.getDependencies(value)) |
| { |
| int index = values.indexOf(dependency); |
| if (index > i) |
| { |
| values.move(i, index); |
| changed = true; |
| } |
| } |
| |
| if (changed) |
| { |
| --i; |
| ++count; |
| } |
| else |
| { |
| count = 0; |
| } |
| } |
| } |
| |
| public static void migrate(Resource resource, Collection<EObject> result) |
| { |
| new Migrator(resource).migrate(result); |
| } |
| |
| public static void sendStats(boolean success, Scope scope, OS os) |
| { |
| if (SKIP_STATS || scope == null) |
| { |
| return; |
| } |
| |
| Resource resource = scope.eResource(); |
| if (resource != null) |
| { |
| ResourceSet resourceSet = resource.getResourceSet(); |
| if (resourceSet != null) |
| { |
| URI statusURI = getStatsURI(success, scope); |
| if (statusURI != null) |
| { |
| if (os != null) |
| { |
| statusURI = statusURI.appendSegment(os.getOsgiOS()); |
| statusURI = statusURI.appendSegment(os.getOsgiWS()); |
| statusURI = statusURI.appendSegment(os.getOsgiArch()); |
| } |
| |
| resourceSet.getURIConverter().exists(statusURI, null); |
| } |
| } |
| } |
| } |
| |
| public static URI getStatsURI(boolean success, Scope scope) |
| { |
| String prefix = getStatsPrefix(scope); |
| if (prefix == null) |
| { |
| return null; |
| } |
| |
| URI statusURI = null; |
| |
| List<String> names = new ArrayList<String>(); |
| for (Scope x = scope; x != null; x = x.getParentScope()) |
| { |
| if (SetupContext.isUserScheme(EcoreUtil.getURI(x).scheme())) |
| { |
| return null; |
| } |
| |
| if (statusURI == null) |
| { |
| Annotation annotation = x.getAnnotation(AnnotationConstants.ANNOTATION_STATS_SENDING); |
| if (annotation != null) |
| { |
| String uri = annotation.getDetails().get(AnnotationConstants.KEY_URI); |
| if (StringUtil.isEmpty(uri)) |
| { |
| return null; |
| } |
| |
| statusURI = URI.createURI(uri); |
| } |
| } |
| |
| names.add(0, URI.encodeSegment(x.getName(), false)); |
| } |
| |
| if (statusURI != null) |
| { |
| statusURI = statusURI.appendSegment(prefix).appendSegment(success ? "success" : "failure"); |
| |
| for (String name : names) |
| { |
| statusURI = statusURI.appendSegment(name); |
| } |
| } |
| |
| return statusURI; |
| } |
| |
| private static String getStatsPrefix(Scope scope) |
| { |
| switch (scope.getType()) |
| { |
| case PRODUCT_VERSION: |
| { |
| return "product"; |
| } |
| |
| case STREAM: |
| { |
| return "project"; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public interface DependencyProvider<T> |
| { |
| Collection<? extends T> getDependencies(T value); |
| } |
| |
| /** |
| * @author Ed Merks |
| */ |
| public static class Migrator |
| { |
| /** |
| * @author Ed Merks |
| */ |
| private static class MigrationCopier extends EcoreUtil.Copier |
| { |
| private static final long serialVersionUID = 1L; |
| |
| private EPackage.Registry packageRegistry; |
| |
| public MigrationCopier(EPackage.Registry packageRegistry) |
| { |
| // super(true, false); |
| |
| this.packageRegistry = packageRegistry; |
| } |
| |
| public EObject copyAsProxy(EObject eObject) |
| { |
| EObject copiedEObject = createCopy(eObject); |
| if (copiedEObject != null) |
| { |
| put(eObject, copiedEObject); |
| ((InternalEObject)copiedEObject).eSetProxyURI(URI.createURI("bogus:/" + BaseUtil.getRootURI(eObject))); |
| } |
| |
| return copiedEObject; |
| } |
| |
| @Override |
| protected EClass getTarget(EClass eClass) |
| { |
| return getEClass(eClass, "name", "nsURI"); |
| } |
| |
| protected EClass getEClass(ENamedElement eNamedElement, String nameAnnotation, String nsURIAnnotation) |
| { |
| String nsURIs = getAnnotation(eNamedElement, nsURIAnnotation); |
| if (nsURIs == null) |
| { |
| for (EObject eContainer = eNamedElement.eContainer(); eContainer != null; eContainer = eContainer.eContainer()) |
| { |
| if (eContainer instanceof EPackage) |
| { |
| nsURIs = getAnnotation((EPackage)eContainer, "nsURIs"); |
| } |
| } |
| } |
| |
| if (nsURIs == null) |
| { |
| throw new IllegalStateException("Cannot find package URIs for " + EcoreUtil.getURI(eNamedElement)); |
| } |
| |
| String name = getAnnotation(eNamedElement, nameAnnotation); |
| if (name == null) |
| { |
| name = eNamedElement.getName(); |
| } |
| |
| for (String nsURI : nsURIs.split(" ")) |
| { |
| EPackage ePackage = packageRegistry.getEPackage(nsURI); |
| if (ePackage != null) |
| { |
| EClassifier eClassifier = ePackage.getEClassifier(name); |
| if (eClassifier instanceof EClass) |
| { |
| return (EClass)eClassifier; |
| } |
| } |
| } |
| |
| throw new IllegalStateException("Cannot find class '" + name + "' for to " + EcoreUtil.getURI(eNamedElement)); |
| } |
| |
| @Override |
| protected EStructuralFeature getTarget(EStructuralFeature eStructuralFeature) |
| { |
| String name = getAnnotation(eStructuralFeature, "name"); |
| if (name == null) |
| { |
| name = eStructuralFeature.getName(); |
| } |
| |
| EStructuralFeature result = getTarget(eStructuralFeature.getEContainingClass()).getEStructuralFeature(name); |
| if (result != null) |
| { |
| return result; |
| } |
| |
| throw new IllegalStateException("Cannot find feature corresponding to " + EcoreUtil.getURI(eStructuralFeature)); |
| } |
| |
| @Override |
| protected Setting getTarget(EStructuralFeature eStructuralFeature, EObject eObject, EObject copyEObject) |
| { |
| String name = getAnnotation(eStructuralFeature, "name"); |
| |
| // The blank name is used to discard features which are not intended to be migrated. |
| if ("".equals(name)) |
| { |
| return null; |
| } |
| |
| if (name == null) |
| { |
| name = eStructuralFeature.getName(); |
| } |
| |
| String targetName = getAnnotation(eStructuralFeature, "targetName"); |
| if (targetName != null) |
| { |
| EClass targetEClass = getEClass(eStructuralFeature, "targetName", "targetNsURI"); |
| EClass eClass = copyEObject.eClass(); |
| for (EReference eReference : eClass.getEAllContainments()) |
| { |
| EClass eReferenceType = eReference.getEReferenceType(); |
| if (eReferenceType == targetEClass) |
| { |
| EStructuralFeature.Setting setting = demandCreateContainer(copyEObject, targetEClass, eReferenceType, name, eStructuralFeature, eReference); |
| if (setting != null && targetEClass == BasePackage.Literals.ANNOTATION) |
| { |
| // Handle mappings to annotations in a special way to record the original as a details entry. |
| Annotation annotation = (Annotation)setting.getEObject(); |
| annotation.setSource(BaseAnnotationConstants.ANNOTATION_SOURCE); |
| @SuppressWarnings("unchecked") |
| Map.Entry<String, String> stringToStringMapEntry = (Map.Entry<String, String>)BaseFactory.eINSTANCE |
| .create(BasePackage.Literals.STRING_TO_STRING_MAP_ENTRY); |
| InternalEObject mapEntry = (InternalEObject)stringToStringMapEntry; |
| mapEntry.eSet(BasePackage.Literals.STRING_TO_STRING_MAP_ENTRY__KEY, EcoreUtil.getURI(eStructuralFeature).toString()); |
| annotation.getDetails().add(stringToStringMapEntry); |
| return mapEntry.eSetting(BasePackage.Literals.STRING_TO_STRING_MAP_ENTRY__VALUE); |
| } |
| return setting; |
| } |
| } |
| } |
| |
| EStructuralFeature.Setting setting = demandCreateContainer(copyEObject, name, eStructuralFeature); |
| if (setting != null) |
| { |
| return setting; |
| } |
| |
| throw new IllegalStateException("Cannot find feature corresponding to " + EcoreUtil.getURI(eStructuralFeature)); |
| } |
| |
| @Override |
| protected void copyAttribute(EAttribute eAttribute, EObject eObject, EObject copyEObject) |
| { |
| // For attributes that are targeting an Annotation to be copied even if eIsSet is false. |
| String targetName = getAnnotation(eAttribute, "targetName"); |
| if (targetName != null) |
| { |
| EClass targetEClass = getEClass(eAttribute, "targetName", "targetNsURI"); |
| if (targetEClass == BasePackage.Literals.ANNOTATION) |
| { |
| EStructuralFeature.Setting setting = getTarget(eAttribute, eObject, copyEObject); |
| if (setting != null) |
| { |
| copyAttributeValue(eAttribute, eObject, eObject.eGet(eAttribute), setting); |
| return; |
| } |
| } |
| } |
| |
| super.copyAttribute(eAttribute, eObject, copyEObject); |
| } |
| |
| protected EStructuralFeature.Setting demandCreateContainer(final EObject copyEObject, String name, EStructuralFeature eStructuralFeature) |
| { |
| return demandCreateContainer(new HashSet<EClass>(), copyEObject, name, eStructuralFeature); |
| } |
| |
| protected EStructuralFeature.Setting demandCreateContainer(Set<EClass> tried, final EObject copyEObject, String name, |
| EStructuralFeature eStructuralFeature) |
| { |
| EClass targetEClass = copyEObject.eClass(); |
| if (!tried.add(targetEClass)) |
| { |
| return null; |
| } |
| |
| EStructuralFeature targetEStructuralFeature = targetEClass.getEStructuralFeature(name); |
| if (targetEStructuralFeature != null) |
| { |
| if (targetEStructuralFeature instanceof EReference && eStructuralFeature instanceof EReference) |
| { |
| EClass actualTargetEClass = ((EReference)targetEStructuralFeature).getEReferenceType(); |
| EClass expectedTargetEClass = getTarget(((EReference)eStructuralFeature).getEReferenceType()); |
| if (actualTargetEClass != expectedTargetEClass) |
| { |
| // Look for a containment feature that can hold the actual target instance. |
| for (EReference eReference : targetEClass.getEAllContainments()) |
| { |
| EClass eReferenceType = eReference.getEReferenceType(); |
| if (eReferenceType.isSuperTypeOf(actualTargetEClass)) |
| { |
| // Look for containment features of that reference's type to find one that can hold the expected target instance. |
| for (EReference childEReference : eReferenceType.getEAllContainments()) |
| { |
| if (childEReference.getEReferenceType().isSuperTypeOf(expectedTargetEClass)) |
| { |
| // Create a container and a setting for that child reference. |
| return demandCreateContainer(copyEObject, actualTargetEClass, eReference, childEReference, true); |
| } |
| } |
| } |
| } |
| |
| throw new IllegalStateException("Couldn't find a matching feature for " + EcoreUtil.getURI(eStructuralFeature)); |
| } |
| } |
| |
| return ((InternalEObject)copyEObject).eSetting(targetEStructuralFeature); |
| } |
| |
| EClass targetEContainingClass = getTarget(eStructuralFeature.getEContainingClass()); |
| if (targetEContainingClass != null) |
| { |
| for (EReference eReference : targetEClass.getEAllContainments()) |
| { |
| EClass eReferenceType = eReference.getEReferenceType(); |
| if (targetEContainingClass.isSuperTypeOf(eReferenceType)) |
| { |
| EStructuralFeature.Setting setting = demandCreateContainer(copyEObject, targetEContainingClass, eReferenceType, name, eStructuralFeature, |
| eReference); |
| if (setting != null) |
| { |
| return setting; |
| } |
| } |
| } |
| |
| // Try to create intermediate containers... |
| for (final EReference eReference : targetEClass.getEAllContainments()) |
| { |
| EClass eReferenceEType = eReference.getEReferenceType(); |
| if (!eReferenceEType.isAbstract()) |
| { |
| EObject targetContainer; |
| Runnable addToContainer = null; |
| Object targetValue = copyEObject.eGet(eReference); |
| if (eReference.isMany()) |
| { |
| @SuppressWarnings("unchecked") |
| final List<EObject> targetValues = (List<EObject>)targetValue; |
| if (targetValues.isEmpty()) |
| { |
| final EObject demandCreatedTargetContainer = EcoreUtil.create(eReferenceEType); |
| targetContainer = demandCreatedTargetContainer; |
| addToContainer = new Runnable() |
| { |
| public void run() |
| { |
| targetValues.add(demandCreatedTargetContainer); |
| } |
| }; |
| } |
| else |
| { |
| targetContainer = targetValues.get(0); |
| } |
| } |
| else if (targetValue == null) |
| { |
| final EObject demandCreatedTargetContainer = EcoreUtil.create(eReferenceEType); |
| targetContainer = demandCreatedTargetContainer; |
| addToContainer = new Runnable() |
| { |
| |
| public void run() |
| { |
| copyEObject.eSet(eReference, demandCreatedTargetContainer); |
| } |
| }; |
| } |
| else |
| |
| { |
| targetContainer = (EObject)targetValue; |
| } |
| |
| // If we can create a setting, add the container to really use it and return that setting. |
| EStructuralFeature.Setting setting = demandCreateContainer(tried, targetContainer, name, eStructuralFeature); |
| if (setting != null) |
| |
| { |
| if (addToContainer != null) |
| { |
| addToContainer.run(); |
| } |
| |
| return setting; |
| } |
| |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| protected EStructuralFeature.Setting demandCreateContainer(EObject copyEObject, EClass targetEClass, EClass eReferenceType, String name, |
| EStructuralFeature eStructuralFeature, EReference eReference) |
| { |
| if (targetEClass.isSuperTypeOf(eReferenceType)) |
| { |
| EStructuralFeature targetEStructuralFeature = targetEClass.getEStructuralFeature(name); |
| if (targetEStructuralFeature == null) |
| { |
| throw new IllegalStateException("Cannot find feature corresponding to " + EcoreUtil.getURI(eStructuralFeature)); |
| } |
| |
| return demandCreateContainer(copyEObject, eReferenceType, eReference, targetEStructuralFeature, false); |
| } |
| |
| return null; |
| } |
| |
| private EStructuralFeature.Setting demandCreateContainer(EObject copyEObject, EClass eReferenceType, EReference eReference, |
| EStructuralFeature settingFeature, boolean additional) |
| { |
| EObject targetContainer; |
| Object targetValue = copyEObject.eGet(eReference); |
| if (eReference.isMany()) |
| { |
| @SuppressWarnings("unchecked") |
| List<EObject> targetValues = (List<EObject>)targetValue; |
| if (additional || targetValues.isEmpty()) |
| { |
| targetContainer = EcoreUtil.create(eReferenceType); |
| targetValues.add(targetContainer); |
| } |
| else |
| { |
| targetContainer = targetValues.get(0); |
| } |
| } |
| else if (additional || targetValue == null) |
| { |
| targetContainer = EcoreUtil.create(eReferenceType); |
| copyEObject.eSet(eReference, targetContainer); |
| } |
| else |
| { |
| targetContainer = (EObject)targetValue; |
| } |
| |
| return ((InternalEObject)targetContainer).eSetting(settingFeature); |
| } |
| |
| @Override |
| protected void copyAttributeValue(EAttribute eAttribute, EObject eObject, Object value, Setting setting) |
| { |
| EDataType eDataType = eAttribute.getEAttributeType(); |
| EDataType targetEDataType = (EDataType)setting.getEStructuralFeature().getEType(); |
| if (eDataType.getInstanceClass() != targetEDataType.getInstanceClass() || eDataType.getInstanceClass() == null) |
| { |
| if (eAttribute.isMany()) |
| { |
| @SuppressWarnings("unchecked") |
| List<Object> values = (List<Object>)value; |
| @SuppressWarnings("unchecked") |
| List<Object> transformedValues = (List<Object>)setting.get(false); |
| for (Object object : values) |
| { |
| transformedValues.add(convert(eDataType, targetEDataType, object)); |
| } |
| } |
| else |
| { |
| setting.set(convert(eDataType, targetEDataType, value)); |
| } |
| } |
| else |
| { |
| super.copyAttributeValue(eAttribute, eObject, value, setting); |
| } |
| } |
| |
| protected Object convert(EDataType sourceEDataType, EDataType targetEDataType, Object sourceValue) |
| { |
| return EcoreUtil.createFromString(targetEDataType, EcoreUtil.convertToString(sourceEDataType, sourceValue)); |
| } |
| |
| private String getAnnotation(EModelElement eModelElement, String key) |
| { |
| return EcoreUtil.getAnnotation(eModelElement, BaseAnnotationConstants.ANNOTATION_SOURCE, key); |
| } |
| } |
| |
| private Resource resource; |
| |
| public Migrator(Resource resource) |
| { |
| this.resource = resource; |
| } |
| |
| public Collection<? extends EObject> migrate(Collection<EObject> result) |
| { |
| MigrationCopier migrationCopier = new MigrationCopier(resource.getResourceSet().getPackageRegistry()); |
| Set<EObject> allContainedObjects = new HashSet<EObject>(); |
| Set<EObject> allCrossReferencedObjects = new HashSet<EObject>(); |
| for (Iterator<EObject> it = resource.getAllContents(); it.hasNext();) |
| { |
| EObject containedEObject = it.next(); |
| allContainedObjects.add(containedEObject); |
| for (EObject eObject : containedEObject.eCrossReferences()) |
| { |
| allCrossReferencedObjects.add(eObject); |
| if (eObject.eIsProxy()) |
| { |
| migrationCopier.copy(eObject); |
| } |
| } |
| } |
| |
| allCrossReferencedObjects.removeAll(allContainedObjects); |
| for (EObject eObject : allCrossReferencedObjects) |
| { |
| migrationCopier.copyAsProxy(eObject); |
| } |
| |
| RuntimeException runtimeException = null; |
| try |
| { |
| migrationCopier.copyAll(resource.getContents()); |
| } |
| catch (RuntimeException ex) |
| { |
| runtimeException = ex; |
| } |
| |
| try |
| { |
| migrationCopier.copyReferences(); |
| } |
| catch (RuntimeException ex) |
| { |
| if (runtimeException == null) |
| { |
| runtimeException = ex; |
| } |
| } |
| |
| for (EObject eObject : resource.getContents()) |
| { |
| EObject copiedEObject = migrationCopier.get(eObject); |
| if (copiedEObject != null) |
| { |
| result.add(copiedEObject); |
| } |
| } |
| |
| if (runtimeException != null) |
| { |
| throw runtimeException; |
| } |
| |
| Set<ModelElement> annotatedModelElements = new LinkedHashSet<ModelElement>(); |
| for (TreeIterator<Object> it = EcoreUtil.getAllContents(result); it.hasNext();) |
| { |
| Object object = it.next(); |
| if (object instanceof Annotation) |
| { |
| Annotation annotation = (Annotation)object; |
| if (BaseAnnotationConstants.ANNOTATION_SOURCE.equals(annotation.getSource())) |
| { |
| annotatedModelElements.add(annotation.getModelElement()); |
| } |
| } |
| } |
| |
| for (ModelElement modelElement : annotatedModelElements) |
| { |
| try |
| { |
| ReflectUtil.invokeMethod(ReflectUtil.getMethod(modelElement.getClass(), "eMigrate"), modelElement); |
| } |
| catch (ReflectionException exception) |
| { |
| // Ignore. |
| } |
| catch (IllegalArgumentException ex) |
| { |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| return result; |
| } |
| } |
| } |