/******************************************************************************* * Copyright (c) 2009, 2010 Fraunhofer IWU 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: * Fraunhofer IWU - initial API and implementation *******************************************************************************/ package net.enilink.komma.model; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.osgi.framework.BundleContext; import net.enilink.commons.util.extensions.RegistryFactoryHelper; import net.enilink.komma.common.AbstractKommaPlugin; import net.enilink.komma.common.util.IResourceLocator; import net.enilink.komma.core.KommaModule; import net.enilink.komma.internal.model.Messages; import net.enilink.komma.internal.model.ModelModule; import net.enilink.komma.internal.model.extensions.ContentFactoriesRegistryReader; import net.enilink.komma.internal.model.extensions.ContentHandlerRegistryReader; import net.enilink.komma.internal.model.extensions.ExtensionFactoriesRegistryReader; import net.enilink.komma.internal.model.extensions.ProtocolFactoriesRegistryReader; import net.enilink.komma.internal.model.extensions.URIMappingRegistryReader; import net.enilink.komma.model.base.ContentHandlerRegistry; import net.enilink.komma.model.base.IURIMapRuleSet; import net.enilink.komma.model.base.ModelFactoryRegistry; import net.enilink.komma.model.base.ModelSetSupport; import net.enilink.komma.model.base.ModelSupport; import net.enilink.komma.model.base.URIMapRuleSet; import net.enilink.komma.model.validation.Diagnostician; import net.enilink.komma.model.validation.IValidator; import net.enilink.komma.model.validation.ValidatorRegistry; /** * The activator class controls the plug-in life cycle */ public class ModelPlugin extends AbstractKommaPlugin { private IValidator.Registry validatorRegistry = new ValidatorRegistry(); private IContentHandler.Registry contentHandlerRegistry = new ContentHandlerRegistry(); private IModel.Factory.Registry modelFactoryRegistry = new ModelFactoryRegistry(); private IURIMapRuleSet uriMap = new URIMapRuleSet(); // The plug-in ID public static final String PLUGIN_ID = "net.enilink.komma.model"; private static final ModelPlugin INSTANCE = new ModelPlugin(); static { if (!IS_ECLIPSE_RUNNING) { readExtensions(); } } /** * The constructor */ public ModelPlugin() { super(new IResourceLocator[] {}); } /** * Returns the shared instance * * @return the shared instance */ public static ModelPlugin getDefault() { return INSTANCE; } public static void logErrorMessage(String message) { getDefault().log( new Status(IStatus.ERROR, PLUGIN_ID, IModelStatusConstants.INTERNAL_ERROR, message, null)); } public static void logErrorStatus(String message, IStatus status) { if (status == null) { logErrorMessage(message); return; } MultiStatus multi = new MultiStatus(PLUGIN_ID, IModelStatusConstants.INTERNAL_ERROR, message, null); multi.add(status); getDefault().log(multi); } public static void log(Throwable e) { getDefault().log( new Status(IStatus.ERROR, PLUGIN_ID, IModelStatusConstants.INTERNAL_ERROR, Messages.ModelCore_internal_error, e)); } @Override public IResourceLocator getBundleResourceLocator() { return plugin; } public IContentHandler.Registry getContentHandlerRegistry() { return contentHandlerRegistry; } public IModel.Factory.Registry getModelFactoryRegistry() { return modelFactoryRegistry; } public IURIMapRuleSet getURIMap() { return uriMap; } public IValidator.Registry getValidatorRegistry() { return validatorRegistry; } private Diagnostician diagnosticion; public IValidator getDefaultValidator() { if (diagnosticion == null) { diagnosticion = new Diagnostician(getValidatorRegistry()); } return diagnosticion; } /** * The plugin singleton */ private static Implementation plugin; /** * The workspace root. * * @see #getWorkspaceRoot */ private static IWorkspaceRoot workspaceRoot; /** * Returns the workspace root, or <code>null</code>, if the runtime * environment is stand-alone. * * @return the workspace root, or <code>null</code>. */ public static IWorkspaceRoot getWorkspaceRoot() { return workspaceRoot; } /** * A plugin implementation that handles Ecore plugin registration. * * @see #startup() */ static public class Implementation extends EclipsePlugin { /** * Creates the singleton instance. */ public Implementation() { plugin = this; } /** * Starts up this plugin by reading some extensions and populating the * relevant registries. * <p> * The {@link org.eclipse.emf.ecore.EPackage.Registry#INSTANCE global} * package registry is populated by plugin registration of the form: * * <pre> * <extension point="org.eclipse.emf.ecore.generated_package" > * <package uri="http://www.example.org/abc/Abc.ecore" class="org.example.abc.AbcPackage"/> * <extension> * </pre> * * </p> * The URI is arbitrary but an absolute URI is recommended. Provision * for access to the serialized model via <code>"http:"</code> is * encouraged. * <p> * The * {@link org.eclipse.ModelSetFactory.ecore.resource.Resource.Factory.Registry#INSTANCE * global} resource factory registry's * {@link org.eclipse.ModelSetFactory.ecore.resource.Resource.Factory.Registry#getExtensionToFactoryMap() * extension} map is populated by plugin registration of the form: * * <pre> * <extension point="org.eclipse.emf.ecore.extension_parser"> * <parser type="abc" class="org.example.abc.util.AbcResourceFactoryImpl"/> * <extension> * </pre> * * </p> * <p> * The * {@link org.eclipse.ModelSetFactory.ecore.resource.Resource.Factory.Registry#INSTANCE * global} resource factory registry's * {@link org.eclipse.ModelSetFactory.ecore.resource.Resource.Factory.Registry#getProtocolToFactoryMap() * protocol} map is populated by plugin registration of the form: * * <pre> * <extension point="org.eclipse.emf.ecore.protocol_parser" > * <parser protocolName="abc" class="org.example.abc.util.AbcResourceFactoryImpl"/> * <extension> * </pre> * * </p> * <p> * The {@link org.eclipse.emf.ecore.resource.URIConverter#URI_MAP * global} URI map is populated by plugin registration of the form: * * <pre> * <extension point="org.eclipse.emf.ecore.uri_mapping" > * <mapping source="//special/" target="special/"/> * <extension> * </pre> * * If the target is relative, it is resolved against the plugin's * installed location, resulting in a URI of the form: * * <pre> * platform:/plugin/plugin-name_1.2.3/... * </pre> * * The above registration would map * * <pre> * // special/a/b.c * </pre> * * to * * <pre> * platform:/plugin/plugin-name_1.2.3/special/a/b.c * </pre> * * </p> * * @throws Exception * if there is a show stopping problem. */ @Override public void start(BundleContext context) throws Exception { super.start(context); if (IS_RESOURCES_BUNDLE_AVAILABLE) { workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); } readExtensions(); } /** * Stops this plugin. * <p> * Calls save() on the workspace to avoid it being closed in an * unsynchronized state when not running the Eclipse IDE. * <p> * If running the Eclipse IDE, this is redundant [1], because the IDE * application calls this in its postShutdown() hook, but it should not * cause harm, either, because * "The workspace is saved before any plug-ins start to shut down ..." * [2] * * @see <a href= * "https://wiki.eclipse.org/FAQ_How_and_when_do_I_save_the_workspace%3F"> * [1] Eclipse wiki: FAQ entry on WS save()</a> * @see <a href= * "https://wiki.eclipse.org/FAQ_How_can_I_be_notified_when_the_workspace_is_being_saved%3F"> * [2] Eclipse wiki: FAQ entry on WS notifications</a> * */ @Override public void stop(BundleContext ctx) throws Exception { if (IS_RESOURCES_BUNDLE_AVAILABLE) { IStatus status; try { IWorkspace ws = workspaceRoot.getWorkspace(); status = ws.save(true, new NullProgressMonitor()); } catch (CoreException e) { status = e.getStatus(); } if (!status.isOK()) { logErrorStatus("workspace could not be saved", status); } } super.stop(ctx); } } /** * Initialize registered extensions. */ private static void readExtensions() { IModel.Factory.Registry modelFactoryRegistry = ModelPlugin.getDefault() .getModelFactoryRegistry(); new ExtensionFactoriesRegistryReader(modelFactoryRegistry) .readRegistry(); new ProtocolFactoriesRegistryReader(modelFactoryRegistry) .readRegistry(); new ContentFactoriesRegistryReader(modelFactoryRegistry).readRegistry(); new ContentHandlerRegistryReader(ModelPlugin.getDefault() .getContentHandlerRegistry()).readRegistry(); new URIMappingRegistryReader(ModelPlugin.getDefault().getURIMap()) .readRegistry(); } /** * Returns models which are registered as individual ones * * @return base models */ public static Collection<ModelDescription> getBaseModels() { List<ModelDescription> descriptions = new ArrayList<ModelDescription>(); IExtensionPoint extensionPoint = RegistryFactoryHelper.getRegistry() .getExtensionPoint(PLUGIN_ID, "models"); if (extensionPoint != null) { // Loop through the config elements. for (IConfigurationElement configElement : extensionPoint .getConfigurationElements()) { ModelDescription modelDescription = new ModelDescription( configElement); if (modelDescription.getNamespace() == null) { logErrorMessage("Attribute namespace required for modelDescription: " + configElement); continue; } descriptions.add(modelDescription); } } return descriptions; } public static KommaModule createModelSetModule(ClassLoader classLoader) { KommaModule module = new KommaModule(classLoader); module.addConcept(ModelSupport.class, MODELS.TYPE_MODEL.toString()); module.addConcept(ModelSetSupport.class, MODELS.TYPE_MODELSET.toString()); module.addConcept(IModel.IDiagnostic.class, MODELS.CLASS_DIAGNOSTIC.toString()); for (KommaModule modelModule : ModelPlugin.getModelModules()) { module.includeModule(modelModule); } return module; } /** * Returns KommaModules with concepts and behaviours for ModelSets and * Models * * @return model modules */ public static Collection<? extends KommaModule> getModelModules() { List<KommaModule> modules = new ArrayList<KommaModule>(); if (RegistryFactoryHelper.getRegistry() != null) { IExtensionPoint extensionPoint = RegistryFactoryHelper .getRegistry().getExtensionPoint(PLUGIN_ID, "modelModules"); if (extensionPoint != null) { // Loop through the config elements. for (IConfigurationElement configElement : extensionPoint .getConfigurationElements()) { String className = configElement.getAttribute("class"); if (className == null) { logErrorMessage("Attribute class required for module: " + configElement); continue; } try { modules.add((KommaModule) configElement .createExecutableExtension("class")); } catch (CoreException e) { log(e); } } } } else { modules.add(new ModelModule()); } return modules; } }