| /******************************************************************************* |
| * Copyright (c) 2008 Oracle Corporation. |
| * 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: |
| * Cameron Bateman/Oracle - initial API and implementation |
| * |
| ********************************************************************************/ |
| |
| package org.eclipse.jst.jsf.designtime.internal; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jst.jsf.core.internal.JSFCorePlugin; |
| import org.eclipse.jst.jsf.designtime.el.IInstancePerProjectResolver; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * @author cbateman |
| * @param <EXTENSIONTYPE> |
| * |
| */ |
| public class BasicExtensionFactory<EXTENSIONTYPE> |
| { |
| private final Bundle _bundle; |
| private final String _extName; |
| private Map<String, ExtensionData<EXTENSIONTYPE>> _registeredResolvers; |
| private final String _elementName; |
| private final ExtensionDataFactory _extensionDataFactory; |
| private final boolean _alwaysPerProject; |
| |
| /** |
| * @param bundle |
| * @param extName |
| * @param elementName |
| * @param alwaysPerProject |
| */ |
| public BasicExtensionFactory(final Bundle bundle, final String extName, |
| final String elementName, final boolean alwaysPerProject) |
| { |
| _bundle = bundle; |
| _extName = extName; |
| _elementName = elementName; |
| _extensionDataFactory = new ExtensionDataFactory<EXTENSIONTYPE>(); |
| _alwaysPerProject = alwaysPerProject; |
| } |
| |
| /** |
| * @return the resolvers. Lazily initialized. |
| */ |
| public final Map<String, ExtensionData<EXTENSIONTYPE>> getExtensions() |
| { |
| if (_registeredResolvers == null) |
| { |
| _registeredResolvers = loadRegisteredExtensions(); |
| } |
| |
| return _registeredResolvers; |
| } |
| |
| /** |
| * @return the map of extensions by id. |
| */ |
| protected Map<String, ExtensionData<EXTENSIONTYPE>> loadRegisteredExtensions() |
| { |
| final Map<String, ExtensionData<EXTENSIONTYPE>> resolvers = new HashMap<String, ExtensionData<EXTENSIONTYPE>>(); |
| |
| final IExtensionPoint point = Platform.getExtensionRegistry() |
| .getExtensionPoint(_bundle.getSymbolicName(), _extName); |
| |
| final IExtension[] extensions = point.getExtensions(); |
| |
| for (final IExtension extension : extensions) |
| { |
| final IConfigurationElement[] elements = extension |
| .getConfigurationElements(); |
| |
| for (final IConfigurationElement element : elements) |
| { |
| if (_elementName.equals(element.getName()) |
| && element.getAttribute("class") != null //$NON-NLS-1$ |
| && element.getAttribute("id") != null) //$NON-NLS-1$ |
| { |
| final ExtensionData extData = processExtension(element, _alwaysPerProject); |
| |
| if (extData != null) |
| { |
| resolvers.put(extData.getId(), extData); |
| } |
| } |
| } |
| } |
| return resolvers; |
| } |
| |
| /** |
| * @param element |
| * @param alwaysPerProject |
| * @return the extension data for the extension or null if can't be created |
| */ |
| protected ExtensionData processExtension(final IConfigurationElement element, final boolean alwaysPerProject) |
| { |
| return _extensionDataFactory.createExtensionData(element, alwaysPerProject); |
| } |
| |
| /** |
| * @author cbateman |
| * |
| * @param <EXTENSIONTYPE> |
| */ |
| protected static class ExtensionDataFactory<EXTENSIONTYPE> |
| { |
| ExtensionData createExtensionData(final IConfigurationElement element, |
| final boolean alwaysPerProject) |
| { |
| if (isPerProjectExtension(element, alwaysPerProject)) |
| { |
| return new PerProjectExtensionData<EXTENSIONTYPE>(element); |
| } |
| return new SingleInstanceExtensionData<EXTENSIONTYPE>(element); |
| } |
| |
| static boolean isPerProjectExtension(final IConfigurationElement element, final boolean alwaysPerProject) |
| { |
| if (alwaysPerProject) |
| { |
| return true; |
| } |
| final String flag = element.getAttribute("instancePerProject"); |
| // must check for null for backward compatibility, since |
| // this attribute wasn't part of the original. |
| if (flag != null) |
| { |
| return Boolean.valueOf(flag).booleanValue(); |
| } |
| return false; |
| } |
| } |
| |
| /** |
| * @param <EXTENSIONTYPE> |
| */ |
| protected static class PerProjectExtensionData<EXTENSIONTYPE> extends |
| ExtensionData<EXTENSIONTYPE> |
| { |
| private Map<IProject, EXTENSIONTYPE> _extensions; |
| |
| /** |
| * @param element |
| */ |
| protected PerProjectExtensionData(IConfigurationElement element) |
| { |
| super(element); |
| } |
| |
| @Override |
| public EXTENSIONTYPE getInstance(final IProject project) |
| { |
| if (!project.isAccessible()) |
| { |
| _extensions.remove(project); |
| return null; |
| } |
| |
| if (_extensions == null) |
| { |
| _extensions = new HashMap<IProject, EXTENSIONTYPE>(); |
| } |
| |
| EXTENSIONTYPE instance = _extensions.get(project); |
| |
| if (instance == null) |
| { |
| try |
| { |
| instance = createInstance(); |
| if (instance instanceof IInstancePerProjectResolver) |
| { |
| ((IInstancePerProjectResolver) instance) |
| .setProject(project); |
| } |
| _extensions.put(project, instance); |
| } |
| catch (Exception e) |
| { |
| JSFCorePlugin.log(e, |
| "Instantiating extension class for id: " + getId()); |
| } |
| } |
| return instance; |
| } |
| |
| @Override |
| public EXTENSIONTYPE removeInstance(IProject project) |
| { |
| return _extensions.remove(project); |
| } |
| } |
| |
| /** |
| * @param <EXTENSIONTYPE> |
| * |
| */ |
| protected static class SingleInstanceExtensionData<EXTENSIONTYPE> extends |
| ExtensionData<EXTENSIONTYPE> |
| { |
| private EXTENSIONTYPE _instance; |
| |
| /** |
| * @param element |
| */ |
| protected SingleInstanceExtensionData(IConfigurationElement element) |
| { |
| super(element); |
| } |
| |
| @Override |
| public EXTENSIONTYPE getInstance(final IProject project) |
| { |
| if (_instance == null) |
| { |
| try |
| { |
| _instance = createInstance(); |
| } |
| catch (CoreException e) |
| { |
| JSFCorePlugin.log(e, |
| "Instantiating extension class for id: " + getId()); |
| } |
| } |
| return _instance; |
| } |
| |
| @Override |
| public EXTENSIONTYPE removeInstance(IProject project) |
| { |
| final EXTENSIONTYPE removedItem = _instance; |
| _instance = null; |
| return removedItem; |
| } |
| } |
| |
| /** |
| * Extension data |
| * |
| * @param <EXTENSIONTYPE> |
| * |
| */ |
| public abstract static class ExtensionData<EXTENSIONTYPE> |
| { |
| private final IConfigurationElement _element; |
| |
| /** |
| * @param element |
| */ |
| protected ExtensionData(final IConfigurationElement element) |
| { |
| super(); |
| _element = element; |
| } |
| |
| /** |
| * @return the unique id of the variable resolver extension |
| */ |
| public String getId() |
| { |
| return _element.getAttribute("id"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * @param project |
| * @return the instance. project may be ignored if there is only one |
| * global instance for this factory. |
| */ |
| public abstract EXTENSIONTYPE getInstance(final IProject project); |
| |
| /** |
| * @param project |
| * @return the extension for the project, removing from any internal |
| * caching. May return null if getInstance was never called for |
| * project. |
| */ |
| public abstract EXTENSIONTYPE removeInstance(final IProject project); |
| |
| /** |
| * @return the resolver |
| * @throws CoreException |
| */ |
| protected EXTENSIONTYPE createInstance() throws CoreException |
| { |
| return (EXTENSIONTYPE) _element.createExecutableExtension("class"); |
| } |
| } |
| } |