| /******************************************************************************* |
| * Copyright (c) 2005, 2009 committers of openArchitectureWare 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: |
| * committers of openArchitectureWare - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.osbp.dsl.mwe; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.lang.reflect.Field; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| import java.util.jar.JarFile; |
| import java.util.jar.Manifest; |
| import java.util.zip.ZipException; |
| |
| import javax.xml.parsers.DocumentBuilderFactory; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EPackage.Registry; |
| import org.eclipse.emf.ecore.EcorePackage; |
| 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.URIConverter; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; |
| import org.eclipse.emf.mwe.core.ConfigurationException; |
| import org.eclipse.emf.mwe.core.resources.ResourceLoaderFactory; |
| import org.eclipse.emf.mwe.utils.GenModelHelper; |
| import org.eclipse.emf.mwe.utils.Mapping; |
| import org.eclipse.emf.mwe.utils.ProjectMapping; |
| import org.w3c.dom.Document; |
| |
| /** |
| * Initializes EMF support. Allows to register additional Packages. |
| * |
| * <h1>Configuration</h1> |
| * |
| * <h2>platformUri</h2> Set the path to the root of the platform, usually ".." |
| * |
| * <h3>Explicit platform mapping</h3> If no .project files are available, an |
| * explicit mapping of projectName to path may be established. |
| * |
| * <pre> |
| * projectMapping = { |
| * projectName = 'org.acme.myproject' |
| * path = '../org.acme.myproject' |
| * } |
| * </pre> |
| * |
| * <h2>URI Mapping</h2> Map one URI to another. This is for example required |
| * when some resource refers to another with <tt>platform:/plugin</tt> URIs. |
| * Platform plugin URIs cannot be resolved in standalone mode, thus these URIs |
| * must be mapped to file or platform resource URIs. |
| * |
| * <pre> |
| * uriMap = { |
| * from = "platform:/plugin/org.eclipse.emf.ecore/model/Ecore.ecore" |
| * to = "platform:/resource/myproject/model/Ecore.ecore" |
| * } |
| * </pre> |
| * |
| * <h2>Bundle name mapping</h2> In the case that the folder name of a project |
| * does not match the bundle name, maps the bundle name to the real directory |
| * name on the platform. |
| * |
| * <pre> |
| * bundleNameMap = { |
| * from = "my.bundle.name" |
| * to = "bundledirectoryname" |
| * } |
| * </pre> |
| */ |
| public class MavenStandaloneSetup { |
| |
| private static String platformRootPath = null; |
| private Map<String, String> bundleNameMapping = new HashMap<String, String>(); |
| |
| public static String getPlatformRootPath() { |
| return platformRootPath; |
| } |
| |
| private Log log = LogFactory.getLog(getClass()); |
| static { |
| Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( |
| Resource.Factory.Registry.DEFAULT_EXTENSION, |
| new XMIResourceFactoryImpl()); |
| EPackage.Registry.INSTANCE.put(EcorePackage.eINSTANCE.getNsURI(), |
| EcorePackage.eINSTANCE); |
| } |
| |
| private boolean ignoreBrokenProjectFiles = false; |
| |
| /** |
| * Allows to ignore exception that occur while reading {@code .project} or |
| * {@code Manifest.MF} files. |
| * |
| * Default is {@code false}. |
| */ |
| public void setIgnoreBrokenProjectFiles(boolean ignoreBrokenProjectFiles) { |
| this.ignoreBrokenProjectFiles = ignoreBrokenProjectFiles; |
| } |
| |
| public boolean isIgnoreBrokenProjectFiles() { |
| return ignoreBrokenProjectFiles; |
| } |
| |
| public void setLogResourceUriMap(boolean doLog) { |
| if (!doLog) |
| return; |
| List<Entry<String, URI>> entrySet = new ArrayList<Entry<String, URI>>( |
| EcorePlugin.getPlatformResourceMap().entrySet()); |
| Collections.sort(entrySet, new Comparator<Entry<String, URI>>() { |
| public int compare(Entry<String, URI> o1, Entry<String, URI> o2) { |
| return o1.getKey().compareTo(o2.getKey()); |
| } |
| }); |
| for (Entry<String, URI> entry : entrySet) { |
| log.info(entry.getKey() + " - " + entry.getValue()); |
| } |
| } |
| |
| public void setScanClassPath(boolean doScan) { |
| if (!doScan) |
| return; |
| String property = System.getProperty("java.class.path"); |
| String separator = System.getProperty("path.separator"); |
| Set<File> scanned = new HashSet<File>(); |
| if (property != null) { |
| String[] entries = property.split(separator); |
| for (String entry : entries) { |
| File file = new File(entry); |
| scanned.add(file); |
| doRegisterResourceMapping(file); |
| } |
| } |
| ClassLoader classLoader = getClass().getClassLoader(); |
| if (classLoader instanceof URLClassLoader) { |
| @SuppressWarnings("resource") |
| URLClassLoader urlClassLoader = (URLClassLoader) classLoader; |
| URL[] urLs = urlClassLoader.getURLs(); |
| for (URL url : urLs) { |
| File file; |
| try { |
| file = new File(url.toURI()); |
| if (scanned.add(file)) |
| doRegisterResourceMapping(file); |
| } catch (URISyntaxException e) { |
| log.debug("Couldn't convert url '" + url + "' to a file : " |
| + e.getMessage()); |
| } |
| } |
| } |
| } |
| |
| protected void doRegisterResourceMapping(File file) { |
| try { |
| File f = file.getCanonicalFile(); |
| if (f.getPath().endsWith(".jar")) { |
| registerBundle(f); |
| } else if (!scanFolder(f)) { |
| // eclipse bin folder? |
| String folderName = f.getCanonicalPath().replace("\\", "/"); |
| if (folderName.endsWith("/target/classes")) { |
| File dotProject = new File(f.getParentFile() |
| .getParentFile(), ".project"); |
| if (dotProject.exists()) |
| registerProject(dotProject); |
| } else if (folderName.endsWith("/bin")) { |
| File dotProject = new File(f.getParentFile(), ".project"); |
| if (dotProject.exists()) |
| registerProject(dotProject); |
| } else { |
| log.error(folderName + " is not a valid path! Needs /bin or /target/classes"); |
| } |
| } |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * sets the platform uri for standalone execution |
| * |
| * @param pathToPlatform |
| */ |
| public void setPlatformUri(String pathToPlatform) { |
| File f = new File(pathToPlatform); |
| if (!f.exists()) |
| throw new ConfigurationException("The platformUri location '" |
| + pathToPlatform + "' does not exist"); |
| if (!f.isDirectory()) |
| throw new ConfigurationException( |
| "The platformUri location must point to a directory"); |
| String path = f.getAbsolutePath(); |
| try { |
| path = f.getCanonicalPath(); |
| } catch (IOException e) { |
| log.error("Error when registering platform location", e); |
| } |
| if (platformRootPath == null || !platformRootPath.equals(path)) { |
| platformRootPath = path; |
| log.info("Registering platform uri '" + path + "'"); |
| if (f.exists()) { |
| if (!scanFolder(f)) |
| log.warn("No projects found in platform location '" |
| + pathToPlatform |
| + "'\n" |
| + "because there are no '.project' files.\n" |
| + "Please use explicit project mappings:\n" |
| + " projectMapping = { projectName = 'com.acme' path = '../path/com.acme' }."); |
| } |
| } |
| } |
| |
| public void addProjectMapping(ProjectMapping projectMapping) { |
| String projectName = projectMapping.getProjectName(); |
| if (isEmptyOrNullString(projectName)) { |
| throw new ConfigurationException("ProjectName must not be empty"); |
| } |
| String path = projectMapping.getPath(); |
| if (isEmptyOrNullString(path)) { |
| throw new ConfigurationException("Path must not be empty"); |
| } |
| |
| File f = new File(path); |
| if (!f.exists()) { |
| throw new ConfigurationException("The project's path '" + path |
| + "' does not exist"); |
| } |
| try { |
| URI uri = URI.createFileURI(f.getCanonicalPath() + File.separator); |
| EcorePlugin.getPlatformResourceMap().put(projectName, uri); |
| if (bundleNameMapping.get(projectName) != null) { |
| EcorePlugin.getPlatformResourceMap().put( |
| bundleNameMapping.get(projectName), uri); |
| } |
| log.info("Registering project " + projectName + " at '" + uri + "'"); |
| } catch (IOException e) { |
| handleException(f, e); |
| } |
| } |
| |
| private boolean isEmptyOrNullString(String string) { |
| return string == null || string.length() == 0; |
| } |
| |
| protected boolean scanFolder(File f) { |
| return scanFolder(f, new HashSet<String>()); |
| } |
| |
| protected boolean scanFolder(File f, Set<String> visitedPathes) { |
| try { |
| if (!visitedPathes.add(f.getCanonicalPath())) |
| return true; |
| } catch (IOException e) { |
| log.error(e.getMessage(), e); |
| return true; |
| } |
| File[] files = f.listFiles(); |
| boolean containsProject = false; |
| File dotProject = null; |
| if (files != null) { |
| for (File file : files) { |
| if (file.exists() && file.isDirectory() |
| && !file.getName().startsWith(".")) { |
| containsProject |= scanFolder(file, visitedPathes); |
| } else if (".project".equals(file.getName())) { |
| dotProject = file; |
| } else if (file.getName().endsWith(".jar")) { |
| registerBundle(file); |
| } |
| } |
| } |
| if (!containsProject && dotProject != null) |
| registerProject(dotProject); |
| return containsProject || dotProject != null; |
| } |
| |
| protected void registerBundle(File file) { |
| JarFile jarFile = null; |
| try { |
| jarFile = new JarFile(file); |
| Manifest manifest = jarFile.getManifest(); |
| if (manifest == null) { |
| jarFile.close(); |
| return; |
| } |
| String name = manifest.getMainAttributes().getValue( |
| "Bundle-SymbolicName"); |
| if (name != null) { |
| final int indexOf = name.indexOf(';'); |
| if (indexOf > 0) |
| name = name.substring(0, indexOf); |
| String path = "archive:" + file.getCanonicalFile().toURI() |
| + "!/"; |
| URI uri = URI.createURI(path); |
| registerMapping(name, uri); |
| } |
| } catch (ZipException e) { |
| log.warn("Could not open Jar file " + file.getAbsolutePath() + "."); |
| } catch (Exception e) { |
| handleException(file, e); |
| } finally { |
| try { |
| if (jarFile != null) |
| jarFile.close(); |
| } catch (IOException e) { |
| log.error(e.getMessage(), e); |
| } |
| } |
| } |
| |
| private void handleException(File file, Exception exception) { |
| if (isIgnoreBrokenProjectFiles()) { |
| try { |
| log.warn("Couldn't read " + file.getCanonicalPath()); |
| } catch (IOException e) { |
| log.warn("Couldn't read " + file.getAbsolutePath()); |
| } |
| } else { |
| throw new RuntimeException(exception); |
| } |
| } |
| |
| protected void registerMapping(String name, URI uri) { |
| Map<String, URI> map = EcorePlugin.getPlatformResourceMap(); |
| if (log.isDebugEnabled()) |
| log.debug("Registering project " + name + " at '" + uri + "'"); |
| URI existing = map.put(name, uri); |
| if (existing != null) { |
| if (!existing.equals(uri)) { |
| if (existing.isArchive() == uri.isArchive()) |
| log.warn("Skipping conflicting project " + name + " at '" |
| + existing + "' and using '" + uri + "' instead."); |
| else if (!existing.isArchive() && uri.isArchive()) { |
| if (log.isDebugEnabled()) |
| log.debug("Skipping duplicate project " + name |
| + " at '" + uri + "' and using '" + existing |
| + "' instead (folders win over JARs)."); |
| map.put(name, existing); |
| } else { |
| if (log.isDebugEnabled()) |
| log.debug("Skipping duplicate project " + name |
| + " at '" + existing + "' and using '" + uri |
| + "' instead (folders win over JARs)."); |
| } |
| } |
| } else { |
| String mappedName = bundleNameMapping.get(name); |
| if (mappedName != null) |
| registerMapping(mappedName, uri); |
| } |
| } |
| |
| protected void registerProject(File file) { |
| try { |
| Document document = DocumentBuilderFactory.newInstance() |
| .newDocumentBuilder().parse(new FileInputStream(file)); |
| String name = document.getDocumentElement() |
| .getElementsByTagName("name").item(0).getTextContent(); |
| |
| URI uri = URI.createFileURI(file.getParentFile().getCanonicalPath() |
| + File.separator); |
| registerMapping(name, uri); |
| } catch (Exception e) { |
| handleException(file, e); |
| } |
| } |
| |
| /** |
| * |
| * @param uriMap |
| */ |
| public void addUriMap(final Mapping uriMap) { |
| log.info("Adding URI mapping from '" + uriMap.getFrom() + "' to '" |
| + uriMap.getTo() + "'"); |
| final URI baseUri = URI.createURI(uriMap.getFrom()); |
| final URI mappedUri = URI.createURI(uriMap.getTo()); |
| if (mappedUri == null) |
| throw new ConfigurationException("cannot make URI out of " |
| + uriMap.getTo()); |
| else { |
| URIConverter.URI_MAP.put(baseUri, mappedUri); |
| } |
| } |
| |
| /** |
| * Adds an extension |
| * |
| * @param m |
| * <tt>from</tt>: extension name, <tt>to</tt> factory classname |
| * @throws ConfigurationException |
| * <ul> |
| * <li>The factory class for the extension cannot be found |
| * <li>The inner factory class for the extension cannot be found |
| * </ul> |
| */ |
| public void addExtensionMap(final Mapping m) throws ConfigurationException { |
| log.info("Adding Extension mapping from '" + m.getFrom() + "' to '" |
| + m.getTo() + "'"); |
| try { |
| // locate the factory class of the extension |
| Class<?> factoryClass = ResourceLoaderFactory |
| .createResourceLoader().loadClass(m.getTo()); |
| if (factoryClass == null) |
| throw new ConfigurationException("cannot find class " |
| + m.getTo() + " for extension " + m.getFrom()); |
| Object factoryInstance = null; |
| if (factoryClass.isInterface()) { |
| final Class<?>[] innerClasses = factoryClass |
| .getDeclaredClasses(); |
| factoryClass = null; |
| for (int j = 0; j < innerClasses.length; j++) { |
| if (Resource.Factory.class |
| .isAssignableFrom(innerClasses[j])) { |
| factoryClass = innerClasses[j]; |
| } |
| } |
| if (factoryClass == null) |
| throw new ConfigurationException( |
| "cannot find inner factory class " + m.getTo() |
| + " for extension " + m.getFrom()); |
| final Field instanceField = factoryClass.getField("INSTANCE"); |
| factoryInstance = instanceField.get(null); |
| } else { |
| factoryInstance = factoryClass.newInstance(); |
| } |
| Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put( |
| m.getFrom(), factoryInstance); |
| } catch (final Exception e) { |
| throw new ConfigurationException(e); |
| } |
| } |
| |
| public void addRegisterGeneratedEPackage(String interfacename) { |
| Class<?> clazz = ResourceLoaderFactory.createResourceLoader() |
| .loadClass(interfacename); |
| if (clazz == null) |
| throw new ConfigurationException("Couldn't find an interface " |
| + interfacename); |
| try { |
| EPackage pack = (EPackage) clazz.getDeclaredField("eINSTANCE").get( |
| null); |
| registry.put(pack.getNsURI(), pack); |
| log.info("Adding generated EPackage '" + interfacename + "'"); |
| |
| } catch (Exception e) { |
| throw new ConfigurationException("Couldn't register " |
| + interfacename |
| + ". Is it the generated EPackage interface? : " |
| + e.getMessage()); |
| } |
| } |
| |
| protected ResourceSet resourceSet = new ResourceSetImpl(); |
| protected Registry registry = EPackage.Registry.INSTANCE; |
| |
| public void setResourceSet(ResourceSet resourceSet) { |
| log.info("Using resourceSet registry. The registered Packages will not be registered in the global EPackage.Registry.INSTANCE!"); |
| this.resourceSet = resourceSet; |
| this.registry = resourceSet.getPackageRegistry(); |
| } |
| |
| public void setResourceSetImpl(ResourceSetImpl resourceSet) { |
| setResourceSet(resourceSet); |
| } |
| |
| protected GenModelHelper createGenModelHelper() { |
| return new GenModelHelper(); |
| } |
| |
| public void addRegisterGenModelFile(String fileName) { |
| createGenModelHelper().registerGenModel(resourceSet, |
| createURI(fileName)); |
| } |
| |
| public void addRegisterEcoreFile(String fileName) |
| throws IllegalArgumentException, SecurityException { |
| Resource res = resourceSet.getResource(createURI(fileName), true); |
| if (res == null) |
| throw new ConfigurationException("Couldn't find resource under " |
| + fileName); |
| if (!res.isLoaded()) { |
| try { |
| res.load(null); |
| } catch (IOException e) { |
| throw new ConfigurationException( |
| "Couldn't load resource under " + fileName + " : " |
| + e.getMessage()); |
| } |
| } |
| List<EObject> result = res.getContents(); |
| for (EObject object : result) { |
| if (object instanceof EPackage) { |
| registerPackage(fileName, object); |
| } |
| for (final TreeIterator<EObject> it = object.eAllContents(); it |
| .hasNext();) { |
| EObject child = it.next(); |
| if (child instanceof EPackage) { |
| registerPackage(fileName, child); |
| } |
| } |
| } |
| } |
| |
| public EPackage getPackage(String nsUri) { |
| return (EPackage) registry.get(nsUri); |
| } |
| |
| public void addBundleNameMap(Mapping mapping) { |
| bundleNameMapping.put(mapping.getFrom(), mapping.getTo()); |
| } |
| |
| private URI createURI(String path) { |
| if (path == null) |
| throw new IllegalArgumentException(); |
| |
| URI uri = URI.createURI(path); |
| if (uri.isRelative()) { |
| URI resolvedURI = URI.createFileURI(new File(path) |
| .getAbsolutePath()); |
| return resolvedURI; |
| } |
| return uri; |
| } |
| |
| private void registerPackage(String fileName, EObject object) { |
| String nsUri = ((EPackage) object).getNsURI(); |
| if (registry.get(nsUri) == null) { |
| registry.put(nsUri, object); |
| log.info("Adding dynamic EPackage '" + nsUri + "' from '" |
| + fileName + "'"); |
| } else if (log.isDebugEnabled()) { |
| log.debug("Dynamic EPackage '" + nsUri + "' from '" + fileName |
| + "' already in the registry!"); |
| } |
| } |
| } |