/**
* Copyright (c) 6 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.genmodel.generator;
import java.util.Arrays;
import org.eclipse.emf.codegen.ecore.CodeGenEcorePlugin;
import org.eclipse.emf.codegen.ecore.generator.Generator;
import org.eclipse.emf.codegen.ecore.generator.GeneratorAdapter;
import org.eclipse.emf.codegen.ecore.generator.GeneratorAdapterFactory;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.util.GenModelAdapterFactory;
import org.eclipse.emf.codegen.jet.JETCompiler;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
/**
* A generator adapter factory for the {@link org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage GenModel package}.
* This implementation creates the adapters that perform default EMF code generation. It can also be subclassed to
* create derived adapters that remove from or change the default code generation, or to create separate adapters
* that augment the default code generation.
*
* <p>The factory implements a singleton adapter pattern, where one adapter is cached and reused for all objects of a
* given type.
*
* <p>This implementation also initializes its generator's options based on the {@link GenModel}.
*
* @since 2.2.0
*/
public class GenModelGeneratorAdapterFactory extends GenModelAdapterFactory implements GeneratorAdapterFactory
{
/**
* A descriptor for this adapter factory, which can be used to programatically
* {@link org.eclipse.emf.codegen.ecore.generator.GeneratorAdapterFactory.Descriptor.Registry#addDescriptor(String, org.eclipse.emf.codegen.ecore.generator.GeneratorAdapterFactory.Descriptor) register}
* it.
* @see org.eclipse.emf.codegen.ecore.generator.GeneratorAdapterFactory.Descriptor.Registry
*/
public static final GeneratorAdapterFactory.Descriptor DESCRIPTOR = new GeneratorAdapterFactory.Descriptor()
{
public GeneratorAdapterFactory createAdapterFactory()
{
return new GenModelGeneratorAdapterFactory();
}
};
/**
* The default JMerge rules file for EMF.
*/
protected static final String MERGE_RULES_PATH_NAME = "emf-merge.xml";
protected Generator generator;
protected GenBaseGeneratorAdapter genModelGeneratorAdapter;
protected GenBaseGeneratorAdapter genPackageGeneratorAdapter;
protected GenBaseGeneratorAdapter genClassGeneratorAdapter;
protected GenBaseGeneratorAdapter genEnumGeneratorAdapter;
public GenModelGeneratorAdapterFactory()
{
super();
}
/**
* Returns <code>true</code> when the type is <code>GeneratorAdapter.class</code>.
*/
@Override
public boolean isFactoryForType(Object type)
{
return type == GeneratorAdapter.class;
}
/**
* Does an {@link org.eclipse.emf.common.notify.impl.AdapterFactoryImpl#adapt(Notifier, Object) adapt(Notifier, Object)},
* substituting <code>this</code> for the given <code>type</code>. This substitution is necessary because each of many
* generator adapter factories can have its own generator adapter on a single object.
*/
@Override
public Adapter adapt(Notifier target, Object type)
{
return super.adapt(target, this);
}
/**
* Returns a singleton {@link GenModelGeneratorAdapter}.
*/
@Override
public Adapter createGenModelAdapter()
{
if (genModelGeneratorAdapter == null)
{
genModelGeneratorAdapter = new GenModelGeneratorAdapter(this);
}
return genModelGeneratorAdapter;
}
/**
* Returns a singleton {@link GenPackageGeneratorAdapter}.
*/
@Override
public Adapter createGenPackageAdapter()
{
if (genPackageGeneratorAdapter == null)
{
genPackageGeneratorAdapter = new GenPackageGeneratorAdapter(this);
}
return genPackageGeneratorAdapter;
}
/**
* Returns a singleton {@link GenClassGeneratorAdapter}.
*/
@Override
public Adapter createGenClassAdapter()
{
if (genClassGeneratorAdapter == null)
{
genClassGeneratorAdapter = new GenClassGeneratorAdapter(this);
}
return genClassGeneratorAdapter;
}
/**
* Returns a singleton {@link GenEnumGeneratorAdapter}.
*/
@Override
public Adapter createGenEnumAdapter()
{
if (genEnumGeneratorAdapter == null)
{
genEnumGeneratorAdapter = new GenEnumGeneratorAdapter(this);
}
return genEnumGeneratorAdapter;
}
public Generator getGenerator()
{
return generator;
}
public void setGenerator(Generator generator)
{
this.generator = generator;
}
/**
* Performs initialization for the given input {@link GenModel}. It is used as the basis for setting
* {@link Generator#getOptions() options} on the associated {@link Generator}.
*/
public void initialize(Object input)
{
Generator.Options options = generator.getOptions();
GenModel genModel = (GenModel)input;
Resource resource = genModel.eResource();
options.redirectionPattern = genModel.getRedirection();
options.forceOverwrite = genModel.isForceOverwrite();
options.dynamicTemplates = genModel.isDynamicTemplates();
initializeMergeRulesURI(options, genModel);
options.mergerFacadeHelperClass = genModel.getFacadeHelperClass();
options.codeFormatting = genModel.isCodeFormatting();
options.commentFormatting = genModel.isCommentFormatting();
options.resourceSet = resource != null ? resource.getResourceSet() : null;
options.templateClasspath = genModel.getTemplatePluginVariables();
}
/**
* For backwards compatibility, we must check whether getTemplatePath() has been overridden to return something
* other than the default, and, if so, behave as before.
*/
@SuppressWarnings("deprecation")
private void initializeMergeRulesURI(Generator.Options options, GenModel genModel)
{
String[] defaultTemplatePath = getDefaultTemplatePath(genModel);
String[] templatePath = getTemplatePath(genModel);
if (!Arrays.equals(templatePath, defaultTemplatePath))
{
options.templatePath = templatePath;
options.mergeRulesURI = JETCompiler.find(templatePath, MERGE_RULES_PATH_NAME);
}
else
{
options.mergeRulesURI = getMergeRulesURI(genModel);
}
}
/**
* Computes the template path for the given <code>GenModel</code>. The result of this method was intended to be used
* in setting the generator's {@link org.eclipse.emf.codegen.ecore.generator.Generator.Options#templatePath templatePath}
* option. However, a single path for all code generation is actually insufficient. The path needs to be specified and
* extended on a per-adapter basis.
*
* <p>If this implementation is not overridden, the generator's <code>templatePath</code> will no longer be set to
* the default value. Instead, it will be left null, and template paths will be computed on a per-adapter basis using
* {@link org.eclipse.emf.codegen.ecore.generator.AbstractGeneratorAdapter#addBaseTemplatePathEntries(java.util.List)}.
*
* <p>In order to preserve backwards compatibility, if this implementation is overridden to return something other
* than the default, the generator's <code>templatePath</code> will be set to this result.
*
* <p>Previously, this path was also searched to obtain the value to set as the generator's
* {@link org.eclipse.emf.codegen.ecore.generator.Generator.Options#mergeRulesURI mergeRulesURI} option. Now, if this
* method is not overridden, the new {@link #getMergeRulesURI(GenModel)} method will be invoked to compute that value.
*
* @deprecated org.eclipse.emf.codegen.ecore 2.2.2 Override
* {@link org.eclipse.emf.codegen.ecore.generator.AbstractGeneratorAdapter#addBaseTemplatePathEntries(java.util.List)}
* and, if needed, {@link #getMergeRulesURI(GenModel)}, instead.
*/
@Deprecated
protected String[] getTemplatePath(GenModel genModel)
{
return getDefaultTemplatePath(genModel);
}
/*
* Computes the default path for the given GenModel. This was previously the implementation of getTemplatePath().
*/
private String[] getDefaultTemplatePath(GenModel genModel)
{
String[] result = null;
String staticLocation = CodeGenEcorePlugin.INSTANCE.getBaseURL().toString() + "templates";
String templateDirectory = genModel.getTemplateDirectory();
if (genModel.isDynamicTemplates() && templateDirectory != null)
{
result = new String[2];
result[0] = templateDirectory.indexOf(':') == -1 ? URI.createPlatformResourceURI(templateDirectory, true).toString() : templateDirectory;
result[1] = staticLocation;
}
else
{
result = new String[1];
result[0] = staticLocation;
}
return result;
}
/**
* Returns the URI of the merge rules file for the given <code>GenModel</code>.
*
* <p>The default implementation of this method is to search the default path that would be returned by
* {@link #getTemplatePath(GenModel)}, if not overridden, for a file called "emf-merge.xml", and return the URI of
* the first such file encountered. Since that method has been deprecated, this method can now be overridden to search
* a different path, or indeed, obtain the merge rules URI in some other way.
*
* <p>This method is only invoked if {@link #getTemplatePath(GenModel)} has not been overridden.
*
* @since org.eclipse.emf.codegen.ecore 2.2.2
*/
protected String getMergeRulesURI(GenModel genModel)
{
return JETCompiler.find(getDefaultTemplatePath(genModel), MERGE_RULES_PATH_NAME);
}
public void dispose()
{
if (genModelGeneratorAdapter != null) genModelGeneratorAdapter.dispose();
if (genPackageGeneratorAdapter != null) genPackageGeneratorAdapter.dispose();
if (genClassGeneratorAdapter != null) genClassGeneratorAdapter.dispose();
if (genEnumGeneratorAdapter != null) genEnumGeneratorAdapter.dispose();
}
}