All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ops4j.peaberry.eclipse.GuiceExtensionFactory Maven / Gradle / Ivy

/**
 * Copyright (C) 2009 Stuart McCulloch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ops4j.peaberry.eclipse;

import static com.google.inject.Guice.createInjector;
import static org.eclipse.core.runtime.ContributorFactoryOSGi.resolve;
import static org.eclipse.core.runtime.RegistryFactory.getRegistry;
import static org.ops4j.peaberry.Peaberry.osgiModule;
import static org.ops4j.peaberry.eclipse.EclipseRegistry.eclipseRegistry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IContributor;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IExecutableExtensionFactory;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.Status;

import com.google.inject.Injector;
import com.google.inject.Module;

/**
 * {@link IExecutableExtensionFactory} that creates an injected extension based
 * on the class named in the adapter data section. If the data section is empty
 * the class is assumed to be in the {@code id} attribute. The factory searches
 * the {@code org.ops4j.peaberry.eclipse.modules} extension for {@link Module}s
 * belonging to the same plug-in and uses them to create a new {@link Injector}.
 * This injector creates the injected extension and is then cached so it can be
 * re-used for other extensions in the same plug-in.
 * 

* To use the factory put it in front of your class name in the extension XML. * Or replace your class with the factory and put your class in the {@code id} * attribute instead. Because the implementation will be injected based on the * bindings you could even replace your class name with one of its interfaces, * and that interface will then be used to lookup the correct implementation. *

* Here's a more detailed walkthrough, based on the example RCP Mail Template: * *

 {@literal <}extension point="org.eclipse.ui.views"{@literal >}
 *   {@literal <}view name="Message"
 *         allowMultiple="true"
 *         icon="icons/sample2.gif"
 *         class="example.ViewImpl"
 *         id="example.view" /{@literal >}
 * {@literal <}/extension{@literal >}
* becomes: * *
 {@literal <}extension point="org.eclipse.ui.views"{@literal >}
 *   {@literal <}view name="Message"
 *         allowMultiple="true"
 *         icon="icons/sample2.gif"
 *         class="org.ops4j.peaberry.eclipse.GuiceExtensionFactory:example.ViewImpl"
 *         id="example.view" /{@literal >}
 * {@literal <}/extension{@literal >}
 * {@literal <}extension point="org.ops4j.peaberry.eclipse.modules"{@literal >}
 *   {@literal <}module class="example.ViewModule" /{@literal >}
 * {@literal <}/extension{@literal >}
* Here's the same example with the class in the {@code id} attribute: * *
 {@literal <}extension point="org.eclipse.ui.views"{@literal >}
 *   {@literal <}view name="Message"
 *         allowMultiple="true"
 *         icon="icons/sample2.gif"
 *         class="org.ops4j.peaberry.eclipse.GuiceExtensionFactory"
 *         id="example.ViewImpl" /{@literal >}
 * {@literal <}/extension{@literal >}
 * {@literal <}extension point="org.ops4j.peaberry.eclipse.modules"{@literal >}
 *   {@literal <}module class="example.ViewModule" /{@literal >}
 * {@literal <}/extension{@literal >}
* and again, this time using an interface instead of the implementation: * *
 {@literal <}extension point="org.eclipse.ui.views"{@literal >}
 *   {@literal <}view name="Message"
 *         allowMultiple="true"
 *         icon="icons/sample2.gif"
 *         class="org.ops4j.peaberry.eclipse.GuiceExtensionFactory:org.eclipse.ui.IViewPart"
 *         id="example.view" /{@literal >}
 * {@literal <}/extension{@literal >}
 * {@literal <}extension point="org.ops4j.peaberry.eclipse.modules"{@literal >}
 *   {@literal <}module class="example.ViewModule" /{@literal >}
 * {@literal <}/extension{@literal >}
* * @author [email protected] (Stuart McCulloch) */ public final class GuiceExtensionFactory implements IExecutableExtension, IExecutableExtensionFactory { public static final String POINT_ID = "org.ops4j.peaberry.eclipse.modules"; private static final Logger LOGGER = Logger.getLogger(GuiceExtensionFactory.class.getName()); // re-use injectors for extensions with the same contributor private static final Map INJECTORS = new HashMap(); private IContributor contributor; private String clazzName; public void setInitializationData(final IConfigurationElement config, final String name, final Object data) { contributor = config.getContributor(); // if there's no (string-based) adapter data then class must be under "id" clazzName = data instanceof String ? (String) data : config.getAttribute("id"); } public Object create() throws CoreException { if (null == clazzName) { throw newCoreException("Configuration is missing class information"); } final Class clazz; try { clazz = resolve(contributor).loadClass(clazzName); } catch (final InvalidRegistryObjectException e) { throw newCoreException(e); } catch (final ClassNotFoundException e) { throw newCoreException(e); } return getInjector().getInstance(clazz); } /** * Remove any {@link Injector}s belonging to uninstalled bundles. */ public static void cleanup() { synchronized (INJECTORS) { // LOCK for (final IContributor c : INJECTORS.keySet()) { if (null == resolve(c)) { INJECTORS.remove(c); } } } // UNLOCK } private Injector getInjector() throws CoreException { synchronized (INJECTORS) { // LOCK Injector injector = INJECTORS.get(contributor); if (null == injector) { final List modules = new ArrayList(); // first add the OSGi service registry and Eclipse extension bindings modules.add(osgiModule(resolve(contributor).getBundleContext(), eclipseRegistry())); // now add any module extensions contributed by the current plug-in for (final IConfigurationElement e : getRegistry().getConfigurationElementsFor(POINT_ID)) { if (contributor.equals(e.getContributor())) { modules.add((Module) e.createExecutableExtension("class")); } } injector = createInjector(modules); INJECTORS.put(contributor, injector); } return injector; } // UNLOCK } private CoreException newCoreException(final Throwable e) { LOGGER.warning(e.getMessage()); return new CoreException(new Status(IStatus.ERROR, contributor.getName(), e.getMessage(), e)); } private CoreException newCoreException(final String message) { LOGGER.warning(message); return new CoreException(new Status(IStatus.ERROR, contributor.getName(), message)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy