blob: c509c49e9ad560327aa2670a10419a30cd3849a2 [file] [log] [blame]
/*
* Copyright (c) 2005, 2010 Borland Software Corporation 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:
* Artem Tikhomirov (Borland) - initial API and implementation
*/
package org.eclipse.gmf.tests.setup;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.StringTokenizer;
import junit.framework.Assert;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.IRegistryChangeListener;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.ecore.plugin.RegistryReader.PluginClassDescriptor;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.gmf.codegen.gmfgen.GenEditorGenerator;
import org.eclipse.gmf.tests.JobTracker;
import org.eclipse.gmf.tests.Plugin;
import org.eclipse.gmf.tests.Utils;
import org.eclipse.swt.widgets.Display;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
/**
* Installs generated GMF plugins to allow invocation of generated code
* @author artem
*/
public class GenProjectSetup extends GenProjectBaseSetup {
private ArrayList<Bundle> myAllInstalledBundes = new ArrayList<Bundle>();
private Bundle myBundle;
private final boolean myIsFullRuntimeRun;
public GenProjectSetup(GeneratorConfiguration generatorFactory) {
super(generatorFactory);
myIsFullRuntimeRun = generatorFactory instanceof RuntimeBasedGeneratorConfiguration;
}
public GenProjectSetup init(DiaGenSource diaGenSource) throws BundleException {
return init(diaGenSource.getGenDiagram().getEditorGen());
}
/**
* Assertion fails on compilation errors.
* @return <code>this</code> for convenience
* @throws BundleException only when shouldInstallInRuntime is true and bundle install fails
* FIXME introduce DiaGenSourceBase with single getDiagram() accessor
*/
public GenProjectSetup init(GenEditorGenerator genEditor) throws BundleException {
final boolean[] extensionChangeNotification = new boolean[] {true};
final IRegistryChangeListener listener = new IRegistryChangeListener() {
public void registryChanged(IRegistryChangeEvent event) {
extensionChangeNotification[0] = false;
}
};
try {
if (myIsFullRuntimeRun) {
RegistryFactory.getRegistry().addRegistryChangeListener(listener, "org.eclipse.gmf.runtime.emf.type.core");
} else {
//Wait for org.eclipse.ui.editors extension point to update. Otherwise, AbstractDiagramEditorTest subclasses fail mysteriously.
RegistryFactory.getRegistry().addRegistryChangeListener(listener, "org.eclipse.ui");
}
myBundle = null;
JobTracker jt = new JobTracker();
jt.start();
generateAndCompile(genEditor);
myBundle.start();
jt.freeze();
// System.out.println("Jobs to wait:" + jt.getJobsCount()); 13!
registerExtensions(myBundle);
registerEMFEditExtensions();
// there should be hit, any .diagram plugin is supposed to register extensions we monitor with the listener above.
monitorExtensionLoad(extensionChangeNotification, 60);
monitorExtensionLoad(jt.getNonEmptyCondition(), 10);
jt.stop();
} catch (BundleException ex) {
throw ex;
} catch (Exception ex) {
Assert.fail(ex.getClass().getSimpleName() + ":" + ex.getMessage());
} finally {
RegistryFactory.getRegistry().removeRegistryChangeListener(listener);
}
return this;
}
/**
* Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=136446
*/
private void monitorExtensionLoad(boolean[] flag, int timeoutSeconds) {
if (null != Display.getCurrent()) {
if (!Utils.dispatchDisplayMessages(flag, timeoutSeconds)) {
// timeout
Plugin.logError("Timeout while waiting for extension point registry to refresh !!!");
// left caller on its own...
}
}
}
protected void hookProjectBuild(IProject p) throws Exception {
super.hookProjectBuild(p);
try {
String url = p.getLocation().toFile().toURL().toExternalForm();
myBundle = Plugin.getBundleContext().installBundle(url);
myAllInstalledBundes.add(myBundle);
} catch (MalformedURLException ex) {
Assert.fail(ex.getMessage());
}
}
/**
* Manually registering all extensions from the generated (diagramming) plugin into eclipse registries
*/
private void registerExtensions(Bundle bundle) {
IConfigurationElement[] configElements = getConfigurationElements(bundle.getSymbolicName(), "org.eclipse.emf.ecore.extension_parser");
for (int i = 0; i < configElements.length; i++) {
try {
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(configElements[i].getAttribute("type"), configElements[i].createExecutableExtension("class"));
} catch (InvalidRegistryObjectException e) {
Assert.fail(e.getMessage());
} catch (CoreException e) {
Assert.fail(e.getMessage());
}
}
}
private void registerEMFEditExtensions() {
for(Bundle next : myAllInstalledBundes) {
IConfigurationElement[] configElements = getConfigurationElements(next.getSymbolicName(), "org.eclipse.emf.edit.itemProviderAdapterFactories");
for(int i = 0; i < configElements.length; i++) {
IConfigurationElement element = configElements[i];
if (element.getName().equals("factory")) {
String packageURI = element.getAttribute("uri");
String className = element.getAttribute("class");
String supportedTypes = element.getAttribute("supportedTypes");
if (packageURI == null) {
continue;
}
else if (className == null) {
continue;
}
else if (supportedTypes == null) {
continue;
}
class PluginAdapterFactoryDescriptor extends PluginClassDescriptor implements ComposedAdapterFactory.Descriptor {
public PluginAdapterFactoryDescriptor(IConfigurationElement element, String attributeName) {
super(element, attributeName);
}
public AdapterFactory createAdapterFactory() {
return (AdapterFactory)createInstance();
}
}
for (StringTokenizer stringTokenizer = new StringTokenizer(supportedTypes); stringTokenizer.hasMoreTokens(); ) {
String supportedType = stringTokenizer.nextToken();
ArrayList<String> key = new ArrayList<String>(2);
key.add(packageURI);
key.add(supportedType);
((ComposedAdapterFactory.Descriptor.Registry.Impl) ComposedAdapterFactory.Descriptor.Registry.INSTANCE).put(key, new PluginAdapterFactoryDescriptor(element, "class"));
}
}
}
}
}
private IConfigurationElement[] getConfigurationElements(String bundlID, String extensionPointID) {
IConfigurationElement[] configs = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointID);
Collection<IConfigurationElement> ownConfigs = new LinkedList<IConfigurationElement>();
for (int i = 0; i < configs.length; i++) {
if (bundlID.equals(configs[i].getContributor().getName())) {
ownConfigs.add(configs[i]);
}
}
return ownConfigs.toArray(new IConfigurationElement[ownConfigs.size()]);
}
public final Bundle getBundle() {
assert myBundle != null : "GenProjectSetup was not initialized";
return myBundle;
}
public void uninstall() throws Exception {
final JobTracker jt = new JobTracker();
jt.start();
for (Bundle next : myAllInstalledBundes) {
next.uninstall();
}
jt.freeze();
// need timeout for ExtensionRegistry to dispatch changes about removed extensions, e.g.
// EditorManager#removeExtensions removes IEditorParts from EditorHistory, to prevent issues
// like https://bugs.eclipse.org/bugs/show_bug.cgi?id=154767
// ExtensionRegistry (namely EqunoxRegistryStrategy) does that either using jobs (ExtensionEventDispatcherJob) or
// in RegistryEventThread, hence all we need to do is give it a chance to complete
Utils.assertDispatchDisplayMessages(jt.getNonEmptyCondition(), 10);
jt.stop();
//
// Then UIExtensionTracker re-dispatches this notification to EditorManager in UI thread, hence need to let them
// reach EditorManager#removeExtensions method
Utils.assertDispatchDisplayMessages(3);
}
}