/** * Copyright (c) 2006 IBM Corporation 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: * IBM - Initial API and implementation */ package org.eclipse.emf.codegen.ecore.generator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.notify.AdapterFactory; /** * A factory for adapters that perform code generation for a {@link Generator}. * * <p>A single <code>GeneratorAdapterFactory</code> is associated with an EMF or Java package, and can return an adapter * that implements {@link GeneratorAdapter} for instances of any or all of the classes within that package. Multiple * factories can be associated can be associated with a single package, with all of their adapters contributing * functionality to code generation for an object. * * <p>A type of <code>GeneratorAdapterFactory</code> is registered, via a {@link Descriptor descriptor}, against a * package ID in a {@link Descriptor.Registry registry}, in order to create adapters for that package. Typically, this * is done via the <code>org.eclipse.emf.codegen.ecore.generatorAdapters</code> extension point, using an * <code>adapterFactory</code> element. * * <p>A <code>GeneratorAdapterFactory</code> is a factory for type <code>GeneratorAdapter.class</code>; that is, its * {@link org.eclipse.emf.common.notify.AdapterFactory#isFactoryForType(Object) isFactoryForType(Object)} method should * return <code>true</code> for this type. However, because EMF's adapter framework supports only one adapter of a given * type on any object and because each of many generator adapter factories needs to be able to have a generator on a * single object, <code>GeneratorAdapter.class</code> cannot be used as the type of the adapters. Instead, each * generator adapter factory should use itself as the type of its adapters. * * <p>This interface is typically implemented by extending either {@link AbstractGeneratorAdapterFactory} or the * generated adapter factory for a package. The latter approach provides efficient, package-specific type switching for * <code>createAdapter(Notifier)</code>, while the former provides simple implementations for several other required * methods. * * <p>There is also a generic implementation provided by the framework that can create a single adapter for just one * type of object. This implementation is used under the covers for adapters registered via the above extension point * with an <code>adapter</code> element. * * @since 2.2.0 */ public interface GeneratorAdapterFactory extends AdapterFactory { /** * In essence, a factory for generator adapter factories. <code>Descriptor</code>s are stored in a * {@link Registry Registry} and create a particular type of {@link GeneratorAdapterFactory}, providing an additional * level of indirection that allows multiple {@link Generator}s to share a single registry and supports * extension-point-based registration with deferred class loading. */ public interface Descriptor { /** * Creates and returns an instance of a particular type of <code>GeneratorAdapterFactory</code>. A new instance * should be returned on each invocation. */ GeneratorAdapterFactory createAdapterFactory(); /** * A registry of {@link GeneratorAdapterFactory.Descriptor Descriptor}s. Descriptors are keyed by package ID, and * multiple descriptors can be associated with each package ID. */ public interface Registry { /** * The global generator adapter factory descriptor registry. */ public static final Registry INSTANCE = new DelegatingRegistry(); /** * Returns the descriptors registered against the given package ID. */ Collection<Descriptor> getDescriptors(String packageID); /** * Registers the given descriptor against the specified package ID. * @return whether the descriptor was added to the collection of descriptors for that package ID. */ boolean addDescriptor(String packageID, Descriptor descriptor); /** * Removes the given descriptor from the collection registered against the given package ID. * @return whether the descriptor was deregistered (this should be true if it was previously registered against * that package ID). */ boolean removeDescriptor(String packageID, Descriptor descriptor); /** * Deregisters all descriptors for a given package ID. * @return whether any descriptors were deregistered (this should be true if any descriptor was previously * registered against it). */ boolean removeDescriptors(String packageID); /** * Clears the registry of all descriptor registrations. */ void clear(); } /** * A simple <code>Registry</code> implementation, in which {@link #getDescriptors(String) getDescriptors(String)} * can delegate to another <code>Registry</code> if no descriptors are locally registered against the given package * ID. This implementation does not prevent duplicate registrations. */ public static class DelegatingRegistry implements Registry { protected Registry delegateRegistry; protected Map<String, List<Descriptor>> map = new HashMap<String, List<Descriptor>>(); public DelegatingRegistry() { super(); } public DelegatingRegistry(Registry delegateRegistry) { this.delegateRegistry = delegateRegistry; } public Collection<Descriptor> getDescriptors(String packageID) { List<Descriptor> descriptors = getDescriptors(packageID, false); return descriptors != null && !descriptors.isEmpty() ? new ArrayList<Descriptor>(descriptors) : delegatedGetDescriptors(packageID); } protected Collection<Descriptor> delegatedGetDescriptors(String packageID) { return delegateRegistry != null ? delegateRegistry.getDescriptors(packageID) : Collections.<Descriptor>emptyList(); } public boolean addDescriptor(String packageID, Descriptor descriptor) { return getDescriptors(packageID, true).add(descriptor); } public boolean removeDescriptor(String packageID, Descriptor descriptor) { List<Descriptor> list = getDescriptors(packageID, false); if (list != null) { return list.remove(descriptor); } return false; } public boolean removeDescriptors(String packageID) { List<Descriptor> list = getDescriptors(packageID, false); if (list != null && !list.isEmpty()) { map.remove(packageID); return true; } return false; } public void clear() { map.clear(); } protected List<Descriptor> getDescriptors(String packageID, boolean forceCreate) { List<Descriptor> result = map.get(packageID); if (result == null && forceCreate) { result = new ArrayList<Descriptor>(); map.put(packageID, result); } return result; } } } /** * Returns the <code>Generator</code> associated with this adapter factory. * * @see #setGenerator(Generator) */ Generator getGenerator(); /** * Sets the <code>Generator</code> associated with this adapter factory. * * @see #getGenerator() */ void setGenerator(Generator generator); /** * Performs initialization for the given model-level input object. Typically, this involves setting * {@link Generator#getOptions() options} on the associated {@link Generator}. */ void initialize(Object input); /** * Disposes this adapter factory and all of the adapters it has created. */ void dispose(); }