diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/PatternActivator.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/PatternActivator.java
new file mode 100644
index 0000000..e7e50d1
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/PatternActivator.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.egf.common.activator.AbstractActivator;
+import org.eclipse.egf.common.progress.IProgressRunnable;
+import org.eclipse.egf.common.progress.ProgressReporter;
+import org.eclipse.egf.fc.builder.java.JavaBuilderActivator;
+import org.eclipse.egf.fc.generator.java.JavaGeneratorActivator;
+import org.eclipse.egf.pattern.production.Messages;
+import org.eclipse.egf.pattern.production.PatternProducer;
+
+
+/**
+ * @author brocard
+ */
+public class PatternActivator extends AbstractActivator {
+ /**
+ * Activator shared instance.
+ */
+ private static PatternActivator __activator;
+ /**
+ * Pattern producer.
+ */
+ private PatternProducer _patternProducer;
+
+ /**
+ * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context_p) throws Exception {
+ super.start(context_p);
+ // Get activator instance.
+ __activator = this;
+ // Ensure dependencies.
+ JavaGeneratorActivator.getDefault();
+ JavaBuilderActivator.getDefault();
+ }
+
+ /**
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context_p) throws Exception {
+ __activator = null;
+ }
+
+ /**
+ * Get shared instance.
+ * @return
+ */
+ public static PatternActivator getDefault() {
+ return __activator;
+ }
+
+ /**
+ * Produce patterns pointed out by given ids path.
+ * @param fullId_p Either the absolute id of a library, or the absolute id of a pattern.
+ * @param forkJob_p Should production be executed in a job ? If true, there is no need for a specific progress monitor.
+ * @param progressMonitor_p A progress monitor to use in case of a synchronous production (can be null if no progress reporting is required).
+ * @return
+ */
+ public boolean producePatterns(
+ final String fullId_p,
+ boolean forkJob_p,
+ IProgressMonitor progressMonitor_p
+ ) {
+ boolean result = true;
+ // Lazy allocation.
+ if (_patternProducer == null) {
+ _patternProducer = new PatternProducer();
+ }
+ // Create progress runnable.
+ final PatternProducer patternProducer = _patternProducer;
+ IProgressRunnable producePattern = new IProgressRunnable() {
+ public String getReportingTitle() {
+ return Messages.PatternProducer_ProgressReporting_Title + fullId_p;
+ }
+ public boolean run(IProgressMonitor runnableProgressMonitor_p) {
+ return patternProducer.producePatterns(fullId_p, runnableProgressMonitor_p);
+ }
+ };
+ // Execute it.
+ if (forkJob_p) {
+ ProgressReporter.asyncExec(producePattern);
+ } else {
+ ProgressReporter.syncExec(producePattern, progressMonitor_p);
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/AbstractPatternGenerator.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/AbstractPatternGenerator.java
new file mode 100644
index 0000000..f3d6501
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/AbstractPatternGenerator.java
@@ -0,0 +1,444 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.PatternHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.model.FactoryComponent;
+import org.eclipse.egf.pattern.Pattern;
+import org.eclipse.egf.pattern.PatternFactory;
+import org.eclipse.egf.pattern.ecore.PatternHandler.ProductionOptionsHandler;
+import org.eclipse.egf.pattern.production.GeneratedContentHelper;
+import org.eclipse.egf.pattern.production.template.TemplateHelper;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+import org.eclipse.egf.pde.EgfPdeActivator;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+
+
+/**
+ * Ecore pattern generator.
+ * @author brocard
+ */
+public abstract class AbstractPatternGenerator {
+
+ /**
+ * Log4j reference logger.
+ */
+ private static final Logger __logger = Logger.getLogger(AbstractPatternGenerator.class.getPackage().getName());
+
+ /**
+ * Ecore ecore file absolute path.
+ */
+ protected static final String ECORE_ECORE_FILE_ABSOLUTE_PATH = "/org.eclipse.emf.ecore/model/Ecore.ecore"; //$NON-NLS-1$
+
+ /**
+ * Pattern ecore file absolute path.
+ */
+ protected static final String PATTERN_ECORE_FILE_RELATIVE_PATH = "/org.eclipse.egf.model/model/pattern.ecore"; //$NON-NLS-1$
+
+ /**
+ * Pattern parent class name, that is 'Pattern'.
+ */
+ protected static final String PATTERN_PARENT_CLASS_NAME = "Pattern"; //$NON-NLS-1$
+
+ /**
+ * Templates folder name.
+ */
+ protected static final String TEMPLATES_FOLDER_NAME = "/templates/"; //$NON-NLS-1$
+
+ /**
+ * Generated templates sub-folder path.
+ */
+ protected static final String GENERATED_TEMPLATE_FOLDER_PATH = ICommonConstants.GENERATED_FOLDER_PATH;
+
+ /**
+ * Find the class corresponding to given name in pointed ecore file.
+ * @param name_p
+ * @param ecoreURI_p
+ * @param resourceSet_p
+ * @return
+ */
+ protected static EClass getDependencyFromName(String name_p, String ecoreURI_p, ResourceSet resourceSet_p) {
+ EClass result = null;
+ // Preconditions.
+ if (name_p == null || ecoreURI_p == null || resourceSet_p == null) {
+ return result;
+ }
+ try {
+ URI patternURI = FileHelper.getFileFullUri(ecoreURI_p);
+ Resource parentResource = resourceSet_p.getResource(patternURI, true);
+ // Extract pattern as type from reloaded resource.
+ TreeIterator<EObject> content = parentResource.getAllContents();
+ while (content.hasNext() && result == null) {
+ EObject object = content.next();
+ if (object instanceof EClass) {
+ EClass class_ = (EClass) object;
+ // Retrieve the pattern EClass.
+ // Do not use something like '...'Package.Literals.'...' because it is not the instance stored in the resource.
+ // Otherwise, the persisted type URI leads to an invalid genmodel.
+ if (name_p.equals(class_.getName())) {
+ result = class_;
+ }
+ }
+ }
+ } catch (Exception exception_p) {
+ StringBuilder loggerMessage = new StringBuilder("AbstractPatternGenerator.getDependencyFromName(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ return result;
+ }
+
+ /**
+ * Get pattern parameters.<br>
+ * Ordered.
+ * @param resourceSet_p
+ * @return
+ */
+ protected List<ParameterRelation> getPatternParameters(ResourceSet resourceSet_p) {
+ return null;
+ }
+
+ /**
+ * Set pattern parent to identified one.<br>
+ * Default parent is {@link Pattern}.
+ * @param pattern_p The pattern that should be updated.
+ * @param parentClassName_p Parent class name, literally, or null if parent is to be reset.
+ * @param parentEcoreURI_p Parent class containing ecore uri, or null if parent is to be reset.
+ * @param resourceSet_p An existing one, or null if none is available.
+ */
+ public static void setPatternParent(Pattern pattern_p, String parentClassName_p, String parentEcoreURI_p, ResourceSet resourceSet_p) {
+ ResourceSet resourceSet = resourceSet_p;
+ // Precondition.
+ if (pattern_p == null) {
+ return;
+ }
+ // Create resource set if none given.
+ if (resourceSet == null) {
+ resourceSet = new ResourceSetImpl();
+ }
+ String parentClassName = parentClassName_p;
+ String parentEcoreURI = parentEcoreURI_p;
+ // Default parent is Pattern.
+ if (parentClassName == null || parentEcoreURI == null) {
+ parentClassName = PATTERN_PARENT_CLASS_NAME;
+ parentEcoreURI = PATTERN_ECORE_FILE_RELATIVE_PATH;
+ }
+ // Load pattern superclass.
+ EClass parent = getDependencyFromName(parentClassName, parentEcoreURI, resourceSet);
+ // Clear previous one, so that if no parent is found, then pattern parent is reset to none.
+ pattern_p.getESuperTypes().clear();
+ if (parent != null) {
+ // Add new one.
+ pattern_p.getESuperTypes().add(parent);
+ }
+ }
+
+ /**
+ * Generate pattern ecore file.
+ */
+ public boolean generateEcoreFile() {
+
+ // Create resource set for future use.
+ ResourceSet resourceSet = new ResourceSetImpl();
+
+ // Create new pattern structure.
+ Pattern newPattern = PatternFactory.eINSTANCE.createPattern();
+ // Set pattern id.
+ newPattern.setId(getPatternFullId());
+ // Set pattern superclass.
+ setPatternParent(newPattern, getParentClassName(), getParentEcoreURI(), resourceSet);
+
+ // Load pattern parameters.
+ List<ParameterRelation> parameters = getPatternParameters(resourceSet);
+ if (parameters != null) {
+ newPattern.getParameters().addAll(parameters);
+ }
+
+ // Create annotation handler.
+ AnnotationHandler annotationHandler = new AnnotationHandler();
+ // Add mandatory generate method to the new pattern.
+ EOperation generateOperation = addOperation(newPattern, PatternConstants.GENERATE_METHOD_NAME);
+ EParameter classLoaderParameter = EcoreFactory.eINSTANCE.createEParameter();
+ classLoaderParameter.setName(PatternConstants.GENERATE_METHOD_PARAMETER_NAME);
+ classLoaderParameter.setEType(EcorePackage.Literals.EJAVA_OBJECT);
+ generateOperation.getEParameters().add(classLoaderParameter);
+
+ // Add mandatory generate pre-matching method to the new pattern.
+ addOperation(newPattern, PatternConstants.GENERATE_PRE_MATCHING_METHOD_NAME);
+
+ // Add mandatory generate post-matching method to the new pattern.
+ addOperation(newPattern, PatternConstants.GENERATE_POST_MATCHING_METHOD_NAME);
+
+ // Add mandatory generate header method to the new pattern.
+ EOperation generateHeader = addOperation(newPattern, PatternConstants.GENERATE_HEADER_METHOD_NAME);
+ annotationHandler.addUidAnnotation(generateHeader);
+
+ // Add mandatory generate footer method to the new pattern.
+ EOperation generateFooter = addOperation(newPattern, PatternConstants.GENERATE_FOOTER_METHOD_NAME);
+ annotationHandler.addUidAnnotation(generateFooter);
+
+ // Fill pattern with specific content.
+ fillPattern(newPattern, annotationHandler, generateOperation);
+
+ String patternContainingPluginId = getPatternContainingPluginId();
+ // Initialize both pattern code and java code annotations for all pattern operations, excluding the generate one.
+ FactoryComponent containingFc = EgfPdeActivator.getDefault().getFactoryComponentForPluginId(patternContainingPluginId);
+ computeOperationsAnnotations(
+ newPattern,
+ containingFc == null ? patternContainingPluginId : containingFc.getId(),
+ annotationHandler
+ );
+
+ // Write pattern structure to ecore file.
+ return writePatternModelToFile(
+ newPattern,
+ getPatternModelRelativePath(
+ patternContainingPluginId,
+ PatternHelper.deresolveId(newPattern.getId()).getValue()
+ )
+ );
+
+ }
+
+ /**
+ * (Re)Compute annotations for all pattern operations.
+ * @param pattern_p
+ * @param fcId_p
+ * @param annotationHandler_p
+ */
+ public static void computeOperationsAnnotations(Pattern pattern_p, String fcId_p, AnnotationHandler annotationHandler_p) {
+ // Precondition.
+ if (pattern_p == null) {
+ return;
+ }
+ // Get annotation handler.
+ AnnotationHandler handler = annotationHandler_p;
+ if (handler == null) {
+ handler = new AnnotationHandler();
+ }
+ // Get pattern name.
+ String patternShortId = PatternHelper.deresolveId(pattern_p.getId()).getValue();
+ // Cycle through pattern operations :
+ // 1) Remove all existing annotations if any.
+ // 2) Add pattern code annotation that reads the corresponding template file.
+ // 2bis) Or replace its content with respect to the new pattern properties.
+ List<EOperation> operations = pattern_p.getEOperations();
+ for (EOperation operation : operations) {
+ String templateRelativePath = TemplateHelper.getTemplateRelativePath(
+ patternShortId,
+ fcId_p,
+ operation.getName(),
+ handler.getUid(operation)
+ );
+ if (templateRelativePath != null) {
+ if (handler.hasPatternCode(operation) == false) {
+ // Add read template file pattern code annotation.
+ handler.addReadFilePatternCode(operation, templateRelativePath);
+ }
+ }
+ }
+ // Now translate pattern code annotations to java code annotations.
+ handler.translateAnnotations(operations);
+ }
+
+ /**
+ * Compute and add production annotation for given pattern.
+ * @param pattern_p The pattern needing to be tagged with a production annotation.
+ * @param handler_p The production options handler, containing the annotation value.
+ * @param annotationHandler_p A possibly existing annotation handler, null if none to provide at call time.
+ */
+ public static void computeProductionAnnotation(Pattern pattern_p, ProductionOptionsHandler handler_p, AnnotationHandler annotationHandler_p) {
+ // Get annotation handler.
+ AnnotationHandler annotationHandler = annotationHandler_p;
+ if (annotationHandler == null) {
+ annotationHandler = new AnnotationHandler();
+ }
+ // Add/replace production annotation.
+ boolean successful = annotationHandler.addProductionAnnotation(pattern_p, handler_p);
+ if (successful == false) {
+ __logger.warn(
+ new StringBuilder("AbstractPatternGenerator.computeProductionAnnotation(..) _ ") //$NON-NLS-1$
+ .append("Could not set production annotation for pattern ") //$NON-NLS-1$
+ .append(pattern_p != null ? pattern_p.getName() : null)
+ .toString()
+ );
+ }
+ }
+
+ /**
+ * Get pattern model relative path.
+ * @param containerId_p either the factory component or the plug-in id, depending on the caller.<br>
+ * It is up to the caller to make sure that given plug-in id (if so) is up-to-date (for instance after a refactoring).
+ * @param patternId_p
+ * @return null if one of the given parameter is null.
+ */
+ public static String getPatternModelRelativePath(String containerId_p, String patternId_p) {
+ // Preconditions.
+ if (containerId_p == null || patternId_p == null) {
+ return null;
+ }
+ return
+ new StringBuilder(containerId_p)
+ .append(PatternConstants.PATTERN_MODEL_FOLDER)
+ .append(StringHelper.replaceNonWordCharactersWithDot(patternId_p))
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(PatternConstants.PATTERN_MODEL_FILE_EXTENSION)
+ .toString();
+ }
+
+ /**
+ * Write pattern model to file.
+ * @param pattern_p
+ * @param fileRelativePath_p
+ * @return true if successfully written, false otherwise.
+ */
+ static boolean writePatternModelToFile(Pattern pattern_p, String fileRelativePath_p) {
+ boolean result = false;
+ // Check if file is writable first.
+ boolean writable = FileHelper.makeFileWritable(fileRelativePath_p);
+ // File was not granted rights for modification (either by the system or by the user), stop here.
+ if (writable == false) {
+ return result;
+ }
+ // Create package that contains the pattern.
+ EPackage container = EcoreFactory.eINSTANCE.createEPackage();
+ container.setName(GeneratedContentHelper.getPatternPackageName(pattern_p));
+ container.setNsURI(GeneratedContentHelper.getPatternPackageNsURI(pattern_p));
+ container.setNsPrefix(GeneratedContentHelper.getPatternPackageNsPrefix(pattern_p));
+ container.getEClassifiers().add(pattern_p);
+ // Write pattern structure to ecore file.
+ try {
+ // Get file full URI.
+ URI fileFullUri = FileHelper.getFileFullUri(fileRelativePath_p);
+ ResourceSet resourceSet = new ResourceSetImpl();
+ // Create associated resource.
+ Resource patternResource = resourceSet.createResource(fileFullUri);
+ patternResource.getContents().add(container);
+ patternResource.save(null);
+ result = true;
+ } catch (Exception exception_p) {
+ result = false;
+ StringBuilder loggerMessage = new StringBuilder("AbstractPatternGenerator.writePatternModelToFile(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ return result;
+ }
+
+ /**
+ * Add a new operation to handled pattern.
+ * @param operationName_p
+ * @return The annotation that will contain the resulting method contents (as defined by the pattern annotation grammar).<br>
+ * Empty at this time.
+ */
+ public static EOperation addOperation(Pattern pattern_p, String operationName_p) {
+ EOperation newOperation = EcoreFactory.eINSTANCE.createEOperation();
+ newOperation.setName(operationName_p);
+ newOperation.setEType(EcorePackage.eINSTANCE.getEString());
+ pattern_p.getEOperations().add(newOperation);
+ return newOperation;
+ }
+
+ /**
+ * Remove operation from given pattern.
+ * @param pattern_p
+ * @param operation_p
+ */
+ public static void removeOperation(Pattern pattern_p, EOperation operation_p) {
+ if (pattern_p != null && operation_p != null) {
+ pattern_p.getEOperations().remove(operation_p);
+ }
+ }
+
+ /**
+ * Get pattern short id.
+ * @param pattern_p
+ * @return
+ */
+ protected String getPatternShortId(Pattern pattern_p) {
+ String result = null;
+ // Precondition.
+ if (pattern_p == null) {
+ return result;
+ }
+ result = PatternHelper.deresolveId(pattern_p.getId()).getValue();
+ return result;
+ }
+
+ /**
+ * Get template relative path from operation name.
+ * @param patternShortId_p
+ * @param operationName_p
+ * @param operationId_p
+ * @return
+ */
+ protected String getTemplateRelativePath(String patternShortId_p, String operationName_p, String operationId_p) {
+ return TemplateHelper.getTemplateRelativePath(
+ patternShortId_p,
+ getPatternContainingPluginId(),
+ operationName_p,
+ operationId_p
+ );
+ }
+
+ /**
+ * Fill newly created pattern with expected content.<br>
+ * The given operation is the 'generate' one, as defined by the pattern metamodel.
+ * @param newPattern_p
+ * @param handler_p
+ * @param generateContent_p
+ */
+ protected abstract void fillPattern(Pattern newPattern_p, AnnotationHandler handler_p, EOperation generate_p);
+
+ /**
+ * Get parent parent class name.
+ * @return
+ */
+ protected String getParentClassName() {
+ return null;
+ }
+
+ /**
+ * Get pattern parent class ecore URI.
+ * @return
+ */
+ protected String getParentEcoreURI() {
+ return null;
+ }
+
+ /**
+ * Get pattern containing plug-in id.
+ * @return
+ */
+ protected abstract String getPatternContainingPluginId();
+
+ /**
+ * Get pattern full id.
+ * @return
+ */
+ protected abstract String getPatternFullId();
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/AnnotationHandler.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/AnnotationHandler.java
new file mode 100644
index 0000000..a243c7b
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/AnnotationHandler.java
@@ -0,0 +1,997 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.Tree;
+import org.apache.log4j.Logger;
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.helper.IDGeneratorHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.pattern.Pattern;
+import org.eclipse.egf.pattern.ecore.PatternHandler.ProductionOptionsHandler;
+import org.eclipse.egf.pattern.ecore.grammar.PatternLanguageLexer;
+import org.eclipse.egf.pattern.ecore.grammar.PatternLanguageParser;
+import org.eclipse.egf.pattern.production.jet.JETConstants;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.emf.ecore.EcoreFactory;
+
+
+/**
+ * The annotation handler translates a pattern methods annotations to java code annotations.<br>
+ * It also provides with a parsing of the methods annotations.
+ * @author brocard
+ */
+public class AnnotationHandler {
+
+ /**
+ * Log4j reference logger.
+ */
+ private static final Logger __logger = Logger.getLogger(AnnotationHandler.class.getPackage().getName());
+
+ /**
+ * Super method call prefix.
+ */
+ protected static final String JAVA_CODE_SUPER_CALL_PREFIX = "super."; //$NON-NLS-1$
+
+ /**
+ * Read file method call prefix.
+ */
+ protected static final String JAVA_CODE_READ_FILE_CALL_PREFIX = "org.eclipse.egf.pattern.production.template.TemplateHelper.readTemplateFile"; //$NON-NLS-1$
+
+ /**
+ * Create string builder.
+ */
+ protected static final String JAVA_CODE_CREATE_STRING_BUILDER = "StringBuilder builder = new StringBuilder();"; //$NON-NLS-1$
+
+ /**
+ * Append to string builder.
+ */
+ protected static final String JAVA_CODE_APPEND_TO_STRING_BUILDER = "builder.append"; //$NON-NLS-1$
+
+ /**
+ * Return string builder result.
+ */
+ protected static final String JAVA_CODE_GET_STRING_BUILDER_RESULT = "return builder.toString();"; //$NON-NLS-1$
+
+ /**
+ * Operation annotation body.
+ */
+ protected static final String OPERATION_ANNOTATION_BODY = "body"; //$NON-NLS-1$
+
+ /**
+ * UID annotation source.
+ */
+ protected static final String UID_ANNOTATION_SOURCE = "http://www.eclipse.org/egf/1.0.0/uid"; //$NON-NLS-1$
+
+ /**
+ * Java code annotation source.
+ */
+ protected static final String JAVA_CODE_ANNOTATION_SOURCE = "http://www.eclipse.org/emf/2002/GenModel"; //$NON-NLS-1$
+
+ /**
+ * Pattern code annotation source.
+ */
+ public static final String PATTERN_CODE_ANNOTATION_SOURCE = "http://www.eclipse.org/egf/1.0.0/Pattern"; //$NON-NLS-1$
+
+ /**
+ * Pattern production annotation source.
+ */
+ public static final String PATTERN_PRODUCTION_ANNOTATION_SOURCE = "http://www.eclipse.org/egf/1.0.0/Pattern/production"; //$NON-NLS-1$
+
+ /**
+ * Pattern production path annotation body.
+ */
+ public static final String PATTERN_PRODUCTION_ANNOTATION_BODY_PATH = "Path"; //$NON-NLS-1$
+
+ /**
+ * Pattern production compilation annotation body.
+ */
+ public static final String PATTERN_PRODUCTION_ANNOTATION_BODY_COMPILATION = "Compilation"; //$NON-NLS-1$
+
+ /**
+ * Pattern production buffer modification annotation body.
+ */
+ public static final String PATTERN_PRODUCTION_ANNOTATION_BODY_BUFFER_MODIFICATION = "BufferModification"; //$NON-NLS-1$
+
+ /**
+ * Pattern method id prefix.
+ */
+ protected static final String PATTERN_METHOD_ID_PREFIX = "PatternMethod"; //$NON-NLS-1$
+
+ /**
+ * Get abstract syntax tree out of given pattern code.
+ * @param patternCode_p
+ * @return
+ */
+ protected CommonTree getTree(String patternCode_p) {
+ CommonTree result = null;
+ // Try and get the abstract syntax tree out of the pattern code.
+ PatternLanguageLexer lexer = new PatternLanguageLexer(new ANTLRStringStream(patternCode_p));
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ PatternLanguageParser parser = new PatternLanguageParser(tokens);
+ try {
+ // Parse pattern code and get the tree.
+ result = (CommonTree) parser.call().getTree();
+ } catch (RecognitionException exception_p) {
+ StringBuilder loggerMessage = new StringBuilder("AnnotationHandler.getTree(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ return result;
+ }
+
+ /**
+ * Get ordered list of pattern code actions for given pattern operation.
+ * @param operation_p
+ * @return List of (action, parameter) couples.
+ */
+ public List<Couple<String, String>> getOrderedActionsFor(EOperation operation_p) {
+ List<Couple<String, String>> actions = new ArrayList<Couple<String, String>>(0);
+ // Precondition.
+ if (null == operation_p) {
+ return actions;
+ }
+ // Get pattern code.
+ String patternCode = getPatternCode(operation_p);
+ // Precondition.
+ if (null == patternCode) {
+ return actions;
+ }
+ CommonTree tree = getTree(patternCode);
+ // Explore the actions tree, and fill given list accordingly (as the tree is being explored).
+ explore(tree, actions);
+ return actions;
+ }
+
+ /**
+ * Get pattern IDs that are called through this operation.<br>
+ * Only applicable to the generate method.
+ * @param operation_p
+ * @return An empty list of String if given method is null or is not the generate method or no external pattern is called.
+ * A list of called patterns full IDs otherwise.
+ */
+ @SuppressWarnings("unchecked")
+ public List<String> getCalledPatternIDs(EOperation operation_p) {
+ // Precondition.
+ if (null == operation_p) {
+ return Collections.EMPTY_LIST;
+ }
+ List<Couple<String, String>> orderedActions = getOrderedActionsFor(operation_p);
+ List<String> result = new ArrayList<String>(0);
+ for (Couple<String, String> action : orderedActions) {
+ // Get call to another pattern.
+ if (PatternConstants.PC_TAG_PATTERN.equals(action.getKey())) {
+ result.add(action.getValue());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Replace old parameter value with new one, everywhere it is used in given actions list.
+ * @param oldParameterValue_p
+ * @param newParameterValue_p As a result, given actions list remains unmodified, but its contained actions are (unless no modification happened).
+ */
+ public void replaceParameter(String oldParameterValue_p, String newParameterValue_p, List<Couple<String, String>> actions_p) {
+ // Preconditions.
+ if ((null == actions_p) || (null == oldParameterValue_p) || (null == newParameterValue_p)) {
+ return;
+ }
+ // Iterate through actions.
+ for (Couple<String, String> action : actions_p) {
+ // Replace old value with new one.
+ if (oldParameterValue_p.equals(action.getValue())) {
+ action.setValue(newParameterValue_p);
+ }
+ }
+ }
+
+ /**
+ * Remove actions using given parameter from given actions list.
+ * @param parameterValue_p
+ * @param actions_p
+ * @return {@link List} of removed actions.
+ * @deprecated
+ */
+ public List<Couple<String, String>> removeActionsFor(String parameterValue_p, List<Couple<String, String>> actions_p) {
+ if ((null == parameterValue_p) || (null == actions_p) || actions_p.isEmpty()) {
+ return null;
+ }
+ // Clone actions list.
+ List<Couple<String, String>> clonedActions = new ArrayList<Couple<String, String>>(0);
+ clonedActions.addAll(actions_p);
+ // Iterate through actions.
+ for (Couple<String, String> action : clonedActions) {
+ // If parameter value matches, then remove action from given list.
+ if (parameterValue_p.equals(action.getValue())) {
+ actions_p.remove(action);
+ }
+ }
+ // Retain removed actions.
+ clonedActions.removeAll(actions_p);
+ return clonedActions;
+ }
+
+ /**
+ * Recompute pattern code annotation for given method using given actions.<br>
+ * As a result, java code annotation is removed, and is to be recomputed.
+ * @param operation_p
+ * @param actions_p
+ */
+ public void recomputeAnnotationFromActions(EOperation operation_p, List<Couple<String, String>> actions_p) {
+ // Preconditions.
+ if ((null == operation_p) || (null == actions_p)) {
+ return;
+ }
+ // Clear recomputed annotations.
+ List<EAnnotation> keptAnnotations = Collections.singletonList(operation_p.getEAnnotation(UID_ANNOTATION_SOURCE));
+ operation_p.getEAnnotations().retainAll(keptAnnotations);
+ // Reconstruct pattern code.
+ for (Couple<String, String> action : actions_p) {
+ String actionType = action.getKey();
+ String actionParameter = action.getValue();
+ if (PatternConstants.PC_TAG_CALL.equals(actionType)) {
+ // Call to a method call.
+ addCallMethodPatternCode(operation_p, actionParameter);
+ } else if (PatternConstants.PC_TAG_PATTERN.equals(actionType)) {
+ // Call to another pattern.
+ addGenerateOtherPatternPatternCode(operation_p, actionParameter);
+ } else if (PatternConstants.PC_TAG_READ.equals(actionType)) {
+ // Call to read template file.
+ addReadFilePatternCode(operation_p, actionParameter);
+ } else if (PatternConstants.PC_TAG_SUPER.equals(actionType)) {
+ // Call to super method.
+ addSuperMethodCallPatternCode(operation_p, actionParameter);
+ }
+ }
+ }
+
+ /**
+ * Add UID annotation to given operation.
+ * @param operation_p
+ * @return String, the UID set for this operation, null if given operation is null.
+ */
+ public String addUidAnnotation(EOperation operation_p) {
+ String result = null;
+ // Precondition.
+ if (null == operation_p) {
+ return result;
+ }
+ // Get existing one, if any.
+ EAnnotation annotation = operation_p.getEAnnotation(UID_ANNOTATION_SOURCE);
+ if (null == annotation) {
+ annotation = EcoreFactory.eINSTANCE.createEAnnotation();
+ // Add it to operation.
+ operation_p.getEAnnotations().add(annotation);
+ annotation.setSource(UID_ANNOTATION_SOURCE);
+ }
+ // Create and set UID.
+ result = IDGeneratorHelper.generatePrefixUID(PATTERN_METHOD_ID_PREFIX);
+ annotation.getDetails().put(OPERATION_ANNOTATION_BODY, result);
+ return result;
+ }
+
+ /**
+ * Add/replace pattern production annotation based on given production handler values.
+ * @param pattern_p
+ * @param productionHandler_p
+ * @return
+ */
+ public boolean addProductionAnnotation(Pattern pattern_p, ProductionOptionsHandler productionHandler_p) {
+ boolean result = false;
+ // Preconditions.
+ if ((null == pattern_p) || (null == productionHandler_p)) {
+ return result;
+ }
+ // Get annotation.
+ EAnnotation annotation = pattern_p.getEAnnotation(PATTERN_PRODUCTION_ANNOTATION_SOURCE);
+ // None existed, create a new one.
+ if (null == annotation) {
+ annotation = EcoreFactory.eINSTANCE.createEAnnotation();
+ annotation.setSource(PATTERN_PRODUCTION_ANNOTATION_SOURCE);
+ // Add it to pattern.
+ pattern_p.getEAnnotations().add(annotation);
+ }
+ // Add/update the different production options.
+ // The produced template relative path.
+ EMap<String, String> details = annotation.getDetails();
+ details.put(PATTERN_PRODUCTION_ANNOTATION_BODY_PATH, productionHandler_p.getPatternTemplatePath());
+ // The compilation flag.
+ details.put(PATTERN_PRODUCTION_ANNOTATION_BODY_COMPILATION, Boolean.toString(productionHandler_p.shouldCompileTemplate()));
+ // The buffer modification flag.
+ details.put(PATTERN_PRODUCTION_ANNOTATION_BODY_BUFFER_MODIFICATION, Boolean.toString(productionHandler_p.shouldModifyBuffer()));
+ result = true;
+ return result;
+ }
+
+ /**
+ * Remove production annotation from given pattern, if any.
+ * @param pattern_p
+ * @return Removed annotation, or null if given pattern is null or is not containing such an annotation.
+ */
+ public EAnnotation removeProductionAnnotation(Pattern pattern_p) {
+ EAnnotation result = null;
+ // Precondition.
+ if (null == pattern_p) {
+ return result;
+ }
+ result = pattern_p.getEAnnotation(PATTERN_PRODUCTION_ANNOTATION_SOURCE);
+ if (null != result) {
+ pattern_p.getEAnnotations().remove(result);
+ }
+ return result;
+ }
+
+ /**
+ * Get operation UID.
+ * @param operation_p
+ * @return null if given operation is null.
+ */
+ public String getUid(EOperation operation_p) {
+ String result = null;
+ // Precondition.
+ if (null == operation_p) {
+ return result;
+ }
+ // Get UID, if any.
+ EAnnotation uidAnnotation = operation_p.getEAnnotation(UID_ANNOTATION_SOURCE);
+ if (null != uidAnnotation) {
+ result = uidAnnotation.getDetails().get(OPERATION_ANNOTATION_BODY);
+ }
+ return result;
+ }
+
+ /**
+ * Get a couple composed of the top action (and its parameter) of given tree.
+ * @param tree_p
+ * @return Key = action name, Value = parameter.
+ */
+ protected Couple<String, String> getActionAndParameter(Tree tree_p) {
+ // Precondition.
+ if (null == tree_p) {
+ return null;
+ }
+ // Get action type (ie action name).
+ String actionType = tree_p.getText();
+ // Get action parameter, if any.
+ String actionParameter = getFirstChild(tree_p);
+ return new Couple<String, String>(actionType, actionParameter);
+ }
+
+ /**
+ * Explore current tree level, and fill given pattern code actions list accordingly.
+ * @param tree_p
+ * @param actions_p
+ */
+ protected void explore(Tree tree_p, List<Couple<String, String>> actions_p) {
+ Couple<String, String> currentAction = getActionAndParameter(tree_p);
+ // Precondition.
+ if (null == currentAction) {
+ return;
+ }
+ String actionType = currentAction.getKey();
+ if (PatternConstants.PC_TAG_CALL.equals(actionType) || PatternConstants.PC_TAG_SUPER.equals(actionType) || PatternConstants.PC_TAG_READ.equals(actionType)
+ || PatternConstants.PC_TAG_PATTERN.equals(actionType)) { // Action type must meet the pattern code grammar definition.
+ actions_p.add(currentAction);
+ } else { // If current node is not one of the looked for word, go-on with children.
+ // Cycle through children.
+ int childCount = tree_p.getChildCount();
+ // Explore first-level children.
+ for (int i = 0; i < childCount; i++) {
+ explore(tree_p.getChild(i), actions_p);
+ }
+ }
+ }
+
+ /**
+ * Translate annotations from pattern code to java code for given pattern operations.
+ * @param operations_p
+ * @return true if successful, false otherwise.
+ */
+ public boolean translateAnnotations(List<EOperation> operations_p) {
+ boolean result = true;
+ // Preconditions.
+ if ((null == operations_p) || operations_p.isEmpty()) {
+ return result;
+ }
+ // Iterate over given operations.
+ for (EOperation operation : operations_p) {
+ result &= doTranslateAnnotation(operation);
+ }
+ return result;
+ }
+
+ /**
+ * Is given operation referencing pattern code ?
+ * @param operation_p
+ * @return
+ */
+ public boolean hasPatternCode(EOperation operation_p) {
+ return (null != getPatternCode(operation_p));
+ }
+
+ /**
+ * Do translate annotation for given operation.
+ * @param operation_p
+ * @return
+ */
+ protected boolean doTranslateAnnotation(EOperation operation_p) {
+ // By default, no translation is a successful one.
+ boolean result = true;
+ // Get pattern code.
+ String patternCode = getPatternCode(operation_p);
+ // Precondition.
+ if (null == patternCode) {
+ return result;
+ }
+ // Initialize java code.
+ initializeJavaCode(operation_p);
+ // Try and get the abstract syntax tree out of the pattern code.
+ CommonTree tree = getTree(patternCode);
+ if (null != tree) {
+ exploreAndTranslate(tree, operation_p);
+ }
+ // Always try to return a correct piece of code.
+ finalizeJavaCode(operation_p);
+ return result;
+ }
+
+ /**
+ * Explore annotation abstract syntax tree and translate accordingly.
+ * @param tree_p
+ * @param operation_p
+ */
+ protected void exploreAndTranslate(Tree tree_p, EOperation operation_p) {
+ Couple<String, String> action = getActionAndParameter(tree_p);
+ // Precondition.
+ if (null == action) {
+ return;
+ }
+ // Get action type (ie action name).
+ String actionType = action.getKey();
+ // Get action parameter, if any.
+ String actionParameter = action.getValue();
+ if (PatternConstants.PC_TAG_CALL.equals(actionType)) { // CALL code ?
+ addCallMethodJavaCode(operation_p, actionParameter);
+ } else if (PatternConstants.PC_TAG_SUPER.equals(actionType)) { // SUPER code ?
+ addSuperMethodCallJavaCode(operation_p, actionParameter);
+ } else if (PatternConstants.PC_TAG_READ.equals(actionType)) { // READ code ?
+ addReadFileJavaCode(operation_p, actionParameter);
+ } else if (PatternConstants.PC_TAG_PATTERN.equals(actionType)) {
+ addGenerateOtherPatternJavaCode(operation_p, actionParameter);
+ } else { // If current node is not one of the looked for word, go-on with children.
+ int childCount = tree_p.getChildCount();
+ // Explore first-level children.
+ for (int i = 0; i < childCount; i++) {
+ exploreAndTranslate(tree_p.getChild(i), operation_p);
+ }
+ }
+ }
+
+ /**
+ * Get first child of given tree as a string.
+ * @param tree_p
+ * @return null if none could be found.
+ */
+ protected String getFirstChild(Tree tree_p) {
+ String result = null;
+ if ((null != tree_p) && (0 < tree_p.getChildCount())) {
+ result = tree_p.getChild(0).getText();
+ }
+ return result;
+ }
+
+ /**
+ * Get pattern code for given operation.
+ * @param operation_p
+ * @return null if no code could be found.
+ */
+ protected String getPatternCode(EOperation operation_p) {
+ // Do not force creation, if no pattern code annotation could be found.
+ EAnnotation patternCodeAnnotation = getOrCreatePatternCodeAnnotation(operation_p, false);
+ // Precondition.
+ if (null == patternCodeAnnotation) {
+ return null;
+ }
+ // Get existing pattern code.
+ return patternCodeAnnotation.getDetails().get(OPERATION_ANNOTATION_BODY);
+ }
+
+ /**
+ * Initialize java code for given operation.<br>
+ * It does create a new java code annotation, and add string builder creation code.
+ * @param operation_p
+ */
+ protected void initializeJavaCode(EOperation operation_p) {
+ // Precondition.
+ if (null == operation_p) {
+ return;
+ }
+ // Done through a code appender.
+ new UnbufferedJavaCodeAppender() {
+ /**
+ * @see org.eclipse.egf.pattern.ecore.AnnotationHandler.JavaCodeAppender#getCodeAnnotation(org.eclipse.emf.ecore.EOperation)
+ */
+ @Override
+ protected EAnnotation getCodeAnnotation(EOperation operation) {
+ // First of all, remove possibly existing java annotation.
+ EAnnotation javaCodeAnnotation = operation.getEAnnotation(JAVA_CODE_ANNOTATION_SOURCE);
+ operation.getEAnnotations().remove(javaCodeAnnotation);
+ // Then behave as expected.
+ return super.getCodeAnnotation(operation);
+ }
+
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Add string builder creation code.
+ existingCode_p.append(JAVA_CODE_CREATE_STRING_BUILDER);
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Finalize java code for given operation.<br>
+ * Adds string builder return code.
+ * @param operation_p
+ */
+ protected void finalizeJavaCode(EOperation operation_p) {
+ // Precondition.
+ if (null == operation_p) {
+ return;
+ }
+ // Done through a code appender.
+ new UnbufferedJavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Add string builder return result code.
+ existingCode_p.append(JAVA_CODE_GET_STRING_BUILDER_RESULT);
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Add generate identified pattern (pattern code) for given operation and pattern full id.
+ * @param operation_p
+ * @param patternFullId_p
+ */
+ public void addGenerateOtherPatternPatternCode(EOperation operation_p, final String patternFullId_p) {
+ // Preconditions.
+ if ((null == operation_p) || (null == patternFullId_p)) {
+ return;
+ }
+ // Done through a code appender.
+ new PatternCodeAppender() {
+ @Override
+ protected String getOperationName() {
+ return PatternConstants.PC_TAG_PATTERN;
+ }
+
+ @Override
+ protected String getParameter() {
+ return patternFullId_p;
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * TODO Guillaume<br>
+ * Specific to JET templates.<br>
+ * Add generate identified pattern (java code) for given operation and pattern full id.
+ * @param operation_p
+ * @param patternFullId_p
+ */
+ protected void addGenerateOtherPatternJavaCode(EOperation operation_p, final String patternFullId_p) {
+ // Precondition.
+ if ((null == operation_p) || (null == patternFullId_p)) {
+ return;
+ }
+ // Add JET start mark-up.
+ new JavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Very specific to JET.
+ existingCode_p.append(JETConstants.EXTERNAL_USE_JET_MARKUP_START);
+ }
+ }.appendCode(operation_p);
+ // Done through a code appender.
+ new JavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Resulting code looks like : "<%stringBuffer.append(com.thalesgroup.*.PatternExecutionHelper.invokePattern("pattern full id", argument));%>"
+ // Specific to JET for stringBuffer is a JET variable.
+ existingCode_p.append(ICommonConstants.QUOTE_CHARACTER).append("stringBuffer.append").append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER); //$NON-NLS-1$
+ existingCode_p.append(getCallOtherPatternTemplateCode(patternFullId_p)).append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER);
+ existingCode_p.append(ICommonConstants.SEMICOLON_CHARACTER).append(ICommonConstants.QUOTE_CHARACTER);
+ }
+ }.appendCode(operation_p);
+ // Add JET end mark-up.
+ new JavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Very specific to JET.
+ existingCode_p.append(JETConstants.EXTERNAL_USE_JET_MARKUP_END);
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * TODO Guillaume<br>
+ * Specific to JET templates.<br>
+ * Get call to another pattern template code.
+ * @param patternFullId_p The pattern to call full id.
+ * @return
+ */
+ protected String getCallOtherPatternTemplateCode(String patternFullId_p) {
+ // Specific to JET for argument is a JET variable.
+ return StringHelper
+ .formatMessage(
+ "org.eclipse.egf.pattern.execution.PatternExecutionHelper.invokePattern(\\\"{0}\\\", argument)", new Object[] { patternFullId_p }); //$NON-NLS-1$
+ }
+
+ /**
+ * Add read file (pattern code) for given operation and file relative path.
+ * @param operation_p
+ * @param fileRelativePath_p
+ */
+ public void addReadFilePatternCode(EOperation operation_p, final String fileRelativePath_p) {
+ // Preconditions.
+ if ((null == operation_p) || (null == fileRelativePath_p)) {
+ return;
+ }
+ // Done through a code appender.
+ new PatternCodeAppender() {
+ @Override
+ protected String getOperationName() {
+ return PatternConstants.PC_TAG_READ;
+ }
+
+ @Override
+ protected String getParameter() {
+ return fileRelativePath_p;
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Add read file (java code) for given operation and file relative path.
+ * @param operation_p
+ * @param fileRelativePath_p
+ */
+ protected void addReadFileJavaCode(EOperation operation_p, final String fileRelativePath_p) {
+ // Preconditions.
+ if ((null == operation_p) || (null == fileRelativePath_p)) {
+ return;
+ }
+ // Done through a code appender.
+ new JavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Resulting code looks like : 'com.thalesgroup.*.TemplateHelper.readTemplateFile("fileRelativePath");'
+ existingCode_p.append(JAVA_CODE_READ_FILE_CALL_PREFIX).append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ existingCode_p.append(ICommonConstants.QUOTE_CHARACTER).append(fileRelativePath_p).append(ICommonConstants.QUOTE_CHARACTER);
+ existingCode_p.append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER);
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Add call method (pattern code) for given operation and method name.
+ * @param operation_p
+ * @param methodName_p
+ */
+ public void addCallMethodPatternCode(EOperation operation_p, final String methodName_p) {
+ // Precondition.
+ if ((null == operation_p) || (null == methodName_p)) {
+ return;
+ }
+ // Done through a code appender.
+ new PatternCodeAppender() {
+ @Override
+ protected String getOperationName() {
+ return PatternConstants.PC_TAG_CALL;
+ }
+
+ @Override
+ protected String getParameter() {
+ return methodName_p;
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Add call method (java code) for given operation and method name.
+ * @param operation_p
+ * @param methodName_p
+ */
+ protected void addCallMethodJavaCode(EOperation operation_p, final String methodName_p) {
+ // Preconditions.
+ if ((null == operation_p) || (null == methodName_p)) {
+ return;
+ }
+ // Done through a code appender.
+ new JavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Resulting java code looks like : 'myMethodName();'
+ existingCode_p.append(methodName_p).append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER).append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER);
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Add call to super method (pattern code) for given operation and method name.
+ * @param operation_p
+ * @param methodName_p
+ */
+ public void addSuperMethodCallPatternCode(EOperation operation_p, final String methodName_p) {
+ // Precondition.
+ if (null == operation_p) {
+ return;
+ }
+ // Done through a code appender.
+ new PatternCodeAppender() {
+ @Override
+ protected String getOperationName() {
+ return PatternConstants.PC_TAG_SUPER;
+ }
+
+ @Override
+ protected String getParameter() {
+ return methodName_p;
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Add call to super method (java code) for given operation and method name.
+ * @param operation_p
+ * @param methodName_p Can be null, the given operation name is used instead.
+ */
+ protected void addSuperMethodCallJavaCode(EOperation operation_p, String methodName_p) {
+ // Precondition.
+ if (null == operation_p) {
+ return;
+ }
+ // Get method name.
+ final String[] methodName = new String[] { methodName_p };
+ // By default, there is no parameters to the super call.
+ final List<EParameter> parametersList = new ArrayList<EParameter>(0);
+ // No method name, make a super call to override method.
+ if (null == methodName_p) {
+ // Method name is the same as currently handled operation.
+ methodName[0] = operation_p.getName();
+ // And parameters are similar too.
+ parametersList.addAll(operation_p.getEParameters());
+ }
+ // Done through a code appender.
+ new JavaCodeAppender() {
+ @Override
+ protected void appendNewOperation(StringBuilder existingCode_p) {
+ // Resulting java code looks like : 'super.myMethodName(methodParameters);'
+ existingCode_p.append(JAVA_CODE_SUPER_CALL_PREFIX).append(methodName[0]).append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ // Add parameters, super parameters should be the same, so there should be no issue there.
+ for (Iterator<EParameter> parameters = parametersList.iterator(); parameters.hasNext();) {
+ existingCode_p.append(parameters.next().getName());
+ // Append comma after parameter if there is a following parameter.
+ if (parameters.hasNext()) {
+ existingCode_p.append(ICommonConstants.COMMA_CHARACTER);
+ }
+ }
+ existingCode_p.append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER);
+ }
+ }.appendCode(operation_p);
+ }
+
+ /**
+ * Get or create java code annotation for given operation.
+ * @param operation_p
+ * @return
+ */
+ protected EAnnotation getOrCreateJavaCodeAnnotation(EOperation operation_p) {
+ return getOrCreateAnnotation(operation_p, JAVA_CODE_ANNOTATION_SOURCE, true);
+ }
+
+ /**
+ * Get or create pattern code annotation for given operation.<br>
+ * If creation flag is set to false, then no creation will be attempted if no annotation could be found.
+ * @param operation_p
+ * @param forceCreation_p
+ * @return
+ */
+ protected EAnnotation getOrCreatePatternCodeAnnotation(EOperation operation_p, boolean forceCreation_p) {
+ return getOrCreateAnnotation(operation_p, PATTERN_CODE_ANNOTATION_SOURCE, forceCreation_p);
+ }
+
+ /**
+ * Get annotation for given operation and source.<br>
+ * If none exists, and force creation flag is set to true, create a new one that matches these parameters.
+ * @param operation_p
+ * @param sourceAnnotation_p
+ * @param forceCreation_p Should an annotation be created if none could be found ?
+ * @return A not null annotation.
+ */
+ protected EAnnotation getOrCreateAnnotation(EOperation operation_p, String sourceAnnotation_p, boolean forceCreation_p) {
+ EAnnotation result = null;
+ // Preconditions.
+ if ((null == operation_p) && (null == sourceAnnotation_p)) {
+ return result;
+ }
+ result = operation_p.getEAnnotation(sourceAnnotation_p);
+ if ((null == result) && forceCreation_p) {
+ result = EcoreFactory.eINSTANCE.createEAnnotation();
+ result.setSource(sourceAnnotation_p);
+ operation_p.getEAnnotations().add(result);
+ }
+ return result;
+ }
+
+ /**
+ * Append operation to given string builder of pattern code.
+ * @param operationName_p Operation to use.
+ * @param parameter_p Operation parameter. Always a {@link String}. May be null.
+ * @param existingCode_p a not null {@link StringBuilder} containing existing pattern code.
+ */
+ protected void doAppendPatternCode(String operationName_p, String parameter_p, StringBuilder existingCode_p) {
+ // Preconditions.
+ if ((null == operationName_p) || (null == existingCode_p)) {
+ return;
+ }
+ // Fill up content.
+ existingCode_p.append(operationName_p);
+ // Add parameters.
+ existingCode_p.append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ if (null != parameter_p) {
+ existingCode_p.append(parameter_p);
+ }
+ // End call.
+ existingCode_p.append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER).append(ICommonConstants.SEMICOLON_CHARACTER);
+ }
+
+ /**
+ * Annotation code appender.<br>
+ * Adds new code as an annotation to a specified operation.<br>
+ * Not dependent on the type of code to append.
+ * @author brocard
+ */
+ protected abstract class AnnotationCodeAppender {
+ /**
+ * Append new code to given operation.<br>
+ * This is done through a specific code annotation.
+ * @param operation_p
+ */
+ public void appendCode(EOperation operation_p) {
+ EAnnotation annotation = getCodeAnnotation(operation_p);
+ // Get existing code.
+ String existingContent = annotation.getDetails().get(OPERATION_ANNOTATION_BODY);
+ // Create string builder on existing code, or new one if none exists.
+ StringBuilder resultingCode = null;
+ if (null != existingContent) {
+ resultingCode = new StringBuilder(existingContent);
+ } else {
+ resultingCode = new StringBuilder();
+ }
+ // Append code to existing one.
+ doAppendCode(resultingCode);
+ // Replace code with new one.
+ annotation.getDetails().put(OPERATION_ANNOTATION_BODY, resultingCode.toString());
+ }
+
+ /**
+ * Get the annotation that is/will be containing the code.
+ * @param operation_p
+ * @return
+ */
+ protected abstract EAnnotation getCodeAnnotation(EOperation operation_p);
+
+ /**
+ * Append new code to existing one.
+ * @param existingCode_p
+ */
+ protected abstract void doAppendCode(StringBuilder existingCode_p);
+ }
+
+ /**
+ * Pattern code appender to existing pattern operation.
+ * @author brocard
+ */
+ protected abstract class PatternCodeAppender extends AnnotationCodeAppender {
+ /**
+ * @see org.eclipse.egf.pattern.ecore.AnnotationHandler.AnnotationCodeAppender#doAppendCode(java.lang.StringBuilder)
+ */
+ @Override
+ protected void doAppendCode(StringBuilder existingCode_p) {
+ doAppendPatternCode(getOperationName(), getParameter(), existingCode_p);
+ }
+
+ /**
+ * @see org.eclipse.egf.pattern.ecore.AnnotationHandler.AnnotationCodeAppender#getCodeAnnotation(org.eclipse.emf.ecore.EOperation)
+ */
+ @Override
+ protected EAnnotation getCodeAnnotation(EOperation operation_p) {
+ // Get the annotation that contains the pattern code for given operation.
+ return getOrCreatePatternCodeAnnotation(operation_p, true);
+ }
+
+ /**
+ * Get operation name to add.
+ * @return
+ */
+ protected abstract String getOperationName();
+
+ /**
+ * Get operation parameter to add.
+ * @return
+ */
+ protected abstract String getParameter();
+ }
+
+ /**
+ * Java code append to existing pattern operation code.<br>
+ * This appender always encapsulate added code within a call to string builder.<br>
+ * Thus the specified code must be compatible with an insertion within a string builder.
+ * @author brocard
+ */
+ protected abstract class JavaCodeAppender extends AnnotationCodeAppender {
+ /**
+ * @see org.eclipse.egf.pattern.ecore.AnnotationHandler.AnnotationCodeAppender#doAppendCode(java.lang.StringBuilder)
+ */
+ @Override
+ protected void doAppendCode(StringBuilder existingCode_p) {
+ existingCode_p.append(JAVA_CODE_APPEND_TO_STRING_BUILDER).append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ appendNewOperation(existingCode_p);
+ existingCode_p.append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER).append(ICommonConstants.SEMICOLON_CHARACTER).append(ICommonConstants.EOL_CHARACTER);
+ }
+
+ /**
+ * @see org.eclipse.egf.pattern.ecore.AnnotationHandler.AnnotationCodeAppender#getCodeAnnotation(org.eclipse.emf.ecore.EOperation)
+ */
+ @Override
+ protected EAnnotation getCodeAnnotation(EOperation operation_p) {
+ return getOrCreateJavaCodeAnnotation(operation_p);
+ }
+
+ /**
+ * Append new code to existing one.<br>
+ * No specific layout is required here (even though the correctness is mandatory).
+ * @return
+ */
+ protected abstract void appendNewOperation(StringBuilder existingCode_p);
+ }
+
+ /**
+ * A java code appender that is not prefixed by a call to the string builder.<br>
+ * Used for appending string builder creation and getting string builder resulting string.
+ * @author brocard
+ */
+ protected abstract class UnbufferedJavaCodeAppender extends JavaCodeAppender {
+ /**
+ * @see org.eclipse.egf.pattern.ecore.AnnotationHandler.JavaCodeAppender#doAppendCode(java.lang.StringBuilder)
+ */
+ @Override
+ protected void doAppendCode(StringBuilder existingCode_p) {
+ appendNewOperation(existingCode_p);
+ existingCode_p.append(ICommonConstants.EOL_CHARACTER);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/Messages.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/Messages.java
new file mode 100644
index 0000000..7ecf6f0
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/Messages.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.ecore;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author Guillaume Brocard
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.egf.pattern.ecore.messages"; //$NON-NLS-1$
+ public static String PatternHandler_AutoGeneratedDescriptionText;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+ private Messages() {
+ // Static initialization.
+ }
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternConditionHelper.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternConditionHelper.java
new file mode 100644
index 0000000..f64edf4
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternConditionHelper.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ **/
+package org.eclipse.egf.pattern.ecore;
+
+import java.util.List;
+
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+
+
+/**
+ * Pattern condition helper.
+ * @author Guillaume Brocard
+ */
+public class PatternConditionHelper {
+
+ /**
+ * Get all parameters for identified pattern.<br>
+ * Does not look for parameters in current workspace.<br>
+ * <b>Should only be used by the condition producer generated result</b>!
+ * @param patternFullId_p The full id of the pattern.
+ * @return null if pattern could not be found, or empty list if it does not declare any parameter.
+ */
+ public static List<ParameterRelation> getPatternParameters(String patternFullId_p) {
+ List<ParameterRelation> result = null;
+ // Ask pattern seeker to resolve path to pattern.
+ List<PatternData> patternDataList = new PatternSeeker(false).getPatternsData(patternFullId_p);
+ if (patternDataList.isEmpty() == false) {
+ // There should be only one possible pattern data (for one pattern full id).
+ PatternData patternData = patternDataList.get(0);
+ result = patternData.getAllParameters();
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternConstants.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternConstants.java
new file mode 100644
index 0000000..1a7bc96
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternConstants.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+
+/**
+ * @author brocard
+ */
+public class PatternConstants {
+
+ /**
+ * Pattern generated classes base package.
+ */
+ public static final String PATTERN_GENERATED_BASE_PACKAGE = "org.eclipse.egf.pattern"; //$NON-NLS-1$
+
+ /**
+ * Condition generated classes base package.
+ */
+ public static final String PATTERN_CONDITION_GENERATED_BASE_PACKAGE = "org.eclipse.egf.condition"; //$NON-NLS-1$
+
+ /**
+ * Pattern generated ecore namespace URI prefix
+ */
+ public static final String PATTERN_GENERATED_ECORE_NS_URI_PREFIX = "http://www.eclipse.org/egf/1.0.0/Pattern/Generated/"; //$NON-NLS-1$
+
+ /**
+ * Read file (pattern code tag).
+ */
+ public static final String PC_TAG_READ = "READ"; //$NON-NLS-1$
+
+ /**
+ * Call to a super method (pattern code tag).
+ */
+ public static final String PC_TAG_SUPER = "SUPER"; //$NON-NLS-1$
+
+ /**
+ * Call to a method (pattern code tag).
+ */
+ public static final String PC_TAG_CALL = "CALL"; //$NON-NLS-1$
+
+ /**
+ * Call to an other pattern generate() method (pattern code tag).
+ */
+ public static final String PC_TAG_PATTERN = "PATTERN"; //$NON-NLS-1$
+
+ /**
+ * Pattern ecore file extension.
+ */
+ public static final String PATTERN_MODEL_FILE_EXTENSION = "pm"; //$NON-NLS-1$
+
+ /**
+ * Pattern method file extension.
+ */
+ public static final String PATTERN_METHOD_FILE_EXTENSION = "pt"; //$NON-NLS-1$
+
+ /**
+ * Generated source code folder (relative to project) path.
+ */
+ public static final String GENERATION_SOURCE_FOLDER = "/generated"; //$NON-NLS-1$
+
+ /**
+ * Generated source code folder (relative to project) relative IPath.
+ */
+ public static final IPath GENERATION_SOURCE_FOLDER_IPATH = new Path("generated"); //$NON-NLS-1$
+
+ /**
+ * Pattern model folder.
+ */
+ public static final String PATTERN_MODEL_FOLDER = "/model/pattern/"; //$NON-NLS-1$
+
+ /**
+ * Pattern model folder relative IPath.
+ */
+ public static final IPath PATTERN_MODEL_FOLDER_IPATH = new Path("model").append("pattern"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * Pattern generate method name.
+ */
+ public static final String GENERATE_METHOD_NAME = "generateBody"; //$NON-NLS-1$
+
+ /**
+ * Generate method parameter name.
+ */
+ protected static final String GENERATE_METHOD_PARAMETER_NAME = "classLoader_p"; //$NON-NLS-1$
+
+ /**
+ * Pattern generate pre-matching method name.
+ */
+ public static final String GENERATE_PRE_MATCHING_METHOD_NAME = "generatePreMatching"; //$NON-NLS-1$
+
+ /**
+ * Pattern generate post-matching method name.
+ */
+ public static final String GENERATE_POST_MATCHING_METHOD_NAME = "generatePostMatching"; //$NON-NLS-1$
+
+ /**
+ * Pattern generate header method name.
+ */
+ public static final String GENERATE_HEADER_METHOD_NAME = "generateHeader"; //$NON-NLS-1$
+
+ /**
+ * Pattern generate footer method name.
+ */
+ public static final String GENERATE_FOOTER_METHOD_NAME = "generateFooter"; //$NON-NLS-1$
+
+ /**
+ * Parameters handler class suffix.
+ */
+ public static final String CLASS_PARAMETERS_HANDLER_SUFFIX = "ParametersHandler"; //$NON-NLS-1$
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternHandler.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternHandler.java
new file mode 100644
index 0000000..28f0e51
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternHandler.java
@@ -0,0 +1,1033 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IJavaProject;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+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.edit.command.SetCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.descriptor.GenericDescriptor;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.descriptor.pattern.helper.IPatternDescriptorHandler;
+import org.eclipse.egf.common.descriptor.pattern.helper.PatternDescriptorStrategy;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.PatternHelper;
+import org.eclipse.egf.common.helper.ProjectHelper;
+import org.eclipse.egf.common.misc.PlatformLocationType;
+import org.eclipse.egf.common.ui.helper.MessageFormatHelper;
+import org.eclipse.egf.core.ui.EgfUiActivator;
+import org.eclipse.egf.fc.generator.java.helper.FileNameHelper;
+import org.eclipse.egf.model.ModelPackage;
+import org.eclipse.egf.model.PatternModel;
+import org.eclipse.egf.model.edit.helper.FactoryComponentHelper;
+import org.eclipse.egf.pattern.Pattern;
+import org.eclipse.egf.pattern.PatternPackage;
+import org.eclipse.egf.pattern.production.GeneratedContentHelper;
+import org.eclipse.egf.pattern.production.GeneratedContentProducer;
+import org.eclipse.egf.pattern.production.template.TemplateHelper;
+import org.eclipse.egf.pattern.relations.CallParameter;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+import org.eclipse.egf.pde.EgfPdeActivator;
+import org.eclipse.egf.pde.emf.plugin.command.EmfExtensionFactory;
+import org.eclipse.egf.pde.pattern.plugin.command.PatternConditionExtensionFactory;
+import org.eclipse.egf.pde.pattern.plugin.command.PatternTemplateExtensionFactory;
+import org.eclipse.egf.pde.pattern.reader.PlatformPatternExtensionReader;
+import org.eclipse.egf.pde.pattern.reader.WorkspacePatternExtensionReader;
+import org.eclipse.egf.pde.plugin.command.IPluginChangesCommand;
+import org.eclipse.egf.pde.plugin.command.IPluginChangesCommandRunner;
+import org.eclipse.egf.pde.plugin.manifest.command.ManifestChangeCommandFactory;
+
+
+/**
+ * Load a pattern from its ecore relative path.<br>
+ * Also creates a new one from its name.<br>
+ * After a pattern has been loaded or created, the instance of {@link PatternHandler} used is bound to this pattern.<br>
+ * Should another pattern be loaded/created, a new instance of {@link PatternHandler} would be used.
+ * @author Guillaume Brocard
+ */
+public class PatternHandler {
+
+ /**
+ * Log4j reference logger.
+ */
+ private static final Logger __logger = Logger.getLogger(PatternHandler.class.getPackage().getName());
+
+ /**
+ * Pattern loaded data.
+ */
+ private PatternData _patternData;
+
+ /**
+ * Is pattern opened in edition mode (true) or in consultation one (false) ?
+ */
+ private boolean _editable;
+
+ /**
+ * Constructor. Pattern is in edition mode, if required.
+ */
+ public PatternHandler() {
+ this(true);
+ }
+
+ /**
+ * Constructor.
+ * @param editable_p
+ */
+ public PatternHandler(boolean editable_p) {
+ _editable = editable_p;
+ }
+
+ /**
+ * Get pattern data.
+ * @return
+ */
+ public PatternData getPatternData() {
+ return _patternData;
+ }
+
+ /**
+ * Is pattern handler enabling modifications or not ?
+ * @return
+ */
+ public boolean isEditable() {
+ return _editable;
+ }
+
+ /**
+ * Set ecore file relative path.
+ * @param fileRelativePath_p Ecore relative path, must be composed of the plug-in id (preceded by a '/') followed by the path in this plug-in.<br>
+ * For instance <i>/org.eclipse.egf.pattern.g2/model/pattern.g2.ecore</i> is a correct entry.<br>
+ * Setting a new value does require that {@link #load()} be called to get the content of {@link PatternData} updated.
+ * @throws IllegalArgumentException if given relative path is null.
+ */
+ public void setFileRelativePath(String fileRelativePath_p) throws Exception {
+ // Illegal argument exception.
+ if (fileRelativePath_p == null) {
+ throw new IllegalArgumentException("Null file relative path !"); //$NON-NLS-1$
+ }
+ // If pattern data does not exist yet, create it.
+ if (_patternData == null) {
+ _patternData = new PatternData();
+ }
+ // Set relative path name.
+ _patternData._fileRelativePath = fileRelativePath_p;
+ }
+
+ /**
+ * Load pattern structure using previously set ecore path.
+ * @param fileRelativePath_p Ecore relative path, must be composed of the factory component id (preceded by a '/') followed by the path in this factory component.<br>
+ * For instance <i>/factoryComponent.121212423141443.54/model/pattern.g2.ecore</i> is a correct entry.
+ * @return A {@link PatternData} pointing to loaded pattern structure.
+ * @throws Exception
+ */
+ public PatternData load(String fileRelativePath_p) throws Exception {
+ setFileRelativePath(fileRelativePath_p);
+ // Set factory component id.
+ _patternData._fcId = new Path(_patternData._fileRelativePath).segment(0);
+ // Get containing java project.
+ _patternData._javaProject = ProjectHelper.getJavaProject(_patternData.getPluginId());
+ // Get file full URI.
+ URI fileFullUri = FileHelper.getFileFullUri(_patternData.getRealRelativePath());
+ // Unable to get it, return.
+ if (fileFullUri == null) {
+ throw new IllegalArgumentException(
+ "File relative path " //$NON-NLS-1$
+ + _patternData._fileRelativePath
+ + " could not be converted to a full URI" //$NON-NLS-1$
+ );
+ }
+ // Load resource from this path.
+ ResourceSet resourceSet = new ResourceSetImpl();
+ Resource resource = resourceSet.getResource(fileFullUri, true);
+ // First element should be of EPackage type, being the pattern container.
+ EPackage containingPackage = (EPackage) resource.getContents().get(0);
+ // Look for the pattern element, should be lonely.
+ Pattern pattern = (Pattern) containingPackage.getEClassifiers().get(0);
+ _patternData._pattern = pattern;
+ _patternData._patternName = pattern.getName();
+ _patternData._patternLogicalName = pattern.getLogicalName();
+ // Get generate body operation.
+ _patternData._generateOperation = getGenerateOperation(pattern);
+ // Get all super types.
+ List<EClass> superTypes = pattern.getESuperTypes();
+ // Try and find the super types that are patterns and get their IDs.
+ // There should be only one pattern as parent (at the most).
+ _patternData._patternDependenciesIds = new HashSet<String>(0);
+ // Set parent pattern.
+ _patternData._parentPattern = null;
+ for (EClass superType : superTypes) {
+ if (superType instanceof Pattern) {
+ _patternData._parentPattern = (Pattern) superType;
+ String patternId = (String) superType.eGet(PatternPackage.Literals.PATTERN__ID, true);
+ _patternData._patternDependenciesIds.add(patternId);
+ }
+ }
+ // Get production options handler.
+ ProductionOptionsHandler optionsHandler = _patternData.getProductionOptionsHandler();
+ // By default, always compile resulting template (that includes the 'no annotation declared' case).
+ optionsHandler._compileTemplate = true;
+ // By default, always replace standard buffer, so as to enable reporting call-back.
+ optionsHandler._bufferModification = true;
+ // Default relative path is empty.
+ optionsHandler._patternTemplatePath = ICommonConstants.EMPTY_STRING;
+ // Default enablement flag is set to false.
+ // That means no annotation locally defined.
+ optionsHandler._enabled = false;
+ // Then search for the annotation.
+ readProductionContext(pattern, _patternData);
+ // Compute all pattern matching parameters.
+ recomputeAllParameters();
+ // Get public method parameters.
+ recomputeCallParameters();
+ return _patternData;
+ }
+
+ /**
+ * Save current pattern data to pattern model file.<br>
+ * Also update given pattern model with new data.
+ * @param patternModel_p
+ * @param physicalFileRelativePath_p
+ * @return
+ * @throws Exception
+ */
+ public PatternData save(
+ PatternModel patternModel_p,
+ String physicalFileRelativePath_p,
+ String logicalFileRelativePath_p
+ ) throws Exception {
+ if (_patternData == null) {
+ throw new IllegalStateException("No pattern to process."); //$NON-NLS-1$
+ }
+ if (_editable == false) {
+ throw new IllegalStateException("Pattern is in read-only mode !"); //$NON-NLS-1$
+ }
+ // Get pattern to save.
+ Pattern pattern = _patternData.getPattern();
+ // Create a dedicated instance of the annotation handler.
+ AnnotationHandler annotationHandler = new AnnotationHandler();
+ // Change operations annotations.
+ AbstractPatternGenerator.computeOperationsAnnotations(pattern, _patternData.getFactoryComponentId(), annotationHandler);
+ // Proceed with production annotation.
+ handleSaveProductionOptions(pattern, annotationHandler);
+ // Write new content.
+ boolean fileSaved = AbstractPatternGenerator.writePatternModelToFile(pattern, physicalFileRelativePath_p);
+ // File could not be written.
+ if (fileSaved == false) {
+ throw new IllegalStateException("Pattern file can not be modified !"); //$NON-NLS-1$
+ }
+ // Reload pattern data content.
+ PatternData patternData = reloadPatternAndUpdateModel(patternModel_p, logicalFileRelativePath_p);
+ // Do post-save processing.
+ postSave();
+ return patternData;
+ }
+
+ /**
+ * Handle the production options saving behavior.<br>
+ * Default implementation figures out if an annotation should be saved for current pattern or not.
+ * @param pattern_p
+ * @param handler_p
+ */
+ protected void handleSaveProductionOptions(Pattern pattern_p, AnnotationHandler handler_p) {
+ ProductionOptionsHandler productionOptionsHandler = _patternData.getProductionOptionsHandler();
+ if (productionOptionsHandler.isEnabled()) {
+ AbstractPatternGenerator.computeProductionAnnotation(pattern_p, productionOptionsHandler, handler_p);
+ } else {
+ handler_p.removeProductionAnnotation(pattern_p);
+ }
+ }
+
+ /**
+ * Save current pattern data to pattern model file.<br>
+ * Also update given pattern model with new data.
+ * @param patternModel_p
+ * @return
+ * @throws Exception
+ */
+ public PatternData save(PatternModel patternModel_p) throws Exception {
+ return save(patternModel_p, _patternData.getRealRelativePath(), _patternData.getFileRelativePath());
+ }
+
+ /**
+ * Post save processing.
+ */
+ protected void postSave() {
+ // Re-compute condition structures.
+ recomputeConditionStructures();
+ // Add dependencies to external patterns.
+ ensurePluginDependencies();
+ }
+
+ /**
+ * Recompute condition structures, if needed.
+ */
+ public void recomputeConditionStructures() {
+ GeneratedContentProducer producer = new GeneratedContentProducer();
+ try {
+ producer.produceConditionStructures(_patternData);
+ } catch (Exception exception_p) {
+ StringBuilder loggerMessage = new StringBuilder("PatternHandler.recomputeConditionStructures(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ }
+
+ /**
+ * Ensure plug-in dependencies.<br>
+ * This is required at save time since the pattern might be produced.<br>
+ * This takes into account the inheritance dependency and the references ones (against called patterns).
+ */
+ protected void ensurePluginDependencies() {
+ // Resulting collection of required dependencies.
+ Collection<String> pluginIDs = new HashSet<String>(0);
+ // Create root descriptor.
+ GenericDescriptor rootDescriptor = new GenericDescriptor();
+ // Read descriptors from workspace and platform.
+ PatternDescriptorStrategy.retainRootOnly(
+ rootDescriptor,
+ new WorkspacePatternExtensionReader().getPatternLibraries()
+ );
+ PatternDescriptorStrategy.retainRootOnly(
+ rootDescriptor,
+ new PlatformPatternExtensionReader().getPatternLibraries()
+ );
+ final IDescriptor[] searchedDescriptor = new IDescriptor[] { null };
+ final String[] searchedFullId = new String[] { null };
+ // Search for corresponding descriptor.
+ PatternDescriptorStrategy strategy = new PatternDescriptorStrategy() {
+ @Override
+ protected boolean stopSearch(IDescriptor parentDescriptor_p) {
+ return searchedDescriptor[0] != null;
+ }
+ };
+ IPatternDescriptorHandler handler = new IPatternDescriptorHandler() {
+ public void handleDescriptor(IDescriptor descriptor_p) {
+ // Nothing to do here.
+ }
+ public void handleLibraryDescriptor(IDescriptor descriptor_p, String parentLibraryId_p) {
+ if (parentLibraryId_p.equals(searchedFullId[0])) {
+ searchedDescriptor[0] = descriptor_p;
+ }
+ }
+ public void handlePatternDescriptor(IDescriptor descriptor_p, String patternFullId_p) {
+ // Nothing to do here.
+ }
+ };
+ // Search dependencies from root library plug-in container.
+ for (String patternId : _patternData.getPatternDependenciesIds()) {
+ // Get root library id.
+ String rootLibraryId = PatternHelper.getRootLibraryId(patternId);
+ // Initialize searched full id.
+ searchedFullId[0] = rootLibraryId;
+ // Initialize resulting descriptor.
+ searchedDescriptor[0] = null;
+ // Launch search for descriptor.
+ strategy.iterateThroughPatternExtensionDescriptor(handler, rootDescriptor);
+ // Get resulting descriptor.
+ IDescriptor returnedDescriptor = searchedDescriptor[0];
+ if (returnedDescriptor != null) {
+ // Add plug-in id to known dependencies.
+ String pluginId = (String) returnedDescriptor.getValue(IPatternConstants.PATTERN_EXTENSION_CONTAINING_PLUGIN_ID);
+ // Do not add null or self dependency.
+ if (pluginId != null && pluginId.equals(_patternData.getPluginId()) == false) {
+ pluginIDs.add(pluginId);
+ }
+ }
+ }
+ // Then write result to the manifest, if it not already registered.
+ IPluginChangesCommand commandsOnManifest = ManifestChangeCommandFactory.setRequiredPlugins(
+ pluginIDs.toArray(new String[pluginIDs.size()]),
+ false
+ );
+ EgfPdeActivator.getDefault().getPluginChangesCommandRunner().performChangesOnManifest(
+ _patternData.getPluginId(),
+ Collections.singletonList(commandsOnManifest)
+ );
+ }
+
+ /**
+ * Reload pattern data and update pattern model accordingly.
+ * @param patternModel_p
+ * @param fileRelativePath_p
+ * @return
+ * @throws Exception if pattern data could not be reloaded.
+ */
+ protected PatternData reloadPatternAndUpdateModel(PatternModel patternModel_p, String fileRelativePath_p) throws Exception {
+ PatternData result = load(fileRelativePath_p);
+ if (_editable) {
+ updatePatternModel(patternModel_p, result);
+ }
+ return result;
+ }
+
+ /**
+ * Update pattern model with new pattern name, path and id.
+ * @param patternModel_p
+ */
+ protected void updatePatternModel(PatternModel patternModel_p, PatternData patternData_p) {
+ // Preconditions.
+ if (patternData_p == null || patternModel_p == null) {
+ return;
+ }
+ // Set pattern path.
+ patternModel_p.setPath(patternData_p.getFileRelativePath());
+ // Update pattern model through editing domain so as to force modification of the plugin.xml file.
+ EditingDomain editingDomain = EgfUiActivator.getDefault().getEditingDomain();
+ editingDomain.getCommandStack().execute(
+ SetCommand.create(
+ editingDomain,
+ patternModel_p,
+ ModelPackage.Literals.NAMED_MODEL_ELEMENT_WITH_ID__NAME,
+ patternData_p.getPatternLogicalName()
+ )
+ );
+ }
+
+ /**
+ * Create a new pattern out of given pattern model.
+ * @param fcId_p
+ * @param patternModel_p
+ * @return A {@link PatternData} pointing to created pattern structure.
+ * @throws Exception.
+ */
+ public PatternData createPattern(final String fcId_p, final PatternModel patternModel_p) throws Exception {
+ // Preconditions.
+ if (patternModel_p == null || fcId_p == null || _editable == false) {
+ return null;
+ }
+ // If handled pattern data does not exist yet, create it.
+ if (_patternData == null) {
+ _patternData = new PatternData();
+ }
+ // New pattern name.
+ final String name = patternModel_p.getName(); // And id.
+ final String[] id = new String[] { null };
+ // Write model.
+ new AbstractPatternGenerator() {
+ @Override
+ protected void fillPattern(Pattern newPattern_p, AnnotationHandler handler_p, EOperation generate_p) {
+ newPattern_p.setName(GeneratedContentHelper.getPatternClassName(newPattern_p));
+ newPattern_p.setLogicalName(name);
+ newPattern_p.setDescription(
+ MessageFormatHelper.formatMessage(
+ Messages.PatternHandler_AutoGeneratedDescriptionText,
+ new Object[] { name }
+ )
+ );
+ }
+ @Override
+ public String getPatternContainingPluginId() {
+ return FactoryComponentHelper.getPluginId(fcId_p, PlatformLocationType.WORKSPACE_ONLY);
+ }
+ @Override
+ public String getPatternFullId() {
+ id[0] = patternModel_p.getId();
+ // Given pattern model id must be the containing library full id.
+ return id[0];
+ }
+ }.generateEcoreFile();
+ // Get relative path.
+ String fileRelativePath = AbstractPatternGenerator.getPatternModelRelativePath(
+ fcId_p,
+ PatternHelper.deresolveId(id[0]).getValue()
+ );
+ // Then reload it.
+ return reloadPatternAndUpdateModel(patternModel_p, fileRelativePath);
+ }
+
+ /**
+ * Delete the handled pattern.<br>
+ * User is advised to release held pattern data reference, since it is no longer synchronized with the persisted data.
+ */
+ public void delete() {
+ // First of all clean generated structures.
+ cleanGeneratedStructures();
+ // Then clean user templates.
+ String pluginId = _patternData.getPluginId();
+ FileHelper.deleteFolder(TemplateHelper.getPatternTemplatesFolderRelativePaths(_patternData.getPattern().getShortId(), pluginId).getKey());
+ // Update plugin.xml content accordingly.
+ IPluginChangesCommandRunner runner = EgfPdeActivator.getDefault().getPluginChangesCommandRunner();
+ runner.performChangesOnPlugin(
+ pluginId,
+ Collections.singletonList(
+ PatternConditionExtensionFactory.unsetPatternConditionExtension(_patternData.getPattern().getId())
+ )
+ );
+ // Delete condition class.
+ String conditionClassRelativePath = GeneratedContentProducer.getConditionFileRelativePath(_patternData);
+ FileHelper.deleteFile(conditionClassRelativePath);
+ // Finally, delete pattern model.
+ FileHelper.deleteFile(_patternData.getRealRelativePath());
+ // Unload pattern data.
+ _patternData = null;
+ }
+
+ /**
+ * Clean pattern generated structures.<br>
+ * List of deleted items :<br>
+ * <ul>
+ * <li>EMF generated classes (based on the pattern model)</li>
+ * <li>Exported runtime section for these classes</li>
+ * <li>Generated package extension for these classes</li>
+ * <li>Generated templates : pre/post matchings and computed whole template file</li>
+ * <li>Generated template class, if any</li>
+ * <li>Generated pattern extension, if any</li>
+ * </ul>
+ */
+ public void cleanGeneratedStructures() {
+ // Plug-in id.
+ String pluginId = _patternData.getPluginId();
+ // Pattern full id.
+ // Pattern name.
+ String patternName = _patternData.getPatternName();
+ // Command runner.
+ IPluginChangesCommandRunner pluginChangesCommandRunner = EgfPdeActivator.getDefault().getPluginChangesCommandRunner();
+ // First of all, clean generated classes.
+ // Clean generation model.
+ String genModelRelativePath = FileNameHelper.getGenModelPath(new Path(_patternData.getRealRelativePath()));
+ FileHelper.deleteFile(genModelRelativePath);
+ // Clean EMF classes.
+ String rootPackageRelativePath = GeneratedContentHelper.getEMFGeneratedRootFolderRelativePath(_patternData);
+ FileHelper.deleteFolder(rootPackageRelativePath);
+ // Clean the exported runtime section if necessary
+ List<String> packageNames = GeneratedContentHelper.getEMFGeneratedPackagesNames(_patternData);
+ List<IPluginChangesCommand> suppressRuntimePackagesCommand = Collections.singletonList(
+ ManifestChangeCommandFactory.unsetExportedPackages(
+ packageNames.toArray(
+ new String[packageNames.size()]
+ )
+ )
+ );
+ pluginChangesCommandRunner.performChangesOnManifest(
+ pluginId,
+ suppressRuntimePackagesCommand
+ );
+ // Suppress generated package extension.
+ List<IPluginChangesCommand> suppressGeneratedPackageCommand = Collections.singletonList(
+ EmfExtensionFactory.unsetEmfGeneratedPackageExtension(GeneratedContentHelper.getPatternPackageNsURI(_patternData.getPattern()))
+ );
+ pluginChangesCommandRunner.performChangesOnPlugin(pluginId, suppressGeneratedPackageCommand);
+ // Clean generated templates.
+ // Starts with generated template file.
+ String generatedTemplateFilePath = TemplateHelper.getPatternTemplatePath(_patternData);
+ FileHelper.deleteFile(generatedTemplateFilePath);
+ // Then suppress generated templates.
+ FileHelper.deleteFolder(TemplateHelper.getPatternTemplatesFolderRelativePaths(_patternData.getPattern().getShortId(), pluginId).getValue());
+ // Clean template resulting class.
+ String generatedPatternClassRelativePath = GeneratedContentHelper.getGeneratedPatternClassRelativePath(_patternData);
+ if (generatedPatternClassRelativePath != null) {
+ FileHelper.deleteFile(generatedPatternClassRelativePath);
+ }
+ // Suppress generated pattern extension.
+ pluginChangesCommandRunner.performChangesOnPlugin(
+ pluginId,
+ Collections.singletonList(PatternTemplateExtensionFactory.unsetPatternTemplateExtension(_patternData.getPattern().getShortId()))
+ );
+ // Remove parameters handler class.
+ String generatedParametersHandlerClassRelativePath = GeneratedContentProducer.getGeneratedClassRelativePath(
+ pluginId,
+ PatternConstants.GENERATION_SOURCE_FOLDER,
+ PatternConstants.PATTERN_GENERATED_BASE_PACKAGE,
+ GeneratedContentProducer.getClassName(
+ patternName,
+ PatternConstants.CLASS_PARAMETERS_HANDLER_SUFFIX
+ )
+ );
+ FileHelper.deleteFile(generatedParametersHandlerClassRelativePath);
+ // Remove exported package.
+ pluginChangesCommandRunner.performChangesOnManifest(
+ pluginId,
+ Collections.singletonList(
+ ManifestChangeCommandFactory.unsetExportedPackages(
+ new String[] {
+ PatternConstants.PATTERN_GENERATED_BASE_PACKAGE
+ }
+ )
+ )
+ );
+ }
+
+ /**
+ * Read production context, looking for both given pattern and its parents (patterns).
+ * @param pattern_p
+ * @param patternData_p
+ * @return
+ */
+ protected boolean readProductionContext(Pattern pattern_p, PatternData patternData_p) {
+ boolean result = false;
+ // Precondition.
+ if (pattern_p == null) {
+ return result;
+ }
+ // Search for given pattern.
+ EAnnotation productionAnnotation = pattern_p.getEAnnotation(AnnotationHandler.PATTERN_PRODUCTION_ANNOTATION_SOURCE);
+ result = productionAnnotation != null;
+ if (result) {
+ // Get production options handler.
+ ProductionOptionsHandler optionsHandler = patternData_p.getProductionOptionsHandler();
+ // Set activation flag.
+ optionsHandler._enabled = (pattern_p == patternData_p.getPattern());
+ // Get annotation details.
+ EMap<String, String> details = productionAnnotation.getDetails();
+ // Compilation flag.
+ String compileString = details.get(AnnotationHandler.PATTERN_PRODUCTION_ANNOTATION_BODY_COMPILATION);
+ // Tested against null because null would return a false boolean, where true should be used.
+ if (compileString != null) {
+ optionsHandler._compileTemplate = Boolean.valueOf(compileString).booleanValue();
+ }
+ // Buffer modification flag.
+ String modifyBuffer = details.get(AnnotationHandler.PATTERN_PRODUCTION_ANNOTATION_BODY_BUFFER_MODIFICATION);
+ if (modifyBuffer != null) {
+ optionsHandler._bufferModification = Boolean.valueOf(modifyBuffer).booleanValue();
+ }
+ // Template path.
+ String path = details.get(AnnotationHandler.PATTERN_PRODUCTION_ANNOTATION_BODY_PATH);
+ if (path != null) {
+ optionsHandler._patternTemplatePath = path;
+ }
+ } else {
+ // Get parent types.
+ List<EClass> parentTypes = pattern_p.getESuperTypes();
+ if (parentTypes.isEmpty() == false) {
+ // Try and find pattern parents.
+ for (Iterator<EClass> parents = parentTypes.iterator(); parents.hasNext() && result == false;) {
+ EClass parent = parents.next();
+ if (parent instanceof Pattern) {
+ result = readProductionContext((Pattern) parent, patternData_p);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get all pattern matching parameters for given pattern.<br>
+ * Includes all first-level and inherited parameters.<br>
+ * Parent parameters are presented first, from the farthest to the nearest.<br>
+ * Thus given pattern parameters appear at the end of resulting list.
+ * @param pattern_p
+ * @return A not null list of {@link ParameterRelation}. Can still be empty.
+ */
+ protected List<ParameterRelation> getAllParameters(Pattern pattern_p) {
+ List<ParameterRelation> result = null;
+ // Precondition.
+ if (pattern_p == null) {
+ result = Collections.emptyList();
+ }
+ // Initiate search.
+ result = new ArrayList<ParameterRelation>(pattern_p.getParameters().size());
+ // Get parent types.
+ List<EClass> parentTypes = pattern_p.getESuperTypes();
+ if (parentTypes.isEmpty() == false) {
+ // Try and find pattern parents.
+ for (EClass parent : parentTypes) {
+ if (parent instanceof Pattern) {
+ // Add their parameters first.
+ List<ParameterRelation> parentResult = getAllParameters((Pattern) parent);
+ result.addAll(parentResult);
+ }
+ }
+ }
+ // Add first-level parameters too.
+ result.addAll(pattern_p.getParameters());
+ return result;
+ }
+
+ /**
+ * Get all public method parameters for given pattern.<br>
+ * Includes at least all first-level parameters.
+ * @param pattern_p
+ * @return A not null list of {@link CallParameter}. Can nevertheless be empty.
+ */
+ protected List<CallParameter> getCallParameters(Pattern pattern_p) {
+ List<CallParameter> result = null;
+ // Precondition.
+ if (pattern_p == null) {
+ result = Collections.emptyList();
+ }
+ // Initiate search.
+ EList<CallParameter> callParameters = pattern_p.getCallParameters();
+ result = new ArrayList<CallParameter>(callParameters.size());
+ // For now, simply add current level parameters.
+ result.addAll(callParameters);
+ return result;
+ }
+
+ /**
+ * Recompute all pattern matching parameters.<br>
+ * As a result, contained pattern data is modified.
+ * @return
+ */
+ public List<ParameterRelation> recomputeAllParameters() {
+ _patternData._parameters = getAllParameters(_patternData.getPattern());
+ return _patternData._parameters;
+ }
+
+ /**
+ * Recompute all public method parameters.<br>
+ * As a result, contained pattern data is modified.
+ * @return
+ */
+ public List<CallParameter> recomputeCallParameters() {
+ _patternData._callParameters = getCallParameters(_patternData.getPattern());
+ return _patternData._callParameters;
+ }
+
+ /**
+ * Get user modifiable generate operation.
+ * @param pattern_p
+ * @return
+ */
+ protected EOperation getGenerateOperation(Pattern pattern_p) {
+ EOperation result = null;
+ // Precondition.
+ if (pattern_p == null) {
+ return result;
+ }
+ List<EOperation> operationsList = pattern_p.getEOperations();
+ for (Iterator<EOperation> operations = operationsList.iterator(); operations.hasNext() && result == null;) {
+ EOperation currentOperation = operations.next();
+ if (PatternConstants.GENERATE_METHOD_NAME.equals(currentOperation.getName())) {
+ result = currentOperation;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Pattern data.<br>
+ * Provides with different pieces of information for locating the pattern file and details about its content.
+ */
+ public class PatternData {
+
+ /**
+ * Ecore file relative path. It is composed of the factory component id containing the pattern, plus the path inside the factory component to the ecore file.
+ */
+ protected String _fileRelativePath;
+
+ /**
+ * The containing factory component id.
+ */
+ protected String _fcId;
+
+ /**
+ * Java project containing the pattern.<br>
+ * Null means pattern has already been deployed.
+ */
+ protected IJavaProject _javaProject;
+
+ /**
+ * Pattern reference as object loaded from the ecore file.<br>
+ * Does not stand for the generated one.
+ */
+ protected Pattern _pattern;
+
+ /**
+ * Pattern name.
+ */
+ protected String _patternName;
+
+ /**
+ * Pattern logical name.
+ */
+ protected String _patternLogicalName;
+
+ /**
+ * Set of parent patterns full ids.
+ */
+ protected Set<String> _patternDependenciesIds;
+
+ /**
+ * All pattern matching parameters, including parents ones.
+ */
+ protected List<ParameterRelation> _parameters;
+
+ /**
+ * Public method parameters.
+ */
+ protected List<CallParameter> _callParameters;
+
+ /**
+ * Generate operation.
+ */
+ protected EOperation _generateOperation;
+
+ /**
+ * Parent pattern, if any.
+ */
+ protected Pattern _parentPattern;
+
+ /**
+ * Production options handler.
+ */
+ protected ProductionOptionsHandler _productionOptionsHandler;
+
+ /**
+ * Get generate operation.
+ * @return
+ */
+ public EOperation getGenerateOperation() {
+ return _generateOperation;
+ }
+
+ /**
+ * Get real pattern model file relative path, based on factory component id to plug-in id resolution mechanism.
+ * @return
+ */
+ public String getRealRelativePath() {
+ return TemplateHelper.getPhysicalRelativePath(_fileRelativePath, getPluginId());
+ }
+
+ /**
+ * @return the fileRelativePath
+ */
+ public String getFileRelativePath() {
+ return _fileRelativePath;
+ }
+
+ /**
+ * @return the pluginId
+ */
+ public String getPluginId() {
+ // Resolve plug-in id from factory component one.
+ String result = FactoryComponentHelper.getPluginId(
+ _fcId,
+ PlatformLocationType.WORKSPACE_THEN_TARGET_PLATFORM
+ );
+ // Could not find plug-in from factory component one.
+ // Return factory component id, hoping that it is in fact a plug-in id that has not been migrated.
+ if (result == null) {
+ result = _fcId;
+ }
+ return result;
+ }
+
+ /**
+ * Get factory component id.
+ * @return
+ */
+ public String getFactoryComponentId() {
+ return _fcId;
+ }
+
+ /**
+ * @return the javaProject
+ */
+ public IJavaProject getJavaProject() {
+ return _javaProject;
+ }
+
+ /**
+ * @return the pattern
+ */
+ public Pattern getPattern() {
+ return _pattern;
+ }
+
+ /**
+ * @return the patternName
+ */
+ public String getPatternName() {
+ return _patternName;
+ }
+
+ /**
+ * @return the patternLogicalName
+ */
+ public String getPatternLogicalName() {
+ return _patternLogicalName;
+ }
+
+ /**
+ * @set the patternLogicalName
+ */
+ public void setPatternLogicalName(String patternLogicalName_p) {
+ _patternLogicalName = patternLogicalName_p;
+ }
+
+ /**
+ * @return the patternDependenciesIds
+ */
+ public Set<String> getPatternDependenciesIds() {
+ return _patternDependenciesIds;
+ }
+
+ /**
+ * Get production options handler.
+ * @return
+ */
+ public ProductionOptionsHandler getProductionOptionsHandler() {
+ if (_productionOptionsHandler == null) {
+ _productionOptionsHandler = new ProductionOptionsHandler();
+ }
+ return _productionOptionsHandler;
+ }
+
+ /**
+ * Get all pattern matching parameters, including parents ones, starting from farthest (higher parent) to closest (current pattern) parameters.
+ * @return the parameters
+ */
+ public List<ParameterRelation> getAllParameters() {
+ return _parameters;
+ }
+
+ /**
+ * Get all public method parameters, also stated as 'Call parameters'.<br>
+ * @return
+ */
+ public List<CallParameter> getCallParameters() {
+ return _callParameters;
+ }
+
+ /**
+ * Get parent pattern.
+ * @return the parentPattern
+ */
+ public Pattern getParentPattern() {
+ return _parentPattern;
+ }
+
+ /**
+ * Clean generated structures.<br>
+ * This is a convenient method for fixing inheritance error bug in 1.2.0_M4.<br>
+ * There should not be such method in {@link PatternData}.<br>
+ * TODO Guillaume. Remove this method from 1.2.0_M5 release and replace it with an access to pattern handlers in pattern producer.
+ */
+ public void cleanGeneratedStructures() {
+ PatternHandler.this.cleanGeneratedStructures();
+ }
+
+ }
+
+ /**
+ * Production options handler.
+ */
+ public class ProductionOptionsHandler {
+
+ /**
+ * Pattern template path, if default behavior is to be overridden.
+ */
+ protected String _patternTemplatePath;
+
+ /**
+ * Should resulting template file be compiled ?
+ */
+ protected boolean _compileTemplate;
+
+ /**
+ * Should buffers be modified, as opposed to using the default declaration.
+ */
+ protected boolean _bufferModification;
+
+ /**
+ * Are options enabled (true) or not (false) ?<br>
+ * If false, the pattern annotation will be destroyed at next save time.
+ */
+ protected boolean _enabled;
+
+ /**
+ * @return the patternTemplatePath
+ */
+ public String getPatternTemplatePath() {
+ return _patternTemplatePath;
+ }
+
+ /**
+ * Set pattern template production relative path.<br>
+ * If set to a not null, non-empty value, then default pattern production behavior is overridden.<br>
+ * The template is no longer produced in <b>templates/generated</b> folder, but in <b>templates/<code>patternTemplatePath_p</code></b> instead. Set again to
+ * null or {@link ICommonConstants#EMPTY_STRING} if default behavior must be restored.
+ * @param patternTemplatePath_p
+ */
+ public void setPatternTemplatePath(String patternTemplatePath_p) {
+ _patternTemplatePath = patternTemplatePath_p;
+ }
+
+ /**
+ * @return the compileTemplate
+ */
+ public boolean shouldCompileTemplate() {
+ return _compileTemplate;
+ }
+
+ /**
+ * Set compile template flag to given one.<br>
+ * If set to true (the default value), then the pattern template is compiled into a Java class.<br>
+ * If set to false, the pattern template file is assembled, but not compiled into a Java class.
+ * @param compile_p
+ */
+ public void setCompileTemplateTo(boolean compile_p) {
+ _compileTemplate = compile_p;
+ }
+
+ /**
+ * Should template buffer be modified (true), including replacement, or should standard way be used (false) ?
+ * @return
+ */
+ public boolean shouldModifyBuffer() {
+ return _bufferModification;
+ }
+
+ /**
+ * Set modify buffer flag to given one.<br>
+ * The buffer modification is required for pattern reporting at runtime.<br>
+ * If set to true (the default value), then the reporting of generation at runtime is active.<br>
+ * If set to false, the default JET behavior is left untouched. That is compatible with EMF-like patterns, but no longer with Pattern Runner execution.
+ * Indeed, EMF-like patterns are expecting JET to behave standardly (and have no use of Pattern Runner as the execution environment).
+ * @param modifyBuffer_p
+ */
+ public void setModifyBufferTo(boolean modifyBuffer_p) {
+ _bufferModification = modifyBuffer_p;
+ }
+
+ /**
+ * Are options locally enabled ?
+ * @return
+ */
+ public boolean isEnabled() {
+ return _enabled;
+ }
+
+ /**
+ * Set options enablement to given value.
+ * @param enabled_p
+ */
+ public void setEnabled(boolean enabled_p) {
+ _enabled = enabled_p;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternSeeker.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternSeeker.java
new file mode 100644
index 0000000..4ff26b6
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/PatternSeeker.java
@@ -0,0 +1,278 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.common.helper.PatternLibrarySequenceHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pde.pattern.reader.IPatternExtensionReader;
+import org.eclipse.egf.pde.pattern.reader.PlatformPatternExtensionReader;
+import org.eclipse.egf.pde.pattern.reader.WorkspacePatternExtensionReader;
+
+
+/**
+ * A pattern seeker that takes a full id as parameter and is able to retrieve all corresponding patterns.<br>
+ * The full id can either be the id of a library or the id of a single pattern.
+ * @author Guillaume Brocard
+ */
+public class PatternSeeker {
+
+ /**
+ * Log4j reference logger.
+ */
+ private static final Logger __logger = Logger.getLogger(PatternSeeker.class.getPackage().getName());
+
+ /**
+ * Pattern extension readers.
+ */
+ private List<IPatternExtensionReader> _readers;
+
+ /**
+ * Constructor.
+ * @param searchInWorkspace_p Should extensions be read in workspace too ?
+ */
+ public PatternSeeker(boolean searchInWorkspace_p) {
+ _readers = new ArrayList<IPatternExtensionReader>(1);
+ if (searchInWorkspace_p) {
+ _readers.add(new WorkspacePatternExtensionReader());
+ }
+ _readers.add(new PlatformPatternExtensionReader());
+ }
+
+ /**
+ * Get patterns from full id.<br>
+ * @param fullId_p The full id is composed of the chain of containing libraries and optionally the pattern id, separated by the <i>#</i> character.<br>
+ * E.g :
+ * <ul>
+ * <li> <i>HelloWorld.Library1#Library2#Pattern1</i><br>
+ * In this case, only Pattern1 will be produced.
+ * <li> <i>HelloWorld.Library1#Library2</i><br>
+ * In this one, the whole library Library2 will be produced, according to its orchestration class.
+ * </ul>
+ * @return not null, may be empty if no pattern to produce could be found.
+ */
+ public List<PatternData> getPatternsData(String fullId_p) {
+ // Create resulting list.
+ List<PatternData> result = new ArrayList<PatternData>(0);
+ // Search for corresponding patterns.
+ getPatternsData(fullId_p, fullId_p, null, result);
+ return result;
+ }
+
+ /**
+ * Get root library from its id.
+ * @param libraryId_p
+ * @return
+ */
+ protected IDescriptor getRootLibraryFromId(String libraryId_p) {
+ IDescriptor result = null;
+ // Iterate over declared possible readers.
+ for (Iterator<IPatternExtensionReader> readers = _readers.iterator(); readers.hasNext() && result == null;) {
+ result = readers.next().getPatternLibrary(libraryId_p);
+ }
+ return result;
+ }
+
+ /**
+ * Get children libraries of given one.
+ * @param parentLibrary_p
+ * @return
+ */
+ protected List<IDescriptor> getChildrenLibraries(IDescriptor parentLibrary_p) {
+ // All children.
+ List<IDescriptor> children = parentLibrary_p.getChildren();
+ List<IDescriptor> result = new ArrayList<IDescriptor>(children.size());
+ // Keep only those that have the 'library' type set.
+ for (IDescriptor descriptor : children) {
+ if (IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_LIBRARY.equals(descriptor.getValue(IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_TYPE))) {
+ result.add(descriptor);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get patterns data from given full id.
+ * @param fullId_p The original full id.
+ * @param partialId_p The partial id, as required by the search step.
+ * @param library_p The extension point element representing a library at given search step.
+ * @param data_p Resulting list of patterns data (to produce).
+ */
+ protected void getPatternsData(String fullId_p, String partialId_p, IDescriptor library_p, List<PatternData> data_p) {
+ // Precondition.
+ if (partialId_p == null) {
+ return;
+ }
+ // Search libraries/patterns separator in pattern id.
+ int separatorPosition = partialId_p.indexOf(IPatternConstants.LIBRARY_PATTERN_ID_SEPARATOR);
+ // Check that path is composed of one library at least.
+ if (separatorPosition > 0) {
+ // There is still work to do before reaching the end-of-chain library.
+ String libraryId = partialId_p.substring(0, separatorPosition);
+ IDescriptor library = null;
+ if (library_p == null) {
+ // No parent library, look for first one.
+ library = getRootLibraryFromId(libraryId);
+ } else {
+ // Look for children libraries.
+ List<IDescriptor> libraries = getChildrenLibraries(library_p);
+ for (Iterator<IDescriptor> librariesIterator = libraries.iterator(); librariesIterator.hasNext() && library == null;) {
+ IDescriptor currentLibrary = librariesIterator.next();
+ // Got the one !
+ if (libraryId.equals(currentLibrary.getValue(ExtensionPointHelper.ATT_ID))) {
+ library = currentLibrary;
+ }
+ }
+ }
+ // Go on with this selected level of library.
+ if (library != null) {
+ getPatternsData(
+ fullId_p,
+ partialId_p.substring(separatorPosition + 1, partialId_p.length()),
+ library,
+ data_p
+ );
+ }
+ } else if (library_p != null) {
+ // At this point, the parent library is reached.
+ // It contains either the library or the pattern to produce.
+ doGetPatternPaths(partialId_p, library_p, data_p);
+ } else {
+ // No parent library, asking for root library production
+ // (indeed a pattern is contained in one and only one library).
+ IDescriptor library = getRootLibraryFromId(fullId_p);
+ resolveLibraryData(library, data_p);
+ }
+ }
+
+ /**
+ * Do retrieved all patterns data from reached library.
+ * @param partialId_p Either a library or pattern id.
+ * @param library_p Reached parent library.
+ * @param data_p Resulting patterns data list.
+ */
+ protected void doGetPatternPaths(String partialId_p, IDescriptor library_p, List<PatternData> data_p) {
+ // Look for a child element that is identified by the given partial id.
+ List<IDescriptor> children = library_p.getChildren();
+ // Search among existing children.
+ for (Iterator<IDescriptor> descriptors = children.iterator(); descriptors.hasNext();) {
+ IDescriptor currentElement = descriptors.next();
+ if (partialId_p.equals(currentElement.getValue(ExtensionPointHelper.ATT_ID))) {
+ String descriptorType = (String) currentElement.getValue(IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_TYPE);
+ if (IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_LIBRARY.equals(descriptorType)) {
+ // Found library to produce, add its patterns data.
+ resolveLibraryData(currentElement, data_p);
+ } else {
+ // Found pattern to produce, add its path.
+ PatternData patternData = resolvePatternData(currentElement);
+ if (patternData != null) {
+ data_p.add(patternData);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Resolve library patterns data that should be produced.
+ * @param library_p
+ * @param data_p
+ */
+ protected void resolveLibraryData(IDescriptor library_p, List<PatternData> data_p) {
+ // The containing library is reached, look for its patterns.
+ // First of all, try and use the orchestration string as a list of patterns/libraries to produce.
+ String orchestrationString = (String) library_p.getValue(IPatternConstants.LIBRARY_PRODUCTION_ORCHESTRATION_ATTRIBUTE_NAME);
+ String[] ids = null;
+ if (orchestrationString != null) {
+ ids = StringHelper.getTokens(orchestrationString, PatternLibrarySequenceHelper.SEQUENCE_SEPARATORS);
+ }
+ // Get library elements.
+ List<IDescriptor> elements = library_p.getChildren();
+ // Cycle through the ids.
+ Map<String, IDescriptor> elementsFromId = null;
+ if (ids != null) {
+ // First, create the map of (id, configuration element) that will be used while searching by ids.
+ elementsFromId = new HashMap<String, IDescriptor>(elements.size());
+ for (IDescriptor element : elements) {
+ elementsFromId.put((String) element.getValue(ExtensionPointHelper.ATT_ID), element);
+ }
+ // Then do return pattern paths, according to orchestration ids.
+ for (String currentId : ids) {
+ // Get element from id, according to the orchestration schema.
+ IDescriptor currentElement = elementsFromId.get(currentId);
+ // Do resolve paths.
+ doResolveLibraryData(currentElement, data_p);
+ }
+ } else { // No orchestration defined, simply cycle through existing child elements in declaration order.
+ for (IDescriptor element : elements) {
+ // Do resolve paths.
+ doResolveLibraryData(element, data_p);
+ }
+ }
+ }
+
+ /**
+ * Do resolve given library child data.
+ * @param libraryChild_p
+ * @param data_p
+ */
+ protected void doResolveLibraryData(IDescriptor libraryChild_p, List<PatternData> data_p) {
+ if (libraryChild_p == null || data_p == null) {
+ return;
+ }
+ // The child element is a library itself, resolve as a library then.
+ String childType = (String) libraryChild_p.getValue(IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_TYPE);
+ if (IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_LIBRARY.equals(childType)) {
+ resolveLibraryData(libraryChild_p, data_p);
+ } else { // The child element is a pattern, add its data to the resulting list.
+ PatternData patternData = resolvePatternData(libraryChild_p);
+ if (patternData != null) {
+ data_p.add(patternData);
+ }
+ }
+ }
+
+ /**
+ * Resolve pattern data from its descriptor.
+ * @param pattern_p
+ * @return
+ */
+ protected PatternData resolvePatternData(IDescriptor pattern_p) {
+ // Create corresponding pattern structure.
+ PatternData result = null;
+ // Get file path.
+ String fileDeclaredPath = (String) pattern_p.getValue(IPatternConstants.PATTERN_MODEL_ATTRIBUTE_NAME);
+ // Could not retrieve ecore relative path, return null.
+ if (fileDeclaredPath == null) {
+ return result;
+ }
+ // Try and load pattern model.
+ try {
+ result = new PatternHandler().load(fileDeclaredPath);
+ } catch (Exception exception_p) {
+ StringBuilder loggerMessage = new StringBuilder("PatternProducer.resolvePatternData(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/AbstractPatternCondition.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/AbstractPatternCondition.java
new file mode 100644
index 0000000..a635cca
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/AbstractPatternCondition.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore.condition;
+
+import org.eclipse.egf.core.context.ProductionContext;
+
+/**
+ * A default root implementation that provides a context to the condition class real implementation.
+ * @author Guillaume Brocard
+ */
+public abstract class AbstractPatternCondition implements IPatternCondition {
+
+ /**
+ * The production context reference.
+ */
+ private ProductionContext _context;
+
+ /**
+ * @see org.eclipse.egf.pattern.ecore.condition.IPatternCondition#setContext(org.eclipse.egf.core.context.ProductionContext)
+ */
+ public void setContext(ProductionContext context_p) {
+ _context = context_p;
+ }
+
+ /**
+ * Get available production context.
+ * @return <code>null</code> if none is available.
+ */
+ protected ProductionContext getContext() {
+ return _context;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/ConditionClassOutput.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/ConditionClassOutput.java
new file mode 100644
index 0000000..ac98fb6
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/ConditionClassOutput.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore.condition;
+
+/**
+ * Container for the generated output.
+ * @author Guillaume Brocard
+ */
+public class ConditionClassOutput {
+
+ /**
+ * Shared instance.
+ */
+ private static ConditionClassOutput __shared;
+
+ /**
+ * Generated condition class content.
+ */
+ private String _generatedConditionClassContent;
+
+ /**
+ * Pattern that should own the result.
+ */
+ private String _patternFullId;
+
+ /**
+ * Constructor.
+ */
+ private ConditionClassOutput() {
+ __shared = this;
+ }
+
+ /**
+ * Get shared instance at the time of calling.
+ * @return
+ */
+ public static ConditionClassOutput getSharedInstance() {
+ if (null == __shared) {
+ __shared = new ConditionClassOutput();
+ }
+ return __shared;
+ }
+
+ /**
+ * Reset stored values.
+ */
+ public void reset() {
+ _generatedConditionClassContent = null;
+ _patternFullId = null;
+ }
+
+ /**
+ * Get generated condition class content.
+ * @param patternFullId_p Identified owner of the result.
+ * @return null if there is no result for identified pattern.
+ */
+ public String getGeneratedConditionClassContent(String patternFullId_p) {
+ if (patternFullId_p == null || patternFullId_p.equals(_patternFullId) == false) {
+ return null;
+ }
+ return _generatedConditionClassContent;
+ }
+
+ /**
+ * Set generated condition class content for identified pattern.
+ * @param generatedConditionClassContent_p
+ * @param patternFullId_p
+ */
+ public void setGeneratedConditionClassContent(String generatedConditionClassContent_p, String patternFullId_p) {
+ _patternFullId = patternFullId_p;
+ _generatedConditionClassContent = generatedConditionClassContent_p;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/GeneratedConditionProducer.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/GeneratedConditionProducer.java
new file mode 100644
index 0000000..9071a84
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/GeneratedConditionProducer.java
@@ -0,0 +1,210 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore.condition;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.helper.EcoreHelper;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.production.GeneratedContentProducer;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+import org.eclipse.emf.ecore.EPackage;
+
+
+/**
+ * @author Guillaume Brocard
+ */
+public class GeneratedConditionProducer {
+
+ /**
+ * Check real implementation default code.
+ */
+ protected static final String CHECK_METHOD_IMPL_DEFAULT_IMPL =
+ ") {\n" //$NON-NLS-1$
+ + IConditionConstants.USER_CODE_BEGINNING_DELIMITER
+ + "\nreturn true;\n" //$NON-NLS-1$
+ + IConditionConstants.USER_CODE_END_DELIMITER
+ + "\n}\n}"; //$NON-NLS-1$
+
+ /**
+ * Check real implementation signature prefix.
+ */
+ protected static final String CHECK_METHOD_IMPL_SIGNATURE_PREFIX = "protected boolean check("; //$NON-NLS-1$
+
+ /**
+ * Check real implementation default comments.
+ */
+ protected static final String CHECK_METHOD_IMPL_DEFAULT_COMMENTS =
+ "/**\n* Check method user implementation.<br>\n* User must implement and comment between delimiters only !\n* Public signature and comments are lost when a merge is performed.\n* " //$NON-NLS-1$
+ + IConditionConstants.UNMODIFIABLE_ANNOTATION_TAG
+ + "\n*/\n"; //$NON-NLS-1$
+
+ /**
+ * Array access to parameter number N prefix.
+ */
+ protected static final String PARAMETER_N_PREFIX = "parameters_p["; //$NON-NLS-1$
+
+ /**
+ * End of generic check method code.
+ */
+ protected static final String GENERIC_CHECK_METHOD_END = ");\n}\n\n"; //$NON-NLS-1$
+
+ /**
+ * Call to check method prefix.
+ */
+ protected static final String CHECK_METHOD_CALL_PREFIX = "return check("; //$NON-NLS-1$
+
+ /**
+ * Generic check method comments.
+ */
+ protected static final String GENERIC_CHECK_METHOD_COMMENTS =
+ "/**\n* Generated check method.<br>\n* User should left this code untouched for it is lost when a merge is performed.\n* " //$NON-NLS-1$
+ + IConditionConstants.UNMODIFIABLE_ANNOTATION_TAG
+ + "\n*/\n";//$NON-NLS-1$
+
+ /**
+ * Generic check method signature.
+ */
+ protected static final String GENERIC_CHECK_METHOD_SIGNATURE =
+ "public boolean check(Object... parameters_p) {\n"; //$NON-NLS-1$
+
+ /**
+ * Default implementation for generated condition class.
+ */
+ protected static final String DEFAULT_CONDITION_IMPLEMENTATION =
+ " extends " //$NON-NLS-1$
+ + AbstractPatternCondition.class.getSimpleName()
+ + " {\n"; //$NON-NLS-1$
+
+ /**
+ * Class comments.
+ */
+ protected static final String CLASS_COMMENTS =
+ "/**\n*Condition class implementation.\n*A merge occurs each time the corresponding pattern parameters are changed.\n*Both check methods are subject to merge (see associated comments).\n*Any other method is left untouched as a result of the merging operation.\n*/\n"; //$NON-NLS-1$
+
+ /**
+ * Class declaration prefix.
+ */
+ protected static final String CLASS_DECLARATION_PREFIX = "public class "; //$NON-NLS-1$
+
+ /**
+ * Default import for an implementation of a condition class.
+ */
+ protected static final String DEFAULT_CONDITION_IMPORT =
+ AbstractPatternCondition.class.getName()
+ + ";\n\n"; //$NON-NLS-1$
+
+ /**
+ * Import directive prefix.
+ */
+ protected static final String IMPORT_DIRECTIVE_PREFIX = "import "; //$NON-NLS-1$
+
+ /**
+ * Import suffix.
+ */
+ protected static final String IMPORT_DIRECTIVE_SUFFIX = ";\n"; //$NON-NLS-1$
+
+ /**
+ * Package declaration prefix.
+ */
+ protected static final String PACKAGE_DECLARATION_PREFIX = "package "; //$NON-NLS-1$
+
+ /**
+ * ']' character.
+ */
+ protected static final char SQUARE_BRACKET_CLOSING_CHARACTER = ']';
+
+ /**
+ * Get condition class expected content, without the already existing user code.<br>
+ * This is the condition class as it should be by default for current pattern content.
+ * @param patternData_p
+ * @param parameters_p
+ * @return
+ */
+ public static String getNewConditionClassDefaultContent(PatternData patternData_p, List<ParameterRelation> parameters_p) {
+ StringBuilder result = new StringBuilder();
+ // Add package declaration.
+ result
+ .append(PACKAGE_DECLARATION_PREFIX)
+ .append(PatternConstants.PATTERN_CONDITION_GENERATED_BASE_PACKAGE);
+ result
+ .append(ICommonConstants.SEMICOLON_CHARACTER)
+ .append(ICommonConstants.EOL_CHARACTER)
+ .append(ICommonConstants.EOL_CHARACTER);
+ // Add imports for all parameters.
+ for (ParameterRelation parameterRelation : parameters_p) {
+ EPackage parameterPackage = parameterRelation.getType().getEPackage();
+ String packageImportedName = EcoreHelper.getImportedPackageName(parameterPackage);
+ if (packageImportedName != null) {
+ // Append import directive.
+ result
+ .append(IMPORT_DIRECTIVE_PREFIX)
+ .append(packageImportedName)
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(parameterRelation.getType().getName())
+ .append(IMPORT_DIRECTIVE_SUFFIX);
+ }
+ }
+ result.append(ICommonConstants.EOL_CHARACTER);
+ // Import parent interface/class.
+ result
+ .append(IMPORT_DIRECTIVE_PREFIX)
+ .append(DEFAULT_CONDITION_IMPORT);
+ // Add class declaration.
+ String className = GeneratedContentProducer.getConditionClassName(patternData_p);
+ result.append(CLASS_COMMENTS);
+ result
+ .append(CLASS_DECLARATION_PREFIX)
+ .append(className)
+ .append(DEFAULT_CONDITION_IMPLEMENTATION);
+ // Add generic check method declaration.
+ result.append(GENERIC_CHECK_METHOD_COMMENTS);
+ result.append(GENERIC_CHECK_METHOD_SIGNATURE);
+ result.append(CHECK_METHOD_CALL_PREFIX);
+ // Parameter position.
+ int i = 0;
+ // True implementation signature.
+ StringBuilder realImplSignature = new StringBuilder();
+ for (Iterator<ParameterRelation> parameters = parameters_p.iterator(); parameters.hasNext(); i++) {
+ ParameterRelation param = parameters.next();
+ String paramTypeName = param.getType().getName();
+ result
+ .append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER)
+ .append(paramTypeName)
+ .append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER);
+ result
+ .append(PARAMETER_N_PREFIX)
+ .append(i)
+ .append(SQUARE_BRACKET_CLOSING_CHARACTER);
+ realImplSignature
+ .append(paramTypeName)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(param.getName());
+ if (parameters.hasNext()) {
+ result.append(ICommonConstants.COMMA_CHARACTER);
+ realImplSignature.append(ICommonConstants.COMMA_CHARACTER);
+ }
+ }
+ // Add generic check method end declaration.
+ result.append(GENERIC_CHECK_METHOD_END);
+ // Add real check implementation declaration.
+ result.append(CHECK_METHOD_IMPL_DEFAULT_COMMENTS);
+ result
+ .append(CHECK_METHOD_IMPL_SIGNATURE_PREFIX)
+ .append(realImplSignature.toString())
+ .append(CHECK_METHOD_IMPL_DEFAULT_IMPL);
+ return result.toString();
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/IConditionConstants.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/IConditionConstants.java
new file mode 100644
index 0000000..dc464c7
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/IConditionConstants.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore.condition;
+
+/**
+ * Condition producer and contributors shared constants.
+ * @author Guillaume Brocard
+ */
+public interface IConditionConstants {
+
+ /**
+ * Condition class name suffix.
+ */
+ public static final String CONDITION_CLASS_NAME_SUFFIX = "Condition"; //$NON-NLS-1$
+
+ /**
+ * Delimiter that marks the beginning of a not generated code block.
+ */
+ public static final String USER_CODE_BEGINNING_DELIMITER = "// begin-user-code"; //$NON-NLS-1$
+
+ /**
+ * Delimiter that marks the end of a not generated code block.
+ */
+ public static final String USER_CODE_END_DELIMITER = "// end-user-code"; //$NON-NLS-1$
+
+ /**
+ * Annotation constant <code>@unmodifiable</code> used to mark methods that are generated and not modifiable by developer except in a specific block delimited by
+ * {@link #USER_CODE_BEGINNING_DELIMITER} and {@link #USER_CODE_END_DELIMITER}.
+ */
+ public static final String UNMODIFIABLE_ANNOTATION_TAG = "@unmodifiable"; //$NON-NLS-1$
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/IPatternCondition.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/IPatternCondition.java
new file mode 100644
index 0000000..83414d9
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/condition/IPatternCondition.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.ecore.condition;
+
+import org.eclipse.egf.core.context.ProductionContext;
+
+/**
+ * Pattern condition interface.<br>
+ * Defines a static condition that the pattern parameters should meet so as to select elements for pattern matching.<br>
+ * The parameters instances that meet this condition at runtime are selected as potential entries for the pattern matching.<br>
+ * <b>Internal purpose only.</b><br>
+ * The pattern framework automatically creates a new Java class implementing this interface for each new pattern that requires
+ * a condition between its parameters. The pattern developer is then asked to fill the generated 'check' method content for the condition
+ * definition. The framework automatically generates the content of the {@link #check(Object...)} method, pointing to the check
+ * method filled by the developer.<br>
+ * Eventually, there is to be a merge when pattern parameters have changed between existing check code and new check method signature.
+ * @author brocard
+ */
+public interface IPatternCondition {
+
+ /**
+ * Check that given parameters meet the pattern condition.<br>
+ * The pattern condition is not supposed to be accessed from the Java code.<br>
+ * Instead use the pattern ui to get full details about the condition.
+ * @param parameters_p
+ * @return
+ */
+ public boolean check(Object... parameters_p);
+
+ /**
+ * Set production context available for this condition.
+ * @param context_p the context to use as available one. <code>null</code> if none.
+ */
+ public void setContext(ProductionContext context_p);
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g
new file mode 100644
index 0000000..7e36aa4
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g
@@ -0,0 +1,19 @@
+grammar PatternLanguage;
+
+options {
+ output=AST;
+ ASTLabelType=CommonTree;
+}
+
+call : operationCall+ ;
+
+operationCall : operationName^ LPAR! PARAM* RPAR! ENDOFCALL! ;
+
+operationName : ('CALL' | 'SUPER' | 'READ' | 'PATTERN') ;
+
+ENDOFCALL : ';' ;
+LPAR : '(' ;
+RPAR : ')' ;
+PARAM : ('a'..'z'|'A'..'Z'|'0'..'9'|'.'|'/'|'#')* ;
+WS : (' '|'\r'|'\n'|'\t'){$channel=HIDDEN;}
+ ;
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.tokens b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.tokens
new file mode 100644
index 0000000..3f53cbb
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.tokens
@@ -0,0 +1,9 @@
+ENDOFCALL=7
+RPAR=6
+WS=8
+LPAR=4
+PARAM=5
+'PATTERN'=12
+'READ'=11
+'CALL'=9
+'SUPER'=10
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguageLexer.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguageLexer.java
new file mode 100644
index 0000000..eb386ed
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguageLexer.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.ecore.grammar;
+
+// $ANTLR 3.0 ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g 2007-06-28 16:45:58
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.Lexer;
+import org.antlr.runtime.MismatchedSetException;
+import org.antlr.runtime.RecognitionException;
+
+public class PatternLanguageLexer extends Lexer {
+ public static final int ENDOFCALL = 7;
+ public static final int T10 = 10;
+ public static final int RPAR = 6;
+ public static final int T11 = 11;
+ public static final int T9 = 9;
+ public static final int EOF = -1;
+ public static final int WS = 8;
+ public static final int LPAR = 4;
+ public static final int T12 = 12;
+ public static final int Tokens = 13;
+ public static final int PARAM = 5;
+
+ public PatternLanguageLexer(CharStream input_p) {
+ super(input_p);
+ }
+
+ @Override
+ public String getGrammarFileName() {
+ return "./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g";} //$NON-NLS-1$
+
+ // $ANTLR start T9
+ public final void mT9() throws RecognitionException {
+ try {
+ int _type = T9;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:3:6: ( 'CALL' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:3:6: 'CALL'
+ {
+ match("CALL"); //$NON-NLS-1$
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end T9
+
+ // $ANTLR start T10
+ public final void mT10() throws RecognitionException {
+ try {
+ int _type = T10;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:4:7: ( 'SUPER' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:4:7: 'SUPER'
+ {
+ match("SUPER"); //$NON-NLS-1$
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end T10
+
+ // $ANTLR start T11
+ public final void mT11() throws RecognitionException {
+ try {
+ int _type = T11;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:5:7: ( 'READ' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:5:7: 'READ'
+ {
+ match("READ"); //$NON-NLS-1$
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end T11
+
+ // $ANTLR start T12
+ public final void mT12() throws RecognitionException {
+ try {
+ int _type = T12;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:6:7: ( 'PATTERN' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:6:7: 'PATTERN'
+ {
+ match("PATTERN"); //$NON-NLS-1$
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end T12
+
+ // $ANTLR start ENDOFCALL
+ public final void mENDOFCALL() throws RecognitionException {
+ try {
+ int _type = ENDOFCALL;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:14:13: ( ';' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:14:13: ';'
+ {
+ match(';');
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end ENDOFCALL
+
+ // $ANTLR start LPAR
+ public final void mLPAR() throws RecognitionException {
+ try {
+ int _type = LPAR;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:15:8: ( '(' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:15:8: '('
+ {
+ match('(');
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end LPAR
+
+ // $ANTLR start RPAR
+ public final void mRPAR() throws RecognitionException {
+ try {
+ int _type = RPAR;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:16:8: ( ')' )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:16:8: ')'
+ {
+ match(')');
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end RPAR
+
+ // $ANTLR start PARAM
+ public final void mPARAM() throws RecognitionException {
+ try {
+ int _type = PARAM;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:17:9: ( ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '/' | '#' )* )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:17:9: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '/' | '#' )*
+ {
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:17:9: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '/' | '#' )*
+ loop1: do {
+ int alt1 = 2;
+ int LA1_0 = input.LA(1);
+
+ if ((LA1_0 == '#' || (LA1_0 >= '.' && LA1_0 <= '9') || (LA1_0 >= 'A' && LA1_0 <= 'Z') || (LA1_0 >= 'a' && LA1_0 <= 'z'))) {
+ alt1 = 1;
+ }
+
+ switch (alt1) {
+ case 1:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:
+ {
+ if (input.LA(1) == '#' || (input.LA(1) >= '.' && input.LA(1) <= '9') || (input.LA(1) >= 'A' && input.LA(1) <= 'Z')
+ || (input.LA(1) >= 'a' && input.LA(1) <= 'z')) {
+ input.consume();
+ } else {
+ MismatchedSetException mse = new MismatchedSetException(null, input);
+ recover(mse);
+ throw mse;
+ }
+ }
+ break;
+
+ default:
+ break loop1;
+ }
+ } while (true);
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end PARAM
+
+ // $ANTLR start WS
+ public final void mWS() throws RecognitionException {
+ try {
+ int _type = WS;
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:18:9: ( ( ' ' | '\\r' | '\\n' | '\\t' ) )
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:18:9: ( ' ' | '\\r' | '\\n' | '\\t' )
+ {
+ if ((input.LA(1) >= '\t' && input.LA(1) <= '\n') || input.LA(1) == '\r' || input.LA(1) == ' ') {
+ input.consume();
+ } else {
+ MismatchedSetException mse = new MismatchedSetException(null, input);
+ recover(mse);
+ throw mse;
+ }
+ channel = HIDDEN;
+ }
+ this.type = _type;
+ } finally {
+ // NTD.
+ }
+ }
+
+ // $ANTLR end WS
+ @Override
+ public void mTokens() throws RecognitionException {
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:10: ( T9 | T10 | T11 | T12 | ENDOFCALL | LPAR | RPAR | PARAM | WS )
+ int alt2 = 9;
+ switch (input.LA(1)) {
+ case 'C': {
+ int LA2_1 = input.LA(2);
+
+ if ((LA2_1 == 'A')) {
+ int LA2_10 = input.LA(3);
+
+ if ((LA2_10 == 'L')) {
+ int LA2_14 = input.LA(4);
+
+ if ((LA2_14 == 'L')) {
+ int LA2_18 = input.LA(5);
+
+ if ((LA2_18 == '#' || (LA2_18 >= '.' && LA2_18 <= '9') || (LA2_18 >= 'A' && LA2_18 <= 'Z') || (LA2_18 >= 'a' && LA2_18 <= 'z'))) {
+ alt2 = 8;
+ } else {
+ alt2 = 1;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ }
+ break;
+ case 'S': {
+ int LA2_2 = input.LA(2);
+
+ if ((LA2_2 == 'U')) {
+ int LA2_11 = input.LA(3);
+
+ if ((LA2_11 == 'P')) {
+ int LA2_15 = input.LA(4);
+
+ if ((LA2_15 == 'E')) {
+ int LA2_19 = input.LA(5);
+
+ if ((LA2_19 == 'R')) {
+ int LA2_23 = input.LA(6);
+
+ if ((LA2_23 == '#' || (LA2_23 >= '.' && LA2_23 <= '9') || (LA2_23 >= 'A' && LA2_23 <= 'Z') || (LA2_23 >= 'a' && LA2_23 <= 'z'))) {
+ alt2 = 8;
+ } else {
+ alt2 = 2;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ }
+ break;
+ case 'R': {
+ int LA2_3 = input.LA(2);
+
+ if ((LA2_3 == 'E')) {
+ int LA2_12 = input.LA(3);
+
+ if ((LA2_12 == 'A')) {
+ int LA2_16 = input.LA(4);
+
+ if ((LA2_16 == 'D')) {
+ int LA2_20 = input.LA(5);
+
+ if ((LA2_20 == '#' || (LA2_20 >= '.' && LA2_20 <= '9') || (LA2_20 >= 'A' && LA2_20 <= 'Z') || (LA2_20 >= 'a' && LA2_20 <= 'z'))) {
+ alt2 = 8;
+ } else {
+ alt2 = 3;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ }
+ break;
+ case 'P': {
+ int LA2_4 = input.LA(2);
+
+ if ((LA2_4 == 'A')) {
+ int LA2_13 = input.LA(3);
+
+ if ((LA2_13 == 'T')) {
+ int LA2_17 = input.LA(4);
+
+ if ((LA2_17 == 'T')) {
+ int LA2_21 = input.LA(5);
+
+ if ((LA2_21 == 'E')) {
+ int LA2_25 = input.LA(6);
+
+ if ((LA2_25 == 'R')) {
+ int LA2_27 = input.LA(7);
+
+ if ((LA2_27 == 'N')) {
+ int LA2_28 = input.LA(8);
+
+ if ((LA2_28 == '#' || (LA2_28 >= '.' && LA2_28 <= '9') || (LA2_28 >= 'A' && LA2_28 <= 'Z') || (LA2_28 >= 'a' && LA2_28 <= 'z'))) {
+ alt2 = 8;
+ } else {
+ alt2 = 4;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ } else {
+ alt2 = 8;
+ }
+ }
+ break;
+ case ';': {
+ alt2 = 5;
+ }
+ break;
+ case '(': {
+ alt2 = 6;
+ }
+ break;
+ case ')': {
+ alt2 = 7;
+ }
+ break;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': {
+ alt2 = 9;
+ }
+ break;
+ default:
+ alt2 = 8;
+ }
+
+ switch (alt2) {
+ case 1:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:10: T9
+ {
+ mT9();
+
+ }
+ break;
+ case 2:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:13: T10
+ {
+ mT10();
+
+ }
+ break;
+ case 3:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:17: T11
+ {
+ mT11();
+
+ }
+ break;
+ case 4:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:21: T12
+ {
+ mT12();
+
+ }
+ break;
+ case 5:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:25: ENDOFCALL
+ {
+ mENDOFCALL();
+
+ }
+ break;
+ case 6:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:35: LPAR
+ {
+ mLPAR();
+
+ }
+ break;
+ case 7:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:40: RPAR
+ {
+ mRPAR();
+
+ }
+ break;
+ case 8:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:45: PARAM
+ {
+ mPARAM();
+
+ }
+ break;
+ case 9:
+ // ./src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage.g:1:51: WS
+ {
+ mWS();
+
+ }
+ break;
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguageParser.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguageParser.java
new file mode 100644
index 0000000..79b5df9
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguageParser.java
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.ecore.grammar;
+
+// $ANTLR 3.0 ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g 2007-06-28 16:45:58
+
+import org.antlr.runtime.BitSet;
+import org.antlr.runtime.EarlyExitException;
+import org.antlr.runtime.MismatchedSetException;
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.ParserRuleReturnScope;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.CommonTreeAdaptor;
+import org.antlr.runtime.tree.TreeAdaptor;
+
+public class PatternLanguageParser extends Parser {
+ public static final String[] tokenNames =
+ new String[] {
+ "<invalid>", "<EOR>", "<DOWN>", "<UP>", "LPAR", "PARAM", "RPAR", "ENDOFCALL", "WS", "'CALL'", "'SUPER'", "'READ'", "'PATTERN'" //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$//$NON-NLS-13$
+ };
+ public static final int ENDOFCALL = 7;
+ public static final int RPAR = 6;
+ public static final int WS = 8;
+ public static final int EOF = -1;
+ public static final int LPAR = 4;
+ public static final int PARAM = 5;
+
+ public PatternLanguageParser(TokenStream input_p) {
+ super(input_p);
+ }
+
+ protected TreeAdaptor adaptor = new CommonTreeAdaptor();
+
+ public void setTreeAdaptor(TreeAdaptor adaptor_p) {
+ this.adaptor = adaptor_p;
+ }
+
+ public TreeAdaptor getTreeAdaptor() {
+ return adaptor;
+ }
+
+ @Override
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+ public String getGrammarFileName() {
+ return "./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g"; //$NON-NLS-1$
+ }
+
+ public static class call_return extends ParserRuleReturnScope {
+ CommonTree tree;
+
+ @Override
+ public Object getTree() {
+ return tree;
+ }
+ }
+
+ // $ANTLR start call
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:8:1: call : ( operationCall )+ ;
+ public final call_return call() throws RecognitionException {
+ call_return retval = new call_return();
+ retval.start = input.LT(1);
+
+ CommonTree root_0 = null;
+
+ operationCall_return operationCall1 = null;
+
+ try {
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:8:8: ( ( operationCall )+ )
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:8:8: ( operationCall )+
+ {
+ root_0 = (CommonTree) adaptor.nil();
+
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:8:8: ( operationCall )+
+ int cnt1 = 0;
+ loop1: do {
+ int alt1 = 2;
+ int LA1_0 = input.LA(1);
+
+ if (((LA1_0 >= 9 && LA1_0 <= 12))) {
+ alt1 = 1;
+ }
+
+ switch (alt1) {
+ case 1:
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:8:8: operationCall
+ {
+ pushFollow(FOLLOW_operationCall_in_call29);
+ operationCall1 = operationCall();
+ _fsp--;
+
+ adaptor.addChild(root_0, operationCall1.getTree());
+
+ }
+ break;
+
+ default:
+ if (cnt1 >= 1)
+ break loop1;
+ EarlyExitException eee = new EarlyExitException(1, input);
+ throw eee;
+ }
+ cnt1++;
+ } while (true);
+
+ }
+
+ retval.stop = input.LT(-1);
+
+ retval.tree = (CommonTree) adaptor.rulePostProcessing(root_0);
+ adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
+
+ } catch (RecognitionException re) {
+ reportError(re);
+ recover(input, re);
+ } finally {
+ // NTD.
+ }
+ return retval;
+ }
+
+ // $ANTLR end call
+
+ public static class operationCall_return extends ParserRuleReturnScope {
+ CommonTree tree;
+
+ @Override
+ public Object getTree() {
+ return tree;
+ }
+ }
+
+ // $ANTLR start operationCall
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:10:1: operationCall : operationName LPAR ( PARAM )* RPAR ENDOFCALL ;
+ @SuppressWarnings("unused")
+ public final operationCall_return operationCall() throws RecognitionException {
+ operationCall_return retval = new operationCall_return();
+ retval.start = input.LT(1);
+
+ CommonTree root_0 = null;
+
+ Token LPAR3 = null;
+ Token PARAM4 = null;
+ Token RPAR5 = null;
+ Token ENDOFCALL6 = null;
+ operationName_return operationName2 = null;
+
+ CommonTree LPAR3_tree = null;
+ CommonTree PARAM4_tree = null;
+ CommonTree RPAR5_tree = null;
+ CommonTree ENDOFCALL6_tree = null;
+
+ try {
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:10:17: ( operationName LPAR ( PARAM )* RPAR ENDOFCALL )
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:10:17: operationName LPAR ( PARAM )* RPAR ENDOFCALL
+ {
+ root_0 = (CommonTree) adaptor.nil();
+
+ pushFollow(FOLLOW_operationName_in_operationCall39);
+ operationName2 = operationName();
+ _fsp--;
+
+ root_0 = (CommonTree) adaptor.becomeRoot(operationName2.getTree(), root_0);
+ LPAR3 = input.LT(1);
+ match(input, LPAR, FOLLOW_LPAR_in_operationCall42);
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:10:38: ( PARAM )*
+ loop2: do {
+ int alt2 = 2;
+ int LA2_0 = input.LA(1);
+
+ if ((LA2_0 == PARAM)) {
+ alt2 = 1;
+ }
+
+ switch (alt2) {
+ case 1:
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:10:38: PARAM
+ {
+ PARAM4 = input.LT(1);
+ match(input, PARAM, FOLLOW_PARAM_in_operationCall45);
+ PARAM4_tree = (CommonTree) adaptor.create(PARAM4);
+ adaptor.addChild(root_0, PARAM4_tree);
+
+ }
+ break;
+
+ default:
+ break loop2;
+ }
+ } while (true);
+
+ RPAR5 = input.LT(1);
+ match(input, RPAR, FOLLOW_RPAR_in_operationCall48);
+ ENDOFCALL6 = input.LT(1);
+ match(input, ENDOFCALL, FOLLOW_ENDOFCALL_in_operationCall51);
+
+ }
+
+ retval.stop = input.LT(-1);
+
+ retval.tree = (CommonTree) adaptor.rulePostProcessing(root_0);
+ adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
+
+ } catch (RecognitionException re) {
+ reportError(re);
+ recover(input, re);
+ } finally {
+ // NTD.
+ }
+ return retval;
+ }
+
+ // $ANTLR end operationCall
+
+ public static class operationName_return extends ParserRuleReturnScope {
+ CommonTree tree;
+
+ @Override
+ public Object getTree() {
+ return tree;
+ }
+ }
+
+ // $ANTLR start operationName
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:12:1: operationName : ( 'CALL' | 'SUPER' | 'READ' | 'PATTERN' ) ;
+ @SuppressWarnings("unused")
+ public final operationName_return operationName() throws RecognitionException {
+ operationName_return retval = new operationName_return();
+ retval.start = input.LT(1);
+
+ CommonTree root_0 = null;
+
+ Token set7 = null;
+
+ CommonTree set7_tree = null;
+
+ try {
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:12:17: ( ( 'CALL' | 'SUPER' | 'READ' | 'PATTERN' ) )
+ // ./src/org/eclipse/egf/pattern/pattern/ecore/grammar/PatternLanguage.g:12:17: ( 'CALL' | 'SUPER' | 'READ' | 'PATTERN' )
+ {
+ root_0 = (CommonTree) adaptor.nil();
+
+ set7 = input.LT(1);
+ if ((input.LA(1) >= 9 && input.LA(1) <= 12)) {
+ input.consume();
+ adaptor.addChild(root_0, adaptor.create(set7));
+ errorRecovery = false;
+ } else {
+ MismatchedSetException mse = new MismatchedSetException(null, input);
+ recoverFromMismatchedSet(input, mse, FOLLOW_set_in_operationName61);
+ throw mse;
+ }
+
+ }
+
+ retval.stop = input.LT(-1);
+
+ retval.tree = (CommonTree) adaptor.rulePostProcessing(root_0);
+ adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
+
+ } catch (RecognitionException re) {
+ reportError(re);
+ recover(input, re);
+ } finally {
+ // NTD.
+ }
+ return retval;
+ }
+
+ // $ANTLR end operationName
+
+ public static final BitSet FOLLOW_operationCall_in_call29 = new BitSet(new long[] { 0x0000000000001E02L });
+ public static final BitSet FOLLOW_operationName_in_operationCall39 = new BitSet(new long[] { 0x0000000000000010L });
+ public static final BitSet FOLLOW_LPAR_in_operationCall42 = new BitSet(new long[] { 0x0000000000000060L });
+ public static final BitSet FOLLOW_PARAM_in_operationCall45 = new BitSet(new long[] { 0x0000000000000060L });
+ public static final BitSet FOLLOW_RPAR_in_operationCall48 = new BitSet(new long[] { 0x0000000000000080L });
+ public static final BitSet FOLLOW_ENDOFCALL_in_operationCall51 = new BitSet(new long[] { 0x0000000000000002L });
+ public static final BitSet FOLLOW_set_in_operationName61 = new BitSet(new long[] { 0x0000000000000002L });
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage__.g b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage__.g
new file mode 100644
index 0000000..eecaa90
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/PatternLanguage__.g
@@ -0,0 +1,18 @@
+lexer grammar PatternLanguage;
+
+T9 : 'CALL' ;
+T10 : 'SUPER' ;
+T11 : 'READ' ;
+T12 : 'PATTERN' ;
+
+// $ANTLR src "./src/com/thalesgroup/mde/mdsofa/asset/pattern/ecore/grammar/PatternLanguage.g" 14
+ENDOFCALL : ';' ;
+// $ANTLR src "./src/com/thalesgroup/mde/mdsofa/asset/pattern/ecore/grammar/PatternLanguage.g" 15
+LPAR : '(' ;
+// $ANTLR src "./src/com/thalesgroup/mde/mdsofa/asset/pattern/ecore/grammar/PatternLanguage.g" 16
+RPAR : ')' ;
+// $ANTLR src "./src/com/thalesgroup/mde/mdsofa/asset/pattern/ecore/grammar/PatternLanguage.g" 17
+PARAM : ('a'..'z'|'A'..'Z'|'0'..'9'|'.'|'/'|'#')* ;
+// $ANTLR src "./src/com/thalesgroup/mde/mdsofa/asset/pattern/ecore/grammar/PatternLanguage.g" 18
+WS : (' '|'\r'|'\n'|'\t'){$channel=HIDDEN;}
+ ;
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/TestGrammar.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/TestGrammar.java
new file mode 100644
index 0000000..dd22a42
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/grammar/TestGrammar.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.ecore.grammar;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.Tree;
+
+/**
+ * @author brocard
+ *
+ */
+public class TestGrammar {
+ /**
+ * @param args
+ */
+ public static void main(String[] args) throws Exception {
+ CharStream in = new ANTLRStringStream("READ(/org.eclipse.egf.pattern.helloworld/templates/helloworld/helloWorld.jet);PATTERN(library1.pattern1#helloworld);CALL(helloworld);SUPER();"); //$NON-NLS-1$
+ PatternLanguageLexer lexer = new PatternLanguageLexer(in);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ PatternLanguageParser parser = new PatternLanguageParser(tokens);
+ CommonTree tree = (CommonTree) parser.call().getTree();
+ System.out.println(tree.toStringTree());
+ explore(tree, 0);
+ }
+
+ /**
+ * Explore tree.
+ * @param tree_p
+ */
+ protected static void explore(Tree tree_p, int tabCount_p) {
+ if (null == tree_p) {
+ return;
+ }
+ int childCount = tree_p.getChildCount();
+ int tabCount = tabCount_p + 2;
+ for (int i = 0; i < childCount; i++) {
+ Tree childTree = tree_p.getChild(i);
+ for (int j = 0; j < tabCount; j++) {
+ System.out.print(" "); //$NON-NLS-1$
+ }
+ System.out.println(childTree.getText());
+ explore(childTree, tabCount);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/messages.properties b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/messages.properties
new file mode 100644
index 0000000..21a1e3f
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/ecore/messages.properties
@@ -0,0 +1,11 @@
+###############################################################################
+# Copyright (c) 2009 Thales Corporate Services S.A.S.
+# 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:
+# Thales Corporate Services S.A.S - initial API and implementation
+###############################################################################
+PatternHandler_AutoGeneratedDescriptionText=Auto-generated description for {0}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/execution/IPatternExecutionReporter.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/execution/IPatternExecutionReporter.java
new file mode 100644
index 0000000..39ac179
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/execution/IPatternExecutionReporter.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.execution;
+
+import java.util.Map;
+
+import org.eclipse.egf.core.context.ProductionContext;
+import org.eclipse.emf.ecore.EObject;
+
+
+/**
+ * Classes which implement this interface provide a method<br>
+ * that deals with the event that is generated when a pattern execution is finished.<br>
+ * Implementors must provide a default constructor.
+ * @author Guillaume Brocard
+ */
+public interface IPatternExecutionReporter {
+ /**
+ * Sent when a pattern overall execution has just finished.
+ * @param patternFullId_p the full identifier of the pattern that the execution is finished for.
+ * @param output_p the output resulting from the pattern execution.
+ */
+ public void patternExecutionFinished(String output_p, String patternFullId_p, ProductionContext context_p);
+
+ /**
+ * Sent when a pattern loop execution is finished.
+ * @param output_p The loop output.
+ * @param patternFullId_p The full id of the pattern that declares the loop.
+ * @param context_p The production context of the pattern execution.
+ * @param tuple_p The contextual loop tuple. This object should not be kept by the implementor for it is used for every possible tuple values.
+ */
+ public void patternLoopExecutionFinished(String output_p, String patternFullId_p, ProductionContext context_p, Map<String, EObject> tuple_p);
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/execution/PatternExecutionHelper.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/execution/PatternExecutionHelper.java
new file mode 100644
index 0000000..63a447b
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/execution/PatternExecutionHelper.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.execution;
+
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternTemplateConstants;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.core.context.ProductionContext;
+import org.eclipse.egf.pattern.production.TemplateType;
+import org.eclipse.egf.pattern.production.jet.IGenerator;
+import org.eclipse.emf.ecore.resource.Resource;
+
+
+/**
+ * @author Guillaume Brocard
+ */
+public class PatternExecutionHelper {
+
+ /**
+ * Log4j reference logger.
+ */
+ private static final Logger __logger = Logger.getLogger(PatternExecutionHelper.class.getPackage().getName());
+
+ /**
+ * Argument key.<br>
+ * Used as a key in the argument map.
+ * @author Guillaume Brocard
+ */
+ public static enum ArgumentKey {
+ EMF_RESOURCE, PRODUCTION_CONTEXT, EXECUTION_REPORTER
+ }
+
+ /**
+ * Get argument value for given key.
+ * @param argument_p
+ * @param key_p
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ private static Object getValue(Object argument_p, ArgumentKey key_p) {
+ Object result = null;
+ if (argument_p instanceof Map) {
+ Map<ArgumentKey, Object> arguments = (Map<ArgumentKey, Object>) argument_p;
+ result = arguments.get(key_p);
+ }
+ return result;
+ }
+
+ /**
+ * Get EMF resource from pattern argument.
+ * @param argument_p
+ * @return
+ */
+ public static Resource getResource(Object argument_p) {
+ return (Resource) getValue(argument_p, ArgumentKey.EMF_RESOURCE);
+ }
+
+ /**
+ * Get production context from pattern argument.
+ * @param argument_p
+ * @return
+ */
+ public static ProductionContext getContext(Object argument_p) {
+ return (ProductionContext) getValue(argument_p, ArgumentKey.PRODUCTION_CONTEXT);
+ }
+
+ /**
+ * Get execution reporter.
+ * @param argument_p
+ * @return
+ */
+ public static IPatternExecutionReporter getExecutionReporter(Object argument_p) {
+ return (IPatternExecutionReporter) getValue(argument_p, ArgumentKey.EXECUTION_REPORTER);
+ }
+
+ /**
+ * Invoke identified pattern with given arguments.
+ * @param patternFullId_p the pattern full id.
+ * @param arguments_p a set of arguments, compatible with the pattern kind.
+ * @return The resulting content of the pattern invocation.
+ */
+ public static Object invokePattern(String patternFullId_p, Object arguments_p) {
+ Object result = ICommonConstants.EMPTY_STRING;
+ try {
+ result = doRunPattern(patternFullId_p, arguments_p);
+ } catch (Exception exception_p) {
+ StringBuilder loggerMessage = new StringBuilder("PatternElementRunnerTask.invokePattern(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ return result;
+ }
+
+ /**
+ * Do run identified pattern with given arguments_p.
+ * @param patternFullId_p the pattern full id.
+ * @param arguments_p a set of arguments, compatible with the pattern kind.
+ * @return The resulting content of the pattern execution.
+ * @throws Exception run failed.
+ */
+ public static Object doRunPattern(String patternFullId_p, Object arguments_p) throws Exception {
+ Object result = ICommonConstants.EMPTY_STRING;
+ // Get the configuration element for given pattern.
+ IConfigurationElement patternConfigElement = ExtensionPointHelper.getConfigurationElement(
+ IPatternTemplateConstants.PATTERN_PLUGIN_ID,
+ IPatternTemplateConstants.PATTERN_TEMPLATE_EXTENSION_POINT_ID,
+ patternFullId_p
+ );
+ if (null != patternConfigElement) {
+ // Get the template engine type.
+ String templateEngineType = patternConfigElement.getAttribute(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_TYPE);
+ if (TemplateType.JET.getId().equals(templateEngineType)) {
+ // JET template engine is selected, let's load the template code.
+ // The template code is a compiled class that implements IGenerator.
+ IGenerator templateCode = (IGenerator) patternConfigElement.createExecutableExtension(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_CLASS);
+ // Execute the template
+ result = templateCode.generate(arguments_p);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/ConditionMergeHelper.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/ConditionMergeHelper.java
new file mode 100644
index 0000000..67167eb
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/ConditionMergeHelper.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.internal;
+
+import static org.eclipse.egf.pattern.ecore.condition.IConditionConstants.USER_CODE_BEGINNING_DELIMITER;
+import static org.eclipse.egf.pattern.ecore.condition.IConditionConstants.USER_CODE_END_DELIMITER;
+
+import java.io.ByteArrayInputStream;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.emf.codegen.merge.java.JControlModel;
+import org.eclipse.emf.codegen.merge.java.JMerger;
+import org.eclipse.emf.codegen.merge.java.facade.ast.ASTFacadeHelper;
+import org.eclipse.emf.common.util.URI;
+
+
+/**
+ * Helper to merge easily merge previous condition generation with new ones.
+ * @author Guillaume Brocard
+ */
+public class ConditionMergeHelper {
+
+ private ConditionMergeHelper() {
+ // Prevent Instantiation
+ }
+
+ /**
+ * Merge given new content with given previous one.
+ * @param newContent_p the new content to merge.
+ * @param previousContent_p the previous content to merge
+ * @return the merged content.
+ */
+ public static String merge(String newContent_p, String previousContent_p) {
+ String mergedContent = ICommonConstants.EMPTY_STRING;
+ // Initialize a merger.
+ JMerger merger = getJMerger();
+ // Set as source the new content.
+ merger.setSourceCompilationUnit(merger.createCompilationUnitForContents(newContent_p));
+ // Set as target the previous content.
+ ByteArrayInputStream previousContentInputStream = new ByteArrayInputStream(previousContent_p.getBytes());
+ merger.setTargetCompilationUnit(merger.createCompilationUnitForInputStream(previousContentInputStream));
+ // Merge the source with the target.
+ merger.merge();
+ // Get the merged content.
+ mergedContent = merger.getTargetCompilationUnit().getContents();
+ // Extract the previous user-code between delimiters.
+ String previousDelimitedContent = StringHelper.substring(
+ USER_CODE_BEGINNING_DELIMITER,
+ USER_CODE_END_DELIMITER,
+ previousContent_p,
+ true
+ );
+ // If successfully extracted, let's continue.
+ if (previousDelimitedContent != null) {
+ // Extract the user-code between delimiters.
+ String newDelimitedContent = StringHelper.substring(
+ USER_CODE_BEGINNING_DELIMITER,
+ USER_CODE_END_DELIMITER,
+ mergedContent,
+ true
+ );
+ // If delimited contents are different ones, replace newDelimitedContent in merged content with the previous one.
+ // Developers won't happy to lose their code.
+ if (previousDelimitedContent.equals(newDelimitedContent) == false) {
+ mergedContent = mergedContent.replace(newDelimitedContent, previousDelimitedContent);
+ }
+ }
+ return mergedContent;
+ }
+
+ /**
+ * Creates and initializes a new JMerger
+ * @return JMerger
+ */
+ private static JMerger getJMerger() {
+ // Get the merge file URL.
+ URI mergeFileURI = FileHelper.getFileFullUri(getRelativePathToMergeFile());
+ // Install a JControlModel.
+ JControlModel controlModel = new JControlModel();
+ controlModel.initialize(new ASTFacadeHelper(), mergeFileURI.toString());
+ JMerger jmerger = new JMerger(controlModel);
+ return jmerger;
+ }
+
+ /**
+ * Get merge.xml file relative path to workspace.<br>
+ * Default implementation points to pattern condition class merge file.
+ * @return
+ */
+ protected static String getRelativePathToMergeFile() {
+ return new StringBuilder(ICommonConstants.SLASH_CHARACTER)
+ .append(PatternActivator.getDefault().getPluginID())
+ .append("/resources/merge.xml") //$NON-NLS-1$
+ .toString();
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/PatternRegistry.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/PatternRegistry.java
new file mode 100644
index 0000000..2da0e96
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/PatternRegistry.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.pde.pattern.reader.WorkspacePatternExtensionReader;
+
+public class PatternRegistry {
+
+ public static Map<String, IDescriptor> getPatterns(IProject project_p) {
+ // Check
+ if (project_p == null) {
+ return null;
+ }
+ Map<String, IDescriptor> patterns = new HashMap<String, IDescriptor>();
+ // Load root descriptor
+ IDescriptor rootDescriptor = new WorkspacePatternExtensionReader().getPatternLibraries(project_p);
+ if (rootDescriptor != null) {
+ // Load available patterns in this project
+ getPatterns(patterns, rootDescriptor);
+ }
+ return patterns;
+ }
+
+ private static void getPatterns(Map<String, IDescriptor> patterns_p, IDescriptor descriptor_p) {
+ // Check
+ if (patterns_p == null || descriptor_p == null) {
+ return;
+ }
+ // Pattern Type
+ if (IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_PATTERN.equals(descriptor_p.getValue(IPatternConstants.PATTERN_EXTENSION_POINT_CHILD_TYPE))) {
+ // Pattern analysis
+ String shortID = (String) descriptor_p.getValue(ExtensionPointHelper.ATT_ID);
+ if (shortID != null && shortID.trim().length() > 0) {
+ patterns_p.put(shortID, descriptor_p);
+ }
+ } else {
+ // Children analysis
+ for (IDescriptor childDescriptor : descriptor_p.getChildren()) {
+ getPatterns(patterns_p, childDescriptor);
+ }
+ }
+ return;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/PatternTemplateRegistry.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/PatternTemplateRegistry.java
new file mode 100644
index 0000000..b3356a2
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/PatternTemplateRegistry.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.egf.common.constant.IPatternTemplateConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.pde.pattern.reader.WorkspacePatternTemplateExtensionReader;
+
+public class PatternTemplateRegistry {
+
+ public static Map<String, IDescriptor> getPatternTemplates(IProject project_p) {
+ // Check
+ if (project_p == null) {
+ return null;
+ }
+ Map<String, IDescriptor> patterns = new HashMap<String, IDescriptor>();
+ // Load root descriptor
+ IDescriptor rootDescriptor = new WorkspacePatternTemplateExtensionReader().getPatternTemplates(project_p);
+ if (rootDescriptor != null) {
+ // Load available patterns in this project
+ getPatternTemplates(patterns, rootDescriptor);
+ }
+ return patterns;
+ }
+
+ private static void getPatternTemplates(Map<String, IDescriptor> patterns_p, IDescriptor descriptor_p) {
+ // Check
+ if (patterns_p == null || descriptor_p == null) {
+ return;
+ }
+ // Pattern Type
+ if (IPatternTemplateConstants.PATTERN_TEMPLATE_EXTENSION_POINT_CHILD_PATTERN_TEMPLATE.equals(descriptor_p.getValue(IPatternTemplateConstants.PATTERN_TEMPLATE_EXTENSION_POINT_CHILD_TYPE))) {
+ // Pattern analysis
+ String shortID = (String) descriptor_p.getValue(ExtensionPointHelper.ATT_ID);
+ if (shortID != null && shortID.trim().length() > 0) {
+ patterns_p.put(shortID, descriptor_p);
+ }
+ } else {
+ // Children analysis
+ for (IDescriptor childDescriptor : descriptor_p.getChildren()) {
+ getPatternTemplates(patterns_p, childDescriptor);
+ }
+ }
+ return;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/builders/PatternBuilder.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/builders/PatternBuilder.java
new file mode 100644
index 0000000..ee6069e
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/builders/PatternBuilder.java
@@ -0,0 +1,348 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - Initial API and implementation
+ * Soyatec - Contribution
+ *
+ * </copyright>
+ *
+ */
+
+package org.eclipse.egf.pattern.internal.builders;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.MathHelper;
+import org.eclipse.egf.console.EGFConsolePlugin;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.internal.PatternRegistry;
+import org.eclipse.egf.pattern.production.PatternProducer;
+
+
+public class PatternBuilder extends IncrementalProjectBuilder {
+
+ private static boolean DEBUG = PatternActivator.getDefault().isDebugging();
+
+ private static IProject[] EMPTY_LIST = new IProject [0];
+
+ private PatternVisitor _patternVisitor = new PatternVisitor();
+
+ private IJavaProject _javaProject;
+
+ private Map<String, IDescriptor> _patterns;
+
+ class PatternVisitor implements IResourceDeltaVisitor {
+
+ private Collection<IDescriptor> _rebuildPatternModel = new ArrayList<IDescriptor>();
+
+ private Collection<IDescriptor> _rebuildFactoryComponent = new ArrayList<IDescriptor>();
+
+ private Collection<IDescriptor> _produce = new ArrayList<IDescriptor>();
+
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if (delta == null) {
+ return false;
+ }
+ int kind = delta.getKind();
+ IResource resource = delta.getResource();
+ // Process Pattern Model and Pattern Method file extension
+ if (resource.getType() == IResource.FILE) {
+ if (PatternConstants.PATTERN_MODEL_FILE_EXTENSION.equals(resource.getFileExtension())) {
+ // Process Pattern Model
+ // Looking for an existing descriptor
+ IDescriptor descriptor = getPatterns().get(resource.getFullPath().removeFileExtension().lastSegment());
+ if (descriptor == null) {
+ return false;
+ }
+ String model = (String) descriptor.getValue(IPatternConstants.PATTERN_MODEL_ATTRIBUTE_NAME);
+ if (model == null || model.trim().length() == 0) {
+ return false;
+ }
+ // Check if the model attribute match an existing workspace resource
+ IResource modelResource = FileHelper.getPlatformResource(new Path(model));
+ if (modelResource == null || modelResource.equals(resource) == false) {
+ return false;
+ }
+ if (kind == IResourceDelta.REMOVED) {
+ _rebuildFactoryComponent.add(descriptor);
+ }
+ if (kind == IResourceDelta.ADDED || kind == IResourceDelta.CHANGED) {
+ _produce.add(descriptor);
+ }
+ } else if (PatternConstants.PATTERN_METHOD_FILE_EXTENSION.equals(resource.getFileExtension())) {
+ // Process Pattern Method
+ // Looking for an existing descriptor
+ IDescriptor descriptor = getPatterns().get(resource.getParent().getFullPath().lastSegment());
+ if (descriptor == null) {
+ return false;
+ }
+ // Pattern Methods are described in the Pattern Model
+ // Deeper analysis should be done
+ if (kind == IResourceDelta.REMOVED) {
+ _rebuildPatternModel.add(descriptor);
+ }
+ // Added are ignored as they cannot appear magically in the pattern model
+ if (kind == IResourceDelta.CHANGED) {
+ _produce.add(descriptor);
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ public void reset() {
+ _produce.clear();
+ _rebuildPatternModel.clear();
+ _rebuildFactoryComponent.clear();
+ }
+
+ public Collection<IDescriptor> getProduce() {
+ return _produce;
+ }
+
+ public Collection<IDescriptor> getRebuildFactoryComponent() {
+ return _rebuildFactoryComponent;
+ }
+
+ public Collection<IDescriptor> getRebuildPatternModel() {
+ return _rebuildPatternModel;
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ protected IProject[] build(int kind_p, Map args_p, IProgressMonitor monitor_p) throws CoreException {
+ // Initialize
+ if (initialize(monitor_p) == false) {
+ return EMPTY_LIST;
+ }
+ // Let's build our delta
+ try {
+ IResourceDelta delta = getDelta(_javaProject.getProject());
+ if (kind_p != FULL_BUILD || delta != null) {
+ if (delta.getKind() != IResourceDelta.NO_CHANGE) {
+ // Visit delta
+ _patternVisitor.reset();
+ delta.accept(_patternVisitor);
+ // Rebuild FactoryComponent
+ rebuildFactoryComponent(_patternVisitor.getRebuildFactoryComponent());
+ // Rebuild PatternModel
+ rebuildPatternModel(_patternVisitor.getRebuildPatternModel());
+ // Produce
+ produce(_patternVisitor.getProduce(), monitor_p);
+ }
+ } else {
+ // Produce All available Pattern Model
+ produce(getPatterns().values(), monitor_p);
+ }
+ } finally {
+ cleanup();
+ }
+ // Nothing to return yet
+ return EMPTY_LIST;
+ }
+
+ protected void produce(Collection<IDescriptor> descriptors_p, IProgressMonitor monitor_p) {
+ if (descriptors_p == null) {
+ return;
+ }
+ // Debug Stuff
+ int rank = 1;
+ long start = System.currentTimeMillis();
+ long stepStart = start;
+ // Produce
+ for (IDescriptor descriptor : descriptors_p) {
+ String definition = (String) descriptor.getValue(IPatternConstants.PATTERN_MODEL_ATTRIBUTE_NAME);
+ if (definition == null || definition.trim().length() == 0) {
+ continue;
+ }
+ PatternHandler patternHandler = new PatternHandler(true);
+ try {
+ PatternData patternData = patternHandler.load(definition);
+ if (patternData != null) {
+ PatternProducer.producePatterns(patternData.getPattern().getId(), monitor_p);
+ long stepStop = System.currentTimeMillis();
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logInfo(
+ NLS.bind(
+ "Produce Pattern Model ''{0}'', step {1}/{2}", //$NON-NLS-1$
+ new Object[] {
+ definition,
+ rank++,
+ descriptors_p.size()
+ }
+ )
+ );
+ EGFConsolePlugin.getConsole().logWarning(
+ NLS.bind(
+ "Total elapsed {0}, Step elapsed {1}", //$NON-NLS-1$
+ MathHelper.formatAsDuration(stepStop - start),
+ MathHelper.formatAsDuration(stepStop - stepStart)
+ ),
+ 1
+ );
+ stepStart = System.currentTimeMillis();
+ }
+ }
+ } catch (Throwable t) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(
+ NLS.bind(
+ "Unable to load Pattern Model ''{0}''", //$NON-NLS-1$
+ definition
+ ),
+ t
+ );
+ }
+ PatternActivator.getDefault().log(t);
+ continue;
+ } finally {
+ // Check Monitor
+ if (monitor_p.isCanceled()) {
+ break;
+ }
+ }
+ }
+ }
+
+ protected void rebuildFactoryComponent(Collection<IDescriptor> descriptors_p) {
+ if (descriptors_p == null) {
+ return;
+ }
+ for (IDescriptor descriptor : descriptors_p) {
+ String definition = (String) descriptor.getValue(IPatternConstants.PATTERN_MODEL_ATTRIBUTE_NAME);
+ if (definition == null || definition.trim().length() == 0) {
+ continue;
+ }
+ PatternHandler patternHandler = new PatternHandler(true);
+ try {
+ PatternData patternData = patternHandler.load(definition);
+ if (patternData != null) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logWarning(
+ NLS.bind(
+ "Factory Component Should be updated ''{0}''", //$NON-NLS-1$
+ patternData.getFactoryComponentId()
+ )
+ );
+ }
+ }
+ } catch (Throwable t) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(
+ NLS.bind(
+ "Unable to load Pattern Model ''{0}''", //$NON-NLS-1$
+ definition
+ ),
+ t
+ );
+ }
+ PatternActivator.getDefault().log(t);
+ continue;
+ }
+ }
+ }
+
+ protected void rebuildPatternModel(Collection<IDescriptor> descriptors_p) {
+ if (descriptors_p == null) {
+ return;
+ }
+ for (IDescriptor descriptor : descriptors_p) {
+ String definition = (String) descriptor.getValue(IPatternConstants.PATTERN_MODEL_ATTRIBUTE_NAME);
+ if (definition == null || definition.trim().length() == 0) {
+ continue;
+ }
+ PatternHandler patternHandler = new PatternHandler(true);
+ try {
+ PatternData patternData = patternHandler.load(definition);
+ if (patternData != null) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logWarning(
+ NLS.bind(
+ "Pattern Model Should be updated ''{0}''", //$NON-NLS-1$
+ definition
+ )
+ );
+ }
+ }
+ } catch (Throwable t) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(
+ NLS.bind(
+ "Unable to load Pattern Model ''{0}''", //$NON-NLS-1$
+ definition
+ ),
+ t
+ );
+ }
+ PatternActivator.getDefault().log(t);
+ continue;
+ }
+ }
+ }
+
+ private void cleanup() {
+ _patterns = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ protected void clean(IProgressMonitor monitor_p) throws CoreException {
+ // Nothing to do
+ }
+
+ private boolean initialize(IProgressMonitor monitor_p) throws CoreException {
+ // Check
+ if (PatternActivator.getDefault().getBundle().getState() != Bundle.ACTIVE || monitor_p.isCanceled()) {
+ return false;
+ }
+ // Get the current Project
+ IProject project = getProject();
+ // At this stage we check unknown, binary or non java project
+ if (project == null || project.isAccessible() == false || project.hasNature(JavaCore.NATURE_ID) == false) {
+ return false;
+ }
+ // Store the current JavaProject
+ _javaProject = JavaCore.create(project);
+ return true;
+ }
+
+ protected Map<String, IDescriptor> getPatterns() {
+ if (_patterns == null) {
+ _patterns = PatternRegistry.getPatterns(_javaProject.getProject());
+ }
+ return _patterns;
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/builders/PatternTemplateBuilder.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/builders/PatternTemplateBuilder.java
new file mode 100644
index 0000000..6248239
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/builders/PatternTemplateBuilder.java
@@ -0,0 +1,363 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - Initial API and implementation
+ * Soyatec - Contribution
+ *
+ * </copyright>
+ *
+ */
+
+package org.eclipse.egf.pattern.internal.builders;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.common.helper.MathHelper;
+import org.eclipse.egf.console.EGFConsolePlugin;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.internal.PatternRegistry;
+import org.eclipse.egf.pattern.internal.PatternTemplateRegistry;
+import org.eclipse.egf.pattern.production.GeneratedContentHelper;
+import org.eclipse.egf.pattern.production.PatternTemplateProducer;
+
+
+public class PatternTemplateBuilder extends IncrementalProjectBuilder {
+
+ private static boolean DEBUG = PatternActivator.getDefault().isDebugging();
+
+ private static IProject[] EMPTY_LIST = new IProject [0];
+
+ private BinaryGeneratedPatternFolderVisitor _patternVisitor = new BinaryGeneratedPatternFolderVisitor();
+
+ private IPath _binaryOutputPatternPath;
+
+ private IJavaProject _javaProject;
+
+ private Map<String, IDescriptor> _patterns;
+
+ private Map<String, IDescriptor> _patternTemplates;
+
+ class BinaryGeneratedPatternFolderVisitor implements IResourceDeltaVisitor {
+
+ private Collection<IDescriptor> _generate = new ArrayList<IDescriptor>();
+
+ private Collection<IDescriptor> _clean = new ArrayList<IDescriptor>();
+
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if (delta != null) {
+ int kind = delta.getKind();
+ IResource resource = delta.getResource();
+ // Process Folders who contain Pattern model generated classes
+ if (resource.getType() == IResource.FOLDER) {
+ if (_binaryOutputPatternPath.toString().startsWith(resource.getFullPath().toString())) {
+ // Parent folder, Deeper analysis
+ return true;
+ } else if (_binaryOutputPatternPath.equals(resource.getFullPath())) {
+ // Root folder of pattern model generated classes
+ // Everything has been deleted
+ if (kind == IResourceDelta.REMOVED) {
+ // Clean all existing pattern templates
+ _clean.addAll(getPatternTemplates().values());
+ // Stop deeper analysis
+ return false;
+ }
+ // Deeper analysis
+ return true;
+ } else if (resource.getFullPath().toString().startsWith(_binaryOutputPatternPath.toString())) {
+ // Inner pattern model generated classes folder
+ // Pattern Folder has been removed
+ if (kind == IResourceDelta.REMOVED) {
+ // check if we have an existing pattern template
+ // descriptor
+ IDescriptor patternTemplateDescriptor = getPatternTemplate((IFolder) resource);
+ if (patternTemplateDescriptor == null) {
+ // Nothing to process, Stop deeper analysis
+ return false;
+ }
+ _clean.add(patternTemplateDescriptor);
+ }
+ // Pattern Folder has been added or changed descriptor
+ if (kind == IResourceDelta.ADDED || kind == IResourceDelta.CHANGED) {
+ // check if we have an existing pattern
+ IDescriptor patternDescriptor = getPattern((IFolder) resource);
+ if (patternDescriptor == null) {
+ // Nothing to process, Stop deeper analysis
+ return false;
+ }
+ _generate.add(patternDescriptor);
+ }
+ // Stop deeper analysis
+ return false;
+ }
+ } else if (resource.getType() == IResource.PROJECT) {
+ // Project, Deep analysis
+ return true;
+ } else if (resource.getType() == IResource.FILE) {
+ String fileExtension = resource.getFileExtension();
+ if ( fileExtension == null || "".equals(fileExtension) || !PatternConstants.PATTERN_METHOD_FILE_EXTENSION.equals(fileExtension) || !(resource.getParent() instanceof IFolder))
+ return false;
+ IDescriptor patternDescriptor = getPattern((IFolder) resource.getParent());
+ if (patternDescriptor == null)
+ return false;
+ _generate.add(patternDescriptor);
+ }
+ }
+ return true;
+ }
+
+ public void reset() {
+ _generate.clear();
+ _clean.clear();
+ }
+
+ public Collection<IDescriptor> getGenerate() {
+ return _generate;
+ }
+
+ public Collection<IDescriptor> getClean() {
+ return _clean;
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ protected IProject[] build(int kind_p, Map args_p, IProgressMonitor monitor_p) throws CoreException {
+ // Initialize
+ if (initialize(monitor_p) == false) {
+ return EMPTY_LIST;
+ }
+ // Let's build our delta
+ try {
+ IResourceDelta delta = getDelta(_javaProject.getProject());
+ if (kind_p != FULL_BUILD || delta != null) {
+ if (delta.getKind() != IResourceDelta.NO_CHANGE) {
+ // Visit delta
+ _patternVisitor.reset();
+ delta.accept(_patternVisitor);
+ // Clean
+ clean(_patternVisitor.getClean());
+ // Generate
+ generate(_patternVisitor.getGenerate(), monitor_p);
+ }
+ } else {
+ // Generate All available patterns
+ generate(getPatterns().values(), monitor_p);
+ }
+ } finally {
+ cleanup();
+ }
+ // Nothing to return yet
+ return EMPTY_LIST;
+ }
+
+ protected void generate(Collection<IDescriptor> descriptors_p, IProgressMonitor monitor_p) {
+ if (descriptors_p == null) {
+ return;
+ }
+ // Debug Stuff
+ int rank = 1;
+ long start = System.currentTimeMillis();
+ long stepStart = start;
+ // Generate
+ for (IDescriptor descriptor : descriptors_p) {
+ String definition = (String) descriptor.getValue(IPatternConstants.PATTERN_MODEL_ATTRIBUTE_NAME);
+ if (definition == null || definition.trim().length() == 0) {
+ continue;
+ }
+ PatternHandler patternHandler = new PatternHandler(true);
+ try {
+ PatternData patternData = patternHandler.load(definition);
+ if (patternData != null) {
+ PatternTemplateProducer.generateTemplate(patternData);
+ if (DEBUG) {
+ long stepStop = System.currentTimeMillis();
+ EGFConsolePlugin.getConsole().logInfo(
+ NLS.bind(
+ "Generate Pattern Template ''{0}'', step {1}/{2}", //$NON-NLS-1$
+ new Object[] {
+ definition,
+ rank++,
+ descriptors_p.size()
+ }
+ )
+ );
+ EGFConsolePlugin.getConsole().logWarning(
+ NLS.bind(
+ "Total elapsed {0}, Step elapsed {1}", //$NON-NLS-1$
+ MathHelper.formatAsDuration(stepStop - start),
+ MathHelper.formatAsDuration(stepStop - stepStart)
+ ),
+ 1
+ );
+ stepStart = System.currentTimeMillis();
+ }
+ }
+ } catch (Throwable t) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(
+ NLS.bind(
+ "Unable to load Pattern Model ''{0}''", //$NON-NLS-1$
+ definition
+ ),
+ t
+ );
+ }
+ PatternActivator.getDefault().log(t);
+ continue;
+ } finally {
+ // Check Monitor
+ if (monitor_p.isCanceled()) {
+ break;
+ }
+ }
+ }
+ // Refresh project.
+ try {
+ _javaProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, monitor_p);
+ } catch (CoreException ce) {
+ PatternActivator.getDefault().log(ce);
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(
+ NLS.bind(
+ "Unable to refresh project ''{0}''", //$NON-NLS-1$
+ _javaProject.getProject().getName()
+ ),
+ ce
+ );
+ }
+ }
+ }
+
+ protected void clean(Collection<IDescriptor> descriptors_p) {
+ if (descriptors_p == null) {
+ return;
+ }
+ for (IDescriptor descriptor : descriptors_p) {
+ String id = (String) descriptor.getValue(ExtensionPointHelper.ATT_ID);
+ if (id == null || id.trim().length() == 0) {
+ continue;
+ }
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logInfo(
+ NLS.bind(
+ "Clean Pattern Template ''{0}''", //$NON-NLS-1$
+ id
+ )
+ );
+ }
+ PatternTemplateProducer.cleanGeneratedStructures(_javaProject, descriptor);
+ }
+ }
+
+ private void cleanup() {
+ _patterns = null;
+ _patternTemplates = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ protected void clean(IProgressMonitor monitor_p) throws CoreException {
+ // Initialize
+ if (initialize(monitor_p) == false) {
+ return;
+ }
+ // Let's do our clean job
+ try {
+ // Clean all available pattern templates
+ clean(getPatternTemplates().values());
+ } finally {
+ cleanup();
+ }
+ }
+
+ private boolean initialize(IProgressMonitor monitor_p) throws CoreException {
+ // Check
+ if (PatternActivator.getDefault().getBundle().getState() != Bundle.ACTIVE || monitor_p.isCanceled()) {
+ return false;
+ }
+ // Get the current Project
+ IProject project = getProject();
+ // At this stage we check unknown, binary or non java project
+ if (project == null || project.isAccessible() == false || project.hasNature(JavaCore.NATURE_ID) == false) {
+ return false;
+ }
+ // Store the current JavaProject
+ _javaProject = JavaCore.create(project);
+ // Get the generated output bin pattern folder
+ _binaryOutputPatternPath = GeneratedContentHelper.getBinaryOutputPatternGeneratedFolder(_javaProject);
+ if (_binaryOutputPatternPath == null) {
+ return false;
+ }
+ return true;
+ }
+
+ protected Map<String, IDescriptor> getPatterns() {
+ if (_patterns == null) {
+ _patterns = PatternRegistry.getPatterns(_javaProject.getProject());
+ }
+ return _patterns;
+ }
+
+ protected Map<String, IDescriptor> getPatternTemplates() {
+ if (_patternTemplates == null) {
+ _patternTemplates = PatternTemplateRegistry.getPatternTemplates(_javaProject.getProject());
+ }
+ return _patternTemplates;
+ }
+
+ protected IDescriptor getPattern(IFolder folder_p) {
+ if (folder_p == null) {
+ return null;
+ }
+ // Build a possible pattern shortID
+ String shortID = GeneratedContentHelper.getPatternIdentifier(folder_p);
+ if (shortID == null) {
+ return null;
+ }
+ return getPatterns().get(shortID);
+ }
+
+ protected IDescriptor getPatternTemplate(IFolder folder_p) {
+ if (folder_p == null) {
+ return null;
+ }
+ // Build a possible pattern shortID
+ String shortID = GeneratedContentHelper.getPatternIdentifier(folder_p);
+ if (shortID == null) {
+ return null;
+ }
+ return getPatternTemplates().get(shortID);
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/production/jet/JetProductionContributor.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/production/jet/JetProductionContributor.java
new file mode 100644
index 0000000..8b2b21f
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/internal/production/jet/JetProductionContributor.java
@@ -0,0 +1,727 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.internal.production.jet;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Path;
+
+import org.eclipse.emf.codegen.jet.JETCompiler;
+import org.eclipse.emf.codegen.jet.JETException;
+import org.eclipse.emf.codegen.jet.JETMark;
+import org.eclipse.emf.codegen.jet.JETSkeleton;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.query.conditions.eobjects.EObjectTypeRelationCondition;
+import org.eclipse.emf.query.conditions.eobjects.TypeRelation;
+import org.eclipse.emf.query.statements.FROM;
+import org.eclipse.emf.query.statements.SELECT;
+import org.eclipse.emf.query.statements.WHERE;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.helper.EcoreHelper;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.core.context.ProductionContext;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.egf.pattern.ecore.AnnotationHandler;
+import org.eclipse.egf.pattern.ecore.PatternConditionHelper;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.ecore.condition.IConditionConstants;
+import org.eclipse.egf.pattern.ecore.condition.IPatternCondition;
+import org.eclipse.egf.pattern.execution.IPatternExecutionReporter;
+import org.eclipse.egf.pattern.execution.PatternExecutionHelper;
+import org.eclipse.egf.pattern.production.IProductionContributor;
+import org.eclipse.egf.pattern.production.TemplateType;
+import org.eclipse.egf.pattern.production.jet.JETConstants;
+import org.eclipse.egf.pattern.production.template.TemplateHelper;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+import org.eclipse.egf.pde.EgfPdeActivator;
+import org.eclipse.egf.pde.pattern.plugin.command.PatternTemplateExtensionFactory;
+import org.eclipse.egf.pde.plugin.command.IPluginChangesCommand;
+import org.eclipse.egf.pde.plugin.command.IPluginChangesCommandRunner;
+import org.eclipse.egf.pde.plugin.manifest.command.ManifestChangeCommandFactory;
+
+
+/**
+ * @author Guillaume Brocard
+ */
+public class JetProductionContributor implements IProductionContributor {
+
+ /**
+ * Generated template Java class default name suffix.
+ */
+ private static final String JET_SKELETON_CLASS_DEFAULT_SUFFIX = "Generator"; //$NON-NLS-1$
+
+ /**
+ * Jet skeleton 'imports' declaration.
+ */
+ private static final String JET_SKELETON_IMPORTS_DECLARATION = " imports="; //$NON-NLS-1$
+
+ /**
+ * Jet skeleton 'class' declaration.
+ */
+ private static final String JET_SKELETON_CLASS_DECLARATION = " class="; //$NON-NLS-1$
+
+ /**
+ * Jet skeleton 'package' declaration.
+ */
+ private static final String JET_SKELETON_PACKAGE_DECLARATION = " package="; //$NON-NLS-1$
+
+ /**
+ * Jet skeleton start mark-up.
+ */
+ private static final String JET_SKELETON_JSP_START = JETConstants.JET_MARKUP_START + "@ jet"; //$NON-NLS-1$
+
+ /**
+ * Jet generated template skeleton key for compiler options map.
+ */
+ private static final String JET_GENERATED_TEMPLATE_SKELETON_KEY = "skeleton"; //$NON-NLS-1$
+
+ /**
+ * Jet generated template skeleton path.
+ */
+ private static final String JET_GENERATED_TEMPLATE_SKELETON_PATH = "/org.eclipse.egf.pattern/resources/templates/generator.skeleton"; //$NON-NLS-1$
+
+ /**
+ * New initialized string builder (with string buffer).
+ */
+ private static final String NEW_INITIALIZED_STRING_BUILDER = " = new StringBuilder(stringBuffer);\n"; //$NON-NLS-1$
+
+ /**
+ * Declare a string builder prefix directive.
+ */
+ private static final String DECLARE_STRING_BUILDER = "StringBuilder "; //$NON-NLS-1$
+
+ /**
+ * Clear JET string buffer.
+ */
+ private static final String CLEAR_STRING_BUFFER = "stringBuffer = new StringBuffer();\n"; //$NON-NLS-1$
+
+ /**
+ * Call to new, with a space suffix.
+ */
+ private static final String NEW_CALL = "new "; //$NON-NLS-1$
+
+ /**
+ * Close java generic type usage.
+ */
+ private static final String CLOSE_JAVA_1_5_GENERIC_TYPE_USAGE = "> "; //$NON-NLS-1$
+
+ /**
+ * Assignment directive.
+ */
+ private static final String ASSIGNMENT_DIRECTIVE = " = "; //$NON-NLS-1$
+
+ /**
+ * Close method call, then new line.
+ */
+ private static final String JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE = ");\n"; //$NON-NLS-1$
+
+ /**
+ * Start a new block.
+ */
+ private static final String JAVA_CODE_OPEN_BLOCK = "{\n"; //$NON-NLS-1$
+
+ /**
+ * Close parenthesis, then start a new block.
+ */
+ private static final String JAVA_CODE_CLOSE_PAREN_AND_OPEN_BLOCK =
+ ICommonConstants.EMPTY_STRING
+ + ICommonConstants.PARENTHESIS_CLOSE_CHARACTER
+ + ICommonConstants.WHITE_SPACE_CHARACTER + JAVA_CODE_OPEN_BLOCK;
+
+ /**
+ * Close block java code.
+ */
+ private static final String JAVA_CODE_CLOSE_BLOCK = "}\n"; //$NON-NLS-1$
+
+ /**
+ * Jet java code end.
+ */
+ private static final String JAVA_CODE_END = "%>\n"; //$NON-NLS-1$
+
+ /**
+ * Jet java code start.
+ */
+ private static final String JAVA_CODE_BEGIN = "<%\n"; //$NON-NLS-1$
+
+ /**
+ * Set condition context Java call.
+ */
+ private static final String SET_CONDITION_CONTEXT_CALL = ".setContext(context);\n"; //$NON-NLS-1$
+
+ /**
+ * @see org.eclipse.egf.pattern.production.IProductionContributor#createPatternMatchingTemplates(org.eclipse.egf.pattern.ecore.PatternHandler.PatternData,
+ * java.util.List)
+ */
+ public Couple<StringBuilder, StringBuilder> createPatternMatchingTemplates(PatternData patternData_p, List<ParameterRelation> parameters_p) {
+ String patternFullId = patternData_p.getPattern().getId();
+ // Replace both pre and post matching results at the same time.
+ StringBuilder preMatchingResult = new StringBuilder();
+ StringBuilder postMatchingResult = new StringBuilder();
+ // Should buffer delegation be used ?
+ boolean delegateBuffer = patternData_p.getProductionOptionsHandler().shouldModifyBuffer();
+ // Open java code.
+ preMatchingResult.append(JAVA_CODE_BEGIN);
+ postMatchingResult.append(JAVA_CODE_BEGIN);
+ // Create a new Java code block for variable names uniqueness.
+ if (delegateBuffer) {
+ preMatchingResult.append(JAVA_CODE_OPEN_BLOCK);
+ }
+ // Pattern name with first letter set to lower case.
+ String patternNameToLowerFirst = StringHelper.toLowerFirst(
+ StringHelper.replaceNonWordCharacters(
+ patternData_p.getPattern().getShortId(),
+ null
+ )
+ );
+ // Add pattern starting comment tag.
+ preMatchingResult
+ .append("// Start of ") //$NON-NLS-1$
+ .append(patternData_p.getPatternLogicalName())
+ .append(" (full id = ") //$NON-NLS-1$
+ .append(patternFullId)
+ .append(").\n"); //$NON-NLS-1$
+ // Add this piece of code if buffer is to be delegated.
+ String pbVariableName = null;
+ String pbSaveVariableName = null;
+ if (delegateBuffer) {
+ // Replace string buffer with a pattern specific string builder.
+ // Pattern builder variable name.
+ pbVariableName = patternNameToLowerFirst + "Builder"; //$NON-NLS-1$
+ // Pattern builder save variable name.
+ pbSaveVariableName = pbVariableName + "Save"; //$NON-NLS-1$
+ // Declare save builder and initialize it.
+ preMatchingResult
+ .append(DECLARE_STRING_BUILDER)
+ .append(pbSaveVariableName)
+ .append(NEW_INITIALIZED_STRING_BUILDER);
+ }
+ // Deals with parameters, if any.
+ if (parameters_p != null && parameters_p.isEmpty() == false) {
+ // Add this piece of code if buffer is to be delegated.
+ if (delegateBuffer) {
+ // Declare pattern builder and initialize it.
+ preMatchingResult
+ .append(DECLARE_STRING_BUILDER)
+ .append(pbVariableName)
+ .append(" = new StringBuilder();\n"); //$NON-NLS-1$
+ }
+ // EObject fully qualified name.
+ String eObjectFullyQualifiedName = EObject.class.getName();
+ // Pattern condition variable name.
+ String pcVariableName = patternNameToLowerFirst + IConditionConstants.CONDITION_CLASS_NAME_SUFFIX;
+ // Declare pattern condition class instance.
+ String patternConditionInterfaceName = IPatternCondition.class.getName();
+ preMatchingResult
+ .append(patternConditionInterfaceName)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(pcVariableName);
+ preMatchingResult.append(ASSIGNMENT_DIRECTIVE);
+ preMatchingResult
+ .append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER)
+ .append(patternConditionInterfaceName)
+ .append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER);
+ preMatchingResult
+ .append(ExtensionPointHelper.class.getName())
+ .append(".createExecutableExtension("); //$NON-NLS-1$
+ preMatchingResult
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(PatternActivator.getDefault().getPluginID())
+ .append(ICommonConstants.QUOTE_CHARACTER);
+ preMatchingResult.append(",\"patternCondition\""); //$NON-NLS-1$
+ preMatchingResult.append(",\"patternId\""); //$NON-NLS-1$
+ preMatchingResult
+ .append(ICommonConstants.COMMA_CHARACTER)
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(patternFullId)
+ .append(ICommonConstants.QUOTE_CHARACTER);
+ preMatchingResult.append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE);
+ // Test it.
+ preMatchingResult
+ .append("if (null != ") //$NON-NLS-1$
+ .append(pcVariableName)
+ .append(JAVA_CODE_CLOSE_PAREN_AND_OPEN_BLOCK);
+ // If it's not being null, then create all query statements for the parameters.
+ // First set context to the condition class.
+ preMatchingResult
+ .append(pcVariableName)
+ .append(SET_CONDITION_CONTEXT_CALL);
+ // Parameters list is not tested against nullity or emptiness.
+ // It is expected that the pattern content has not changed between the generation of the condition structures and the
+ // use of the pattern. If not, there has been an error during a modification (such as a re-factoring).
+ String patternParametersVariableName = patternNameToLowerFirst + "Parameters"; //$NON-NLS-1$
+ preMatchingResult
+ .append(List.class.getName())
+ .append('<')
+ .append(ParameterRelation.class.getName())
+ .append(CLOSE_JAVA_1_5_GENERIC_TYPE_USAGE);
+ preMatchingResult.append(patternParametersVariableName);
+ preMatchingResult
+ .append(ASSIGNMENT_DIRECTIVE)
+ .append(PatternConditionHelper.class.getName())
+ .append(".getPatternParameters("); //$NON-NLS-1$
+ preMatchingResult
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(patternFullId)
+ .append(ICommonConstants.QUOTE_CHARACTER);
+ preMatchingResult.append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE);
+ // Define the tuple map result.
+ String resultMapVariableName = patternNameToLowerFirst + "Result"; //$NON-NLS-1$
+ String resultMapVariableGenerics = "<String, " + eObjectFullyQualifiedName + CLOSE_JAVA_1_5_GENERIC_TYPE_USAGE; //$NON-NLS-1$
+ preMatchingResult
+ .append(Map.class.getName())
+ .append(resultMapVariableGenerics);
+ preMatchingResult
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(resultMapVariableName)
+ .append(ASSIGNMENT_DIRECTIVE);
+ preMatchingResult
+ .append(NEW_CALL)
+ .append(HashMap.class.getName())
+ .append(resultMapVariableGenerics)
+ .append("();\n"); //$NON-NLS-1$
+ // Injected in preMatchingResult in the end. Allows to cycle through parameters only one time.
+ StringBuilder temporaryLoops = new StringBuilder();
+ StringBuilder temporaryCondition = new StringBuilder("if (") //$NON-NLS-1$
+ .append(pcVariableName)
+ .append(".check("); //$NON-NLS-1$
+ // Injected in postMatchingResult in the end, for the very same reason.
+ StringBuilder temporaryPostLoops = new StringBuilder();
+ // Create string content based on given parameters.
+ int i = 0;
+ for (Iterator<ParameterRelation> parameters = parameters_p.iterator(); parameters.hasNext();) {
+ ParameterRelation currentParameter = parameters.next();
+ // Parameter name.
+ String paramName = currentParameter.getName();
+ // Parameter type name.
+ String paramTypeName = currentParameter.getType().getName();
+ // Parameter relation variable.
+ String paramRelationName = paramName + "Relation"; //$NON-NLS-1$
+ preMatchingResult
+ .append(ParameterRelation.class.getName())
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(paramRelationName);
+ preMatchingResult
+ .append(ASSIGNMENT_DIRECTIVE)
+ .append(patternParametersVariableName)
+ .append(".get(") //$NON-NLS-1$
+ .append(i)
+ .append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE);
+ // Loop parameter name.
+ String loopParamName = paramName + "Loop"; //$NON-NLS-1$
+ // Declared collection of objects for current parameter.
+ String collectionVariableName = paramName + "Collection"; //$NON-NLS-1$
+ // Compute such a collection.
+ preMatchingResult
+ .append(Collection.class.getName())
+ .append('<')
+ .append(eObjectFullyQualifiedName)
+ .append(CLOSE_JAVA_1_5_GENERIC_TYPE_USAGE)
+ .append(collectionVariableName)
+ .append(ASSIGNMENT_DIRECTIVE);
+ preMatchingResult
+ .append(NEW_CALL)
+ .append(SELECT.class.getName())
+ .append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ preMatchingResult
+ .append(NEW_CALL)
+ .append(FROM.class.getName())
+ .append("(resource.getContents()), "); //$NON-NLS-1$
+ preMatchingResult
+ .append(NEW_CALL)
+ .append(WHERE.class.getName())
+ .append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ preMatchingResult
+ .append(NEW_CALL)
+ .append(EObjectTypeRelationCondition.class.getName())
+ .append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ preMatchingResult
+ .append(EcoreHelper.class.getName())
+ .append(".getStaticClass(") //$NON-NLS-1$
+ .append(paramRelationName)
+ .append(".getType()),"); //$NON-NLS-1$
+ // Append query relation type.
+ // By default, always search for elements of the same type, or that are a sub-type, of given one.
+ preMatchingResult
+ .append(TypeRelation.class.getName())
+ .append(".SAMETYPE_OR_SUBTYPE_LITERAL"); //$NON-NLS-1$
+ // Close query call.
+ preMatchingResult.append("))).execute();\n"); //$NON-NLS-1$
+ // Add for directive associated to current parameter.
+ temporaryLoops
+ .append("for (") //$NON-NLS-1$
+ .append(eObjectFullyQualifiedName)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(loopParamName).append(" : ") //$NON-NLS-1$
+ .append(collectionVariableName)
+ .append(JAVA_CODE_CLOSE_PAREN_AND_OPEN_BLOCK);
+ // Add real parameter declaration (for use in the template), for the parameter is used as an EObject so far.
+ // Eg : EClass myParameter = (EClass) myParameterLoop;
+ temporaryLoops
+ .append(paramTypeName)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(paramName);
+ temporaryLoops
+ .append(ASSIGNMENT_DIRECTIVE)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(ICommonConstants.PARENTHESIS_OPEN_CHARACTER);
+ temporaryLoops
+ .append(paramTypeName)
+ .append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER)
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER);
+ temporaryLoops
+ .append(loopParamName)
+ .append(ICommonConstants.SEMICOLON_CHARACTER)
+ .append(ICommonConstants.EOL_CHARACTER);
+ // Add completion of the tuple to postMatchingResult.
+ postMatchingResult
+ .append(resultMapVariableName)
+ .append(".put(") //$NON-NLS-1$
+ .append(paramRelationName)
+ .append(".getName(), "); //$NON-NLS-1$
+ postMatchingResult
+ .append(loopParamName)
+ .append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE);
+ // Add an end for directive.
+ temporaryPostLoops.append(JAVA_CODE_CLOSE_BLOCK);
+ // Append parameter name for condition call.
+ temporaryCondition.append(loopParamName);
+ if (parameters.hasNext()) {
+ temporaryCondition.append(ICommonConstants.COMMA_CHARACTER);
+ }
+ // Increment parameter position.
+ i++;
+ }
+ // Add for loops to pre-matching.
+ preMatchingResult.append(temporaryLoops.toString());
+ // If condition directive.
+ preMatchingResult.append(temporaryCondition.toString());
+ preMatchingResult.append(")) {\n"); //$NON-NLS-1$
+ // Add this piece of code if buffer is to be delegated.
+ if (delegateBuffer) {
+ // Clear string buffer.
+ preMatchingResult.append(CLEAR_STRING_BUFFER);
+ // Call reporter for current string buffer content.
+ // Output result.
+ postMatchingResult
+ .append("reporter.patternLoopExecutionFinished(") //$NON-NLS-1$
+ .append("stringBuffer.toString(),"); //$NON-NLS-1$
+ // Pattern fullId.
+ postMatchingResult
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(patternFullId)
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(ICommonConstants.COMMA_CHARACTER);
+ // Context.
+ postMatchingResult.append("context,"); //$NON-NLS-1$
+ // Resulting tuple.
+ postMatchingResult
+ .append(resultMapVariableName)
+ .append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE);
+ // Append tuple result to pattern builder.
+ postMatchingResult
+ .append(pbVariableName)
+ .append(".append(stringBuffer)") //$NON-NLS-1$
+ .append(ICommonConstants.SEMICOLON_CHARACTER)
+ .append(ICommonConstants.EOL_CHARACTER);
+ }
+ // Append loops closures.
+ postMatchingResult.append(temporaryPostLoops);
+ // Close if condition directive.
+ postMatchingResult.append(JAVA_CODE_CLOSE_BLOCK);
+ // Close if condition not null directive.
+ postMatchingResult.append(JAVA_CODE_CLOSE_BLOCK);
+ } else if (delegateBuffer) {
+ // Clear string buffer, now that it is saved.
+ preMatchingResult.append(CLEAR_STRING_BUFFER);
+ // Set pattern builder to string buffer, when work is done.
+ postMatchingResult
+ .append(DECLARE_STRING_BUILDER)
+ .append(pbVariableName)
+ .append(NEW_INITIALIZED_STRING_BUILDER);
+ }
+ // Add this piece of code if buffer is to be delegated.
+ if (delegateBuffer) {
+ // Restore string buffer.
+ postMatchingResult
+ .append("stringBuffer = new StringBuffer(") //$NON-NLS-1$
+ .append(pbSaveVariableName)
+ .append(ICommonConstants.PARENTHESIS_CLOSE_CHARACTER);
+ postMatchingResult
+ .append(".append(") //$NON-NLS-1$
+ .append(pbVariableName)
+ .append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE);
+ // Call reporter for pattern execution.
+ postMatchingResult
+ .append("reporter.patternExecutionFinished(") //$NON-NLS-1$
+ .append(pbVariableName)
+ .append(".toString(),"); //$NON-NLS-1$
+ postMatchingResult
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(patternFullId)
+ .append(ICommonConstants.QUOTE_CHARACTER)
+ .append(ICommonConstants.COMMA_CHARACTER);
+ postMatchingResult
+ .append("context")
+ .append(JAVA_CODE_CLOSE_CALL_AND_RETURN_LINE); //$NON-NLS-1$
+ }
+ // Add pattern ending comment tag.
+ postMatchingResult
+ .append("// End of ") //$NON-NLS-1$
+ .append(patternData_p.getPatternLogicalName())
+ .append(" (full id = ") //$NON-NLS-1$
+ .append(patternData_p.getPattern().getId())
+ .append(").\n"); //$NON-NLS-1$
+ // Close Java code block for variable names uniqueness.
+ if (delegateBuffer) {
+ postMatchingResult.append(JAVA_CODE_CLOSE_BLOCK);
+ }
+ // Close java code.
+ preMatchingResult.append(JAVA_CODE_END);
+ postMatchingResult.append(JAVA_CODE_END);
+ // Return result.
+ return new Couple<StringBuilder, StringBuilder>(preMatchingResult, postMatchingResult);
+ }
+
+ /**
+ * @see org.eclipse.egf.pattern.production.IProductionContributor#compileTemplate(java.lang.String,
+ * org.eclipse.egf.pattern.ecore.PatternHandler.PatternData)
+ */
+ public boolean compileTemplate(String patternTemplatePath_p, PatternData patternData_p) throws Exception {
+ // Now that the template is created, compile it.
+ // Get mandatory templates containers.
+ String[] templateContainerUris = {
+ FileHelper.getFileFullUri(patternData_p.getPluginId() + TemplateHelper.TEMPLATES_ROOT_PATH).toString(),
+ URI.createURI("platform:/plugin/org.eclipse.emf.codegen.ecore/templates").toString() //$NON-NLS-1$
+ };
+ // Format template relative path.
+ String relativePath = new Path(patternTemplatePath_p).removeFirstSegments(2).toString();
+ // Call jet compiler.
+ JETCompiler jetCompiler = new JETCompiler(templateContainerUris, relativePath) {
+ @Override
+ public void handleDirective(String directive_p, JETMark start_p, JETMark stop_p, Map<String, String> attributes_p) throws JETException {
+ attributes_p.put(
+ JET_GENERATED_TEMPLATE_SKELETON_KEY,
+ FileHelper.getFileFullUri(JET_GENERATED_TEMPLATE_SKELETON_PATH).toString()
+ );
+ super.handleDirective(directive_p, start_p, stop_p, attributes_p);
+ }
+ };
+ jetCompiler.parse();
+ // And write the resulting java code !
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ jetCompiler.generate(outputStream);
+ JETSkeleton skeleton = jetCompiler.getSkeleton();
+ StringBuilder ultimateGeneratedClassPath = new StringBuilder(patternData_p.getJavaProject().getProject().getFolder(PatternConstants.GENERATION_SOURCE_FOLDER).getFullPath().toString());
+ ultimateGeneratedClassPath
+ .append(ICommonConstants.SLASH_CHARACTER)
+ .append(FileHelper.convertPackageNameToFolderPath(skeleton.getPackageName()));
+ ultimateGeneratedClassPath
+ .append(ICommonConstants.SLASH_CHARACTER)
+ .append(skeleton.getClassName())
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(IPatternConstants.JAVA_SOURCE_FILE_EXTENSION);
+ // Generated Java code.
+ String javaCode = new String(outputStream.toByteArray());
+ // Modify generated Java code buffer declaration.
+ if (patternData_p.getProductionOptionsHandler().shouldModifyBuffer()) {
+ StringBuilder codeTweak = new StringBuilder("StringBuffer stringBuffer = new StringBuffer();\n"); //$NON-NLS-1$
+ String helperClassName = PatternExecutionHelper.class.getName();
+ // Append resource variable.
+ codeTweak
+ .append(Resource.class.getName())
+ .append(" resource = ") //$NON-NLS-1$
+ .append(helperClassName)
+ .append(".getResource(argument);\n"); //$NON-NLS-1$
+ // Append context variable.
+ codeTweak
+ .append(ProductionContext.class.getName())
+ .append(" context = ") //$NON-NLS-1$
+ .append(helperClassName)
+ .append(".getContext(argument);\n"); //$NON-NLS-1$
+ // Append reporter variable.
+ codeTweak
+ .append(IPatternExecutionReporter.class.getName())
+ .append(" reporter = ") //$NON-NLS-1$
+ .append(helperClassName)
+ .append(".getExecutionReporter(argument);\n"); //$NON-NLS-1$
+ // Remove final statement in the declaration of the string buffer.
+ javaCode = javaCode.replace("final StringBuffer stringBuffer = new StringBuffer();", codeTweak.toString()); //$NON-NLS-1$
+ }
+ boolean fileWritten = FileHelper.writeFile(
+ ultimateGeneratedClassPath.toString(),
+ true,
+ javaCode
+ );
+ if (fileWritten) {
+ // Add containing package to exported ones.
+ performManifestChanges(
+ patternData_p,
+ ManifestChangeCommandFactory.setExportedPackages(
+ new String[] {
+ skeleton.getPackageName()
+ }
+ )
+ );
+ // Update plugin.xml content accordingly.
+ performPluginChanges(
+ patternData_p,
+ PatternTemplateExtensionFactory.setPatternTemplateExtension(
+ patternData_p.getPattern().getId(),
+ new StringBuilder(skeleton.getPackageName())
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(skeleton.getClassName())
+ .toString(),
+ TemplateType.JET.getId(),
+ patternTemplatePath_p
+ )
+ );
+ }
+ return fileWritten;
+ }
+
+ /**
+ * @see org.eclipse.egf.pattern.production.IProductionContributor#fillGenerateHeader(org.eclipse.egf.pattern.ecore.PatternHandler.PatternData,
+ * org.eclipse.egf.pattern.ecore.AnnotationHandler)
+ */
+ public void fillGenerateHeader(PatternData patternData_p, AnnotationHandler handler_p) throws Exception {
+ // Precondition.
+ // Pattern is not expected to be compiled to a Java class.
+ // Do not create a useless header, that may well indeed be a new source of confusion for both users
+ // and Jet compiler.
+ if (patternData_p.getProductionOptionsHandler().shouldCompileTemplate() == false) {
+ return;
+ }
+ AnnotationHandler handler = handler_p;
+ // Instantiate annotation handler, if none provided.
+ if (handler == null) {
+ handler = new AnnotationHandler();
+ }
+ // Get template file path.
+ // First get generateHeader method.
+ // Should always be not null, for it is added automatically at creation time.
+ EOperation generateHeader = null;
+ String generateHeaderName = PatternConstants.GENERATE_HEADER_METHOD_NAME;
+ for (EOperation operation : patternData_p.getPattern().getEOperations()) {
+ if (generateHeaderName.equals(operation.getName())) {
+ generateHeader = operation;
+ break;
+ }
+ }
+ // Again, should not be null, for it is computed at creation time.
+ String generateHeaderUid = handler.getUid(generateHeader);
+ // Associated template file relative path.
+ String templateFileRelativePath = TemplateHelper.getTemplateRelativePath(
+ patternData_p.getPattern().getShortId(),
+ patternData_p.getPluginId(),
+ generateHeaderName,
+ generateHeaderUid
+ );
+ // Read generate header template content.
+ String generateHeaderContent = FileHelper.readFile(templateFileRelativePath);
+ // Existing content, stop here.
+ if (ICommonConstants.EMPTY_STRING.equals(StringHelper.replaceNonWordCharacters(generateHeaderContent, null).trim()) == false) {
+ return;
+ }
+ // Empty content, create default one.
+ // Start JET mark-up.
+ StringBuilder content = new StringBuilder(JET_SKELETON_JSP_START);
+ // Fill package structure and value.
+ content
+ .append(JET_SKELETON_PACKAGE_DECLARATION)
+ .append(ICommonConstants.QUOTE_CHARACTER);
+ // Computed package name
+ String patternName = patternData_p.getPatternLogicalName();
+ content
+ .append(patternData_p.getPluginId())
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(patternName.toLowerCase());
+ // End package structure.
+ content.append(ICommonConstants.QUOTE_CHARACTER);
+ // Fill class structure and value.
+ content
+ .append(JET_SKELETON_CLASS_DECLARATION)
+ .append(ICommonConstants.QUOTE_CHARACTER);
+ // Computed class name looks like toUpperFirst('patternName')Generator
+ content
+ .append(StringHelper.toUpperFirst(patternName))
+ .append(JET_SKELETON_CLASS_DEFAULT_SUFFIX);
+ // End class structure.
+ content.append(ICommonConstants.QUOTE_CHARACTER);
+ // Fill imports structure and value.
+ content
+ .append(JET_SKELETON_IMPORTS_DECLARATION)
+ .append(ICommonConstants.QUOTE_CHARACTER);
+ // Compute parameters dependencies.
+ List<ParameterRelation> parameters = patternData_p.getAllParameters();
+ // Add imports for each of them.
+ for (ParameterRelation parameterRelation : parameters) {
+ EPackage parameterPackage = parameterRelation.getType().getEPackage();
+ // Parameter package name.
+ String packageImportedName = EcoreHelper.getImportedPackageName(parameterPackage);
+ if (packageImportedName != null) {
+ // Added import looks like
+ content
+ .append(packageImportedName)
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(parameterRelation.getType().getName())
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER);
+ }
+ }
+ // End imports structure.
+ content.append(ICommonConstants.QUOTE_CHARACTER);
+ // End JET mark-up.
+ content
+ .append(ICommonConstants.WHITE_SPACE_CHARACTER)
+ .append(JETConstants.JET_MARKUP_END)
+ .append(ICommonConstants.EOL_CHARACTER)
+ .append(ICommonConstants.EOL_CHARACTER);
+ // Write content to file.
+ FileHelper.writeFile(templateFileRelativePath, true, content.toString());
+ }
+
+ /**
+ * Perform changes on manifest file.
+ * @param patternData_p
+ * @param command_p
+ */
+ protected static void performManifestChanges(PatternData patternData_p, IPluginChangesCommand command_p) {
+ IPluginChangesCommandRunner runner = EgfPdeActivator.getDefault().getPluginChangesCommandRunner();
+ runner.performChangesOnManifest(patternData_p.getPluginId(), Collections.singletonList(command_p));
+ }
+
+ /**
+ * Perform changes on plugin.xml file.
+ * @param patternData_p
+ * @param command_p
+ */
+ protected static void performPluginChanges(PatternData patternData_p, IPluginChangesCommand command_p) {
+ IPluginChangesCommandRunner runner = EgfPdeActivator.getDefault().getPluginChangesCommandRunner();
+ runner.performChangesOnPlugin(patternData_p.getPluginId(), Collections.singletonList(command_p));
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/GeneratedContentHelper.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/GeneratedContentHelper.java
new file mode 100644
index 0000000..ce53930
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/GeneratedContentHelper.java
@@ -0,0 +1,288 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaModelException;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.constant.IPatternTemplateConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.generator.IEgfGeneratorConstants;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.pattern.Pattern;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pde.pattern.reader.WorkspacePatternTemplateExtensionReader;
+
+
+/**
+ * @author Guillaume Brocard
+ */
+public class GeneratedContentHelper {
+
+ /**
+ * Get the pattern model output IFolder.
+ * @param project_p
+ * @return null if given parameter is null.
+ */
+ public static IFolder getPatternOutputPath(IProject project_p) {
+ // Precondition.
+ if (project_p == null) {
+ return null;
+ }
+ IResource resource = project_p.findMember(PatternConstants.PATTERN_MODEL_FOLDER_IPATH);
+ if (resource != null && resource instanceof IFolder) {
+ return (IFolder) resource;
+ }
+ return null;
+ }
+
+ /**
+ * Get the binary output pattern generated IPath.
+ * @param project_p
+ * @return null if given parameter is null.
+ */
+ public static IPath getBinaryOutputPatternGeneratedFolder(IJavaProject project_p) {
+ // Precondition.
+ if (project_p == null) {
+ return null;
+ }
+ IPath path = null;
+ try {
+ path = project_p.getOutputLocation()
+ .append(
+ FileHelper.convertPackageNameToFolderPath(
+ PatternConstants.PATTERN_GENERATED_BASE_PACKAGE
+ )
+ );
+ } catch (JavaModelException jme) {
+ // Just Ignore
+ }
+ return path;
+ }
+
+ /**
+ * Get an IFile as a normalized Pattern shortID.
+ * This implementation is the opposite transformation of
+ * the getPatternClassName method.
+ * @param pattern_p
+ * @return null if given parameter is null.
+ */
+ public static String getPatternIdentifier(IFile element_p) {
+ // Precondition.
+ if (element_p == null || element_p.getFullPath() == null) {
+ return null;
+ }
+ return StringHelper.replaceNonWordCharactersWithDot(element_p.getFullPath().removeFileExtension().lastSegment());
+ }
+
+ /**
+ * Get pattern generated EMF class name.
+ * This implementation is the opposite transformation of
+ * the getPatternIdentifier method.
+ * @param pattern_p
+ * @return null if given parameter is null.
+ */
+ public static String getPatternClassName(Pattern pattern_p) {
+ // Precondition.
+ if (pattern_p == null) {
+ return null;
+ }
+ return StringHelper.replaceNonWordCharactersWithUnderscore(pattern_p.getShortId());
+ }
+
+ /**
+ * Get an IFolder as a normalized Pattern shortID.
+ * This implementation is the opposite transformation of
+ * the getPatternPackageName method.
+ * @param pattern_p
+ * @return null if given parameter is null.
+ */
+ public static String getPatternIdentifier(IFolder element_p) {
+ // Precondition.
+ if (element_p == null || element_p.getName() == null) {
+ return null;
+ }
+ return StringHelper.replaceNonWordCharactersWithDot(StringHelper.toUpperFirst(element_p.getName()));
+ }
+
+ /**
+ * Get pattern generated EMF package name.
+ * This implementation is the opposite transformation of
+ * the getPatternIdentifier method.
+ * @param pattern_p
+ * @return null if given parameter is null.
+ */
+ public static String getPatternPackageName(Pattern pattern_p) {
+ // Precondition.
+ if (pattern_p == null || pattern_p.getShortId() == null) {
+ return null;
+ }
+ return StringHelper.replaceNonWordCharactersWithUnderscore(StringHelper.toLowerFirst(pattern_p.getShortId()));
+ }
+
+ /**
+ * Get pattern generated EMF package namespace prefix.
+ * @param pattern_p
+ * @return null if given parameter is null.
+ */
+ public static String getPatternPackageNsPrefix(Pattern pattern_p) {
+ return getPatternPackageName(pattern_p);
+ }
+
+ /**
+ * Get pattern generated EMF package namespace URI.
+ * @param pattern_p
+ * @return null if given parameter is null.
+ */
+ public static String getPatternPackageNsURI(Pattern pattern_p) {
+ // Precondition.
+ if (pattern_p == null || pattern_p.getShortId() == null) {
+ return null;
+ }
+ return PatternConstants.PATTERN_GENERATED_ECORE_NS_URI_PREFIX + pattern_p.getShortId();
+ }
+
+ /**
+ * Get pattern generated EMF root folder path.
+ * @param patternData_p
+ * @return null if given parameter is null.
+ */
+ public static String getEMFGeneratedRootFolderRelativePath(PatternData patternData_p) {
+ // Precondition.
+ if (patternData_p == null) {
+ return null;
+ }
+ // And its relative path.
+ IPath rootGeneratedPackageRelativePath =
+ new Path(
+ ICommonConstants.SLASH_CHARACTER
+ + patternData_p.getPluginId()
+ ).append(
+ PatternConstants.GENERATION_SOURCE_FOLDER
+ ).append(
+ ICommonConstants.SLASH_CHARACTER
+ + FileHelper.convertPackageNameToFolderPath(
+ PatternConstants.PATTERN_GENERATED_BASE_PACKAGE
+ + ICommonConstants.DOT_CHARACTER
+ + getPatternPackageName(patternData_p.getPattern())
+ )
+ );
+ return rootGeneratedPackageRelativePath.toString();
+ }
+
+ /**
+ * Get pattern generated EMF packages names.
+ * @param patternData_p
+ * @return a list of packages names. Empty if given pattern data is null.
+ */
+ public static List<String> getEMFGeneratedPackagesNames(PatternData patternData_p) {
+ // Precondition.
+ List<String> result = Collections.emptyList();
+ if (patternData_p == null) {
+ return result;
+ }
+ result = new ArrayList<String>(3);
+ // Compute base package name.
+ String baseGeneratedPackageName =
+ PatternConstants.PATTERN_GENERATED_BASE_PACKAGE
+ + ICommonConstants.DOT_CHARACTER
+ + getPatternPackageName(patternData_p.getPattern());
+ // Add base package relative path.
+ result.add(baseGeneratedPackageName);
+ // Add implementation package relative path.
+ result.add(
+ baseGeneratedPackageName
+ + IEgfGeneratorConstants.GENERATED_IMPL_JAVA_PACKAGE_SUFFIX
+ );
+ // Add tools package relative path.
+ result.add(
+ baseGeneratedPackageName
+ + IEgfGeneratorConstants.GENERATED_UTIL_JAVA_PACKAGE_SUFFIX
+ );
+ return result;
+ }
+
+ /**
+ * Get generated pattern class description, if applicable.<br>
+ * That is, if the pattern engine leads to a compiled Java class, get its package and class names.<br>
+ * @param patternData_p
+ * @return null if not applicable, or could not be found (not compiled yet). Else, a (package name, class name) couple.
+ */
+ protected static Couple<String, String> getPatternTemplateClassDescription(PatternData patternData_p) {
+ Couple<String, String> result = null;
+ if (patternData_p == null) {
+ return result;
+ }
+ IDescriptor classDescriptor = new WorkspacePatternTemplateExtensionReader().readPatternTemplateExtension(
+ patternData_p.getJavaProject().getProject(),
+ patternData_p.getPattern().getShortId()
+ );
+ if (classDescriptor == null) {
+ return result;
+ }
+ String templateClass = (String) classDescriptor.getValue(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_CLASS);
+ if (templateClass != null) {
+ String className = StringHelper.substringAfter(ICommonConstants.DOT_CHARACTER, templateClass);
+ String packageName = StringHelper.substringBefore(ICommonConstants.DOT_CHARACTER, templateClass);
+ result = new Couple<String, String>(packageName, className);
+ }
+ return result;
+ }
+
+ /**
+ * Get generated pattern class relative path, if any.<br>
+ * A pattern may not have a generated class, if :<br>
+ * <ul>
+ * <li>either the pattern engine type does not support a Java class transformation.</li>
+ * <li>or the pattern has not been produced yet, and thus no Java class can be found.</li>
+ * </ul>
+ * @param patternData_p
+ * @return null if it could not be found, else the workspace relative path to the Java class.
+ */
+ public static String getGeneratedPatternClassRelativePath(PatternData patternData_p) {
+ Couple<String, String> generatedPatternClassDescription = getPatternTemplateClassDescription(patternData_p);
+ if (generatedPatternClassDescription == null) {
+ return null;
+ }
+ IPath generatedPatternClassRelativePath =
+ new Path(
+ ICommonConstants.SLASH_CHARACTER
+ + patternData_p.getPluginId()
+ ).append(
+ PatternConstants.GENERATION_SOURCE_FOLDER
+ ).append(
+ ICommonConstants.SLASH_CHARACTER
+ + FileHelper.convertPackageNameToFolderPath(generatedPatternClassDescription.getKey())
+ ).append(
+ ICommonConstants.SLASH_CHARACTER
+ + generatedPatternClassDescription.getValue()
+ ).addFileExtension(
+ IPatternConstants.JAVA_SOURCE_FILE_EXTENSION
+ );
+ return generatedPatternClassRelativePath.toString();
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/GeneratedContentProducer.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/GeneratedContentProducer.java
new file mode 100644
index 0000000..9702d56
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/GeneratedContentProducer.java
@@ -0,0 +1,383 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.ProjectHelper;
+import org.eclipse.egf.common.helper.StringHelper;
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.core.CoreActivator;
+import org.eclipse.egf.model.Context;
+import org.eclipse.egf.model.FactoryComponent;
+import org.eclipse.egf.model.FactoryComponentInvocation;
+import org.eclipse.egf.model.ModelFactory;
+import org.eclipse.egf.model.data.helper.ModelHelper;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.ecore.condition.ConditionClassOutput;
+import org.eclipse.egf.pattern.ecore.condition.IConditionConstants;
+import org.eclipse.egf.pattern.internal.ConditionMergeHelper;
+import org.eclipse.egf.pattern.internal.production.jet.JetProductionContributor;
+import org.eclipse.egf.pattern.production.template.TemplateHelper;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+import org.eclipse.egf.pde.EgfPdeActivator;
+import org.eclipse.egf.pde.pattern.plugin.command.PatternConditionExtensionFactory;
+import org.eclipse.egf.pde.plugin.command.IPluginChangesCommandRunner;
+
+/**
+ * The producer responsible for all generated content.
+ * @author Guillaume Brocard
+ */
+public class GeneratedContentProducer {
+
+ /**
+ * Condition source code folder.
+ */
+ protected static final String CONDITION_SOURCE_FOLDER = "/src"; //$NON-NLS-1$
+
+ /**
+ * Platform specific production contributor.
+ */
+ private IProductionContributor _contributor;
+
+ /**
+ * Constructor.
+ */
+ public GeneratedContentProducer() {
+ _contributor = new JetProductionContributor();
+ }
+
+ /**
+ * Get associated production contributor.
+ * @return
+ */
+ public IProductionContributor getProductionContributor() {
+ return _contributor;
+ }
+
+ /**
+ * @see org.eclipse.egf.pattern.ecore.condition.IConditionProducer#produceConditionStructures(java.lang.String)
+ */
+ public void produceConditionStructures(String fileRelativePath_p) throws Exception {
+ PatternData patternData = new PatternHandler().load(fileRelativePath_p);
+ // Call sibling method.
+ produceConditionStructures(patternData);
+ }
+
+ /**
+ * Produce condition structures based on given pattern data.
+ * @param patternData_p
+ * @throws Exception
+ */
+ public void produceConditionStructures(PatternData patternData_p) throws Exception {
+ // Precondition.
+ if (patternData_p == null) {
+ return;
+ }
+ // Get all parameters.
+ List<ParameterRelation> parameters = patternData_p.getAllParameters();
+ // Preconditions.
+ if (parameters == null || parameters.isEmpty()) {
+ removeOldConditionStructures(patternData_p);
+ // Refresh project.
+ ProjectHelper.refreshProject(
+ patternData_p.getJavaProject().getProject(),
+ null
+ );
+ return;
+ }
+ // Update condition Java class code, according to parameters list.
+ updateConditionClass(patternData_p, parameters);
+ // Replace matching pre/post templates.
+ replacePatternMatchingTemplates(patternData_p, parameters);
+ // Refresh project.
+ ProjectHelper.refreshProject(
+ patternData_p.getJavaProject().getProject(),
+ null
+ );
+ }
+
+ /**
+ * Produce public parameters handler.
+ * @param patternData_p
+ */
+ protected void producePublicParametersHandler(PatternData patternData_p) {
+ // Create a factory component dynamically.
+ FactoryComponent fc = ModelHelper.createEmptyMinimalFC("GeneratePublicParametersHandler"); //$NON-NLS-1$
+ // Add required factory component invocation.
+ String generatorId = "asset.1212745121407.14"; //$NON-NLS-1$
+ FactoryComponentInvocation fcInvocation = ModelHelper.addFactoryComponentInvocation(
+ fc,
+ generatorId
+ );
+ // Add a context.
+ Context context = ModelFactory.eINSTANCE.createContext();
+ fcInvocation.setContext(context);
+ // Add context elements.
+ String contributorId = PatternActivator.getDefault().getPluginID();
+ // Model path.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ generatorId,
+ "contractElement.1212763579828.93", //$NON-NLS-1$
+ patternData_p.getRealRelativePath(),
+ contributorId
+ );
+ // Pattern name.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ generatorId,
+ "contractElement.1212763518024.91", //$NON-NLS-1$
+ patternData_p.getPatternName(),
+ contributorId
+ );
+ // Plug-in ID.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ generatorId,
+ "contractElement.1212763360724.90", //$NON-NLS-1$
+ patternData_p.getPluginId(),
+ contributorId
+ );
+ // Execute it.
+ CoreActivator.getDefault().generateFactoryComponentSynchronously(fc);
+ }
+
+ /**
+ * Get condition class content as for given pattern data.
+ * @param patternData_p
+ * @return null if an error occurred, {@link ICommonConstants#EMPTY_STRING} if it could not be generated.
+ */
+ protected String getConditionClassContent(PatternData patternData_p) {
+ // Result output container.
+ ConditionClassOutput.getSharedInstance().reset();
+ // Create a factory component dynamically.
+ FactoryComponent fc = ModelHelper.createEmptyMinimalFC("GenerateConditionClass"); //$NON-NLS-1$
+ // Add required factory component invocation.
+ String generatorId = "asset.1213692164306.87"; //$NON-NLS-1$
+ FactoryComponentInvocation fcInvocation = ModelHelper.addFactoryComponentInvocation(
+ fc,
+ generatorId
+ );
+ // Add a context.
+ Context context = ModelFactory.eINSTANCE.createContext();
+ fcInvocation.setContext(context);
+ // Add context elements.
+ String contributorId = PatternActivator.getDefault().getPluginID();
+ // Model path.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ generatorId,
+ "contractElement.1213715622825.42", //$NON-NLS-1$
+ patternData_p.getRealRelativePath(),
+ contributorId
+ );
+ // Execute it.
+ CoreActivator.getDefault().generateFactoryComponentSynchronously(fc);
+ // Extract result.
+ return ConditionClassOutput.getSharedInstance().getGeneratedConditionClassContent(patternData_p.getPattern().getId());
+ }
+
+ /**
+ * Update condition class if it already exists, else create it with empty content.
+ * @param patternData_p
+ * @param parameters_p
+ * @return
+ */
+ protected void updateConditionClass(PatternData patternData_p, List<ParameterRelation> parameters_p) throws Exception {
+ // Resulting content is generated.
+ String resultingContent = getConditionClassContent(patternData_p);
+ if (resultingContent == null || ICommonConstants.EMPTY_STRING.equals(resultingContent)) {
+ throw new IllegalArgumentException();
+ }
+ // Check existing condition class.
+ String conditionClassRelativePath = getConditionFileRelativePath(patternData_p);
+ // Merge required.
+ if (FileHelper.exists(conditionClassRelativePath)) {
+ resultingContent = ConditionMergeHelper.merge(
+ resultingContent,
+ FileHelper.readFile(conditionClassRelativePath)
+ );
+ }
+ // Write result to file.
+ FileHelper.writeFile(conditionClassRelativePath, true, resultingContent);
+ // Update plugin.xml content accordingly.
+ IPluginChangesCommandRunner runner = EgfPdeActivator.getDefault().getPluginChangesCommandRunner();
+ runner.performChangesOnPlugin(
+ patternData_p.getPluginId(),
+ Collections.singletonList(
+ PatternConditionExtensionFactory.setPatternConditionExtension(
+ patternData_p.getPattern().getId(),
+ new StringBuilder(PatternConstants.PATTERN_CONDITION_GENERATED_BASE_PACKAGE)
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(getConditionClassName(patternData_p))
+ .toString()
+ )
+ )
+ );
+ }
+
+ /**
+ * Get condition file relative path from given parameters.
+ * @param patternData_p
+ * @return
+ */
+ public static String getConditionFileRelativePath(PatternData patternData_p) {
+ // Return computed name.
+ return getGeneratedClassRelativePath(
+ patternData_p.getPluginId(),
+ CONDITION_SOURCE_FOLDER,
+ PatternConstants.PATTERN_CONDITION_GENERATED_BASE_PACKAGE,
+ getConditionClassName(patternData_p)
+ );
+ }
+
+ /**
+ * Get generated class relative path.
+ * @param pluginId_p
+ * @param sourceFolder_p
+ * @param packageName_p
+ * @param className_p
+ * @return
+ */
+ public static String getGeneratedClassRelativePath(
+ String pluginId_p,
+ String sourceFolder_p,
+ String packageName_p,
+ String className_p
+ ) {
+ // Preconditions.
+ if (pluginId_p == null || sourceFolder_p == null || packageName_p == null || className_p == null) {
+ return ICommonConstants.EMPTY_STRING;
+ }
+ // Compute file relative path (does imply that dot-separated package name is converted into folder path).
+ return
+ new StringBuilder(pluginId_p)
+ .append(sourceFolder_p)
+ .append(ICommonConstants.SLASH_CHARACTER)
+ .append(FileHelper.convertPackageNameToFolderPath(packageName_p))
+ .append(ICommonConstants.SLASH_CHARACTER)
+ .append(className_p)
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(IPatternConstants.JAVA_SOURCE_FILE_EXTENSION)
+ .toString();
+ }
+
+ /**
+ * Get condition class name from pattern data.
+ * @param patternData_p
+ * @return
+ */
+ public static String getConditionClassName(PatternData patternData_p) {
+ return getClassName(
+ patternData_p.getPatternName(),
+ IConditionConstants.CONDITION_CLASS_NAME_SUFFIX
+ );
+ }
+
+ /**
+ * Get generated class name from pattern one and suffix.
+ * @param patternName_p
+ * @param suffix_p
+ * @return
+ */
+ public static String getClassName(String patternName_p, String suffix_p) {
+ return
+ new StringBuilder(StringHelper.toUpperFirst(patternName_p))
+ .append(suffix_p)
+ .toString();
+ }
+
+ /**
+ * Replace pre and post pattern matching templates that are included in the generated pattern template.
+ * @param patternData_p
+ * @param parameters_p
+ */
+ protected void replacePatternMatchingTemplates(PatternData patternData_p, List<ParameterRelation> parameters_p) {
+ // (Re-)Create template files content.
+ Couple<StringBuilder, StringBuilder> resultingTemplates = _contributor.createPatternMatchingTemplates(
+ patternData_p,
+ parameters_p
+ );
+ // Save templates files.
+ String patternShortId = patternData_p.getPattern().getShortId();
+ String pluginId = patternData_p.getPluginId();
+ FileHelper.writeFile(
+ TemplateHelper.getTemplateRelativePath(
+ patternShortId,
+ pluginId,
+ PatternConstants.GENERATE_PRE_MATCHING_METHOD_NAME,
+ null
+ ),
+ true,
+ resultingTemplates.getKey().toString()
+ );
+ FileHelper.writeFile(
+ TemplateHelper.getTemplateRelativePath(
+ patternShortId,
+ pluginId,
+ PatternConstants.GENERATE_POST_MATCHING_METHOD_NAME,
+ null
+ ),
+ true,
+ resultingTemplates.getValue().toString()
+ );
+ }
+
+ /**
+ * Remove no longer needed condition structures, if any.<br>
+ * That might happen, when the pattern is loosing all its parameters, due to a user decision.
+ * @param patternData_p
+ */
+ protected void removeOldConditionStructures(PatternData patternData_p) {
+ // Delete existing condition class, if any.
+ String conditionClassRelativePath = getConditionFileRelativePath(patternData_p);
+ if (FileHelper.exists(conditionClassRelativePath)) {
+ FileHelper.deleteFile(conditionClassRelativePath);
+ }
+ String patternShortId = patternData_p.getPattern().getShortId();
+ String pluginId = patternData_p.getPluginId();
+ // Delete pre-matching template, if any.
+ String preMatchingRelativePath = TemplateHelper.getTemplateRelativePath(
+ patternShortId,
+ pluginId,
+ PatternConstants.GENERATE_PRE_MATCHING_METHOD_NAME,
+ null
+ );
+ if (FileHelper.exists(preMatchingRelativePath)) {
+ FileHelper.deleteFile(preMatchingRelativePath);
+ }
+ // Delete post-matching template, if any.
+ String postMatchingRelativePath = TemplateHelper.getTemplateRelativePath(
+ patternShortId,
+ pluginId,
+ PatternConstants.GENERATE_POST_MATCHING_METHOD_NAME,
+ null
+ );
+ if (FileHelper.exists(postMatchingRelativePath)) {
+ FileHelper.deleteFile(postMatchingRelativePath);
+ }
+ // Ask for reconstruction of pre and post matching, if required.
+ replacePatternMatchingTemplates(
+ patternData_p,
+ new ArrayList<ParameterRelation>(0)
+ );
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/IProductionContributor.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/IProductionContributor.java
new file mode 100644
index 0000000..bcbdaa1
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/IProductionContributor.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production;
+
+import java.util.List;
+
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.pattern.ecore.AnnotationHandler;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.relations.ParameterRelation;
+
+
+/**
+ * A production contributor.<br>
+ * Typically handles a specific platform production code.
+ * @author Guillaume Brocard
+ */
+public interface IProductionContributor {
+
+ /**
+ * Create pre/post pattern matching templates.<br>
+ * Those are supposed to be produced in the generated templates folder.<br>
+ * Their physical form depends on the template engine used (as for the file extension for instance).
+ * @param patternData_p The structure containing most of the pattern required data for generation.
+ * @param parameters_p The fully resolved list of parameters (including parent hierarchy) for considered pattern.
+ * @return A couple of (pre-matching, post-matching) {@link StringBuilder} containing resulting template code, null if there is no such content.
+ */
+ public Couple<StringBuilder, StringBuilder> createPatternMatchingTemplates(PatternData patternData_p, List<ParameterRelation> parameters_p);
+
+ /**
+ * Compile given template, if applicable.
+ * @param generatedTemplatePath_p
+ * @param patternData_p
+ * @return
+ * @throws Exception
+ */
+ public boolean compileTemplate(String generatedTemplatePath_p, PatternData patternData_p) throws Exception;
+
+ /**
+ * Fill, if applicable, generateHeader method of the pattern, if it does not exist or is empty.<br>
+ * Given content should ensure pattern compilation phase, whether this lead to a valid status or not.<br>
+ * The user will then be able to choose a more convenient content.
+ * @param patternData_p
+ * @param handler_p A usable annotation handler, null if none.
+ * @throws Exception
+ */
+ public void fillGenerateHeader(PatternData patternData_p, AnnotationHandler handler_p) throws Exception;
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/Messages.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/Messages.java
new file mode 100644
index 0000000..ff70210
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/Messages.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.production;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author brocard
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.egf.pattern.production.messages"; //$NON-NLS-1$
+
+ public static String PatternTemplateProducer_PatternProductionErrorMessage;
+
+ public static String PatternProducer_PatternProductionErrorTitle;
+ public static String PatternProducer_ProgressReporting_GetPath;
+ public static String PatternProducer_ProgressReporting_JavaToResult;
+ public static String PatternProducer_ProgressReporting_PatternToJava;
+ public static String PatternProducer_ProgressReporting_Title;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ // Static initialization
+ }
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/PatternProducer.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/PatternProducer.java
new file mode 100644
index 0000000..aaf5817
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/PatternProducer.java
@@ -0,0 +1,439 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+
+import org.eclipse.emf.codegen.ecore.genmodel.GenJDKLevel;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternTemplateConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.MathHelper;
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.common.progress.ProductionProgressMonitor;
+import org.eclipse.egf.common.progress.ProgressReporter;
+import org.eclipse.egf.core.CoreActivator;
+import org.eclipse.egf.fc.generator.java.model.EcoreGenModelGenerator;
+import org.eclipse.egf.model.Context;
+import org.eclipse.egf.model.FactoryComponent;
+import org.eclipse.egf.model.FactoryComponentInvocation;
+import org.eclipse.egf.model.ModelFactory;
+import org.eclipse.egf.model.data.helper.ModelHelper;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternSeeker;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.production.template.TemplateHelper;
+
+
+/**
+ * Pattern producer.<br>
+ * Can either produce a library of patterns, or a single pattern.
+ * @author brocard
+ */
+public class PatternProducer {
+
+ /**
+ * Log4j reference logger.
+ */
+ private static final Logger __logger = Logger.getLogger(PatternProducer.class.getPackage().getName());
+
+ /**
+ * Java builder factory component id.
+ */
+ protected static final String JAVA_BUILDER_FACTORY_COMPONENT_ID = "java.builder.asset"; //$NON-NLS-1$
+
+ /**
+ * Java builder project name contract element id.
+ */
+ protected static final String JAVA_BUILDER_FACTORY_COMPONENT_CONTRACT_FACTORY_COMPONENT_PROJECT_NAME = "java.builder.asset.contract.assetProjectName"; //$NON-NLS-1$
+
+ /**
+ * Java code generator jdk compliance level contract element id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_JDK_COMPLIANCE_LEVEL = "javaCodeGeneratorAsset.contract.jdkComplianceLevel"; //$NON-NLS-1$
+
+ /**
+ * Java code generator genModel generator contract element id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_GEN_MODEL_GENERATOR = "javaCodeGeneratorAsset.contract.genModelGenerator"; //$NON-NLS-1$
+
+ /**
+ * Java code generator base package contract element id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_BASE_PACKAGE = "javaCodeGeneratorAsset.contract.basePackage"; //$NON-NLS-1$
+
+ /**
+ * Java code generator project name contract element id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_FACTORY_COMPONENT_PROJECT_NAME = "javaCodeGeneratorAsset.contract.assetProjectName"; //$NON-NLS-1$
+
+ /**
+ * Java code generator input path contract element id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_INPUT_PATH = "javaCodeGeneratorAsset.contract.inputPath"; //$NON-NLS-1$
+
+ /**
+ * Java code generator model directory contract element id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_MODEL_DIRECTORY = "javaCodeGeneratorAsset.contract.modelDirectory"; //$NON-NLS-1$
+
+ /**
+ * Java code generator factory component id.
+ */
+ protected static final String JAVA_CODE_GENERATOR_FACTORY_COMPONENT_ID = "javaCodeGeneratorAsset"; //$NON-NLS-1$
+
+ /**
+ * Pattern seeker reference.
+ */
+ private static PatternSeeker _seeker;
+
+ /**
+ * Constructor.
+ */
+ public PatternProducer() {
+ //Nothing to do
+ }
+
+ /**
+ * Get pattern seeker.
+ * @return
+ */
+ protected static PatternSeeker getPatternSeeker() {
+ if (_seeker == null) {
+ // Do look for patterns in workspace.
+ _seeker = new PatternSeeker(true);
+ }
+ return _seeker;
+ }
+
+ /**
+ * Build the java project holding the currently produced pattern.
+ * @param patternData_p
+ * @return
+ */
+ protected boolean buildPatternProject(PatternData patternData_p) {
+ // Create a factory component dynamically which goal is to build the pattern project.
+ // It is referencing java builder factory component.
+ String referencedFcId = JAVA_BUILDER_FACTORY_COMPONENT_ID;
+ Couple<FactoryComponent, Context> buildProjectFc = createFactoryComponentSkeleton(
+ "patternProducer.factoryComponent.buildProject", //$NON-NLS-1$
+ referencedFcId
+ );
+ // Fill context.
+ // FactoryComponent project name.
+ ModelHelper.addReferencingContractContextElement(
+ buildProjectFc.getValue(),
+ referencedFcId,
+ JAVA_BUILDER_FACTORY_COMPONENT_CONTRACT_FACTORY_COMPONENT_PROJECT_NAME,
+ patternData_p.getPluginId(),
+ PatternActivator.getDefault().getPluginID()
+ );
+ return generateFactoryComponent(buildProjectFc.getKey());
+ }
+
+ /**
+ * Create a factory component with given name.<br>
+ * By default, a factory with a unique production plan is added to the newly created factory component.<br>
+ * This production plan contains a factory component invocation containing a default context.<br>
+ * This context should be filled up.
+ * @param fcName_p
+ * @return
+ */
+ protected static Couple<FactoryComponent, Context> createFactoryComponentSkeleton(String fcName_p, String referencedFcId_p) {
+ // Create a factory component dynamically.
+ FactoryComponent fc = ModelHelper.createEmptyMinimalFC(fcName_p);
+ // Add required factory component invocation.
+ FactoryComponentInvocation fcInvocation = ModelHelper.addFactoryComponentInvocation(
+ fc,
+ referencedFcId_p
+ );
+ // Add a default context.
+ Context context = ModelFactory.eINSTANCE.createContext();
+ fcInvocation.setContext(context);
+ return new Couple<FactoryComponent, Context>(fc, context);
+ }
+
+ /**
+ * Generate given factory component in current thread.
+ * @param fc_p
+ * @return
+ */
+ protected static boolean generateFactoryComponent(FactoryComponent fc_p) {
+ return CoreActivator.getDefault().generateFactoryComponentSynchronously(fc_p);
+ }
+
+ /**
+ * Generate pattern classes.<br>
+ * That is generate classes that are describing the pattern structure as an object one.<br>
+ * Such classes are composed of a <i>String generate()</i> method, and several internal pattern methods.<br>
+ * Calling <i>generate()</i> method results in getting the content of a new template file that is indeed acting as the whole pattern, when applied.<br>
+ * When all classes are generated, also force project build so that they may subsequently be used.
+ * @param patternData_p
+ * @return
+ */
+ protected static boolean generatePatternClasses(PatternData patternData_p) {
+ IJavaProject javaProject = patternData_p.getJavaProject();
+ // Precondition.
+ // Only produce pattern for in-development patterns (that is not do-able for already deployed patterns).
+ if (javaProject == null) {
+ return false;
+ }
+ // Should fix bug prod00015930
+ try {
+ // That might be a good time to generate pre and post matching templates, if applicable.
+ GeneratedContentProducer conditionProducer = new GeneratedContentProducer();
+ conditionProducer.produceConditionStructures(patternData_p);
+ // Fill generate header, if none is provided.
+ conditionProducer.getProductionContributor().fillGenerateHeader(patternData_p, null);
+ } catch (Exception exception_p) {
+ StringBuilder loggerMessage = new StringBuilder("PatternProducer.generatePatternClasses(..) _ "); //$NON-NLS-1$
+ __logger.warn(loggerMessage.toString(), exception_p);
+ }
+ // End of fix for prod00015930
+ // Make sure all dependencies are already compiled.
+ ensurePatternsJavaFiles(patternData_p.getPatternDependenciesIds());
+ // Create a factory component dynamically, used to produce the java code for this pattern.
+ // It is referencing java code generator factory component.
+ String referencedFcId = JAVA_CODE_GENERATOR_FACTORY_COMPONENT_ID;
+ Couple<FactoryComponent, Context> producePatternCouple = createFactoryComponentSkeleton(
+ "patternProducer.factoryComponent.ecoreToJava", //$NON-NLS-1$
+ referencedFcId
+ );
+ // Get context.
+ Context context = producePatternCouple.getValue();
+ // Fill context up.
+ context.getContextElements().clear();
+ String contributorId = PatternActivator.getDefault().getPluginID();
+ // Model directory.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ referencedFcId,
+ JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_MODEL_DIRECTORY,
+ new Path(PatternConstants.GENERATION_SOURCE_FOLDER).segment(0),
+ contributorId
+ );
+ // Input path.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ referencedFcId,
+ JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_INPUT_PATH,
+ patternData_p.getRealRelativePath(),
+ contributorId
+ );
+ // FactoryComponent project name.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ referencedFcId,
+ JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_FACTORY_COMPONENT_PROJECT_NAME,
+ patternData_p.getPluginId(),
+ contributorId
+ );
+ // Base package.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ referencedFcId,
+ JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_BASE_PACKAGE,
+ PatternConstants.PATTERN_GENERATED_BASE_PACKAGE,
+ contributorId
+ );
+ // GenModel generator.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ referencedFcId,
+ JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_GEN_MODEL_GENERATOR,
+ EcoreGenModelGenerator.class.getName(),
+ contributorId
+ );
+ // Jdk compliance level.
+ ModelHelper.addReferencingContractContextElement(
+ context,
+ referencedFcId,
+ JAVA_CODE_GENERATOR_FACTORY_COMPONENT_CONTRACT_ELEMENT_JDK_COMPLIANCE_LEVEL,
+ GenJDKLevel.JDK50_LITERAL.getLiteral(),
+ contributorId
+ );
+ return generateFactoryComponent(producePatternCouple.getKey());
+ }
+
+ /**
+ * Ensure all identified patterns are indeed usable as java classes.<br>
+ * That is, if one of these patterns is being developed and has never been generated, do use its ecore file to generate its java classes form, and compile
+ * them.
+ * @param fullIds_p
+ */
+ protected static void ensurePatternsJavaFiles(Set<String> fullIds_p) {
+ // Precondition.
+ if (fullIds_p == null) {
+ return;
+ }
+ // Get list of pattern paths.
+ List<PatternData> patternsData = new ArrayList<PatternData>(0);
+ for (String patternId : fullIds_p) {
+ patternsData.addAll(getPatternSeeker().getPatternsData(patternId));
+ }
+ // Now just generate pattern classes for all selected ones.
+ for (PatternData patternData : patternsData) {
+ // Generate pattern java classes and ensure build of containing project.
+ generatePatternClasses(patternData);
+ }
+ }
+
+ /**
+ * Take care of the whole production chain for given patterns data.
+ * @param data_p
+ * @param monitor_p
+ * @param ticksCount_p
+ * @return
+ */
+ protected static boolean handlePatternsProduction(List<PatternData> data_p, SubMonitor monitor_p, int ticksCount_p) {
+ boolean result = true;
+ // How many ticks should monitor eat each time ?
+ int stepCount = ticksCount_p / data_p.size();
+ // Cycle through pattern paths.
+ for (PatternData patternData : data_p) {
+ // Monitor each pattern to produce.
+ ProductionProgressMonitor monitor = new ProductionProgressMonitor(
+ monitor_p,
+ patternData.getPatternLogicalName(),
+ stepCount
+ );
+ // Check hosting java project.
+ boolean proceed = patternData.getJavaProject() != null;
+ if (proceed) {
+ // Convert pattern ecore file to java files.
+ proceed = generatePatternClasses(patternData);
+ }
+ result &= proceed;
+ // Acknowledge each pattern production.
+ monitor.end();
+ }
+ return result;
+ }
+
+ /**
+ * Produce identified pattern.
+ * @param fullId_p The absolute id of either a library or a pattern.
+ * @return
+ */
+ public static boolean producePatterns(String fullId_p, IProgressMonitor progressMonitor_p) {
+ boolean result = fullId_p != null;
+ // Precondition.
+ if (result == false) {
+ progressMonitor_p.done();
+ return result;
+ }
+ try {
+ // Do produce the patterns.
+ String productionMessage = Messages.PatternProducer_ProgressReporting_Title + fullId_p;
+ // Convert progress monitor to sub monitor.
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor_p, productionMessage, ProgressReporter.TASK_DEFAULT_TICKS_COUNT);
+ // Get pattern path.
+ int ticksCount = MathHelper.multiply(ProgressReporter.TASK_DEFAULT_TICKS_COUNT, 0.1f);
+ List<PatternData> patternsData = getPatternSeeker().getPatternsData(fullId_p);
+ int patternsCount = patternsData.size();
+ subMonitor.worked(ticksCount);
+ ticksCount = ProgressReporter.TASK_DEFAULT_TICKS_COUNT - ticksCount;
+ subMonitor.setWorkRemaining(ticksCount);
+ result = (patternsCount > 0);
+ // Got the patterns paths, go on with production.
+ if (result) {
+ // Generate patterns classes.
+ handlePatternsProduction(patternsData, subMonitor, ticksCount);
+ subMonitor.setWorkRemaining(0);
+ }
+ } finally {
+ // Whatever happened, always complete the progress monitor.
+ progressMonitor_p.done();
+ // Return false if cancellation happened.
+ result &= progressMonitor_p.isCanceled() == false;
+ }
+ return result;
+ }
+
+ /**
+ * Generate identified pattern.<br>
+ * That is, generate resulting template and return it as a string.<br>
+ * The resulting template does include neither the header, nor the footer.<br>
+ * This method should only be called in the case of an inclusion of the identified pattern in another one.
+ * @param fullId_p
+ * @param classLoader_p
+ * @return
+ */
+ public String generatePatterns(String fullId_p, Object classLoader_p) {
+ String result = ICommonConstants.EMPTY_STRING;
+ // Precondition.
+ if (fullId_p == null || classLoader_p instanceof ClassLoader == false) {
+ return result;
+ }
+ // Get class loader.
+ ClassLoader usableClassLoader = (ClassLoader) classLoader_p;
+ // Get pattern paths.
+ List<PatternData> patternsData = getPatternSeeker().getPatternsData(fullId_p);
+ // Check that there is indeed some work to do.
+ if (patternsData.size() < 0) {
+ return result;
+ }
+ StringBuilder resultingBuilder = new StringBuilder();
+ // Now, go on with the good work.
+ for (PatternData patternData : patternsData) {
+ // Try and transform ecore pattern file to java classes, if it is necessary.
+ generatePatternClasses(patternData);
+ // Then get pattern template as a string.
+ String patternTemplate = PatternTemplateProducer.getPatternTemplateAsString(patternData, usableClassLoader);
+ if (patternTemplate != null) {
+ resultingBuilder.append(patternTemplate);
+ }
+ }
+ return resultingBuilder.toString();
+ }
+
+ /**
+ * Clean pattern template structure.
+ * @param javaProject_p
+ * @param descriptor_p
+ */
+ public static void cleanGeneratedStructures(IJavaProject javaProject_p, IDescriptor descriptor_p) {
+ if (javaProject_p == null || descriptor_p == null) {
+ return;
+ }
+ // Process only Workspace Plugin
+ IPluginModelBase model = PluginRegistry.findModel(javaProject_p.getProject());
+ if (model == null) {
+ return;
+ }
+ // Retrieve needed informations from IDescriptor
+ String patternShortId = (String) descriptor_p.getValue(ExtensionPointHelper.ATT_ID);
+ String patternTemplatePath = (String) descriptor_p.getValue(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_PATH);
+ String patternTemplateClass = (String) descriptor_p.getValue(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_CLASS);
+ // Clean generated templates if any
+ FileHelper.deleteResource(
+ TemplateHelper.getTemplateRootIFolder(javaProject_p),
+ TemplateHelper.getGeneratedPatternTemplateIFolder(javaProject_p, patternShortId),
+ true
+ );
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/PatternTemplateProducer.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/PatternTemplateProducer.java
new file mode 100644
index 0000000..a6f4022
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/PatternTemplateProducer.java
@@ -0,0 +1,285 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *
+ * </copyright>
+ *
+ */
+package org.eclipse.egf.pattern.production;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collections;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.constant.IPatternConstants;
+import org.eclipse.egf.common.constant.IPatternTemplateConstants;
+import org.eclipse.egf.common.descriptor.IDescriptor;
+import org.eclipse.egf.common.helper.ExtensionPointHelper;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.helper.JavaHelper;
+import org.eclipse.egf.common.helper.ProjectHelper;
+import org.eclipse.egf.console.EGFConsolePlugin;
+import org.eclipse.egf.pattern.Pattern;
+import org.eclipse.egf.pattern.PatternActivator;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+import org.eclipse.egf.pattern.production.template.TemplateHelper;
+import org.eclipse.egf.pde.EgfPdeActivator;
+import org.eclipse.egf.pde.pattern.plugin.command.PatternTemplateExtensionFactory;
+import org.eclipse.egf.pde.plugin.command.IPluginChangesCommandRunner;
+
+
+public class PatternTemplateProducer {
+
+ /**
+ * Debug mode.
+ */
+ private static boolean DEBUG = PatternActivator.getDefault().isDebugging();
+
+ /**
+ * Emf factory create methods prefix.
+ */
+ protected static final String PATTERN_FACTORY_CREATE_METHOD_PREFIX = "create"; //$NON-NLS-1$
+
+ /**
+ * Emf factory name prefix.
+ */
+ protected static final String PATTERN_FACTORY_NAME_SUFFIX = "Factory"; //$NON-NLS-1$
+
+ /**
+ * Emf factory attribute name from interface to implementation.
+ */
+ protected static final String PATTERN_FACTORY_ATTRIBUTE_NAME = "eINSTANCE"; //$NON-NLS-1$
+
+ /**
+ * Generate resulting template for given pattern data.
+ * @param patternData_p
+ * @return
+ */
+ public static boolean generateTemplate(final PatternData patternData_p) {
+ try {
+ // Do produce the pattern.
+ // That is instantiate its generated class, and invoke production method.
+ String patternTemplatePath = doProducePattern(patternData_p);
+ if (patternTemplatePath == null) {
+ return false;
+ }
+ // Should template be compiled ?
+ if (patternData_p.getProductionOptionsHandler().shouldCompileTemplate()) {
+ // Now that the template is created, compile it.
+ if (compileResultingTemplate(patternTemplatePath, patternData_p) == false) {
+ return false;
+ }
+ }
+ } catch (Exception e) {
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(
+ NLS.bind(Messages.PatternTemplateProducer_PatternProductionErrorMessage, patternData_p.getPatternLogicalName()),
+ e
+ );
+ }
+ PatternActivator.getDefault().log(e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Produce identified pattern.<br>
+ * Do instantiate pattern generated class, and call its production method.<br>
+ * As a result, a new template file is created.
+ * @param patternData_p
+ * @return Resulting template file (relative to workspace) path.
+ * @throws Exception
+ */
+ public static String doProducePattern(PatternData patternData_p) throws Exception {
+ // Instantiate pattern.
+ ClassLoader classLoader[] = new ClassLoader[] { null };
+ Pattern pattern = instantiatePattern(patternData_p, classLoader);
+ // Unable to instantiate pattern.
+ if (pattern == null) {
+ return null;
+ }
+ // Call the pattern 'produce' method.
+ String templateContent = pattern.produce(classLoader[0]);
+ // Write a new template file to the project, with the content set to new one.
+ String patternTemplatePath = TemplateHelper.getPatternTemplatePath(patternData_p);
+ if (FileHelper.writeFile(patternTemplatePath, true, templateContent)) {
+ return patternTemplatePath;
+ }
+ return null;
+ }
+
+ /**
+ * Instantiate identified pattern.
+ * @param patternData_p The pattern required data.
+ * @param classLoader_p The class loader used to instantiate the pattern as an array of one element.<br>
+ * Can be null, it is then created using given pattern path java project, and returned in given array (as the only element).
+ * @return
+ * @throws Exception
+ */
+ public static Pattern instantiatePattern(PatternData patternData_p, ClassLoader[] classLoader_p) throws Exception {
+ // Precondition.
+ if (patternData_p == null) {
+ return null;
+ }
+ // Set some useful variables
+ IJavaProject javaProject = patternData_p.getJavaProject();
+ ClassLoader classLoader = classLoader_p[0];
+ // Build the path string to the java resource we need to instantiate
+ String pathString = new StringBuilder(PatternConstants.PATTERN_GENERATED_BASE_PACKAGE)
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(GeneratedContentHelper.getPatternPackageName(patternData_p.getPattern()))
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(GeneratedContentHelper.getPatternClassName(patternData_p.getPattern()))
+ .append(PATTERN_FACTORY_NAME_SUFFIX)
+ .toString();
+ // Locate the resource to instantiate, if not found, we skip it
+ // This check is less expensive than a classloader building and the according loading attempt
+ IFile file = JavaHelper.getJavaSourceFile(
+ javaProject,
+ new Path(FileHelper.convertPackageNameToFolderPath(pathString)).addFileExtension(IPatternConstants.JAVA_SOURCE_FILE_EXTENSION)
+ );
+ if (file == null) {
+ return null;
+ }
+ // Build a classloader able to load our pattern
+ // Only build and create class loader for an in-development pattern.
+ if (javaProject != null) {
+ // Create the class loader.
+ // Use pattern plugin classloader as parent one.
+ classLoader = ProjectHelper.getClassLoaderFor(javaProject, PatternActivator.getDefault().getClass().getClassLoader());
+ if (classLoader == null) { // Try using given one instead.
+ classLoader = classLoader_p[0];
+ } else {
+ // Return created class loader.
+ classLoader_p[0] = classLoader;
+ }
+ }
+ // Precondition.
+ if (classLoader == null) {
+ return null;
+ }
+ // Get the pattern factory.
+ Class<?> factoryInterface = null;
+ try {
+ factoryInterface = classLoader.loadClass(pathString);
+ } catch (ClassNotFoundException cnfe) {
+ // We can do nothing so we leave
+ return null;
+ }
+ // And its instance through the eInstance EMF factory attribute.
+ Field factoryEInstance = factoryInterface.getDeclaredField(PATTERN_FACTORY_ATTRIBUTE_NAME);
+ Object factoryObject = factoryEInstance.get(factoryInterface);
+ // Now instantiate the pattern java class, previously generated and compiled.
+ Method createMethod = factoryInterface.getDeclaredMethod(
+ new StringBuilder(PATTERN_FACTORY_CREATE_METHOD_PREFIX)
+ .append(patternData_p.getPatternName())
+ .toString(),
+ (Class[]) null
+ );
+ // Invoke and return it
+ return (Pattern) createMethod.invoke(factoryObject, (Object[]) null);
+ }
+
+ /**
+ * Do compile/interpret resulting template, if applicable, into a resulting java class.<br>
+ * Resulting class is not compiled, until a java compiler is applied.
+ * @param patternTemplatePath_p
+ * @param patternData_p
+ * @return
+ * @throws Exception
+ */
+ public static boolean compileResultingTemplate(String patternTemplatePath_p, PatternData patternData_p) throws Exception {
+ return new GeneratedContentProducer().getProductionContributor().compileTemplate(patternTemplatePath_p, patternData_p);
+ }
+
+ /**
+ * Get pattern template as a string.
+ * @param patternData_p
+ * @param classLoader_p
+ * @return the resulting template as a string, or empty string if an error occurred.
+ */
+ protected static String getPatternTemplateAsString(PatternData patternData_p, ClassLoader classLoader_p) {
+ String result = ICommonConstants.EMPTY_STRING;
+ // Instantiate pattern.
+ ClassLoader classLoader[] = new ClassLoader[] { classLoader_p };
+ try {
+ Pattern pattern = instantiatePattern(patternData_p, classLoader);
+ // Get result by generating instantiated pattern.
+ if (pattern != null) {
+ result = pattern.generate(classLoader[0]);
+ }
+ } catch (Exception e) {
+ String msg = new String("PatternTemplateProducer.getPatternTemplateAsString(..) _ "); //$NON-NLS-1$
+ if (DEBUG) {
+ EGFConsolePlugin.getConsole().logThrowable(msg, e);
+ }
+ PatternActivator.getDefault().log(e);
+ }
+ return result;
+ }
+
+ /**
+ * Clean pattern template structure.
+ * @param javaProject_p
+ * @param descriptor_p
+ */
+ public static void cleanGeneratedStructures(IJavaProject javaProject_p, IDescriptor descriptor_p) {
+ if (javaProject_p == null || descriptor_p == null) {
+ return;
+ }
+ // Process only Workspace Plugin
+ IPluginModelBase model = PluginRegistry.findModel(javaProject_p.getProject());
+ if (model == null) {
+ return;
+ }
+ // Retrieve needed informations from IDescriptor
+ String patternShortId = (String) descriptor_p.getValue(ExtensionPointHelper.ATT_ID);
+ String patternTemplatePath = (String) descriptor_p.getValue(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_PATH);
+ String patternTemplateClass = (String) descriptor_p.getValue(IPatternTemplateConstants.PATTERN_TEMPLATE_ATT_CLASS);
+ // Clean templates if any (this value is mandatory, but who knows...)
+ if (patternTemplatePath != null && patternTemplatePath.trim().length() > 0) {
+ FileHelper.deleteResource(
+ TemplateHelper.getTemplateRootIFolder(javaProject_p),
+ FileHelper.getPlatformResource(new Path(patternTemplatePath)),
+ true
+ );
+ }
+ // Clean template resulting class if necessary (this value is optional)
+ if (patternTemplateClass != null && patternTemplateClass.trim().length() > 0) {
+ JavaHelper.deleteJavaClass(
+ javaProject_p,
+ new Path(FileHelper.convertPackageNameToFolderPath(patternTemplateClass)).addFileExtension(IPatternConstants.JAVA_SOURCE_FILE_EXTENSION),
+ true
+ );
+ }
+ // Suppress generated pattern extension if any (this value is mandatory, but who knows...)
+ if (patternShortId != null && patternShortId.trim().length() > 0) {
+ IPluginChangesCommandRunner pluginChangesCommandRunner = EgfPdeActivator.getDefault().getPluginChangesCommandRunner();
+ pluginChangesCommandRunner.performChangesOnPlugin(
+ model.getBundleDescription().getSymbolicName(),
+ Collections.singletonList(
+ PatternTemplateExtensionFactory.unsetPatternTemplateExtension(patternShortId)
+ )
+ );
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/TemplateType.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/TemplateType.java
new file mode 100644
index 0000000..64264d8
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/TemplateType.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production;
+
+/**
+ * Defines an enumeration to list all available template engines.
+ * @author Guillaume Brocard
+ */
+public enum TemplateType {
+
+ /**
+ * ACCELEO template engine.
+ */
+ ACCELEO("ACCELEO", "acceleo"), //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * JET template engine.
+ */
+ JET("JET", "jet"), //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * JET2 template engine.
+ */
+ JET2("JET2", "jet2"), //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * VELOCITY template engine.
+ */
+ VELOCITY("VELOCITY", "velocity"), //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * XPAND template engine.
+ */
+ XPAND("XPAND", "xpand"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * Simple description.
+ */
+ private String _description;
+
+ /**
+ * Identifier.
+ */
+ private String _id;
+
+ /**
+ * Constructor.
+ * @param description_p
+ * @param id_p
+ */
+ private TemplateType(String description_p, String id_p) {
+ _description = description_p;
+ _id = id_p;
+ }
+
+ /**
+ * Get the description of this enumeration.
+ * @return the description
+ */
+ public String getDescription() {
+ return _description;
+ }
+
+ /**
+ * Get the identifier of this enumeration.
+ * @return the id
+ */
+ public String getId() {
+ return _id;
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/jet/IGenerator.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/jet/IGenerator.java
new file mode 100644
index 0000000..df87c68
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/jet/IGenerator.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production.jet;
+
+/**
+ * Default jet produced template skeleton.<br>
+ * Note that the argument name is unchanged due to EMF compatibility issues.
+ * @author Guillaume Brocard
+ */
+public interface IGenerator {
+
+ /**
+ * Apply template generation, and get result as a {@link String}.
+ * @param argument
+ * @return
+ */
+ public String generate(Object argument);
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/jet/JETConstants.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/jet/JETConstants.java
new file mode 100644
index 0000000..7df83f5
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/jet/JETConstants.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.production.jet;
+
+/**
+ * Patterns JET specific constants.
+ * @author Guillaume Brocard
+ */
+public interface JETConstants {
+ /**
+ * Start mark-up.
+ */
+ public static final String JET_MARKUP_START = "<%"; //$NON-NLS-1$
+ public static final String EXTERNAL_USE_JET_MARKUP_START = JETConstants.class.getName() + ".JET_MARKUP_START"; //$NON-NLS-1$
+ /**
+ * End mark-up.
+ */
+ public static final String JET_MARKUP_END = "%>"; //$NON-NLS-1$
+ public static final String EXTERNAL_USE_JET_MARKUP_END = JETConstants.class.getName() + ".JET_MARKUP_END"; //$NON-NLS-1$
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/messages.properties b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/messages.properties
new file mode 100644
index 0000000..5c6d323
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/messages.properties
@@ -0,0 +1,18 @@
+##
+# Copyright (c) 2009 Thales Corporate Services S.A.S.
+# 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:
+# Thales Corporate Services S.A.S - initial API and implementation
+##
+
+PatternProducer_ProgressReporting_GetPath=Resolving path for ''{0}''
+PatternProducer_PatternProductionErrorTitle=Pattern generation error
+PatternProducer_ProgressReporting_Title=Producing patterns
+PatternProducer_ProgressReporting_PatternToJava=Generating pattern classes for ''{0}''
+PatternProducer_ProgressReporting_JavaToResult=Compiling resulting template for ''{0}''
+
+PatternTemplateProducer_PatternProductionErrorMessage=Error while generating pattern ''{0}''
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/template/TemplateHelper.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/template/TemplateHelper.java
new file mode 100644
index 0000000..51c6eba
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/production/template/TemplateHelper.java
@@ -0,0 +1,335 @@
+/**
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ */
+package org.eclipse.egf.pattern.production.template;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IJavaProject;
+
+import org.eclipse.egf.common.constant.ICommonConstants;
+import org.eclipse.egf.common.helper.FileHelper;
+import org.eclipse.egf.common.misc.Couple;
+import org.eclipse.egf.common.misc.PlatformLocationType;
+import org.eclipse.egf.model.edit.helper.FactoryComponentHelper;
+import org.eclipse.egf.pattern.ecore.PatternConstants;
+import org.eclipse.egf.pattern.ecore.PatternHandler.PatternData;
+
+
+/**
+ * @author Guillaume Brocard
+ */
+public class TemplateHelper {
+
+ /**
+ * Generated templates relative root path.
+ */
+ public static final String TEMPLATES_ROOT_PATH = "/templates/"; //$NON-NLS-1$
+
+ /**
+ * Generated templates relative root IPath.
+ */
+ public static final IPath TEMPLATES_ROOT_IPATH = new Path("templates"); //$NON-NLS-1$
+
+ /**
+ * Generated templates relative path.
+ */
+ protected static final String GENERATED_TEMPLATES_PATH = TEMPLATES_ROOT_PATH + "generated/"; //$NON-NLS-1$
+
+ /**
+ * Generated templates relative IPath.
+ */
+ protected static final IPath GENERATED_TEMPLATES_IPATH = TEMPLATES_ROOT_IPATH.append("generated"); //$NON-NLS-1$
+
+ /**
+ * Get generated template root IFolder for given project.<br>
+ * @param javaProject_p
+ * @return
+ */
+ public static IFolder getTemplateRootIFolder(IJavaProject javaProject_p) {
+ // Check
+ if (javaProject_p == null) {
+ return null;
+ }
+ // Find template root path member
+ IResource resource = ResourcesPlugin
+ .getWorkspace()
+ .getRoot()
+ .findMember(
+ javaProject_p
+ .getPath()
+ .append(TEMPLATES_ROOT_IPATH)
+ );
+ if (resource != null && resource instanceof IFolder) {
+ return (IFolder) resource;
+ }
+ return null;
+ }
+
+ /**
+ * Get generated template IFolder for given project.<br>
+ * @param javaProject_p
+ * @return
+ */
+ public static IFolder getGeneratedTemplateIFolder(IJavaProject javaProject_p) {
+ // Check
+ if (javaProject_p == null) {
+ return null;
+ }
+ // Find template generated path member
+ IResource resource = ResourcesPlugin
+ .getWorkspace()
+ .getRoot()
+ .findMember(
+ javaProject_p
+ .getPath()
+ .append(GENERATED_TEMPLATES_IPATH)
+ );
+ if (resource != null && resource instanceof IFolder) {
+ return (IFolder) resource;
+ }
+ return null;
+ }
+
+ /**
+ * Get generated template IFolder for given pattern short id.<br>
+ * @param javaProject_p
+ * @param patternShortId_p
+ * @return
+ */
+ public static IFolder getGeneratedPatternTemplateIFolder(IJavaProject javaProject_p, String patternShortId_p) {
+ // Check
+ if (javaProject_p == null || patternShortId_p == null) {
+ return null;
+ }
+ IFolder folder = getGeneratedTemplateIFolder(javaProject_p);
+ if (folder == null) {
+ return null;
+ }
+ IResource resource = folder.findMember(patternShortId_p);
+ if (resource != null && resource instanceof IFolder) {
+ return (IFolder) resource;
+ }
+ return null;
+ }
+
+ /**
+ * Get generated template file path for given pattern data.<br>
+ * Only usable for in-development patterns.<br>
+ * Deployed patterns templates should be dealt with differently.<br>
+ * TODO Guillaume Write a unique helper method that can deal with both cases.
+ * @param patternData_p
+ * @return
+ */
+ public static String getPatternTemplatePath(PatternData patternData_p) {
+ String result = null;
+ // Precondition.
+ if (patternData_p == null) {
+ return result;
+ }
+ // Get overriding template path.
+ String templatePath = patternData_p.getProductionOptionsHandler().getPatternTemplatePath();
+ if (templatePath != null && templatePath.trim().length() > 0) { // Use given template file path.
+ // Location is local to the java project hosting the pattern.
+ IPath patternTemplatePath = patternData_p.getJavaProject().getPath();
+ patternTemplatePath = patternTemplatePath.append(TEMPLATES_ROOT_PATH).append(templatePath);
+ result = patternTemplatePath.toString();
+ } else { // Use default template file construction.
+ result = computeTemplatePath(
+ patternData_p.getPluginId(),
+ GENERATED_TEMPLATES_PATH,
+ patternData_p.getPattern().getShortId()
+ );
+ }
+ return result;
+ }
+
+ /**
+ * Read template file.
+ * @param templateRelativePath_p the template relative path, prefixed by the factory component id.
+ * @return
+ */
+ public static String readTemplateFile(String templateRelativePath_p) {
+ String result = ICommonConstants.EMPTY_STRING;
+ // Precondition.
+ if (templateRelativePath_p == null) {
+ return result;
+ }
+ // Get plug-in id.
+ String fcId = new Path(templateRelativePath_p).segment(0);
+ String pluginId = FactoryComponentHelper.getPluginId(fcId, PlatformLocationType.WORKSPACE_THEN_TARGET_PLATFORM);
+ // Compatibility issue with the old way (v1.0.1) of referencing the templates.
+ if (pluginId == null) {
+ pluginId = fcId;
+ }
+ // Recompute physical path.
+ String physicalTemplateRelativePath = getPhysicalRelativePath(templateRelativePath_p, pluginId);
+ // Then read file at this relative path.
+ return FileHelper.readFile(physicalTemplateRelativePath);
+ }
+
+ /**
+ * Get physical relative path from logical one.
+ * @param logicalRelativePath_p
+ * @return
+ */
+ public static String getPhysicalRelativePath(String logicalRelativePath_p) {
+ String result = null;
+ if (logicalRelativePath_p == null) {
+ return result;
+ }
+ // Get plug-in id.
+ String fcId = new Path(logicalRelativePath_p).segment(0);
+ String pluginId = FactoryComponentHelper.getPluginId(fcId, PlatformLocationType.WORKSPACE_THEN_TARGET_PLATFORM);
+ // If plug-in id can not be resolved, then the logical path is not relative to an existing factory component.
+ // Try with first segment of the logical path directly (which is likely to be a plug-in id).
+ if (pluginId == null) {
+ pluginId = fcId;
+ }
+ // Then return physical relative path.
+ return getPhysicalRelativePath(logicalRelativePath_p, pluginId);
+ }
+
+ /**
+ * Get physical relative path from logical given one.
+ * @param logicalRelativePath_p
+ * @param pluginId_p
+ * @return
+ */
+ public static String getPhysicalRelativePath(String logicalRelativePath_p, String pluginId_p) {
+ String result = null;
+ if (logicalRelativePath_p == null || pluginId_p == null) {
+ return result;
+ }
+ // Exclude factory component id from logical relative path.
+ IPath relativePath = new Path(logicalRelativePath_p).removeFirstSegments(1);
+ // Then recompute relative path using the plug-in id as a prefix.
+ return
+ new Path(pluginId_p + ICommonConstants.EMPTY_STRING)
+ .append(relativePath)
+ .toString();
+ }
+
+ /**
+ * Get template relative path for identified operation.
+ * @param patternShortId_p
+ * @param pluginId_p
+ * @param operationName_p
+ * @param operationId_p
+ * @return
+ */
+ public static String getTemplateRelativePath(String patternShortId_p, String pluginId_p, String operationName_p, String operationId_p) {
+ String result = null;
+ // Preconditions.
+ if (patternShortId_p == null || pluginId_p == null || operationName_p == null) {
+ return result;
+ }
+ // Unexpected entry. Generate method code does not point to a template but to other pattern methods.
+ if (PatternConstants.GENERATE_METHOD_NAME.equals(operationName_p)) {
+ return result;
+ }
+ Couple<String, String> folderNames = getTemplatesFolderNames(patternShortId_p);
+ String folderName = null;
+ // In case template is also generated, then add generated folder path before.
+ if (
+ PatternConstants.GENERATE_PRE_MATCHING_METHOD_NAME.equals(operationName_p)
+ || PatternConstants.GENERATE_POST_MATCHING_METHOD_NAME.equals(operationName_p)
+ ) {
+ folderName = folderNames.getValue();
+ // Compute correct relative path.
+ result = computeTemplatePath(pluginId_p, folderName, operationName_p);
+ } else if (operationId_p != null) { // By default, folder name is pattern one.
+ folderName = folderNames.getKey();
+ // Compute correct relative path.
+ result = computeTemplatePath(pluginId_p, folderName, operationId_p);
+ }
+ return result;
+ }
+
+ /**
+ * Get templates folder names from pattern name.
+ * @param patternShortId_p
+ * @return A couple of (User templates folder path (whatever the containing plug-in may be), Generated templates folder path (whatever the containing plug-in
+ * may be)), null if given pattern name is.
+ */
+ private static Couple<String, String> getTemplatesFolderNames(String patternShortId_p) {
+ if (patternShortId_p == null) {
+ return null;
+ }
+ return
+ new Couple<String, String>(
+ new StringBuilder(TEMPLATES_ROOT_PATH).append(patternShortId_p).toString(),
+ new StringBuilder(GENERATED_TEMPLATES_PATH).append(patternShortId_p).toString()
+ );
+ }
+
+ /**
+ * Get templates folder relative paths.<br>
+ * @param patternShortId_p
+ * @param pluginId_p
+ * @return A couple of (User templates relative (to workspace) path, Generated templates relative (to workspace) path).
+ */
+ public static Couple<String, String> getPatternTemplatesFolderRelativePaths(String patternShortId_p, String pluginId_p) {
+ Couple<String, String> folderNames = getTemplatesFolderNames(patternShortId_p);
+ // Precondition.
+ if (folderNames == null) {
+ return null;
+ }
+ return
+ new Couple<String, String>(
+ computeTemplateFolderPath(pluginId_p, folderNames.getKey()),
+ computeTemplateFolderPath(pluginId_p, folderNames.getValue())
+ );
+ }
+
+ /**
+ * Compute template file relative path from containing plugin id, containing folder path, and template file name.
+ * @param containingPluginId_p
+ * @param subFolderPath_p
+ * @param templateFileName_p
+ * @return
+ */
+ private static String computeTemplatePath(
+ String containingPluginId_p,
+ String subFolderPath_p,
+ String templateFileName_p
+ ) {
+ return
+ new StringBuilder(
+ computeTemplateFolderPath(
+ containingPluginId_p,
+ subFolderPath_p
+ )
+ )
+ .append(ICommonConstants.SLASH_CHARACTER)
+ .append(templateFileName_p)
+ .append(ICommonConstants.DOT_CHARACTER)
+ .append(PatternConstants.PATTERN_METHOD_FILE_EXTENSION)
+ .toString();
+ }
+
+ /**
+ * Compute template folder relative path from containing plugin id.
+ * @param containingPluginId_p
+ * @param subFolderPath_p
+ * @return
+ */
+ private static String computeTemplateFolderPath(String containingPluginId_p, String subFolderPath_p) {
+ return
+ new StringBuilder(ICommonConstants.SLASH_CHARACTER)
+ .append(containingPluginId_p)
+ .append(subFolderPath_p)
+ .toString();
+ }
+
+}
diff --git a/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/validation/PatternValidationHelper.java b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/validation/PatternValidationHelper.java
new file mode 100644
index 0000000..8a7bd2c
--- /dev/null
+++ b/plugins/org.eclipse.egf.pattern/src/org/eclipse/egf/pattern/validation/PatternValidationHelper.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Thales Corporate Services S.A.S.
+ * 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:
+ * Thales Corporate Services S.A.S - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egf.pattern.validation;
+
+import org.eclipse.egf.pattern.Pattern;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.util.Diagnostician;
+
+
+/**
+ * @author Guillaume Brocard
+ */
+public class PatternValidationHelper {
+ /**
+ * Validate given pattern.
+ * @param pattern_p
+ * @param validationHandler_p A validation handler, that allows the creation of a specific parent diagnostic in case of an error.<br>
+ * <code>null</code> if returned one is sufficient.<br>
+ * Note that this is only required if diagnostic is to be shown in a user dialog, default diagnostic message might then seem too confusing.
+ * @return
+ */
+ public static Diagnostic validatePattern(Pattern pattern_p, IValidationHandler validationHandler_p) {
+ // Validate the pattern model as a whole.
+ Diagnostician diagnostician = new Diagnostician();
+ // Invoke validation.
+ Diagnostic diagnostic = diagnostician.validate(pattern_p);
+ // If on error, try validation handler.
+ boolean validationError = (Diagnostic.ERROR == diagnostic.getSeverity());
+ if (validationError && (null != validationHandler_p)) {
+ // Create sub-diagnostic dedicated to the model validation.
+ DiagnosticChain validationDiagnostic = validationHandler_p.createErrorRootDiagnostic();
+ // Then attach all the validation diagnostic children.
+ validationDiagnostic.addAll(diagnostic);
+ }
+ return diagnostic;
+ }
+
+ /**
+ * Validation handler, that creates expected diagnostic structure for results.
+ * @author Guillaume Brocard
+ */
+ public interface IValidationHandler {
+ /**
+ * Create a root diagnostic error that contains all the validation error.<br>
+ * Allows to choose a different way of
+ * @return
+ */
+ public abstract DiagnosticChain createErrorRootDiagnostic();
+ }
+}