/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.extension; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.teiid.core.designer.PluginUtil; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.core.designer.util.LoggingUtil; import org.teiid.designer.extension.definition.ExtendableMetaclassNameProvider; import org.teiid.designer.extension.definition.ModelExtensionAssistant; import org.teiid.designer.extension.definition.ModelExtensionDefinition; import org.teiid.designer.extension.definition.ModelExtensionDefinitionParser; import org.teiid.designer.extension.definition.ModelObjectExtensionAssistant; import org.teiid.designer.extension.definition.ModelObjectExtensionAssistantFactory; import org.teiid.designer.extension.registry.ModelExtensionRegistry; /** * @since 8.0 */ public class ExtensionPlugin extends Plugin implements ExtensionConstants { /** * Visitor that collects mxd resources */ public static class MxdResourceCollectorVisitor implements IResourceVisitor { List<IFile> resources = new ArrayList<IFile>(); @Override public boolean visit(IResource resource) { /* * Always needs to return true since the search will not recurse into * projects and folders! * * However, we only add the resource if its an mxd. */ if (! resource.exists() || resource.getType() != IResource.FILE) return true; if (MED_EXTENSION.equalsIgnoreCase(resource.getFileExtension())) resources.add((IFile) resource); return true; } /** * Get the found file resource collection * * @return collection of {@link IFile} resources */ public Collection<IFile> getFileResources() { return Collections.unmodifiableCollection(resources); } } /** * The shared instance. */ private static ExtensionPlugin plugin; /** * Logging Utility instance */ public static PluginUtil Util = new LoggingUtil(PLUGIN_ID); /** * @return singleton instance */ public static ExtensionPlugin getInstance() { return plugin; } private static IPath runtimePath; private ModelExtensionAssistantAggregator assistantAggregator; private Map<String, ExtendableMetaclassNameProvider> metaclassNameProvidersMap; /** * A factory that creates model object extension assistants. */ private ModelObjectExtensionAssistantFactory modelObjectAssistantFactory; private ModelExtensionRegistry registry; private File schemaFile; /** * @return the assistant (never <code>null</code>) */ public ModelObjectExtensionAssistant createDefaultModelObjectExtensionAssistant() { if (this.modelObjectAssistantFactory == null) { loadModelObjectExtensionAssistantFactories(); // should always have at least one factory if (this.modelObjectAssistantFactory == null) { // should not happen this.modelObjectAssistantFactory = new ModelObjectExtensionAssistantFactory() { /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistantFactory#getModelObjectType() */ @Override public String getModelObjectType() { return "NO MODEL OBJECT ASSISTANT FACTORY FOUND"; //$NON-NLS-1$ } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistantFactory#createAssistant() */ @Override public ModelObjectExtensionAssistant createAssistant() { Util.log(IStatus.ERROR, Messages.modelObjectExtensionAssistantFactoryNotFound); return new ModelObjectExtensionAssistantAdapter(); } }; } } return this.modelObjectAssistantFactory.createAssistant(); } /** * @param namespacePrefix the namespace prefix to assign the assistant (cannot be <code>null</code> or empty) * @return the assistant (never <code>null</code>) */ public ModelObjectExtensionAssistant createDefaultModelObjectExtensionAssistant( String namespacePrefix ) { CoreArgCheck.isNotEmpty(namespacePrefix, "namespacePrefix is empty"); //$NON-NLS-1$ ModelObjectExtensionAssistant assistant = createDefaultModelObjectExtensionAssistant(); assistant.createModelExtensionDefinition(namespacePrefix, null, null, null, null, null); return assistant; } /** * @return the assistant aggregator */ public ModelExtensionAssistantAggregator getModelExtensionAssistantAggregator() { if(this.assistantAggregator==null) { initializeMedRegistry(); } return this.assistantAggregator; } /** * @return the model extension registry */ public ModelExtensionRegistry getRegistry() { if (this.registry == null) { initializeMedRegistry(); } return this.registry; } /* * Create and load the ModelExtensionRegistry */ private void initializeMedRegistry() { try { this.registry = new ModelExtensionRegistry(getMedSchema()); loadExtensibleMetamodelUriClassnameMap(); this.registry.setMetamodelUris(this.metaclassNameProvidersMap.keySet()); this.assistantAggregator = new ModelExtensionAssistantAggregator(this.registry); // Load Built-In MEDs into the Registry loadBuiltInMeds(); // Load Imported and custom MEDs into the Registry loadDefinedMeds(); } catch (Exception e) { Util.log(e); } } /** * @param metaclassUri * @return meta class name provider for given uri */ public ExtendableMetaclassNameProvider getMetaclassNameProvider( String metaclassUri ) { // if metaclassNameProvidersMap is null, MED registry has not yet been initialized if(this.metaclassNameProvidersMap==null) { initializeMedRegistry(); } return this.metaclassNameProvidersMap.get(metaclassUri); } /** * @param modelObject the model object being checked (cannot be <code>null</code>) * @return <code>true</code> if the model object is related to a model extension definition */ public boolean isModelExtensionDefinitionRelated( Object modelObject ) { for (String namespacePrefix : this.registry.getAllNamespacePrefixes()) { ModelExtensionAssistant assistant = this.registry.getModelExtensionAssistant(namespacePrefix); try { if ((assistant instanceof ModelObjectExtensionAssistant) && ((ModelObjectExtensionAssistant)assistant).isModelExtensionDefinitionRelated(modelObject)) { return true; } } catch (Exception e) { Util.log(e); } } return false; } /** * @return the MED schema file * @throws Exception it there is a problem obtaining the schema file */ public File getMedSchema() throws Exception { if (this.schemaFile == null) { Bundle bundle = Platform.getBundle(PLUGIN_ID); URL url = bundle.getEntry(ExtensionConstants.SCHEMA_FILENAME); if (url == null) { throw new Exception(NLS.bind(Messages.definitionSchemaFileNotFoundInWorkspace, PLUGIN_ID)); } this.schemaFile = new File(FileLocator.toFileURL(url).getFile()); if (!this.schemaFile.exists()) { throw new Exception(NLS.bind(Messages.definitionSchemaFileNotFoundInFilesystem, PLUGIN_ID)); } } return this.schemaFile; } /** * Loads the extension point contributors which indicate the valid extensible metamodel URIs, plus the extendable classname * provider which correspond to each. */ private void loadExtensibleMetamodelUriClassnameMap() { final String EXT_PT = PLUGIN_ID + ".extensibleMetamodelProvider"; //$NON-NLS-1$ final String METAMODEL_URI_ELEMENT = "definition"; //$NON-NLS-1$ final String METAMODEL_URI_ATTR = "metamodelUri"; //$NON-NLS-1$ final String METACLASS_PROVIDER_ATTR = "metaclassProviderClass"; //$NON-NLS-1$ this.metaclassNameProvidersMap = new HashMap(); IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXT_PT); for (IConfigurationElement configElement : configElements) { String sElementName = configElement.getName(); final String pluginId = configElement.getNamespaceIdentifier(); if (METAMODEL_URI_ELEMENT.equals(sElementName)) { String metamodelUri = configElement.getAttribute(METAMODEL_URI_ATTR); if ((metamodelUri != null) && (metamodelUri.trim().length() != 0)) { // Init the map entry with the metamodelUri this.metaclassNameProvidersMap.put(metamodelUri, null); // must have an extendable metaclass name provider Object provider = null; try { provider = configElement.createExecutableExtension(METACLASS_PROVIDER_ATTR); } catch (Exception e) { // attribute CLASS_NAME could be missing or a no-arg constructor in was not found Util.log(IStatus.ERROR, NLS.bind(Messages.problemConstructingMetaclassNameProviderClass, ModelExtensionAssistant.class.getSimpleName(), pluginId)); continue; } final Object metaClassnameProvider = provider; if ((metaClassnameProvider != null) && !(metaClassnameProvider instanceof ExtendableMetaclassNameProvider)) { Util.log(IStatus.ERROR, NLS.bind(Messages.incorrectMetaclassNameProviderClass, metaClassnameProvider.getClass().getName(), pluginId)); continue; } // Get the MetamodelDescriptor for the name provider this.metaclassNameProvidersMap.put(metamodelUri, (ExtendableMetaclassNameProvider)metaClassnameProvider); } } } } /* * Load the Built In MEDS (which are contributed from extension point) into the Registry. */ private void loadBuiltInMeds() throws Exception { final String EXT_PT = PLUGIN_ID + ".modelExtensionProvider"; //$NON-NLS-1$ final String PATH = "path"; //$NON-NLS-1$ final String CLASS_NAME = "className"; //$NON-NLS-1$ try { IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXT_PT); for (IConfigurationElement configElement : configElements) { final String pluginId = configElement.getNamespaceIdentifier(); try { // loop over model definitions String tempPath = configElement.getAttribute(PATH); // make sure path attribute exists if (CoreStringUtil.isEmpty(tempPath)) { Util.log(IStatus.ERROR, NLS.bind(Messages.missingDefinitionPath, pluginId, PATH)); continue; } // make sure path represents a file in workspace and on the filesystem final Bundle bundle = Platform.getBundle(pluginId); final IPath path = new Path(tempPath); final URL url = FileLocator.find(bundle, path, null); if (url == null) { Util.log(IStatus.ERROR, NLS.bind(Messages.definitionFileNotFoundInWorkspace, path, pluginId)); continue; } final File defnFile = new File(FileLocator.toFileURL(url).getFile()); if (!defnFile.isFile() || !defnFile.exists()) { Util.log(IStatus.ERROR, NLS.bind(Messages.definitionFileNotFoundInFilesystem, path, pluginId)); continue; } // must have a model extension assistant Object tempAssistant = null; try { tempAssistant = configElement.createExecutableExtension(CLASS_NAME); } catch (Exception e) { // attribute CLASS_NAME could be missing or a no-arg constructor in was not found Util.log(IStatus.ERROR, NLS.bind(Messages.problemConstructingModelExtensionAssistantClass, ModelExtensionAssistant.class.getSimpleName(), pluginId)); continue; } final Object assistant = tempAssistant; if ((assistant != null) && !(assistant instanceof ModelExtensionAssistant)) { Util.log(IStatus.ERROR, NLS.bind(Messages.incorrectModelExtensionAssistantClass, assistant.getClass().getName(), pluginId)); continue; } ModelExtensionDefinition definition; try { definition = getRegistry().addDefinition(new FileInputStream(defnFile),(ModelExtensionAssistant)assistant); } catch (Exception ex) { Util.log(IStatus.ERROR, ex, NLS.bind(Messages.errorProcessingDefinitionFile, path, pluginId)); throw ex; } if(definition!=null) { definition.markAsBuiltIn(); } } catch (Exception e) { Util.log(IStatus.ERROR, e, NLS.bind(Messages.errorProcessingModelExtension, pluginId)); } } } catch (Exception e) { Util.log(IStatus.ERROR, e, NLS.bind(Messages.errorProcessingExtensionPoint, EXT_PT)); throw e; } } /** * Loads the extensions for the factories that creatE model object assistants. */ private void loadModelObjectExtensionAssistantFactories() { final String EXT_PT = PLUGIN_ID + ".modelObjectExtensionAssistantFactory"; //$NON-NLS-1$ // final String TYPE = "modelObjectType"; //$NON-NLS-1$ final String CLASS_NAME = "className"; //$NON-NLS-1$ try { IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXT_PT); for (IConfigurationElement configElement : configElements) { final String pluginId = configElement.getNamespaceIdentifier(); try { // loop over factories // String type = configElement.getAttribute(TYPE); // must have a factory class Object tempFactory = null; try { tempFactory = configElement.createExecutableExtension(CLASS_NAME); } catch (Exception e) { // attribute CLASS_NAME could be missing or a no-arg constructor in was not found Util.log(IStatus.ERROR, NLS.bind(Messages.problemConstructingModelExtensionAssistantFactoryClass, ModelObjectExtensionAssistantFactory.class.getSimpleName(), pluginId)); continue; } final Object factory = tempFactory; if ((factory != null) && !(factory instanceof ModelObjectExtensionAssistantFactory)) { Util.log(IStatus.ERROR, NLS.bind(Messages.incorrectModelExtensionAssistantFactoryClass, factory.getClass() .getName(), pluginId)); continue; } this.modelObjectAssistantFactory = (ModelObjectExtensionAssistantFactory)factory; break; // currently allow only one factory } catch (Exception e) { Util.log(IStatus.ERROR, e, NLS.bind(Messages.errorProcessingModelExtensionAssistantFactory, pluginId)); } } } catch (Exception e) { Util.log(IStatus.ERROR, e, NLS.bind(Messages.errorProcessingExtensionPoint, EXT_PT)); } } /** * {@inheritDoc} * * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext) */ @Override public void start( final BundleContext context ) throws Exception { super.start(context); plugin = this; // initialize logger first so that other methods can use logger ((LoggingUtil)Util).initializePlatformLogger(this); // initialized the Med schema try { this.schemaFile = getMedSchema(); } catch (Exception e) { Util.log(e); throw e; } } /** * {@inheritDoc} * <p> * * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) */ @Override public void stop( final BundleContext context ) throws Exception { try { // Save the used-defined and imported MEDs that are currently // in the registry (not necessary to save Built Ins) saveDefinedMeds(); } finally { super.stop(context); } } /** * Stream needs to be closed by caller. * * @param medFileStream the input stream for the model extension definition file being parsed (never <code>null</code>) * @return the model extension definition (never <code>null</code>) * @throws Exception if there is a problem parsing the input stream */ public ModelExtensionDefinition parse( InputStream medFileStream ) throws Exception { ModelExtensionDefinitionParser parser = new ModelExtensionDefinitionParser(getMedSchema()); return parser.parse(medFileStream, createDefaultModelObjectExtensionAssistant()); } /* * Save the defined MEDS in the Registry to the defined file system location. */ private void saveDefinedMeds() { if (this.registry != null) { // Save the registry User-Defined Definitions to the specified location this.registry.saveDefinedDefinitions(getUserDefinitionsPath()); } } /* * Load the User-Defined MEDS into the Registry. These are the MEDS which were previously registered and saved at the last * shutdown. */ private void loadDefinedMeds() throws CoreException { if (this.registry != null) { // Restore the User-Defined Definitions into the Registry final IStatus status = this.registry.restoreDefinedDefinitions(getUserDefinitionsPath()); if (!status.isOK()) { Util.log(status); } if (status.getSeverity() == IStatus.ERROR) { throw new CoreException(status); } } } /** * @return the path string to the directory containing the persisted user definitions. */ public String getUserDefinitionsPath() { return getRuntimePath().toFile().getAbsolutePath(); } /** * @return the <code>designer.extension</code> plugin's runtime workspace path or the test runtime path * @since 6.0.0 */ public IPath getRuntimePath() { if (runtimePath == null) { runtimePath = ExtensionPlugin.getInstance().getStateLocation(); } return (IPath)runtimePath.clone(); } protected static class ModelObjectExtensionAssistantAdapter extends ModelObjectExtensionAssistant { /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#cleanupModelResourceMEDs(java.lang.Object) * @throws Exception if error trying to detect and remove incompatible MEDs from model resource */ @Override public void cleanupModelResourceMEDs(Object modelResource) throws Exception { // nothing to do } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#getModelExtensionDefinition(java.lang.Object) */ @Override public ModelExtensionDefinition getModelExtensionDefinition( Object modelObject ) throws Exception { return null; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#getOverriddenValue(java.lang.Object, java.lang.String) */ @Override public String getOverriddenValue( Object modelObject, String propId ) throws Exception { return null; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#getOverriddenValues(java.lang.Object) */ @Override public Properties getOverriddenValues( Object modelObject ) throws Exception { return new Properties(); } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#getPropertyValue(java.lang.Object, java.lang.String) */ @Override public String getPropertyValue( Object modelObject, String propId ) throws Exception { return null; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#getPropertyValues(java.lang.Object) */ @Override public Properties getPropertyValues( Object modelObject ) throws Exception { return new Properties(); } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#getSupportedNamespaces(java.lang.Object) */ @Override public Collection<String> getSupportedNamespaces( Object modelObject ) throws Exception { return Collections.emptyList(); } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#hasExtensionProperties(java.io.File) */ @Override public boolean hasExtensionProperties( File file ) throws Exception { return false; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#hasExtensionProperties(java.lang.Object) */ @Override public boolean hasExtensionProperties( Object modelObject ) throws Exception { return false; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#isModelExtensionDefinitionRelated(java.lang.Object) */ @Override public boolean isModelExtensionDefinitionRelated( Object modelObject ) throws Exception { return false; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#removeModelExtensionDefinition(java.lang.Object) */ @Override public void removeModelExtensionDefinition( Object modelObject ) throws Exception { // nothing to do } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#removeProperty(java.lang.Object, java.lang.String) */ @Override public void removeProperty( Object modelObject, String propId ) throws Exception { // nothing to do } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#saveModelExtensionDefinition(java.lang.Object) */ @Override public void saveModelExtensionDefinition( Object modelObject ) throws Exception { // nothing to do } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#setPropertyValue(java.lang.Object, java.lang.String, java.lang.String) */ @Override public void setPropertyValue( Object modelObject, String propId, String newValue ) throws Exception { // nothing to do } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelExtensionAssistant#supportsMedOperation(java.lang.String, java.lang.Object) */ @Override public boolean supportsMedOperation( String proposedOperationName, Object context ) { return false; } /** * {@inheritDoc} * * @see org.teiid.designer.extension.definition.ModelObjectExtensionAssistant#supportsMyNamespace(java.lang.Object) */ @Override public boolean supportsMyNamespace( Object modelObject ) throws Exception { return false; } /** * {@inheritDoc} * */ @Override public boolean supportsProperty(Object modelObject, String propId) throws Exception { // TODO Auto-generated method stub return false; } } }