From b6a18b4dc17dbfeb2cd526dd97d24c00e0a0d7ad Mon Sep 17 00:00:00 2001 From: Uwe Stieber Date: Thu, 24 Nov 2011 18:47:09 +0100 Subject: Target Explorer: Add extensible model node factory and implement type correct data node recreation from the persistence storage --- .../core/adapters/ModelNodePersistableAdapter.java | 89 ++++++++- .../src/org/eclipse/tcf/te/core/nls/Messages.java | 2 + .../eclipse/tcf/te/core/nls/Messages.properties | 2 + .../META-INF/MANIFEST.MF | 3 + .../build.properties | 3 +- .../org.eclipse.tcf.te.runtime.model/plugin.xml | 6 + .../schema/factoryDelegates.exsd | 221 +++++++++++++++++++++ .../model/factory/AbstractFactoryDelegate.java | 21 ++ .../tcf/te/runtime/model/factory/Factory.java | 63 ++++++ .../runtime/model/interfaces/factory/IFactory.java | 28 +++ .../model/interfaces/factory/IFactoryDelegate.java | 28 +++ .../internal/factory/FactoryDelegateManager.java | 78 ++++++++ .../internal/factory/FactoryDelegateProxy.java | 107 ++++++++++ .../eclipse/tcf/te/runtime/model/nls/Messages.java | 2 + .../tcf/te/runtime/model/nls/Messages.properties | 2 + .../persistence/interfaces/IPersistable.java | 12 ++ .../PropertiesFilePersistenceDelegate.java | 3 +- .../internal/adapters/MapPersistableAdapter.java | 14 +- .../adapters/PeerModelPersistableAdapter.java | 14 +- 19 files changed, 691 insertions(+), 7 deletions(-) create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/plugin.xml create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/schema/factoryDelegates.exsd create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/AbstractFactoryDelegate.java create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/Factory.java create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactory.java create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactoryDelegate.java create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateManager.java create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateProxy.java (limited to 'target_explorer/plugins') diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/adapters/ModelNodePersistableAdapter.java b/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/adapters/ModelNodePersistableAdapter.java index b1064bbe0..739a76a6f 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/adapters/ModelNodePersistableAdapter.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/adapters/ModelNodePersistableAdapter.java @@ -26,10 +26,13 @@ import org.eclipse.core.runtime.Platform; import org.eclipse.osgi.util.NLS; import org.eclipse.tcf.te.core.activator.CoreBundleActivator; import org.eclipse.tcf.te.core.nls.Messages; +import org.eclipse.tcf.te.runtime.model.factory.Factory; +import org.eclipse.tcf.te.runtime.model.interfaces.IContainerModelNode; import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; import org.eclipse.tcf.te.runtime.persistence.PersistenceDelegateManager; import org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable; import org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistenceDelegate; +import org.osgi.framework.Bundle; /** * Model node persistable adapter implementation. @@ -67,7 +70,7 @@ public class ModelNodePersistableAdapter implements IPersistable { IPath path = new Path(node.getStringProperty("Path")); //$NON-NLS-1$ uri = path.toFile().toURI(); } - // Final fallback is to use the UUID + // No name and no explicit path is set -> use the UUID else if (node.getUUID() != null) { IPath path = getRoot().append(makeValidFileSystemName(node.getUUID().toString().trim())); if (!"ini".equals(path.getFileExtension())) path = path.addFileExtension("ini"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -117,6 +120,20 @@ public class ModelNodePersistableAdapter implements IPersistable { return location; } + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable#getInterfaceType(java.lang.Object) + */ + @SuppressWarnings("restriction") + @Override + public String getInterfaceTypeName(Object data) { + if (data instanceof IContainerModelNode) { + return org.eclipse.tcf.te.runtime.model.activator.CoreBundleActivator.getUniqueIdentifier() + ":" + IContainerModelNode.class.getName(); //$NON-NLS-1$ + } else if (data instanceof IModelNode) { + return org.eclipse.tcf.te.runtime.model.activator.CoreBundleActivator.getUniqueIdentifier() + ":" + IModelNode.class.getName(); //$NON-NLS-1$ + } + return null; + } + /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable#exportFrom(java.lang.Object) */ @@ -201,6 +218,7 @@ public class ModelNodePersistableAdapter implements IPersistable { if (persistable != null) { String storageID = persistable.getStorageID(); URI uri = persistable.getURI(value); + String interfaceTypeName = persistable.getInterfaceTypeName(value); // Check if the persistable returns complete information to create the reference if (storageID == null) { @@ -209,16 +227,20 @@ public class ModelNodePersistableAdapter implements IPersistable { if (uri == null) { throw new IOException(NLS.bind(Messages.ModelNodePersistableAdapter_export_invalidPersistable, value.getClass().getCanonicalName(), "uri")); //$NON-NLS-1$ } + if (interfaceTypeName == null) { + throw new IOException(NLS.bind(Messages.ModelNodePersistableAdapter_export_invalidPersistable, value.getClass().getCanonicalName(), "interfaceTypeName")); //$NON-NLS-1$ + } // Create a reference object Map reference = new HashMap(); reference.put("storageID", storageID); //$NON-NLS-1$ reference.put("uri", uri.toString()); //$NON-NLS-1$ + reference.put("interfaceType", interfaceTypeName); //$NON-NLS-1$ IPersistenceDelegate delegate = PersistenceDelegateManager.getInstance().getDelegate(storageID, false); if (delegate != null) { delegate.write(uri, persistable.exportFrom(value)); - dst.put(key, reference); + dst.put("reference:" + key, reference); //$NON-NLS-1$ continue; } } @@ -241,7 +263,68 @@ public class ModelNodePersistableAdapter implements IPersistable { if (data instanceof IModelNode) { IModelNode node = (IModelNode) data; for (String key : external.keySet()) { - node.setProperty(key, external.get(key)); + // Get the property value + Object value = external.get(key); + + // Check for reference objects + if (key.startsWith("reference:") && value instanceof Map) { //$NON-NLS-1$ + // Cut the "reference:" from the key + String newKey = key.substring(10); + + @SuppressWarnings("unchecked") + Map reference = (Map)value; + + // Get the storage id and the URI from the reference + String storageID = reference.get("storageID"); //$NON-NLS-1$ + String uri = reference.get("uri"); //$NON-NLS-1$ + String interfaceTypeName = reference.get("interfaceType"); //$NON-NLS-1$ + + // Check if the reference returns complete information to read the referenced storage + if (storageID == null) { + throw new IOException(NLS.bind(Messages.ModelNodePersistableAdapter_import_invalidReference, "storageID")); //$NON-NLS-1$ + } + if (uri == null) { + throw new IOException(NLS.bind(Messages.ModelNodePersistableAdapter_import_invalidReference, "uri")); //$NON-NLS-1$ + } + if (interfaceTypeName == null) { + throw new IOException(NLS.bind(Messages.ModelNodePersistableAdapter_import_invalidReference, "interfaceType")); //$NON-NLS-1$ + } + + // Get the persistence delegate + IPersistenceDelegate delegate = PersistenceDelegateManager.getInstance().getDelegate(storageID, false); + if (delegate != null) { + Map referenceData = delegate.read(URI.create(uri)); + if (referenceData != null && !referenceData.isEmpty()) { + try { + // Now, we have to recreate the object + + // Separate the bundleId from the interface name + String[] pieces = interfaceTypeName.split(":", 2); //$NON-NLS-1$ + String bundleId = pieces.length > 1 ? pieces[0] : null; + if (pieces.length > 1) interfaceTypeName = pieces[1]; + + // Determine the bundle to use for loading the class + Bundle bundle = bundleId != null && !"".equals(bundleId.trim()) ? Platform.getBundle(bundleId.trim()) : CoreBundleActivator.getContext().getBundle(); //$NON-NLS-1$ + + Class interfaceType = (Class)bundle.loadClass(interfaceTypeName); + IModelNode referenceNode = Factory.getInstance().newInstance(interfaceType); + + IPersistable persistable = (IPersistable)referenceNode.getAdapter(IPersistable.class); + if (persistable == null) persistable = (IPersistable)Platform.getAdapterManager().getAdapter(referenceNode, IPersistable.class); + if (persistable != null) { + persistable.importTo(referenceNode, referenceData); + node.setProperty(newKey, referenceNode); + } + } catch (ClassNotFoundException e) { + throw new IOException(NLS.bind(Messages.ModelNodePersistableAdapter_import_cannotLoadClass, interfaceTypeName), e); + } + } + } + } + // Not a reference object -> store the object as is to the node + else { + node.setProperty(key, value); + } } } } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.java index b5f669273..ae2936030 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.java @@ -37,4 +37,6 @@ public class Messages extends NLS { public static String ModelNodePersistableAdapter_export_invalidPersistable; public static String ModelNodePersistableAdapter_export_unknownType; + public static String ModelNodePersistableAdapter_import_invalidReference; + public static String ModelNodePersistableAdapter_import_cannotLoadClass; } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.properties index 2c5f058ee..f80734b73 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tcf.te.core/src/org/eclipse/tcf/te/core/nls/Messages.properties @@ -20,3 +20,5 @@ ConnectStrategyStepExecutor_stepFailed_debugInfo=Debug info:\n{0} ModelNodePersistableAdapter_export_invalidPersistable=Persistable for object type ''{0}'' provides incomplete information for property ''{1}''. ModelNodePersistableAdapter_export_unknownType=No strategy to persist an object of type ''{0}'', key = ''{1}''. +ModelNodePersistableAdapter_import_invalidReference=Reference provides incomplete information for property ''{0}'' to restore the object. +ModelNodePersistableAdapter_import_cannotLoadClass=Cannot load class for name ''{0}'' diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/META-INF/MANIFEST.MF index 0018cebd8..b4025fdc1 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/META-INF/MANIFEST.MF +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/META-INF/MANIFEST.MF @@ -12,5 +12,8 @@ Bundle-ActivationPolicy: lazy Bundle-Localization: plugin Export-Package: org.eclipse.tcf.te.runtime.model, org.eclipse.tcf.te.runtime.model.activator;x-internal:=true, + org.eclipse.tcf.te.runtime.model.factory, org.eclipse.tcf.te.runtime.model.interfaces, + org.eclipse.tcf.te.runtime.model.interfaces.factory, + org.eclipse.tcf.te.runtime.model.internal.factory;x-internal:=true, org.eclipse.tcf.te.runtime.model.nls;x-internal:=true diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/build.properties b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/build.properties index f4ae97015..73a5119ed 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/build.properties +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/build.properties @@ -2,4 +2,5 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ .,\ - plugin.properties + plugin.properties,\ + plugin.xml diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/plugin.xml b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/plugin.xml new file mode 100644 index 000000000..34249eeb3 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/plugin.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/schema/factoryDelegates.exsd b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/schema/factoryDelegates.exsd new file mode 100644 index 000000000..33854922f --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/schema/factoryDelegates.exsd @@ -0,0 +1,221 @@ + + + + + + + + + This extension point is used to contribute model node factory delegates. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Declares a model node factory delegate contribution. + + + + + + + + + + + The unique id of the model node factory delegate contribution. + + + + + + + The label representing the model node factory delegate. + + + + + + + The class that implements <code>org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate</code> or extends <code>org.eclipse.tcf.te.runtime.model.factory.AbstractFactoryDelegate</code>. +<p> +The model node factory delegate implementation class must be specified either by the class attribute or the class child element! + + + + + + + + + + + + + Used when creating an <code>IExecutableExtension</code> with a named parameter, or more than one. + + + + + + + + + + The class that implements <code>org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate</code> or extends <code>org.eclipse.tcf.te.runtime.model.factory.AbstractFactoryDelegate</code>. +<p> +The model node factory delegate implementation class must be specified either by the class attribute or the class child element! + + + + + + + + + + + + + A parameter for an <code>IExecutableExtension</code>. + + + + + + + <p>The parameter name.</p> + + + + + + + <p>The parameter value.</p> + + + + + + + + + + The node type interface implemented by nodes created by the factory delegate. + + + + + + + + + + + + + + + + + The unique id of the bundle which contains the class loader required to load the node type class. If not specified, the plugin's own class loader is used. + + + + + + + + + + + + Target Explorer 1.0.0 + + + + + + + + + This is an example of the extension point usage: +<p> +<pre><code> + <extension point="org.eclipse.tcf.te.runtime.model.factoryDelegates"> + <delegate + id="org.eclipse.tcf.te.runtime.model.factory.modelNode" + class="org.eclipse.tcf.te.runtime.model.internal.ModelNodeFactoryDelegate" + label="Model Node Factory Delegate"> + <nodeType class="org.eclipse.tcf.te.runtime.model.interfaces.IModelNode"/> + <nodeType class="org.eclipse.tcf.te.runtime.model.interfaces.IContainerModelNode"/> + </delegate> + </extension> +</code></pre> + + + + + + + + + The provider of a model node factory delegate must implement <samp>org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate</samp>. + + + + + + + + + + Copyright (c) 2011 Wind River Systems, Inc. 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. + + + + diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/AbstractFactoryDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/AbstractFactoryDelegate.java new file mode 100644 index 000000000..f2dc3d5ff --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/AbstractFactoryDelegate.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.te.runtime.model.factory; + +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtension; +import org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate; + + +/** + * Abstract model node factory delegate implementation. + */ +public abstract class AbstractFactoryDelegate extends ExecutableExtension implements IFactoryDelegate { + +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/Factory.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/Factory.java new file mode 100644 index 000000000..b4c47aad7 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/factory/Factory.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.te.runtime.model.factory; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; +import org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactory; +import org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate; +import org.eclipse.tcf.te.runtime.model.internal.factory.FactoryDelegateManager; + +/** + * Model node factory implementation. + */ +public final class Factory extends PlatformObject implements IFactory { + private final FactoryDelegateManager manager = new FactoryDelegateManager(); + + /* + * Thread save singleton instance creation. + */ + private static class LazyInstance { + public static Factory instance = new Factory(); + } + + /** + * Returns the singleton instance of the service manager. + */ + public static Factory getInstance() { + return LazyInstance.instance; + } + + /** + * Constructor. + */ + Factory() { + super(); + } + + /** + * Creates an new instance of the model node object implementing + * the specified node interface. + * + * @param nodeInterface The node interface to be implemented by the model node object to create. + * Must not be null. + * @return The model not object implementing the specified node interface or null. + */ + @Override + public V newInstance(Class nodeInterface) { + Assert.isNotNull(nodeInterface); + + // Determine the model node factory delegate to use + IFactoryDelegate delegate = manager.getFactoryDelegate(nodeInterface); + // Return the model node instance + return delegate != null ? (V)delegate.newInstance(nodeInterface) : null; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactory.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactory.java new file mode 100644 index 000000000..0c1b5b407 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactory.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.te.runtime.model.interfaces.factory; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; + +/** + * Interface to be implemented by model node factories. + */ +public interface IFactory extends IAdaptable { + + /** + * Creates an new instance of an node object implementing the specified node interface. + * + * @param nodeInterface The node interface to be implemented by the node object to be created. + * Must not be null. + * @return The node object implementing the specified node interface or null. + */ + public V newInstance(Class nodeInterface); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactoryDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactoryDelegate.java new file mode 100644 index 000000000..18cead26f --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/interfaces/factory/IFactoryDelegate.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.te.runtime.model.interfaces.factory; + +import org.eclipse.tcf.te.runtime.interfaces.extensions.IExecutableExtension; +import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; + +/** + * Interface to be implemented by model node factory delegates. + */ +public interface IFactoryDelegate extends IExecutableExtension { + + /** + * Returns a new instance of an node object implementing the given node interface. + * + * @param nodeInterface The node interface to be implemented by the node object to be created. + * Must not be null. + * @return The node object implementing the specified node interface or null. + */ + public V newInstance(Class nodeInterface); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateManager.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateManager.java new file mode 100644 index 000000000..1e5e00354 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateManager.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.te.runtime.model.internal.factory; + +import java.util.Collection; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy; +import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; +import org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate; + + +/** + * Model node factory delegate extension point manager implementation. + */ +public class FactoryDelegateManager extends AbstractExtensionPointManager { + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getExtensionPointId() + */ + @Override + protected String getExtensionPointId() { + return "org.eclipse.tcf.te.runtime.model.factoryDelegates"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#getConfigurationElementName() + */ + @Override + protected String getConfigurationElementName() { + return "delegate"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.extensions.AbstractExtensionPointManager#doCreateExtensionProxy(org.eclipse.core.runtime.IConfigurationElement) + */ + @Override + protected ExecutableExtensionProxy doCreateExtensionProxy(IConfigurationElement element) throws CoreException { + return new FactoryDelegateProxy(element); + } + + /** + * Returns the model node factory delegate for the given node type. + *

+ * Note: The first factory delegate declaring the given node type + * as supported will be returned. + * + * @param nodeType The node type. Must not be null. + * @return The model node factory delegate or null. + */ + public IFactoryDelegate getFactoryDelegate(Class nodeType) { + Assert.isNotNull(nodeType); + + IFactoryDelegate delegate = null; + + Collection> delegates = getExtensions().values(); + for (ExecutableExtensionProxy candidate : delegates) { + if (!(candidate instanceof FactoryDelegateProxy)) continue; + if (((FactoryDelegateProxy)candidate).getNodeTypes().contains(nodeType)) { + delegate = candidate.getInstance(); + break; + } + } + + return delegate; + } + +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateProxy.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateProxy.java new file mode 100644 index 000000000..05af0cc82 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/internal/factory/FactoryDelegateProxy.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tcf.te.runtime.model.internal.factory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tcf.te.runtime.activator.CoreBundleActivator; +import org.eclipse.tcf.te.runtime.extensions.ExecutableExtensionProxy; +import org.eclipse.tcf.te.runtime.model.interfaces.IModelNode; +import org.eclipse.tcf.te.runtime.model.interfaces.factory.IFactoryDelegate; +import org.eclipse.tcf.te.runtime.model.nls.Messages; +import org.osgi.framework.Bundle; + +/** + * Model node factory delegate executable extension proxy implementation. + */ +public class FactoryDelegateProxy extends ExecutableExtensionProxy { + // The list of node types supported by the model node factory delegate + private final List> nodeTypes = new ArrayList>(); + // Flag to mark if the node types has been loaded + private boolean nodeTypesLoaded = false; + + /** + * Constructor. + * + * @param element The configuration element. Must not be null. + * @throws CoreException In case the configuration element attribute id is null or empty. + */ + public FactoryDelegateProxy(IConfigurationElement element) throws CoreException { + super(element); + } + + /** + * Constructor. + * + * @param id The id for this instance. + * @param instance The instance to add to proxy. + */ + public FactoryDelegateProxy(String id, IFactoryDelegate instance) { + super(id, instance); + } + + /** + * Returns the list of node types supported by the model node factory. + * + * @return The unmodifiable list of node types. + */ + public List> getNodeTypes() { + if (!nodeTypesLoaded) loadNodeTypes(); + return Collections.unmodifiableList(nodeTypes); + } + + /** + * Load the node types. + */ + protected void loadNodeTypes() { + IConfigurationElement element = getConfigurationElement(); + Assert.isNotNull(element); + + nodeTypes.clear(); + + IConfigurationElement[] nodeTypeElements = element.getChildren("nodeType"); //$NON-NLS-1$ + if (nodeTypeElements != null && nodeTypeElements.length > 0) { + for (IConfigurationElement nodeTypeElement : nodeTypeElements) { + try { + String type = nodeTypeElement.getAttribute("class"); //$NON-NLS-1$ + String bundleId = nodeTypeElement.getAttribute("bundleId"); //$NON-NLS-1$ + + // If a bundle id got specified, use the specified bundle to load the node type class + Bundle bundle = bundleId != null ? bundle = Platform.getBundle(bundleId) : null; + // If we don't have a bundle to load from yet, fallback to the declaring bundle + if (bundle == null) bundle = Platform.getBundle(element.getDeclaringExtension().getNamespaceIdentifier()); + // And finally, use our own bundle to load the class. + // This fallback is expected to never be used. + if (bundle == null) bundle = CoreBundleActivator.getContext().getBundle(); + + // Try to load the node type class now. + Class typeClass = (Class)(bundle != null ? bundle.loadClass(type) : Class.forName(type)); + this.nodeTypes.add(typeClass); + } + catch (Exception e) { + IStatus status = new Status(IStatus.WARNING, CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.FactoryDelegateProxy_warning_failedToLoadNodeType, nodeTypeElement.getAttribute("class"), element.getDeclaringExtension().getUniqueIdentifier()), e); //$NON-NLS-1$ + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + } + + nodeTypesLoaded = true; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.java index eccd6a288..b739d0ce9 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.java @@ -30,4 +30,6 @@ public class Messages extends NLS { // **** Declare externalized string id's down here ***** public static String PendingOperationModelNode_label; + + public static String FactoryDelegateProxy_warning_failedToLoadNodeType; } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.properties index 9fa4cbffc..74497992b 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.model/src/org/eclipse/tcf/te/runtime/model/nls/Messages.properties @@ -4,3 +4,5 @@ # PendingOperationModelNode_label=Pending... + +FactoryDelegateProxy_warning_failedToLoadNodeType=Cannot create node type ''{0}'' for model node factory delegate ''{1}''. diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/interfaces/IPersistable.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/interfaces/IPersistable.java index d93f862fd..17368c32a 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/interfaces/IPersistable.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/interfaces/IPersistable.java @@ -40,6 +40,18 @@ public interface IPersistable { */ public URI getURI(Object data); + /** + * Returns the interface type name to use for recreating the object from the + * persisted object representation. + *

+ * Note: The returned string is expected in the format "<bundleId>:<full qualified interface type name>". + * If the bundle id is not present, it is very likely that the object recreation will fail with a {@link ClassNotFoundException}. + * + * @param data The data object. Must not be null. + * @return The interface type or null. + */ + public String getInterfaceTypeName(Object data); + /** * Exports the given data object to an external representation. *

diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/properties/PropertiesFilePersistenceDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/properties/PropertiesFilePersistenceDelegate.java index d18465c6d..8522891c2 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/properties/PropertiesFilePersistenceDelegate.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.persistence/src/org/eclipse/tcf/te/runtime/persistence/properties/PropertiesFilePersistenceDelegate.java @@ -224,7 +224,8 @@ public class PropertiesFilePersistenceDelegate extends AbstractPersistenceDelega while (line != null) { Matcher matcher = SECTION.matcher(line); if (matcher.matches()) { - currentSection = matcher.group(1).toLowerCase(); + // Section names are case-sensitive too + currentSection = matcher.group(1); if (sections.get(currentSection) == null) { sections.put(currentSection, new HashMap()); } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/MapPersistableAdapter.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/MapPersistableAdapter.java index e2695c393..d302d769f 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/MapPersistableAdapter.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/MapPersistableAdapter.java @@ -18,8 +18,8 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.tcf.protocol.IPeer; -import org.eclipse.tcf.te.tcf.locator.activator.CoreBundleActivator; import org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable; +import org.eclipse.tcf.te.tcf.locator.activator.CoreBundleActivator; /** * Persistable implementation handling peer attributes. @@ -97,6 +97,18 @@ public class MapPersistableAdapter implements IPersistable { return location; } + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable#getInterfaceType(java.lang.Object) + */ + @Override + public String getInterfaceTypeName(Object data) { + if (data instanceof Map) { + // No bundle id needed here, it's a POJO + return Map.class.getName(); + } + return null; + } + /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable#exportFrom(java.lang.Object) */ diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/PeerModelPersistableAdapter.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/PeerModelPersistableAdapter.java index fa7ee71ff..adce7db44 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/PeerModelPersistableAdapter.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/internal/adapters/PeerModelPersistableAdapter.java @@ -16,8 +16,9 @@ import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Path; import org.eclipse.tcf.protocol.Protocol; -import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; import org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable; +import org.eclipse.tcf.te.tcf.locator.activator.CoreBundleActivator; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; /** * Persistable implementation handling peer attributes. @@ -64,6 +65,17 @@ public class PeerModelPersistableAdapter implements IPersistable { return uri; } + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable#getInterfaceType(java.lang.Object) + */ + @Override + public String getInterfaceTypeName(Object data) { + if (data instanceof IPeerModel) { + return CoreBundleActivator.getUniqueIdentifier() + ":" + IPeerModel.class.getName(); //$NON-NLS-1$ + } + return null; + } + /* (non-Javadoc) * @see org.eclipse.tcf.te.runtime.persistence.interfaces.IPersistable#exportFrom(java.lang.Object) */ -- cgit v1.2.3