/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.project.internal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; 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.core.runtime.dynamichelpers.ExtensionTracker; import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler; import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; import org.eclipse.core.runtime.dynamichelpers.IFilter; import org.simantics.project.features.registry.GroupReference; import org.simantics.project.features.registry.IProjectFeatureExtension; import org.simantics.project.features.registry.IProjectFeatureRegistry; import org.simantics.project.features.registry.InjectedDependency; import org.simantics.project.features.registry.ProjectFeatureReference; import org.simantics.utils.strings.StringUtils; /** * This registry implementation is not properly dynamic-enabled. * injectDependency is not handled well enough to work dynamically. * * @author Tuukka Lehtonen */ public class ProjectFeatureRegistry implements IProjectFeatureRegistry, IExtensionChangeHandler { private final static String NAMESPACE = "org.simantics.project"; private final static String EP_NAME = "feature"; private final static String FEATURE = "feature"; private final static String INJECT_DEPENDENCY = "injectDependency"; private final ExtensionTracker tracker; private IProjectFeatureExtension[] extensions = new IProjectFeatureExtension[0]; public ProjectFeatureRegistry() { tracker = new ExtensionTracker(); // Cache defined actions IExtensionPoint expt = Platform.getExtensionRegistry().getExtensionPoint(NAMESPACE, EP_NAME); loadExtensions(expt.getConfigurationElements()); // Start tracking for new and removed extensions IFilter filter = ExtensionTracker.createExtensionPointFilter(expt); tracker.registerHandler(this, filter); } private void loadExtensions(IConfigurationElement[] configurationElements) { Set newExtensions = new HashSet(Arrays.asList(extensions)); // These are all "feature" elements with required attributes // - id // - feature for (IConfigurationElement el : configurationElements) { if (FEATURE.equals(el.getName())) { String id = StringUtils.safeString(el.getAttribute("id")); if (ProjectPolicy.TRACE_PROJECT_FEATURE_LOAD) System.out.println(this + " Trying to load project feature extension id '" + id + "' contributed by " + el.getContributor().getName()); if (id.isEmpty()) { // Ignore extension without an ID // TODO: log warning if (ProjectPolicy.TRACE_PROJECT_FEATURE_LOAD) System.out.println(this + " skipping feature with empty ID contributed by " + el.getContributor().getName()); continue; } if (StringUtils.safeString(el.getAttribute("class")).isEmpty()) { // Ignore extension without a feature class // TODO: log warning if (ProjectPolicy.TRACE_PROJECT_FEATURE_LOAD) System.out.println(this + " skipping feature missing 'class' attribute contributed by " + el.getContributor().getName()); continue; } // Load optional attributes String label = StringUtils.safeString(el.getAttribute("label")); String description = StringUtils.safeString(el.getAttribute("description")); boolean published = "true".equalsIgnoreCase(el.getAttribute("published")); Collection requires = readProjectFeatureReferenceCollection(el, "requires"); Collection injections = readInjectedDependencies(el, id); Collection installGroups = readGroupReferenceCollection(el, "installGroup"); ProjectFeatureExtension ext = new ProjectFeatureExtension(el, id, label, description, published, requires, injections, installGroups); // Start tracking the new extension object, its removal will be notified of // with removeExtension(extension, Object[]). tracker.registerObject(el.getDeclaringExtension(), ext, IExtensionTracker.REF_STRONG); newExtensions.add(ext); } } // Atomic assignment this.extensions = newExtensions.toArray(new IProjectFeatureExtension[newExtensions.size()]); } private Collection readInjectedDependencies(IConfigurationElement element, String id) { Collection result = new ArrayList(); for (IConfigurationElement child : element.getChildren(INJECT_DEPENDENCY)) { String targetId = StringUtils.safeString(child.getAttribute("targetId")); if (targetId.isEmpty()) // Invalid extension return null; result.add(new InjectedDependency(new ProjectFeatureReference(id, false), new ProjectFeatureReference(targetId, false))); } return result; } private Collection readProjectFeatureReferenceCollection(IConfigurationElement element, String childName) { Collection result = new ArrayList(); for (IConfigurationElement child : element.getChildren(childName)) { String id = StringUtils.safeString(child.getAttribute("id")); if (id.isEmpty()) { // Invalid extension continue; } boolean optional = "true".equalsIgnoreCase( child.getAttribute("optional") ); result.add(new ProjectFeatureReference(id, optional)); } return result; } private Collection readGroupReferenceCollection(IConfigurationElement element, String childName) { Collection result = new ArrayList(); for (IConfigurationElement child : element.getChildren(childName)) { String id = StringUtils.safeString(child.getAttribute("id")); if (id.isEmpty()) { // Invalid extension // TODO: log warning continue; } String version = StringUtils.safeString(child.getAttribute("version")); if (version.isEmpty()) // Empty version implies no version, mark that with null. version = null; result.add(new GroupReference(id, version)); } return result; } @Override public void addExtension(IExtensionTracker tracker, IExtension extension) { loadExtensions(extension.getConfigurationElements()); } @Override public void removeExtension(IExtension extension, Object[] objects) { Set newExtensions = new HashSet(Arrays.asList(extensions)); for (Object o : objects) { tracker.unregisterObject(extension, o); newExtensions.remove(o); } // Atomic assignment this.extensions = newExtensions.toArray(new IProjectFeatureExtension[newExtensions.size()]); } /* (non-Javadoc) * @see org.simantics.project.IProjectFeatureRegistry#getExtensions() */ @Override public IProjectFeatureExtension[] getExtensions() { return extensions; } @Override public IProjectFeatureExtension getExtensionById(String id) { if (id == null) throw new IllegalArgumentException("null id"); for (IProjectFeatureExtension ext : extensions) { if (id.equals(ext.getId())) return ext; } return null; } }