blob: f95f78d6a04988a348e0f5df5de74ea0ae593fb8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2014 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alexandra Buzila - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.ide.spi.util;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EPackage.Descriptor;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.EStructuralFeature;
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.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMap.ValueListIterator;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xml.type.AnyType;
import org.eclipse.emf.ecp.view.spi.model.VView;
import org.eclipse.emf.ecp.view.spi.model.VViewPackage;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
/**
* Helper class for view model objects.
*
* @author Alexandra Buzila
*
* @since 1.13
*/
public final class ViewModelHelper {
private ViewModelHelper() {
}
/**
* Creates a new view model file.
*
* @param modelFile the file in which the view should be saved
* @param selectedEClass the <em>Root EClass</em> for the new {@link VView}
* @param selectedEcore the ecore containing the <em>selectedEClass</em>. If the <em>selectedEcore</em> is null,
* then the <em>selectedEClass</em> must come from an EPackage which is registered by default in
* the
* package registry.
*
* @return the newly created {@link VView}
*
* @throws IOException when something goes wrong while loading or saving the resource
*
*/
public static VView createViewModel(IFile modelFile, EClass selectedEClass, IFile selectedEcore)
throws IOException {
AdapterFactory adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
adapterFactory = new ComposedAdapterFactory(new AdapterFactory[] { adapterFactory,
new ReflectiveItemProviderAdapterFactory() });
final AdapterFactoryEditingDomain domain = new AdapterFactoryEditingDomain(adapterFactory,
new BasicCommandStack());
// create resource for the view
final URI fileURI = URI.createPlatformResourceURI(modelFile.getFullPath().toString(), true);
final Resource resource = domain.createResource(fileURI.toString());
// Add the initial model object to the contents.
final VView view = VViewPackage.eINSTANCE.getViewFactory().createView();
if (view == null) {
return null;
}
resource.getContents().add(view);
// Add the selected EClass as the VView's RootEClass
//
// get the EClass from the registry, to ensure it has the correct href
final EPackage ePackage = selectedEClass.getEPackage();
final Registry instance = org.eclipse.emf.ecore.EPackage.Registry.INSTANCE;
final Object ePackageObject = instance.get(ePackage.getNsURI());
EPackage ep;
if (EPackage.Descriptor.class.isInstance(ePackageObject)) {
final Descriptor descriptor = EPackage.Descriptor.class.cast(ePackageObject);
ep = descriptor.getEPackage();
} else if (EPackage.class.isInstance(ePackageObject)) {
ep = (EPackage) ePackageObject;
} else {
ep = null;
}
if (ep == null && selectedEcore != null) {
EcoreHelper.registerEcore(selectedEcore.getFullPath().toString());
ep = (EPackage) instance.get(ePackage.getNsURI());
}
final EClass ec = (EClass) ep.getEClassifier(selectedEClass.getName());
view.setRootEClass(ec);
view.setName(selectedEClass.getName());
// Update the VView-EClass mapping
if (selectedEcore != null
&& !view.getEcorePaths().contains(selectedEcore.getFullPath().toString())) {
view.getEcorePaths().add(selectedEcore.getFullPath().toString());
}
// Save the contents of the resource to the file system.
resource.save(Collections.singletonMap(XMLResource.OPTION_ENCODING, "UTF-8")); //$NON-NLS-1$
return view;
}
/**
* Tries to load a view from the given file.
*
* @param file the {@link IFile} that contains the view model to be loaded
* @param registeredEcores a {@link Collection} that will contain the paths of all
* Ecores that are necessary to load the view. call
* @return the {@link VView}. Note that view resolution may fail, so callers should check
* whether the view has been resolved successfully
* @throws IOException in case an error occurs while loading the view
*/
public static VView loadView(IFile file, Collection<String> registeredEcores) throws IOException {
final String path = file.getLocation().toString();
final VView view = loadView(path);
registerReferencedEcores(view, registeredEcores);
if (view != null && !viewIsResolved(view)) {
EcoreUtil.resolveAll(view);
}
return view;
}
private static void registerReferencedEcores(VView view, Collection<String> registeredEcores)
throws IOException {
if (view == null || view.getEcorePaths() == null) {
return;
}
for (final String ecorePath : view.getEcorePaths()) {
if (ResourcesPlugin.getWorkspace().getRoot().findMember(ecorePath) == null) {
throw new FileNotFoundException(ecorePath);
}
EcoreHelper.registerEcore(ecorePath);
registeredEcores.add(ecorePath);
}
}
/**
* Check whether the given view has been resolved, i.e. whether it is a proxy or not
*
* @param view the {@link VView} to be checked
* @return {@code true}, if the view is not a proxy, {@code false} otherwise
*/
public static boolean viewIsResolved(VView view) {
return !view.getRootEClass().eIsProxy();
}
/**
* @since 1.16
*/
private static VView loadView(String path) {
final ResourceSet resourceSet = new ResourceSetImpl();
final URI fileURI = URI.createFileURI(path);
final Resource resource = resourceSet.getResource(fileURI, true);
if (resource != null) {
return (VView) resource.getContents().get(0);
}
return null;
}
/**
* Extract the list of Ecore paths from a view model resource.
*
* @param resource the resource to extract the paths from
* @return list of Ecore paths
*
* @since 1.17
*/
public static List<String> getEcorePaths(Resource resource) {
if (resource == null || resource.getContents().isEmpty()) {
return Collections.emptyList();
}
final EObject eObject = resource.getContents().get(0);
if (VView.class.isInstance(eObject)) {
return VView.class.cast(eObject).getEcorePaths();
}
if (AnyType.class.isInstance(eObject)) {
/* view model has older ns uri */
// up to 1.16.0
final FeatureMap anyAttribute = AnyType.class.cast(eObject).getAnyAttribute();
for (int i = 0; i < anyAttribute.size(); i++) {
final EStructuralFeature feature = anyAttribute.getEStructuralFeature(i);
if ("ecorePath".equals(feature.getName())) { //$NON-NLS-1$
return Arrays.asList(new String[] { (String) anyAttribute.getValue(i) });
}
}
// from 1.17.0
final FeatureMap any = AnyType.class.cast(eObject).getAny();
final List<String> ecorePaths = new LinkedList<String>();
for (int i = 0; i < any.size(); i++) {
final EStructuralFeature feature = any.getEStructuralFeature(i);
if ("ecorePaths".equals(feature.getName())) { //$NON-NLS-1$
final AnyType listType = (AnyType) any.getValue(i);
final FeatureMap mixed = listType.getMixed();
// Use iterator to avoid IndexOutOfBounce exceptions for empty ecore paths
final ValueListIterator<Object> iterator = mixed.valueListIterator();
if (iterator.hasNext()) {
ecorePaths.add((String) iterator.next());
}
}
}
return ecorePaths;
}
return Collections.emptyList();
}
}