Bug 546974 - [Data Templates] Template instantiation extensibility

- generate support for child creation extenders
- support pluggable template filters
- support pluggable template resource loaders

Change-Id: I54a7962bab5d506c74b60916e78c25ad3b8ca2f4
Signed-off-by: Christian W. Damus <give.a.damus@gmail.com>
diff --git a/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/TemplateCreateNewModelElementStrategyProvider.xml b/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/TemplateCreateNewModelElementStrategyProvider.xml
index b1e155f..a7ed56a 100644
--- a/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/TemplateCreateNewModelElementStrategyProvider.xml
+++ b/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/TemplateCreateNewModelElementStrategyProvider.xml
@@ -5,6 +5,7 @@
       <provide interface="org.eclipse.emf.ecp.ui.view.swt.reference.CreateNewModelElementStrategy$Provider"/>
    </service>
    <reference bind="addEClassSelectionStrategyProvider" cardinality="0..n" interface="org.eclipse.emf.ecp.ui.view.swt.reference.EClassSelectionStrategy$Provider" name="EClassSelectionStrategyProvider" policy="dynamic" unbind="removeEClassSelectionStrategyProvider"/>
+   <reference bind="addFilterServiceProvider" cardinality="0..n" interface="org.eclipse.emfforms.core.services.datatemplate.TemplateFilterService$Provider" name="FilterServiceProvider" policy="dynamic" unbind="removeFilterServiceProvider"/>
    <reference bind="setLocalizationService" interface="org.eclipse.emfforms.spi.localization.EMFFormsLocalizationService" name="LocalizationService"/>
    <reference bind="registerTemplateProvider" cardinality="0..n" interface="org.eclipse.emfforms.core.services.datatemplate.TemplateProvider" name="registerTemplateProvider" unbind="unregisterTemplateProvider"/>
    <implementation class="org.eclipse.emfforms.internal.core.services.datatemplate.TemplateCreateNewModelElementStrategyProvider"/>
diff --git a/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/XmiTemplateProvider.xml b/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/XmiTemplateProvider.xml
index 963863e..f722a5d 100644
--- a/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/XmiTemplateProvider.xml
+++ b/bundles/org.eclipse.emfforms.core.services.datatemplate/OSGI-INF/XmiTemplateProvider.xml
@@ -3,6 +3,8 @@
    <service>
       <provide interface="org.eclipse.emfforms.core.services.datatemplate.TemplateProvider"/>
    </service>
+   <reference bind="setExtensionRegistry" interface="org.eclipse.core.runtime.IExtensionRegistry" name="ExtensionRegistry"/>
+   <reference bind="addLoaderServiceProvider" cardinality="0..n" interface="org.eclipse.emfforms.core.services.datatemplate.TemplateLoaderService$Provider" name="LoaderServiceProvider" policy="dynamic" unbind="removeLoaderServiceProvider"/>
    <reference bind="setReportService" interface="org.eclipse.emfforms.spi.common.report.ReportService" name="ReportService"/>
    <implementation class="org.eclipse.emfforms.internal.core.services.datatemplate.XmiTemplateProvider"/>
 </scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/core/services/datatemplate/TemplateFilterService.java b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/core/services/datatemplate/TemplateFilterService.java
new file mode 100644
index 0000000..ec0bc79
--- /dev/null
+++ b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/core/services/datatemplate/TemplateFilterService.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Christian W. Damus 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:
+ * Christian W. Damus - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emfforms.core.services.datatemplate;
+
+import java.util.function.Predicate;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emfforms.bazaar.Vendor;
+import org.eclipse.emfforms.datatemplate.Template;
+
+/**
+ * Protocol for a data template filter service.
+ *
+ * @since 1.21
+ */
+public interface TemplateFilterService {
+
+	/**
+	 * A filter service that provides no filtering.
+	 */
+	TemplateFilterService NULL = (owner, reference) -> null;
+
+	/**
+	 * Obtain a template filter applicable to templates provided for the given
+	 * {@code reference} of an {@code owner} object in the editor.
+	 *
+	 * @param owner the object owning a {@code reference} to be assigned from a template
+	 * @param reference a reference feature of the {@code owner} that is to be assigned from a template.
+	 *            If the {@code reference} is a {@link EReference#isContainment() containment} then
+	 *            the {@code owner} would be the {@link EObject#eContainer() container} of the template
+	 *
+	 * @return a predicate with which to filter templates (only templates satisfying the predicate
+	 *         are retained), or else {@code null} to opt out of filtering
+	 */
+	Predicate<? super Template> getTemplateFilter(EObject owner, EReference reference);
+
+	//
+	// Nested types
+	//
+
+	/**
+	 * Specific Bazaar vendor interface for {@link TemplateFilterService} providers.
+	 * It is intended that implementations be registered as OSGi services, for
+	 * clients of the template providers to find them and apply as appropriate
+	 * to the data templates that they obtain.
+	 *
+	 * @since 1.21
+	 */
+	public interface Provider extends Vendor<TemplateFilterService> {
+		// Nothing to add to the superinterface
+	}
+
+}
diff --git a/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/core/services/datatemplate/TemplateLoaderService.java b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/core/services/datatemplate/TemplateLoaderService.java
new file mode 100644
index 0000000..fa0945d
--- /dev/null
+++ b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/core/services/datatemplate/TemplateLoaderService.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Christian W. Damus 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:
+ * Christian W. Damus - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emfforms.core.services.datatemplate;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+
+import javax.inject.Named;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emfforms.bazaar.Vendor;
+import org.eclipse.emfforms.datatemplate.DataTemplatePackage;
+import org.eclipse.emfforms.datatemplate.TemplateCollection;
+
+/**
+ * Protocol for a data template loader service.
+ *
+ * @since 1.21
+ */
+public interface TemplateLoaderService {
+
+	/**
+	 * The default template loader service.
+	 */
+	TemplateLoaderService DEFAULT = uri -> {
+		final ResourceSet resourceSet = new ResourceSetImpl();
+		final Resource resource = resourceSet.createResource(URI.createURI("VIRTUAL_URI.xmi")); //$NON-NLS-1$
+		try (InputStream inputStream = resourceSet.getURIConverter().createInputStream(uri, null)) {
+			resource.load(inputStream, null);
+			return EcoreUtil.getObjectsByType(resource.getContents(), DataTemplatePackage.Literals.TEMPLATE_COLLECTION);
+		}
+	};
+
+	/**
+	 * Load a template resource from an URI.
+	 *
+	 * @param uri the URI of the template resource to load
+	 * @return the template collection(s) loaded from the resource
+	 *
+	 * @throws IOException on failure to load the templates
+	 */
+	Collection<? extends TemplateCollection> loadTemplates(URI uri) throws IOException;
+
+	//
+	// Nested types
+	//
+
+	/**
+	 * Specific Bazaar vendor interface for {@link TemplateLoaderService} providers.
+	 * It is intended that implementations be registered as OSGi services, for
+	 * the XMI-based {@link TemplateProvider} to use to load template resources.
+	 * The Bazaar context provides the following dependencies for injection:
+	 * <ul>
+	 * <li>the {@link URI} of the resource to be loaded</li>
+	 * <li>the contributor ID of the bundle providing the resource, as a
+	 * {@link String} {@linkplain Named named} {@link Provider#CONTRIBUTOR_ID "contributorID"}</li>
+	 * </ul>
+	 *
+	 * @since 1.21
+	 */
+	// CHECKSTYLE.OFF: Interface - Prefer a distinct type from Vendor for OSGi registration
+	public interface Provider extends Vendor<TemplateLoaderService> {
+		// CHECKSTYLE.ON: Interface
+		/**
+		 * Name of the {@link String}-valued context variable for the contributor ID.
+		 *
+		 * @see Named @Named
+		 */
+		String CONTRIBUTOR_ID = "contributorID"; //$NON-NLS-1$
+
+		// Nothing to add to the superinterface
+	}
+
+}
diff --git a/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider.java b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider.java
index 254e768..1c3abb9 100644
--- a/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider.java
+++ b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider.java
@@ -8,7 +8,7 @@
  *
  * Contributors:
  * lucas - initial API and implementation
- * Christian W. Damus - bugs 529138, 543461
+ * Christian W. Damus - bugs 529138, 543461, 546974
  ******************************************************************************/
 package org.eclipse.emfforms.internal.core.services.datatemplate;
 
@@ -18,6 +18,7 @@
 import java.util.LinkedHashSet;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import org.eclipse.emf.ecore.EClass;
@@ -31,8 +32,10 @@
 import org.eclipse.emf.ecp.ui.view.swt.reference.ReferenceServiceCustomizationVendor;
 import org.eclipse.emf.ecp.ui.view.swt.reference.ReferenceStrategyUtil;
 import org.eclipse.emfforms.bazaar.Bazaar;
+import org.eclipse.emfforms.bazaar.BazaarContext;
 import org.eclipse.emfforms.bazaar.Create;
 import org.eclipse.emfforms.common.Optional;
+import org.eclipse.emfforms.core.services.datatemplate.TemplateFilterService;
 import org.eclipse.emfforms.core.services.datatemplate.TemplateProvider;
 import org.eclipse.emfforms.datatemplate.Template;
 import org.eclipse.emfforms.spi.bazaar.BazaarUtil;
@@ -63,6 +66,8 @@
 
 	private final Bazaar<EClassSelectionStrategy> eclassSelectionStrategyBazaar = BazaarUtil.createBazaar(
 		EClassSelectionStrategy.NULL);
+	private final Bazaar<TemplateFilterService> templateFilterBazaar = BazaarUtil.createBazaar(
+		TemplateFilterService.NULL);
 	private ComponentContext context;
 
 	/**
@@ -122,6 +127,27 @@
 	}
 
 	/**
+	 * Add a template filter service provider.
+	 *
+	 * @param provider the provider to add
+	 *
+	 * @since 1.21
+	 */
+	@Reference(cardinality = MULTIPLE, policy = DYNAMIC)
+	public void addFilterServiceProvider(TemplateFilterService.Provider provider) {
+		templateFilterBazaar.addVendor(provider);
+	}
+
+	/**
+	 * Remove a template filter service provider.
+	 *
+	 * @param provider the provider to remove
+	 */
+	void removeFilterServiceProvider(TemplateFilterService.Provider provider) {
+		templateFilterBazaar.removeVendor(provider);
+	}
+
+	/**
 	 * Called by the framework to set the {@link EMFFormsLocalizationService}.
 	 *
 	 * @param localizationService The {@link EMFFormsLocalizationService}
@@ -150,22 +176,31 @@
 	 */
 	protected Set<Template> collectAvailableTemplates(EObject eObject, EReference eReference) {
 		final Set<Template> templates = new LinkedHashSet<Template>();
+
+		final Predicate<? super Template> filter = getFilter(eObject, eReference);
+
 		for (final TemplateProvider provider : templateProviders) {
 			if (!provider.canProvideTemplates(eObject, eReference)) {
 				continue;
 			}
-			Set<Template> provideTemplates;
+
+			Set<Template> providedTemplates;
 			if (provider instanceof BlankTemplateProvider) {
 				final EClassSelectionStrategy eClassSelectionStrategy = ReferenceStrategyUtil
 					.createDynamicEClassSelectionStrategy(eclassSelectionStrategyBazaar, context);
-				provideTemplates = ((BlankTemplateProvider) provider).provideTemplates(eObject, eReference,
+				providedTemplates = ((BlankTemplateProvider) provider).provideTemplates(eObject, eReference,
 					eClassSelectionStrategy);
 			} else {
-				provideTemplates = provider.provideTemplates(eObject, eReference);
+				providedTemplates = provider.provideTemplates(eObject, eReference);
 			}
-			templates.addAll(provideTemplates);
 
+			if (filter == null) {
+				templates.addAll(providedTemplates);
+			} else {
+				providedTemplates.stream().filter(filter).forEach(templates::add);
+			}
 		}
+
 		return templates;
 	}
 
@@ -182,6 +217,26 @@
 	}
 
 	/**
+	 * Obtain a filter predicate for the templates provided for the given {@code reference}
+	 * of an {@code owner} object in the editor.
+	 *
+	 * @param owner the {@link EObject} in the model
+	 * @param reference the {@link EReference} in which templates are to be instantiated
+	 *
+	 * @return the filter, or {@code null} if none
+	 *
+	 * @since 1.21
+	 */
+	protected Predicate<? super Template> getFilter(EObject owner, EReference reference) {
+		final BazaarContext bazaarContext = ReferenceStrategyUtil.createBazaarContext(context, owner, reference);
+		return templateFilterBazaar.createProducts(bazaarContext).stream()
+			.map(service -> service.getTemplateFilter(owner, reference))
+			.filter(Objects::nonNull)
+			.reduce(Predicate::and)
+			.orElse(null);
+	}
+
+	/**
 	 * The actual {@link CreateNewModelElementStrategy strategy} that creates a new element based on a template selected
 	 * by the user.
 	 *
diff --git a/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider.java b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider.java
index c79503f..69c48c5 100644
--- a/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider.java
+++ b/bundles/org.eclipse.emfforms.core.services.datatemplate/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2018 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,30 +8,33 @@
  *
  * Contributors:
  * Lucas Koehler - initial API and implementation
- * Christian W. Damus - bug 529138
+ * Christian W. Damus - bugs 529138, 546974
  ******************************************************************************/
 package org.eclipse.emfforms.internal.core.services.datatemplate;
 
+import static org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE;
+import static org.osgi.service.component.annotations.ReferencePolicy.DYNAMIC;
+
 import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 
 import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.IExtensionRegistry;
 import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emfforms.bazaar.Bazaar;
+import org.eclipse.emfforms.bazaar.BazaarContext;
+import org.eclipse.emfforms.core.services.datatemplate.TemplateLoaderService;
 import org.eclipse.emfforms.core.services.datatemplate.TemplateProvider;
 import org.eclipse.emfforms.datatemplate.Template;
 import org.eclipse.emfforms.datatemplate.TemplateCollection;
+import org.eclipse.emfforms.spi.bazaar.BazaarUtil;
 import org.eclipse.emfforms.spi.common.report.AbstractReport;
 import org.eclipse.emfforms.spi.common.report.ReportService;
 import org.osgi.service.component.annotations.Activate;
@@ -50,8 +53,12 @@
 	private static final String FILE_ATTRIBUTE = "file"; //$NON-NLS-1$
 	private static final String EXTENSION_POINT = "org.eclipse.emfforms.core.services.datatemplate.xmi"; //$NON-NLS-1$
 
+	private final Bazaar<TemplateLoaderService> templateLoaderBazaar = BazaarUtil.createBazaar(
+		TemplateLoaderService.DEFAULT);
+
 	private final Map<EClass, LinkedHashSet<Template>> templates = new LinkedHashMap<EClass, LinkedHashSet<Template>>();
 	private ReportService reportService;
+	private IExtensionRegistry extensionRegistry;
 
 	/**
 	 * Sets the {@link ReportService}.
@@ -64,6 +71,16 @@
 	}
 
 	/**
+	 * Sets the extension registry dependency.
+	 *
+	 * @param extensionRegistry the extension registry
+	 */
+	@Reference
+	void setExtensionRegistry(IExtensionRegistry extensionRegistry) {
+		this.extensionRegistry = extensionRegistry;
+	}
+
+	/**
 	 * Reads the extension point on service activation.
 	 */
 	@Activate
@@ -72,27 +89,43 @@
 	}
 
 	/**
+	 * Add a template loader service provider.
+	 *
+	 * @param provider the provider to add
+	 *
+	 * @since 1.21
+	 */
+	@Reference(cardinality = MULTIPLE, policy = DYNAMIC)
+	public void addLoaderServiceProvider(TemplateLoaderService.Provider provider) {
+		templateLoaderBazaar.addVendor(provider);
+	}
+
+	/**
+	 * Remove a template loader service provider.
+	 *
+	 * @param provider the provider to remove
+	 */
+	void removeLoaderServiceProvider(TemplateLoaderService.Provider provider) {
+		templateLoaderBazaar.removeVendor(provider);
+	}
+
+	/**
 	 * Reads in the registered templates from the extension point.
 	 */
 	void readExtensionPoint() {
-		final IConfigurationElement[] configurationElements = Platform.getExtensionRegistry()
+		final IConfigurationElement[] configurationElements = extensionRegistry
 			.getConfigurationElementsFor(EXTENSION_POINT);
 
 		for (final IConfigurationElement configurationElement : configurationElements) {
 			try {
-				final URL resourceURL = Platform.getBundle(configurationElement.getContributor().getName())
-					.getResource(configurationElement.getAttribute(FILE_ATTRIBUTE));
-				final ResourceSet resourceSet = new ResourceSetImpl();
-				// resourceSet.getLoadOptions().putAll(LOAD_OPTIONS);
-				final Resource resource = resourceSet.createResource(URI.createURI("VIRTUAL_URI")); //$NON-NLS-1$
-				final InputStream inputStream = resourceURL.openStream();
-				try {
-					resource.load(inputStream, null);
-					final TemplateCollection templateCollection = (TemplateCollection) resource.getContents().get(0);
-					registerTemplateCollection(templateCollection);
-				} finally {
-					inputStream.close();
-				}
+				final String contributor = configurationElement.getContributor().getName();
+				final String path = configurationElement.getAttribute(FILE_ATTRIBUTE).replaceFirst("^/*", ""); //$NON-NLS-1$//$NON-NLS-2$
+				final URI resourceURI = URI.createPlatformPluginURI(
+					String.format("%s/%s", contributor, path), true); //$NON-NLS-1$
+
+				final TemplateLoaderService loader = getLoader(resourceURI, contributor);
+				final Collection<? extends TemplateCollection> collections = loader.loadTemplates(resourceURI);
+				collections.forEach(this::registerTemplateCollection);
 			} catch (final IOException ex) {
 				reportService.report(new AbstractReport(ex, "An Exception occured while reading in a data template.")); //$NON-NLS-1$
 			}
@@ -131,6 +164,14 @@
 		return matchingTemplates;
 	}
 
+	private TemplateLoaderService getLoader(URI uri, String contributorID) {
+		final BazaarContext context = BazaarContext.Builder.empty()
+			.put(URI.class, uri)
+			.put(TemplateLoaderService.Provider.CONTRIBUTOR_ID, contributorID)
+			.build();
+		return templateLoaderBazaar.createProduct(context);
+	}
+
 	private void addToTemplateMap(EClass type, Template template) {
 		if (!templates.containsKey(type)) {
 			templates.put(type, new LinkedHashSet<Template>());
diff --git a/bundles/org.eclipse.emfforms.datatemplate.model.edit/META-INF/MANIFEST.MF b/bundles/org.eclipse.emfforms.datatemplate.model.edit/META-INF/MANIFEST.MF
index 0f0e442..048a654 100644
--- a/bundles/org.eclipse.emfforms.datatemplate.model.edit/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.emfforms.datatemplate.model.edit/META-INF/MANIFEST.MF
@@ -1,11 +1,11 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
-Bundle-Name: EMFForms DataTemplate Edit
+Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.emfforms.datatemplate.model.edit;singleton:=true
 Bundle-Version: 1.21.0.qualifier
 Bundle-ClassPath: .
 Bundle-Activator: org.eclipse.emfforms.datatemplate.provider.DatatemplateEditPlugin$Implementation
-Bundle-Vendor: Eclipse Modeling Project
+Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Export-Package: org.eclipse.emfforms.datatemplate.provider;version="1.21.0";x-internal:=true
 Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.13.0,4.0.0)",
diff --git a/bundles/org.eclipse.emfforms.datatemplate.model.edit/plugin.properties b/bundles/org.eclipse.emfforms.datatemplate.model.edit/plugin.properties
index d041cf8..0f1ab0c 100644
--- a/bundles/org.eclipse.emfforms.datatemplate.model.edit/plugin.properties
+++ b/bundles/org.eclipse.emfforms.datatemplate.model.edit/plugin.properties
@@ -1,4 +1,4 @@
-# Copyright (c) 2011-2017 EclipseSource Muenchen GmbH and others.
+# Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
 # 
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
@@ -7,9 +7,11 @@
 # 
 # Contributors:
 # EclipseSource Munich - initial API and implementation
+# Christian W. Damus - bug 546974
+# 
 
-pluginName = DataTemplate Edit Support
-providerName = www.example.org
+pluginName = EMFForms DataTemplate Edit
+providerName = Eclipse Modeling Project
 
 _UI_CreateChild_text = {0}
 _UI_CreateChild_text2 = {1} {0}
diff --git a/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/DataTemplateItemProviderAdapterFactory.java b/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/DataTemplateItemProviderAdapterFactory.java
index de138f9..6dc0e47 100644
--- a/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/DataTemplateItemProviderAdapterFactory.java
+++ b/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/DataTemplateItemProviderAdapterFactory.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2018 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,19 +8,25 @@
  *
  * Contributors:
  * EclipseSource Muenchen GmbH - initial API and implementation
+ * Christian W. Damus - bug 546974
  */
 package org.eclipse.emfforms.datatemplate.provider;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 import org.eclipse.emf.common.notify.Adapter;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.edit.domain.EditingDomain;
 import org.eclipse.emf.edit.provider.ChangeNotifier;
+import org.eclipse.emf.edit.provider.ChildCreationExtenderManager;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
 import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
 import org.eclipse.emf.edit.provider.IChangeNotifier;
+import org.eclipse.emf.edit.provider.IChildCreationExtender;
 import org.eclipse.emf.edit.provider.IDisposable;
 import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
 import org.eclipse.emf.edit.provider.IItemLabelProvider;
@@ -28,6 +34,7 @@
 import org.eclipse.emf.edit.provider.INotifyChangedListener;
 import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
 import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
+import org.eclipse.emfforms.datatemplate.DataTemplatePackage;
 import org.eclipse.emfforms.datatemplate.util.DataTemplateAdapterFactory;
 
 /**
@@ -42,7 +49,7 @@
  * @generated
  */
 public class DataTemplateItemProviderAdapterFactory extends DataTemplateAdapterFactory
-	implements ComposeableAdapterFactory, IChangeNotifier, IDisposable {
+	implements ComposeableAdapterFactory, IChangeNotifier, IDisposable, IChildCreationExtender {
 	/**
 	 * This keeps track of the root adapter factory that delegates to this adapter factory.
 	 * <!-- begin-user-doc -->
@@ -62,13 +69,23 @@
 	protected IChangeNotifier changeNotifier = new ChangeNotifier();
 
 	/**
+	 * This helps manage the child creation extenders.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * 
+	 * @generated
+	 */
+	protected ChildCreationExtenderManager childCreationExtenderManager = new ChildCreationExtenderManager(
+		DatatemplateEditPlugin.INSTANCE, DataTemplatePackage.eNS_URI);
+
+	/**
 	 * This keeps track of all the supported types checked by {@link #isFactoryForType isFactoryForType}.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
 	 * 
 	 * @generated
 	 */
-	protected Collection<Object> supportedTypes = new ArrayList<Object>();
+	protected Collection<Object> supportedTypes = new ArrayList<>();
 
 	/**
 	 * This constructs an instance.
@@ -202,6 +219,38 @@
 	}
 
 	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * 
+	 * @generated
+	 */
+	public List<IChildCreationExtender> getChildCreationExtenders() {
+		return childCreationExtenderManager.getChildCreationExtenders();
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * 
+	 * @generated
+	 */
+	@Override
+	public Collection<?> getNewChildDescriptors(Object object, EditingDomain editingDomain) {
+		return childCreationExtenderManager.getNewChildDescriptors(object, editingDomain);
+	}
+
+	/**
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * 
+	 * @generated
+	 */
+	@Override
+	public ResourceLocator getResourceLocator() {
+		return childCreationExtenderManager;
+	}
+
+	/**
 	 * This adds a listener.
 	 * <!-- begin-user-doc -->
 	 * <!-- end-user-doc -->
diff --git a/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateCollectionItemProvider.java b/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateCollectionItemProvider.java
index fe77c42..bbc8a11 100644
--- a/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateCollectionItemProvider.java
+++ b/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateCollectionItemProvider.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2018 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,7 @@
  *
  * Contributors:
  * EclipseSource Muenchen GmbH - initial API and implementation
+ * Christian W. Damus - bug 546974
  */
 package org.eclipse.emfforms.datatemplate.provider;
 
@@ -19,6 +20,7 @@
 import org.eclipse.emf.common.util.ResourceLocator;
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.IChildCreationExtender;
 import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
 import org.eclipse.emf.edit.provider.IItemLabelProvider;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
@@ -198,7 +200,7 @@
 	 */
 	@Override
 	public ResourceLocator getResourceLocator() {
-		return DatatemplateEditPlugin.INSTANCE;
+		return ((IChildCreationExtender) adapterFactory).getResourceLocator();
 	}
 
 }
diff --git a/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateItemProvider.java b/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateItemProvider.java
index 1c53c75..08b0bf7 100644
--- a/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateItemProvider.java
+++ b/bundles/org.eclipse.emfforms.datatemplate.model.edit/src/org/eclipse/emfforms/datatemplate/provider/TemplateItemProvider.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2018 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,7 @@
  *
  * Contributors:
  * EclipseSource Muenchen GmbH - initial API and implementation
+ * Christian W. Damus - bug 546974
  */
 package org.eclipse.emfforms.datatemplate.provider;
 
@@ -19,6 +20,7 @@
 import org.eclipse.emf.common.util.ResourceLocator;
 import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.IChildCreationExtender;
 import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
 import org.eclipse.emf.edit.provider.IItemLabelProvider;
 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
@@ -221,7 +223,7 @@
 	 */
 	@Override
 	public ResourceLocator getResourceLocator() {
-		return DatatemplateEditPlugin.INSTANCE;
+		return ((IChildCreationExtender) adapterFactory).getResourceLocator();
 	}
 
 }
diff --git a/bundles/org.eclipse.emfforms.datatemplate.model/model/datatemplate.genmodel b/bundles/org.eclipse.emfforms.datatemplate.model/model/datatemplate.genmodel
index 036e249..a5b5a73 100644
--- a/bundles/org.eclipse.emfforms.datatemplate.model/model/datatemplate.genmodel
+++ b/bundles/org.eclipse.emfforms.datatemplate.model/model/datatemplate.genmodel
@@ -10,7 +10,8 @@
     operationReflection="true" importOrganizing="true" cleanup="true">
   <foreignModel>datatemplate.ecore</foreignModel>
   <genPackages prefix="DataTemplate" basePackage="org.eclipse.emfforms" disposableProviderFactory="true"
-      contentTypeIdentifier="org.eclipse.emfforms.datatemplate.model" ecorePackage="datatemplate.ecore#/">
+      extensibleProviderFactory="true" contentTypeIdentifier="org.eclipse.emfforms.datatemplate.model"
+      ecorePackage="datatemplate.ecore#/">
     <genClasses ecoreClass="datatemplate.ecore#//Template">
       <genFeatures createChild="false" ecoreFeature="ecore:EAttribute datatemplate.ecore#//Template/name"/>
       <genFeatures children="true" createChild="false" ecoreFeature="ecore:EReference datatemplate.ecore#//Template/instance"/>
diff --git a/tests/org.eclipse.emfforms.core.services.datatemplate.test/AllPluginTests for core.services.datatemplate.launch b/tests/org.eclipse.emfforms.core.services.datatemplate.test/AllPluginTests for core.services.datatemplate.launch
index b9479e1..c611c09 100644
--- a/tests/org.eclipse.emfforms.core.services.datatemplate.test/AllPluginTests for core.services.datatemplate.launch
+++ b/tests/org.eclipse.emfforms.core.services.datatemplate.test/AllPluginTests for core.services.datatemplate.launch
@@ -33,8 +33,8 @@
 <stringAttribute key="pde.version" value="3.3"/>
 <stringAttribute key="product" value="org.eclipse.platform.ide"/>
 <booleanAttribute key="run_in_ui_thread" value="true"/>
-<stringAttribute key="selected_target_plugins" value="com.ibm.icu@default:default,javax.annotation@default:default,javax.el@default:default,javax.inject@default:default,javax.servlet.jsp@default:default,javax.servlet@default:default,org.apache.batik.css*1.8.0.v20170214-1941@default:default,org.apache.batik.util*1.8.0.v20170214-1941@default:default,org.apache.commons.codec@default:default,org.apache.commons.jxpath@default:default,org.apache.commons.logging@default:default,org.apache.felix.scr@default:default,org.apache.jasper.glassfish@default:default,org.apache.lucene.analyzers-common@default:default,org.apache.lucene.analyzers-smartcn@default:default,org.apache.lucene.core@default:default,org.apache.lucene.misc@default:default,org.eclipse.ant.core@default:default,org.eclipse.compare.core@default:default,org.eclipse.compare@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding*1.6.100.v20170515-1119@default:default,org.eclipse.core.databinding.observable*1.6.100.v20170515-1119@default:default,org.eclipse.core.databinding.property*1.6.100.v20170515-1119@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filebuffers@default:default,org.eclipse.core.filesystem.linux.x86_64@default:false,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.net.linux.x86_64@default:false,org.eclipse.core.net@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime@default:true,org.eclipse.core.variables@default:default,org.eclipse.e4.core.commands@default:default,org.eclipse.e4.core.contexts@default:default,org.eclipse.e4.core.di.annotations@default:default,org.eclipse.e4.core.di.extensions.supplier@default:default,org.eclipse.e4.core.di.extensions@default:default,org.eclipse.e4.core.di@default:default,org.eclipse.e4.core.services@default:default,org.eclipse.e4.emf.xpath@default:default,org.eclipse.e4.ui.bindings@default:default,org.eclipse.e4.ui.css.core@default:default,org.eclipse.e4.ui.css.swt.theme@default:default,org.eclipse.e4.ui.css.swt@default:default,org.eclipse.e4.ui.di@default:default,org.eclipse.e4.ui.model.workbench@default:default,org.eclipse.e4.ui.services@default:default,org.eclipse.e4.ui.swt.gtk@default:false,org.eclipse.e4.ui.widgets@default:default,org.eclipse.e4.ui.workbench.addons.swt@default:default,org.eclipse.e4.ui.workbench.renderers.swt@default:default,org.eclipse.e4.ui.workbench.swt@default:default,org.eclipse.e4.ui.workbench3@default:default,org.eclipse.e4.ui.workbench@default:default,org.eclipse.emf.common.ui@default:default,org.eclipse.emf.common@default:default,org.eclipse.emf.databinding.edit@default:default,org.eclipse.emf.databinding@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.edit@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.emf.edit.ui@default:default,org.eclipse.emf.edit@default:default,org.eclipse.emf.emfstore.client@default:default,org.eclipse.emf.emfstore.common.model@default:default,org.eclipse.emf.emfstore.common@default:default,org.eclipse.emf.emfstore.examplemodel.edit@default:default,org.eclipse.emf.emfstore.examplemodel@default:default,org.eclipse.emf.emfstore.migration@default:default,org.eclipse.emf.emfstore.server.model@default:default,org.eclipse.emf.emfstore.server@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.bidi@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.http.registry@default:default,org.eclipse.equinox.jsp.jasper.registry@default:default,org.eclipse.equinox.jsp.jasper@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.metadata.repository@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.repository@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.security.linux.x86_64@default:false,org.eclipse.equinox.security@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help.base@default:default,org.eclipse.help.ui@default:default,org.eclipse.help.webapp@default:default,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface.text@default:default,org.eclipse.jface@default:default,org.eclipse.ltk.core.refactoring@default:default,org.eclipse.ltk.ui.refactoring@default:default,org.eclipse.net4j.util@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.eclipse.platform@default:default,org.eclipse.rcp@default:default,org.eclipse.swt.gtk.linux.x86_64@default:false,org.eclipse.swt@default:default,org.eclipse.team.core@default:default,org.eclipse.team.ui@default:default,org.eclipse.text@default:default,org.eclipse.ui.editors@default:default,org.eclipse.ui.forms@default:default,org.eclipse.ui.ide.application@default:default,org.eclipse.ui.ide@default:default,org.eclipse.ui.intro@default:default,org.eclipse.ui.navigator.resources@default:default,org.eclipse.ui.navigator@default:default,org.eclipse.ui.trace@default:default,org.eclipse.ui.views.properties.tabbed@default:default,org.eclipse.ui.views@default:default,org.eclipse.ui.workbench.texteditor@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.ui@default:default,org.hamcrest.core@default:default,org.junit@default:default,org.mockito.mockito-core-hamcrest-modified@default:default,org.objenesis@default:default,org.tukaani.xz@default:default,org.w3c.css.sac@default:default"/>
-<stringAttribute key="selected_workspace_plugins" value="org.eclipse.emf.ecp.common.test@default:false,org.eclipse.emf.ecp.common.ui@default:default,org.eclipse.emf.ecp.common@default:default,org.eclipse.emf.ecp.core.test@default:false,org.eclipse.emf.ecp.core@default:default,org.eclipse.emf.ecp.edit.swt.test@default:false,org.eclipse.emf.ecp.edit.swt@default:default,org.eclipse.emf.ecp.edit@default:default,org.eclipse.emf.ecp.editor.e3@default:default,org.eclipse.emf.ecp.emfstore.core@default:default,org.eclipse.emf.ecp.explorereditorbridge@default:default,org.eclipse.emf.ecp.makeithappen.model@default:default,org.eclipse.emf.ecp.test.common@default:default,org.eclipse.emf.ecp.test.model@default:default,org.eclipse.emf.ecp.ui.view.swt.test@default:false,org.eclipse.emf.ecp.ui.view.swt@default:default,org.eclipse.emf.ecp.ui.view.test@default:default,org.eclipse.emf.ecp.ui.view@default:default,org.eclipse.emf.ecp.ui@default:default,org.eclipse.emf.ecp.view.context.tests@default:false,org.eclipse.emf.ecp.view.context@default:default,org.eclipse.emf.ecp.view.group.model@default:default,org.eclipse.emf.ecp.view.migrator@default:default,org.eclipse.emf.ecp.view.model.common.test@default:false,org.eclipse.emf.ecp.view.model.common@default:default,org.eclipse.emf.ecp.view.model.edit.test@default:false,org.eclipse.emf.ecp.view.model.edit@default:default,org.eclipse.emf.ecp.view.model.provider.generator@default:default,org.eclipse.emf.ecp.view.model.provider.xmi.test@default:false,org.eclipse.emf.ecp.view.model.provider.xmi@default:default,org.eclipse.emf.ecp.view.model.test@default:false,org.eclipse.emf.ecp.view.model@default:default,org.eclipse.emf.ecp.view.table.model.test@default:false,org.eclipse.emf.ecp.view.table.model@default:default,org.eclipse.emf.ecp.view.template.annotation.model@default:default,org.eclipse.emf.ecp.view.template.model.edit@default:default,org.eclipse.emf.ecp.view.template.model.test@default:false,org.eclipse.emf.ecp.view.template.model@default:default,org.eclipse.emf.ecp.view.test.common.swt@default:default,org.eclipse.emf.ecp.view.test.common@default:default,org.eclipse.emf.ecp.view.util.swt@default:default,org.eclipse.emf.ecp.view.validation.test@default:false,org.eclipse.emf.ecp.view.validation@default:default,org.eclipse.emf.ecp.view.vertical.model@default:default,org.eclipse.emfforms.common.prevalidation@default:default,org.eclipse.emfforms.common.tests@default:false,org.eclipse.emfforms.common.validation.tests@default:false,org.eclipse.emfforms.common.validation@default:default,org.eclipse.emfforms.common@default:default,org.eclipse.emfforms.core.bazaar.tests@default:false,org.eclipse.emfforms.core.bazaar@default:default,org.eclipse.emfforms.core.services.databinding.testmodel@default:default,org.eclipse.emfforms.core.services.datatemplate.test@default:false,org.eclipse.emfforms.core.services.datatemplate@default:default,org.eclipse.emfforms.core.services.domainexpander.default.tests@default:false,org.eclipse.emfforms.core.services.domainexpander.default@default:default,org.eclipse.emfforms.core.services.domainexpander.table@default:default,org.eclipse.emfforms.core.services.editsupport@default:default,org.eclipse.emfforms.core.services.emf.tests@default:false,org.eclipse.emfforms.core.services.emf@default:default,org.eclipse.emfforms.core.services.emfspecificservice@default:default,org.eclipse.emfforms.core.services.legacy.tests@default:false,org.eclipse.emfforms.core.services.legacy@default:default,org.eclipse.emfforms.core.services.locale.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.table.test@default:false,org.eclipse.emfforms.core.services.mappingprovider.table@default:default,org.eclipse.emfforms.core.services.structuralchange.default@default:default,org.eclipse.emfforms.core.services.structuralchange@default:default,org.eclipse.emfforms.core.services.tests@default:false,org.eclipse.emfforms.core.services@default:default,org.eclipse.emfforms.datatemplate.model@default:default,org.eclipse.emfforms.localization.tests@default:false,org.eclipse.emfforms.localization@default:default,org.eclipse.emfforms.swt.core.tests@default:false,org.eclipse.emfforms.swt.core@default:default,org.eclipse.emfforms.view.annotation.model@default:default,org.eclipse.emfforms.view.controlgrid.model@default:default"/>
+<stringAttribute key="selected_target_plugins" value="com.ibm.icu@default:default,javax.annotation@default:default,javax.el@default:default,javax.inject@default:default,javax.servlet.jsp@default:default,javax.servlet@default:default,org.apache.batik.constants@default:default,org.apache.batik.css*1.10.0.v20180703-1553@default:default,org.apache.batik.i18n@default:default,org.apache.batik.util*1.10.0.v20180703-1553@default:default,org.apache.commons.codec@default:default,org.apache.commons.jxpath@default:default,org.apache.commons.logging*1.1.1.v201101211721@default:default,org.apache.commons.logging*1.2.0.v20180409-1502@default:default,org.apache.felix.scr@1:true,org.apache.jasper.glassfish@default:default,org.apache.lucene.analyzers-common@default:default,org.apache.lucene.analyzers-smartcn@default:default,org.apache.lucene.core@default:default,org.apache.xmlgraphics@default:default,org.eclipse.ant.core@default:default,org.eclipse.compare.core@default:default,org.eclipse.compare@default:default,org.eclipse.core.commands@default:default,org.eclipse.core.contenttype@default:default,org.eclipse.core.databinding*1.7.200.v20190216-1545@default:default,org.eclipse.core.databinding.observable*1.6.400.v20190218-2049@default:default,org.eclipse.core.databinding.property*1.6.400.v20190215-1957@default:default,org.eclipse.core.expressions@default:default,org.eclipse.core.filebuffers@default:default,org.eclipse.core.filesystem@default:default,org.eclipse.core.jobs@default:default,org.eclipse.core.net@default:default,org.eclipse.core.resources@default:default,org.eclipse.core.runtime@default:true,org.eclipse.core.variables@default:default,org.eclipse.e4.core.commands@default:default,org.eclipse.e4.core.contexts@default:default,org.eclipse.e4.core.di.annotations@default:default,org.eclipse.e4.core.di.extensions.supplier@default:default,org.eclipse.e4.core.di.extensions@default:default,org.eclipse.e4.core.di@default:default,org.eclipse.e4.core.services@default:default,org.eclipse.e4.emf.xpath@default:default,org.eclipse.e4.ui.bindings@default:default,org.eclipse.e4.ui.css.core@default:default,org.eclipse.e4.ui.css.swt.theme@default:default,org.eclipse.e4.ui.css.swt@default:default,org.eclipse.e4.ui.di@default:default,org.eclipse.e4.ui.model.workbench@default:default,org.eclipse.e4.ui.services@default:default,org.eclipse.e4.ui.widgets@default:default,org.eclipse.e4.ui.workbench.addons.swt@default:default,org.eclipse.e4.ui.workbench.renderers.swt@default:default,org.eclipse.e4.ui.workbench.swt@default:default,org.eclipse.e4.ui.workbench3@default:default,org.eclipse.e4.ui.workbench@default:default,org.eclipse.emf.common.ui@default:default,org.eclipse.emf.common@default:default,org.eclipse.emf.databinding.edit@default:default,org.eclipse.emf.databinding@default:default,org.eclipse.emf.ecore.change@default:default,org.eclipse.emf.ecore.edit@default:default,org.eclipse.emf.ecore.xmi@default:default,org.eclipse.emf.ecore@default:default,org.eclipse.emf.edit.ui@default:default,org.eclipse.emf.edit@default:default,org.eclipse.emf.emfstore.client@default:default,org.eclipse.emf.emfstore.common.model@default:default,org.eclipse.emf.emfstore.common@default:default,org.eclipse.emf.emfstore.examplemodel.edit@default:default,org.eclipse.emf.emfstore.examplemodel@default:default,org.eclipse.emf.emfstore.migration@default:default,org.eclipse.emf.emfstore.server.model@default:default,org.eclipse.emf.emfstore.server@default:default,org.eclipse.equinox.app@default:default,org.eclipse.equinox.bidi@default:default,org.eclipse.equinox.common@2:true,org.eclipse.equinox.ds@1:true,org.eclipse.equinox.event@default:default,org.eclipse.equinox.http.registry@default:default,org.eclipse.equinox.jsp.jasper.registry@default:default,org.eclipse.equinox.jsp.jasper@default:default,org.eclipse.equinox.p2.core@default:default,org.eclipse.equinox.p2.engine@default:default,org.eclipse.equinox.p2.metadata.repository@default:default,org.eclipse.equinox.p2.metadata@default:default,org.eclipse.equinox.p2.repository@default:default,org.eclipse.equinox.preferences@default:default,org.eclipse.equinox.region@default:false,org.eclipse.equinox.registry@default:default,org.eclipse.equinox.security@default:default,org.eclipse.equinox.transforms.hook@default:false,org.eclipse.equinox.weaving.hook@default:false,org.eclipse.help.base@default:default,org.eclipse.help.ui@default:default,org.eclipse.help.webapp@default:default,org.eclipse.help@default:default,org.eclipse.jface.databinding@default:default,org.eclipse.jface.text@default:default,org.eclipse.jface@default:default,org.eclipse.ltk.core.refactoring@default:default,org.eclipse.ltk.ui.refactoring@default:default,org.eclipse.net4j.util@default:default,org.eclipse.osgi.compatibility.state@default:false,org.eclipse.osgi.services@default:default,org.eclipse.osgi.util@default:default,org.eclipse.osgi@-1:true,org.eclipse.platform@default:default,org.eclipse.rcp@default:default,org.eclipse.swt.cocoa.macosx.x86_64@default:false,org.eclipse.swt@default:default,org.eclipse.team.core@default:default,org.eclipse.team.ui@default:default,org.eclipse.text@default:default,org.eclipse.ui.editors@default:default,org.eclipse.ui.forms@default:default,org.eclipse.ui.ide.application@default:default,org.eclipse.ui.ide@default:default,org.eclipse.ui.intro@default:default,org.eclipse.ui.navigator.resources@default:default,org.eclipse.ui.navigator@default:default,org.eclipse.ui.trace@default:default,org.eclipse.ui.views.properties.tabbed@default:default,org.eclipse.ui.views@default:default,org.eclipse.ui.workbench.texteditor@default:default,org.eclipse.ui.workbench@default:default,org.eclipse.ui@default:default,org.eclipse.urischeme@default:default,org.hamcrest.core@default:default,org.hamcrest.library@default:default,org.junit@default:default,org.mockito.mockito-core-hamcrest-modified@default:default,org.objenesis@default:default,org.tukaani.xz@default:default,org.w3c.css.sac@default:default,org.w3c.dom.events@default:default,org.w3c.dom.smil*1.0.1.v200903091627@default:default,org.w3c.dom.svg@default:default"/>
+<stringAttribute key="selected_workspace_plugins" value="org.eclipse.emf.ecp.common.test@default:false,org.eclipse.emf.ecp.common.ui@default:default,org.eclipse.emf.ecp.common@default:default,org.eclipse.emf.ecp.core.test@default:false,org.eclipse.emf.ecp.core@default:default,org.eclipse.emf.ecp.edit.swt.test@default:false,org.eclipse.emf.ecp.edit.swt@default:default,org.eclipse.emf.ecp.edit@default:default,org.eclipse.emf.ecp.editor.e3@default:default,org.eclipse.emf.ecp.emfstore.core@default:default,org.eclipse.emf.ecp.explorereditorbridge@default:default,org.eclipse.emf.ecp.makeithappen.model@default:default,org.eclipse.emf.ecp.test.common@default:default,org.eclipse.emf.ecp.test.model@default:default,org.eclipse.emf.ecp.ui.view.swt.test@default:false,org.eclipse.emf.ecp.ui.view.swt@default:default,org.eclipse.emf.ecp.ui.view.test@default:default,org.eclipse.emf.ecp.ui.view@default:default,org.eclipse.emf.ecp.ui@default:default,org.eclipse.emf.ecp.view.context.tests@default:false,org.eclipse.emf.ecp.view.context@default:default,org.eclipse.emf.ecp.view.core.swt@default:default,org.eclipse.emf.ecp.view.group.model@default:default,org.eclipse.emf.ecp.view.migrator@default:default,org.eclipse.emf.ecp.view.model.common.test@default:false,org.eclipse.emf.ecp.view.model.common@default:default,org.eclipse.emf.ecp.view.model.edit.test@default:false,org.eclipse.emf.ecp.view.model.edit@default:default,org.eclipse.emf.ecp.view.model.provider.generator@default:default,org.eclipse.emf.ecp.view.model.provider.xmi.test@default:false,org.eclipse.emf.ecp.view.model.provider.xmi@default:default,org.eclipse.emf.ecp.view.model.test@default:false,org.eclipse.emf.ecp.view.model@default:default,org.eclipse.emf.ecp.view.table.model.test@default:false,org.eclipse.emf.ecp.view.table.model@default:default,org.eclipse.emf.ecp.view.template.annotation.model@default:default,org.eclipse.emf.ecp.view.template.model.edit@default:default,org.eclipse.emf.ecp.view.template.model.test@default:false,org.eclipse.emf.ecp.view.template.model@default:default,org.eclipse.emf.ecp.view.test.common.swt@default:default,org.eclipse.emf.ecp.view.test.common@default:default,org.eclipse.emf.ecp.view.treemasterdetail.model@default:default,org.eclipse.emf.ecp.view.util.swt@default:default,org.eclipse.emf.ecp.view.validation.test@default:false,org.eclipse.emf.ecp.view.validation@default:default,org.eclipse.emf.ecp.view.vertical.model@default:default,org.eclipse.emfforms.common.prevalidation@default:default,org.eclipse.emfforms.common.tests@default:false,org.eclipse.emfforms.common.validation.tests@default:false,org.eclipse.emfforms.common.validation@default:default,org.eclipse.emfforms.common@default:default,org.eclipse.emfforms.core.bazaar.tests@default:false,org.eclipse.emfforms.core.bazaar@default:default,org.eclipse.emfforms.core.services.databinding.testmodel@default:default,org.eclipse.emfforms.core.services.datatemplate.test@default:false,org.eclipse.emfforms.core.services.datatemplate@default:default,org.eclipse.emfforms.core.services.domainexpander.default.tests@default:false,org.eclipse.emfforms.core.services.domainexpander.default@default:default,org.eclipse.emfforms.core.services.domainexpander.table@default:default,org.eclipse.emfforms.core.services.editsupport@default:default,org.eclipse.emfforms.core.services.emf.tests@default:false,org.eclipse.emfforms.core.services.emf@default:default,org.eclipse.emfforms.core.services.emfspecificservice@default:default,org.eclipse.emfforms.core.services.legacy.tests@default:false,org.eclipse.emfforms.core.services.legacy@default:default,org.eclipse.emfforms.core.services.locale.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.default@default:default,org.eclipse.emfforms.core.services.mappingprovider.table.test@default:false,org.eclipse.emfforms.core.services.mappingprovider.table@default:default,org.eclipse.emfforms.core.services.structuralchange.default@default:default,org.eclipse.emfforms.core.services.structuralchange@default:default,org.eclipse.emfforms.core.services.tests@default:false,org.eclipse.emfforms.core.services@default:default,org.eclipse.emfforms.datatemplate.model@default:default,org.eclipse.emfforms.editor@default:default,org.eclipse.emfforms.localization.tests@default:false,org.eclipse.emfforms.localization@default:default,org.eclipse.emfforms.swt.core.di@default:default,org.eclipse.emfforms.swt.core.tests@default:false,org.eclipse.emfforms.swt.core@default:default,org.eclipse.emfforms.swt.treemasterdetail.decorator.validation.default@default:default,org.eclipse.emfforms.swt.treemasterdetail@default:default,org.eclipse.emfforms.view.annotation.model@default:default,org.eclipse.emfforms.view.controlgrid.model@default:default,org.eclipse.emfforms.view.multisegment.model@default:default"/>
 <booleanAttribute key="show_selected_only" value="false"/>
 <booleanAttribute key="tracing" value="false"/>
 <booleanAttribute key="useCustomFeatures" value="false"/>
diff --git a/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider_Test.java b/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider_Test.java
index bcdccb5..d8e866d 100644
--- a/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider_Test.java
+++ b/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/TemplateCreateNewModelElementStrategyProvider_Test.java
@@ -8,16 +8,22 @@
  *
  * Contributors:
  * Lucas Koehler - initial API and implementation
- * Christian W. Damus - bug 543461
+ * Christian W. Damus - bugs 543461, 546974
  ******************************************************************************/
 package org.eclipse.emfforms.internal.core.services.datatemplate;
 
+import static org.hamcrest.CoreMatchers.anything;
+import static org.hamcrest.CoreMatchers.both;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.hasItems;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anySetOf;
@@ -30,10 +36,12 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Hashtable;
 import java.util.LinkedHashSet;
 import java.util.Set;
+import java.util.function.Predicate;
 
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.EDataType;
@@ -48,7 +56,9 @@
 import org.eclipse.emf.ecp.ui.view.swt.reference.EClassSelectionStrategy;
 import org.eclipse.emfforms.bazaar.Bid;
 import org.eclipse.emfforms.bazaar.Create;
+import org.eclipse.emfforms.bazaar.StaticBid;
 import org.eclipse.emfforms.common.Optional;
+import org.eclipse.emfforms.core.services.datatemplate.TemplateFilterService;
 import org.eclipse.emfforms.core.services.datatemplate.TemplateProvider;
 import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AdminUser;
 import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AuditFactory;
@@ -81,7 +91,11 @@
 	 */
 	@Before
 	public void setUp() throws Exception {
+		final ComponentContext context = mock(ComponentContext.class);
+		when(context.getProperties()).thenReturn(new Hashtable<>());
+
 		strategyProvider = new TemplateCreateNewModelElementStrategyProvider();
+		strategyProvider.activate(context);
 	}
 
 	@Test
@@ -270,6 +284,85 @@
 			Matchers.<Collection<EClass>> any());
 	}
 
+	@SuppressWarnings("nls")
+	@Test
+	public void testTemplateFilters() {
+		final TemplateProvider canProvide = mock(TemplateProvider.class);
+		when(canProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(true);
+		final Template template1 = mock(Template.class);
+		when(template1.getName()).thenReturn("First Template");
+		final Template template2 = mock(Template.class);
+		when(template2.getName()).thenReturn("Second Template");
+		final Template template3 = mock(Template.class);
+		when(template3.getName()).thenReturn("Third Template");
+		final Set<Template> canProvideTemplates = new LinkedHashSet<>(Arrays.asList(template1, template2, template3));
+		when(canProvide.provideTemplates(any(EObject.class), any(EReference.class))).thenReturn(canProvideTemplates);
+		strategyProvider.registerTemplateProvider(canProvide);
+
+		final RegexFilterService.Provider filter1 = new RegexFilterService.Provider("^Template$");
+		final RegexFilterService.Provider filter2 = new RegexFilterService.Provider("^\\w{5} .+$");
+		strategyProvider.addFilterServiceProvider(filter1);
+		strategyProvider.addFilterServiceProvider(filter2);
+
+		final EObject eObject = mock(EObject.class);
+		final EReference eReference = mock(EReference.class);
+		Set<Template> templates = strategyProvider.collectAvailableTemplates(eObject, eReference);
+
+		assertThat("Filters should have excluded everything", templates, not(hasItem(anything())));
+
+		filter1.setRegex("^.+ Template$");
+		templates = strategyProvider.collectAvailableTemplates(eObject, eReference);
+		assertThat("Filters should have excluded only Second Template", templates,
+			both(hasItems(template1, template3)).and(not(hasItem(template2))));
+
+		strategyProvider.removeFilterServiceProvider(filter2);
+		templates = strategyProvider.collectAvailableTemplates(eObject, eReference);
+		assertThat("Filters should have excluded no templates", templates, hasItems(template1, template2, template3));
+	}
+
+	//
+	// Test framework
+	//
+
+	static class RegexFilterService implements TemplateFilterService {
+		private String regex;
+
+		@Override
+		public Predicate<? super Template> getTemplateFilter(EObject owner, EReference reference) {
+			assertThat(owner, notNullValue());
+			assertThat(reference, notNullValue());
+
+			return template -> //
+			template.getName().matches(regex);
+		}
+
+		//
+		// Nested types
+		//
+
+		@StaticBid(bid = 10.0)
+		static final class Provider implements TemplateFilterService.Provider {
+			private final RegexFilterService service = new RegexFilterService();
+
+			Provider(String regex) {
+				super();
+
+				setRegex(regex);
+			}
+
+			void setRegex(String regex) {
+				service.regex = regex;
+			}
+
+			@Create
+			public TemplateFilterService create() {
+				return service;
+			}
+
+		}
+
+	}
+
 	class TestEClassSelectionStrategyProvider implements EClassSelectionStrategy.Provider {
 		private final Double bid;
 		private final EClassSelectionStrategy strategy;
diff --git a/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider_Test.java b/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider_Test.java
index 727c375..377dd86 100644
--- a/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider_Test.java
+++ b/tests/org.eclipse.emfforms.core.services.datatemplate.test/src/org/eclipse/emfforms/internal/core/services/datatemplate/XmiTemplateProvider_Test.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2018 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,7 @@
  *
  * Contributors:
  * Lucas Koehler - initial API and implementation
+ * Christian W. Damus - bug 546974
  ******************************************************************************/
 package org.eclipse.emfforms.internal.core.services.datatemplate;
 
@@ -15,9 +16,22 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import java.io.IOException;
 import java.util.Set;
 
+import javax.inject.Named;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IContributor;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emfforms.bazaar.Bid;
+import org.eclipse.emfforms.bazaar.Create;
+import org.eclipse.emfforms.core.services.datatemplate.TemplateLoaderService;
 import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AdminUser;
 import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AuditFactory;
 import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AuditPackage;
@@ -118,4 +132,45 @@
 		final Set<Template> userGroupSet = provider.provideTemplates(user, AuditPackage.Literals.USER__SUB_USERS);
 		assertEquals(0, userGroupSet.size());
 	}
+
+	@SuppressWarnings("nls")
+	@Test
+	public void testTemplateLoaders() throws IOException {
+		final IExtensionRegistry reg = mock(IExtensionRegistry.class);
+		final URI uri = URI.createPlatformPluginURI("datatemplate.test/templates/whatever.xmi", true);
+		final String contributorID = "datatemplate.test";
+		final IConfigurationElement config = mock(IConfigurationElement.class);
+		final IContributor contributor = mock(IContributor.class);
+		when(contributor.getName()).thenReturn(contributorID);
+		when(config.getContributor()).thenReturn(contributor);
+		when(config.getAttribute("file")).thenReturn("/templates/whatever.xmi");
+		final IConfigurationElement[] configs = { config };
+		when(reg.getConfigurationElementsFor("org.eclipse.emfforms.core.services.datatemplate.xmi"))
+			.thenReturn(configs);
+
+		provider.setExtensionRegistry(reg);
+
+		final TemplateLoaderService loader = mock(TemplateLoaderService.class);
+
+		class LoaderProvider implements TemplateLoaderService.Provider {
+
+			@Bid
+			public double bid(@Named(CONTRIBUTOR_ID) String contributor, URI uri) {
+				return Double.POSITIVE_INFINITY;
+			}
+
+			@Create
+			public TemplateLoaderService create() {
+				return loader;
+			}
+		}
+		final LoaderProvider loaderProvider = spy(new LoaderProvider());
+		provider.addLoaderServiceProvider(loaderProvider);
+
+		provider.activate();
+
+		verify(loaderProvider).bid(contributorID, uri);
+		verify(loader).loadTemplates(uri);
+	}
+
 }