package org.eclipse.gmf.codegen.util; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Platform; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.wiring.FrameworkWiring; public class ExtensionTemplatesProviderImpl implements IExtensionTemplatesProvider { private static final String PLATFORM_PLUGIN_PREFIX = "platform:/plugin/"; public static final String DEFAULT_DYNAMIC_TEMPLATES_FOLDER = "aspects"; public static final String POINT_SEPARATOR = "."; public static final String EMPLTY_STRING = ""; public static final String TEMPLATE_FILE_EXTENSIION = "xtend"; private final String myCustomTemplatePath; private List<Class<?>> myDynamicClasses; private List<Class<?>> myCustomClasses; private static final String SLASH = "/"; private final Bundle myBundle; private final boolean myNeedAspects; private final boolean myUsePluginNotProject; public ExtensionTemplatesProviderImpl(String customPath, boolean needAspects) { boolean usePluginNotProject = customPath.startsWith(PLATFORM_PLUGIN_PREFIX); customPath = cutPrefix(customPath, PLATFORM_PLUGIN_PREFIX); customPath = cutPrefix(customPath, SLASH); String bundleName = customPath.split(SLASH)[0]; myCustomTemplatePath = cutPrefix(cutPrefix(customPath, bundleName), SLASH); Bundle platformBundle = Platform.getBundle(bundleName); if (usePluginNotProject) { myBundle = platformBundle; } else { if (platformBundle != null) { // TODO: could be test-specific usePluginNotProject = true; System.err.println("Bundle presents in platform: " + bundleName); myBundle = platformBundle; } else { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(bundleName); ManifestUtil.createOrFillManifest(project); try { myBundle = loadBundle(project); } catch (MalformedURLException e) { throw new RuntimeException("Cannot create correct URL for Bundle.", e); } catch (BundleException e) { throw new RuntimeException("Error. Bundle was not load.", e); } } } myUsePluginNotProject = usePluginNotProject; myNeedAspects = needAspects; } private static String cutPrefix(String text, String prefix) { if (text.startsWith(prefix)) { return text.substring(prefix.length()); } else { return text; } } private static Bundle loadBundle(IProject project) throws MalformedURLException, BundleException { String url = project.getLocation().toFile().toURI().toURL().toExternalForm(); BundleContext bundleContext = CodegenXtendPlugin.getInstance().getContext(); return bundleContext.installBundle(url); } @Override public List<Class<?>> getCustomTemplateClasses() { loadClassesFromBundle(); return myCustomClasses; } @Override public List<Class<?>> getDynamicTemplateClasses() { loadClassesFromBundle(); return myDynamicClasses; } @Override public Class<?> getSuperClassForDynamic(Class<?> _class) { return _class.getSuperclass(); } private Class<?> loadClass(String className) throws ClassNotFoundException, IOException { return myBundle.loadClass(className); } @Override public void dispose() { if (!myUsePluginNotProject) { try { Bundle systemBundle = CodegenXtendPlugin.getInstance().getContext().getBundle(0); myBundle.uninstall(); FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class); frameworkWiring.refreshBundles(frameworkWiring.getRemovalPendingBundles()); } catch (BundleException e) { throw new RuntimeException("Error while unloading bundle.", e); } } } private void loadClassesFromBundle() { if (myDynamicClasses != null && myCustomClasses != null) { return; } myDynamicClasses = new ArrayList<Class<?>>(); myCustomClasses = new ArrayList<Class<?>>(); Enumeration<java.net.URL> classURLs = myBundle.findEntries(myCustomTemplatePath, "*." + TEMPLATE_FILE_EXTENSIION, true); while (classURLs != null && classURLs.hasMoreElements()) { String classPath = classURLs.nextElement().toString().trim(); classPath = classPath.substring(classPath.indexOf(myCustomTemplatePath), classPath.length()).replace(myCustomTemplatePath, EMPLTY_STRING) .replace(POINT_SEPARATOR + TEMPLATE_FILE_EXTENSIION, EMPLTY_STRING); try { Class<?> templateClass = loadClass(getFQCN(classPath)); if (classPath.startsWith(DEFAULT_DYNAMIC_TEMPLATES_FOLDER) && isAspectClass(templateClass)) { if (myNeedAspects) { myDynamicClasses.add(templateClass); } } else { myCustomClasses.add(templateClass); } } catch (ClassNotFoundException e) { throw new RuntimeException("Error. Did not load " + classPath + ". Class not found.", e); } catch (IOException e) { throw new RuntimeException("Error has occurred when try to load " + classPath, e); } } } private boolean isAspectClass(Class<?> customClass) { Class<?> superClass = customClass.getSuperclass(); if (superClass == null) { return false; } String superTemplateResourceName = superClass.getName().replace(POINT_SEPARATOR, SLASH) + "." + TEMPLATE_FILE_EXTENSIION; URL codegenEntry = CodegenXtendPlugin.getInstance().getBundle().getResource(superTemplateResourceName); return codegenEntry != null; } private String getFQCN(String entryPath) { return entryPath.replace(SLASH, POINT_SEPARATOR); } }