summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjmusset2009-03-05 11:48:55 (EST)
committer jmusset2009-03-05 11:48:55 (EST)
commite89769ce63ed0432164b4249320a49bca61d1691 (patch)
tree52d78078ed4871aa2bdfad169483de545afb957a
parent3187dff74d915a1e95a908da9d6e7a2209fd6d2c (diff)
downloadorg.eclipse.acceleo-e89769ce63ed0432164b4249320a49bca61d1691.zip
org.eclipse.acceleo-e89769ce63ed0432164b4249320a49bca61d1691.tar.gz
org.eclipse.acceleo-e89769ce63ed0432164b4249320a49bca61d1691.tar.bz2
Project renaming from MTL to Acceleo
-rw-r--r--plugins/org.eclipse.acceleo.common/.checkstyle9
-rw-r--r--plugins/org.eclipse.acceleo.common/.classpath7
-rw-r--r--plugins/org.eclipse.acceleo.common/.project34
-rw-r--r--plugins/org.eclipse.acceleo.common/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--plugins/org.eclipse.acceleo.common/META-INF/MANIFEST.MF18
-rw-r--r--plugins/org.eclipse.acceleo.common/about.html57
-rw-r--r--plugins/org.eclipse.acceleo.common/build.properties19
-rw-r--r--plugins/org.eclipse.acceleo.common/plugin.properties12
-rw-r--r--plugins/org.eclipse.acceleo.common/plugin.xml5
-rw-r--r--plugins/org.eclipse.acceleo.common/schema/java.services.exsd114
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonMessages.java81
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonPlugin.java264
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoServicesRegistry.java134
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/IAcceleoConstants.java349
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/acceleocommonmessages.properties35
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/internal/utils/AcceleoServicesEclipseUtil.java307
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoNonStandardLibrary.java212
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoStandardLibrary.java227
-rw-r--r--plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/ModelUtils.java390
19 files changed, 2281 insertions, 0 deletions
diff --git a/plugins/org.eclipse.acceleo.common/.checkstyle b/plugins/org.eclipse.acceleo.common/.checkstyle
new file mode 100644
index 0000000..60d2e33
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/.checkstyle
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fileset-config file-format-version="1.2.0" simple-config="true">
+ <local-check-config name="Acceleo" location="/org.eclipse.acceleo-feature/codestyle/AcceleoCheckstyleConfiguration.xml" type="project" description="">
+ <additional-data name="protect-config-file" value="false"/>
+ </local-check-config>
+ <fileset name="tous" enabled="true" check-config-name="Acceleo" local="true">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/plugins/org.eclipse.acceleo.common/.classpath b/plugins/org.eclipse.acceleo.common/.classpath
new file mode 100644
index 0000000..64c5e31
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.acceleo.common/.project b/plugins/org.eclipse.acceleo.common/.project
new file mode 100644
index 0000000..8ac8a4c
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.acceleo.common</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>com.atlassw.tools.eclipse.checkstyle.CheckstyleBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>com.atlassw.tools.eclipse.checkstyle.CheckstyleNature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.acceleo.common/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.acceleo.common/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..26e9c66
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Fri May 23 13:21:19 CEST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/plugins/org.eclipse.acceleo.common/META-INF/MANIFEST.MF b/plugins/org.eclipse.acceleo.common/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..1aa1a64
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.acceleo.common;singleton:=true
+Bundle-Version: 0.8.0.qualifier
+Bundle-Vendor: %providerName
+Export-Package: org.eclipse.acceleo.common,
+ org.eclipse.acceleo.common.internal.utils;x-friends:="org.eclipse.acceleo.engine,org.eclipse.acceleo.parser",
+ org.eclipse.acceleo.common.utils
+Require-Bundle: org.eclipse.emf.ecore.xmi,
+ org.eclipse.ocl.ecore,
+ org.eclipse.core.runtime;bundle-version="3.3.0";resolution:=optional,
+ org.eclipse.pde.core;bundle-version="3.3.0";resolution:=optional,
+ org.eclipse.core.resources;bundle-version="3.3.0";resolution:=optional
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.acceleo.common.AcceleoCommonPlugin
diff --git a/plugins/org.eclipse.acceleo.common/about.html b/plugins/org.eclipse.acceleo.common/about.html
new file mode 100644
index 0000000..7e1117e
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/about.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>About</title>
+</head><body lang="EN-US">
+<h2>About This Content</h2>
+
+<em>July 25, 2008</em></p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+
+ <h3>Third Party Content</h3>
+ <p>The Content includes items that have been sourced from third parties as set out below. If you
+ did not receive this Content directly from the Eclipse Foundation, the following is provided
+ for informational purposes only, and you should look to the Redistributor's license for
+ terms and conditions of use.</p>
+ <p><em>
+ <br><br>
+ <strong>OMG MOF 2.0 Specification (06-01-01)</strong> <br>
+ <ul>
+ <li><a href="http://www.omg.org/technology/documents/formal/mof.htm">MOF 2.0 main page</a></li>
+ <li><a href="http://www.omg.org/docs/formal/06-01-01.pdf">MOF 2.0 specification</a></li>
+ <li><a href="http://www.omg.org/">OMG site</a></li>
+ </ul>
+ <br>
+ <strong>OMG OCL 2.0 specification (06-05-01)</strong> <br>
+ <ul>
+ <li><a href="http://www.omg.org/technology/documents/formal/ocl.htm">OCL 2.0 main page</a></li>
+ <li><a href="http://www.omg.org/docs/formal/06-05-01.pdf">OCL 2.0 specification</a></li>
+ <li><a href="http://www.omg.org/">OMG site</a></li>
+ </ul>
+ <br>
+ <strong>OMG MTL 1.0 specification (08-01-16)</strong> <br>
+ <ul>
+ <li><a href="http://www.omg.org/spec/MOFM2T/1.0/">MTL 1.0 main page</a></li>
+ <li><a href="http://www.omg.org/spec/MOFM2T/1.0/PDF">MTL 1.0 specification</a></li>
+ <li><a href="http://www.omg.org/">OMG site</a></li>
+ </ul>
+ <br>
+ </em></p>
+ <p>A detailed list of fixes and clarifications with respect to those specifications may be found in the plug-in directly realizing them.</p>
+</body></html> \ No newline at end of file
diff --git a/plugins/org.eclipse.acceleo.common/build.properties b/plugins/org.eclipse.acceleo.common/build.properties
new file mode 100644
index 0000000..4ef204b
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/build.properties
@@ -0,0 +1,19 @@
+################################################################################
+# Copyright (c) 2008, 2009 Obeo.
+# 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:
+# Obeo - initial API and implementation
+################################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ plugin.xml,\
+ schema/,\
+ plugin.properties
+Bundle-ClassPath: .
diff --git a/plugins/org.eclipse.acceleo.common/plugin.properties b/plugins/org.eclipse.acceleo.common/plugin.properties
new file mode 100644
index 0000000..ed7c0a6
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/plugin.properties
@@ -0,0 +1,12 @@
+#################################################################################
+# Copyright (c) 2008, 2009 Obeo.
+# 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:
+# Obeo - initial API and implementation
+#################################################################################
+pluginName = Acceleo Common Utility Classes
+providerName = Eclipse Modeling Project \ No newline at end of file
diff --git a/plugins/org.eclipse.acceleo.common/plugin.xml b/plugins/org.eclipse.acceleo.common/plugin.xml
new file mode 100644
index 0000000..0e90cf7
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/plugin.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension-point id="org.eclipse.acceleo.common.java.services" name="org.eclipse.acceleo.common.java.services" schema="schema/java.services.exsd"/>
+</plugin>
diff --git a/plugins/org.eclipse.acceleo.common/schema/java.services.exsd b/plugins/org.eclipse.acceleo.common/schema/java.services.exsd
new file mode 100644
index 0000000..00f81c8
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/schema/java.services.exsd
@@ -0,0 +1,114 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.acceleo.common" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.acceleo.common" id="org.eclipse.acceleo.common.java.services" name="org.eclipse.acceleo.common.java.services"/>
+ </appinfo>
+ <documentation>
+ This extension point allows a third-party plugin to add java services to the generation context.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="service"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="service">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 0.8
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Entrez ici un exemple d&apos;utilisation du point d&apos;extension.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ [Entrez ici les informations d&apos;API.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ [Entrez ici les informations relatives à l&apos;implémentation fournie de ce point d&apos;extension.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2009 Obeo.
+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
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonMessages.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonMessages.java
new file mode 100644
index 0000000..91d1e0a
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonMessages.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007, 2008, 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Utility class to access externalized Strings for the Acceleo common plugin.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public final class AcceleoCommonMessages {
+ /** Qualified path to the properties file in which to seek the keys. */
+ private static final String BUNDLE_NAME = "org.eclipse.acceleo.common.acceleocommonmessages"; //$NON-NLS-1$
+
+ /** Contains the locale specific {@link String}s needed by this plug-in. */
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+
+ /**
+ * Utility classes don't need to (and shouldn't) be instantiated.
+ */
+ private AcceleoCommonMessages() {
+ // prevents instantiation
+ }
+
+ /**
+ * This will return an unformatted String from the resource bundle.
+ *
+ * @param key
+ * Key of the String we seek.
+ * @return An unformatted String from the bundle.
+ */
+ private static String internalGetString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+
+ /**
+ * Returns the specified {@link String} from the resource bundle.
+ *
+ * @param key
+ * Key of the String we seek.
+ * @return The String from the resource bundle associated with <code>key</code>.
+ * <code>'!' + key + '!'</code> will be returned in case we didn't find it in the bundle.
+ */
+ public static String getString(String key) {
+ // Pass through MessageFormat so that we're consistent in the handling of special chars such as the
+ // apostrophe
+ return MessageFormat.format(internalGetString(key), new Object[] {});
+ }
+
+ /**
+ * Returns a String from the resource bundle bound with the given arguments.
+ *
+ * @param key
+ * Key of the String we seek.
+ * @param arguments
+ * Arguments for the String formatting.
+ * @return formatted {@link String}.
+ * @see MessageFormat#format(String, Object[])
+ */
+ public static String getString(String key, Object... arguments) {
+ if (arguments == null) {
+ return getString(key);
+ }
+ return MessageFormat.format(internalGetString(key), arguments);
+ }
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonPlugin.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonPlugin.java
new file mode 100644
index 0000000..1197319
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoCommonPlugin.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common;
+
+import org.eclipse.acceleo.common.internal.utils.AcceleoServicesEclipseUtil;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryEventListener;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public class AcceleoCommonPlugin extends Plugin {
+ /** The plug-in ID. */
+ public static final String PLUGIN_ID = "org.eclipse.acceleo.common"; //$NON-NLS-1$
+
+ /** Name of the extension point to parse for service classes. */
+ public static final String SERVICES_EXTENSION_POINT = "org.eclipse.acceleo.common.java.services"; //$NON-NLS-1$
+
+ /** Exact name of the "class" tag of the extension point. */
+ private static final String CLASS_TAG_NAME = "class"; //$NON-NLS-1$
+
+ /** This plug-in's shared instance. */
+ private static AcceleoCommonPlugin plugin;
+
+ /** The registry listener that will be used to listen to Acceleo service changes. */
+ private final AcceleoServicesRegistryListener servicesListener = new AcceleoServicesRegistryListener();
+
+ /** Keeps a reference to this bundle's context. */
+ private BundleContext context;
+
+ /**
+ * Default constructor for the plugin.
+ */
+ public AcceleoCommonPlugin() {
+ plugin = this;
+ }
+
+ /**
+ * Returns the shared instance.
+ *
+ * @return the shared instance
+ */
+ public static AcceleoCommonPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Trace an Exception in the error log.
+ *
+ * @param e
+ * Exception to log.
+ * @param blocker
+ * <code>True</code> if the exception must be logged as error, <code>False</code> to log it as
+ * a warning.
+ */
+ public static void log(Exception e, boolean blocker) {
+ if (e == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("AcceleoCommonPlugin.LogNullException")); //$NON-NLS-1$
+ }
+
+ if (getDefault() == null) {
+ // We are out of eclipse. Prints the stack trace on standard error.
+ // CHECKSTYLE:OFF
+ e.printStackTrace();
+ // CHECKSTYLE:ON
+ } else if (e instanceof CoreException) {
+ log(((CoreException)e).getStatus());
+ } else if (e instanceof NullPointerException) {
+ int severity = IStatus.WARNING;
+ if (blocker) {
+ severity = IStatus.ERROR;
+ }
+ log(new Status(severity, PLUGIN_ID, severity, AcceleoCommonMessages
+ .getString("AcceleoCommonPlugin.ElementNotFound"), e)); //$NON-NLS-1$
+ } else {
+ int severity = IStatus.WARNING;
+ if (blocker) {
+ severity = IStatus.ERROR;
+ }
+ log(new Status(severity, PLUGIN_ID, severity, AcceleoCommonMessages
+ .getString("AcceleoCommonPlugin.JavaException"), e)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Puts the given status in the error log view.
+ *
+ * @param status
+ * Error Status.
+ */
+ public static void log(IStatus status) {
+ // Eclipse platform displays NullPointer on standard error instead of throwing it.
+ // We'll handle this by throwing it ourselves.
+ if (status == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("AcceleoCommonPlugin.LogNullStatus")); //$NON-NLS-1$
+ }
+
+ if (getDefault() != null) {
+ getDefault().getLog().log(status);
+ } else {
+ // CHECKSTYLE:OFF
+ System.err.println(status.getMessage());
+ status.getException().printStackTrace();
+ // CHECKSTYLE:ON
+ }
+ }
+
+ /**
+ * Puts the given message in the error log view, as error or warning.
+ *
+ * @param message
+ * The message to put in the error log view.
+ * @param blocker
+ * <code>True</code> if the message must be logged as error, <code>False</code> to log it as a
+ * warning.
+ */
+ public static void log(String message, boolean blocker) {
+ if (getDefault() == null) {
+ // We are out of eclipse. Prints the message on standard error.
+ // CHECKSTYLE:OFF
+ System.err.println(message);
+ // CHECKSTYLE:ON
+ } else {
+ int severity = IStatus.WARNING;
+ if (blocker) {
+ severity = IStatus.ERROR;
+ }
+ String errorMessage = message;
+ if (errorMessage == null || "".equals(errorMessage)) { //$NON-NLS-1$
+ errorMessage = AcceleoCommonMessages.getString("AcceleoCommonPlugin.UnexpectedException"); //$NON-NLS-1$
+ }
+ log(new Status(severity, PLUGIN_ID, errorMessage));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(final BundleContext bundleContext) throws Exception {
+ super.start(bundleContext);
+ context = bundleContext;
+ final IExtensionRegistry registry = Platform.getExtensionRegistry();
+ registry.addListener(servicesListener, SERVICES_EXTENSION_POINT);
+ parseInitialContributions();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(final BundleContext bundleContext) throws Exception {
+ plugin = null;
+ context = null;
+ super.stop(bundleContext);
+ final IExtensionRegistry registry = Platform.getExtensionRegistry();
+ registry.removeListener(servicesListener);
+ AcceleoServicesEclipseUtil.clearRegistry();
+ }
+
+ /**
+ * Though we have listeners on both provided extension points, there could have been contributions before
+ * this plugin got started. This will parse them.
+ */
+ private void parseInitialContributions() {
+ final IExtensionRegistry registry = Platform.getExtensionRegistry();
+ for (IExtension extension : registry.getExtensionPoint(SERVICES_EXTENSION_POINT).getExtensions()) {
+ for (IConfigurationElement service : extension.getConfigurationElements()) {
+ try {
+ AcceleoServicesEclipseUtil.addService(service.createExecutableExtension(CLASS_TAG_NAME));
+ } catch (CoreException e) {
+ log(e, false);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns this bundle's context.
+ *
+ * @return This bundle's context.
+ */
+ public BundleContext getContext() {
+ return context;
+ }
+
+ /**
+ * This will allow us to be aware of changes of extension against the Acceleo services extension point.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+ final class AcceleoServicesRegistryListener implements IRegistryEventListener {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryEventListener#added(org.eclipse.core.runtime.IExtension[])
+ */
+ public void added(IExtension[] extensions) {
+ for (IExtension extension : extensions) {
+ for (IConfigurationElement service : extension.getConfigurationElements()) {
+ try {
+ AcceleoServicesEclipseUtil.addService(service.createExecutableExtension(CLASS_TAG_NAME));
+ } catch (CoreException e) {
+ log(e, false);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryEventListener#removed(org.eclipse.core.runtime.IExtension[])
+ */
+ public void removed(IExtension[] extensions) {
+ for (IExtension extension : extensions) {
+ for (IConfigurationElement service : extension.getConfigurationElements()) {
+ AcceleoServicesEclipseUtil.removeService(service.getAttribute(CLASS_TAG_NAME));
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryEventListener#added(org.eclipse.core.runtime.IExtensionPoint[])
+ */
+ public void added(IExtensionPoint[] extensionPoints) {
+ // no need to listen to this
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryEventListener#removed(org.eclipse.core.runtime.IExtensionPoint[])
+ */
+ public void removed(IExtensionPoint[] extensionPoints) {
+ // no need to listen to this event
+ }
+ }
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoServicesRegistry.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoServicesRegistry.java
new file mode 100644
index 0000000..0648a94
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/AcceleoServicesRegistry.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common;
+
+import java.lang.reflect.Method;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.acceleo.common.internal.utils.AcceleoServicesEclipseUtil;
+import org.eclipse.emf.common.EMFPlugin;
+
+/**
+ * This will allow Acceleo to know which java services are to be added to the evaluation context.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ * @since 0.8
+ */
+public final class AcceleoServicesRegistry {
+ /** Singleton instance of the registry. */
+ public static final AcceleoServicesRegistry INSTANCE = new AcceleoServicesRegistry();
+
+ /** This will contain the services registered for Acceleo evaluations. */
+ private final Set<Object> registeredServices = new LinkedHashSet<Object>();
+
+ /**
+ * This class is a singleton. Access instance through {@link #INSTANCE}.
+ */
+ private AcceleoServicesRegistry() {
+ // Hides default constructor
+ }
+
+ /**
+ * Adds a service to the registry.
+ *
+ * @param service
+ * Service that is to be registered for Acceleo evaluations.
+ * @return <code>true</code> if the set didn't already contain <code>service</code>.
+ */
+ public boolean addService(Object service) {
+ if (service instanceof Class) {
+ try {
+ registeredServices.add(((Class<?>)service).newInstance());
+ } catch (InstantiationException e) {
+ AcceleoCommonPlugin.log(AcceleoCommonMessages.getString(
+ "AcceleoServicesRegistry.ServiceInstantiationFailure", ((Class<?>)service).getName(), e //$NON-NLS-1$
+ .getMessage()), false);
+ } catch (IllegalAccessException e) {
+ AcceleoCommonPlugin.log(AcceleoCommonMessages.getString(
+ "AcceleoServicesRegistry.ServiceInstantiationFailure", ((Class<?>)service).getName(), e //$NON-NLS-1$
+ .getMessage()), false);
+ }
+ }
+ return registeredServices.add(service);
+ }
+
+ /**
+ * Returns all registered services classes. <b>Note</b> that workspace services are refreshed each time
+ * this is called if Eclipse is running.
+ *
+ * @return All registered services classes.
+ */
+ public Set<Object> getAllRegisteredServiceInstances() {
+ final Set<Object> compound = new LinkedHashSet<Object>();
+ if (EMFPlugin.IS_ECLIPSE_RUNNING) {
+ compound.addAll(AcceleoServicesEclipseUtil.getRegisteredServices());
+ }
+ compound.addAll(registeredServices);
+ return compound;
+ }
+
+ /**
+ * Returns all registered services methods. <b>Note</b> that workspace services are refreshed each time
+ * this is called if Eclipse is running.
+ *
+ * @return All applicable registered services methods.
+ */
+ public Set<Method> getAllRegisteredServices() {
+ final Set<Object> serviceInstances = getAllRegisteredServiceInstances();
+ // at least
+ final Set<Method> services = new LinkedHashSet<Method>(serviceInstances.size());
+ for (Object serviceInstance : serviceInstances) {
+ for (Method method : serviceInstance.getClass().getMethods()) {
+ services.add(method);
+ }
+ }
+ return services;
+ }
+
+ /**
+ * Returns all registered services methods applicable for the given type. <b>Note</b> that workspace
+ * services are refreshed each time this is called if Eclipse is running.
+ *
+ * @param receiverType
+ * Type of the receiver we seek applicable services for.
+ * @return All applicable registered services methods.
+ */
+ public Set<Method> getRegisteredServices(Class<?> receiverType) {
+ final Set<Method> allServices = getAllRegisteredServices();
+ final Set<Method> applicableServices = new LinkedHashSet<Method>(allServices.size());
+ for (Method method : allServices) {
+ final Class<?>[] parameters = method.getParameterTypes();
+ if (parameters.length > 0 && parameters[0].equals(receiverType)) {
+ applicableServices.add(method);
+ }
+ }
+ return applicableServices;
+ }
+
+ /**
+ * Removes a service from the registry.
+ *
+ * @param service
+ * Service that is to be removed from Acceleo evaluations contexts.
+ * @return <code>true</code> if the set contained <code>service</code>.
+ */
+ public boolean removeService(Object service) {
+ return registeredServices.remove(service);
+ }
+
+ /**
+ * Clears all registered services out of the registry.
+ */
+ public void clearRegistry() {
+ registeredServices.clear();
+ }
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/IAcceleoConstants.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/IAcceleoConstants.java
new file mode 100644
index 0000000..3f35585
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/IAcceleoConstants.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common;
+
+/**
+ * Concrete syntax constants for text explicit mode only.
+ *
+ * @author <a href="mailto:jonathan.musset@obeo.fr">Jonathan Musset</a>
+ */
+public interface IAcceleoConstants {
+
+ /**
+ * Extension of the concrete syntax file.
+ */
+ String MTL_FILE_EXTENSION = "mtl"; //$NON-NLS-1$
+
+ /**
+ * Extension of the abstract syntax file.
+ */
+ String EMTL_FILE_EXTENSION = "emtl"; //$NON-NLS-1$
+
+ /**
+ * Module block keyword.
+ * <p>
+ * [module ... /]
+ */
+ String MODULE = "module"; //$NON-NLS-1$
+
+ /**
+ * Comment block keyword.
+ * <p>
+ * [comment ... ] ... [/comment]
+ */
+ String COMMENT = "comment"; //$NON-NLS-1$
+
+ /**
+ * Import block keyword.
+ * <p>
+ * [import ... /]
+ */
+ String IMPORT = "import"; //$NON-NLS-1$
+
+ /**
+ * Extends keyword.
+ * <p>
+ * [module ... extends ... /]
+ * <p>
+ */
+ String EXTENDS = "extends"; //$NON-NLS-1$
+
+ /**
+ * Overrides keyword.
+ * <p>
+ * [template ... overrides ... ] ... [/template]
+ */
+ String OVERRIDES = "overrides"; //$NON-NLS-1$
+
+ /**
+ * Template block keyword.
+ * <p>
+ * [template ... ] ... [/template]
+ */
+ String TEMPLATE = "template"; //$NON-NLS-1$
+
+ /**
+ * Public visibility keyword.
+ * <p>
+ * [template public ... ] ... [/template]
+ */
+ String VISIBILITY_KIND_PUBLIC = "public"; //$NON-NLS-1$
+
+ /**
+ * Protected visibility keyword.
+ * <p>
+ * [template protected ... ] ... [/template]
+ */
+ String VISIBILITY_KIND_PROTECTED = "protected"; //$NON-NLS-1$
+
+ /**
+ * Private visibility keyword.
+ * <p>
+ * [template private ... ] ... [/template]
+ */
+ String VISIBILITY_KIND_PRIVATE = "private"; //$NON-NLS-1$
+
+ /**
+ * Query block keyword.
+ * <p>
+ * [query ... ] ... [/query]
+ */
+ String QUERY = "query"; //$NON-NLS-1$
+
+ /**
+ * For block keyword.
+ * <p>
+ * [for ... ] ... [/for]
+ */
+ String FOR = "for"; //$NON-NLS-1$
+
+ /**
+ * Before keyword.
+ * <p>
+ * [for ... before (...) ] ... [/for]
+ */
+ String BEFORE = "before"; //$NON-NLS-1$
+
+ /**
+ * After keyword.
+ * <p>
+ * [for ... after (...) ] ... [/for]
+ */
+ String AFTER = "after"; //$NON-NLS-1$
+
+ /**
+ * Separator keyword.
+ * <p>
+ * [for ... separator (...) ] ... [/for]
+ */
+ String SEPARATOR = "separator"; //$NON-NLS-1$
+
+ /**
+ * Guard keyword.
+ * <p>
+ * [template ... <b>?</b> (...) ] ... [/template]
+ */
+ String GUARD = "?"; //$NON-NLS-1$
+
+ /**
+ * If block keyword.
+ * <p>
+ * [if ... ] ... [/if]
+ */
+ String IF = "if"; //$NON-NLS-1$
+
+ /**
+ * Else If keyword.
+ * <p>
+ * [elseif ... /]
+ */
+ String ELSE_IF = "elseif"; //$NON-NLS-1$
+
+ /**
+ * Else keyword.
+ * <p>
+ * [else]
+ */
+ String ELSE = "else"; //$NON-NLS-1$
+
+ /**
+ * Let block keyword.
+ * <p>
+ * [let ... ] ... [/let]
+ */
+ String LET = "let"; //$NON-NLS-1$
+
+ /**
+ * Else Let keyword.
+ * <p>
+ * [elselet ... /]
+ */
+ String ELSE_LET = "elselet"; //$NON-NLS-1$
+
+ /**
+ * Trace block keyword.
+ * <p>
+ * [trace ... ] ... [/trace]
+ */
+ String TRACE = "trace"; //$NON-NLS-1$
+
+ /**
+ * Macro block keyword.
+ * <p>
+ * [macro ... ] ... [/macro]
+ */
+ String MACRO = "macro"; //$NON-NLS-1$
+
+ /**
+ * File block keyword.
+ * <p>
+ * [file ... ] ... [/file]
+ */
+ String FILE = "file"; //$NON-NLS-1$
+
+ /**
+ * Protected Area keyword.
+ * <p>
+ * [protected ... ] ... [/protected]
+ */
+ String PROTECTED_AREA = "protected"; //$NON-NLS-1$
+
+ /**
+ * Beginning delimiter of a literal expression.
+ * <p>
+ * <b>'</b>...'
+ */
+ String LITERAL_BEGIN = "'"; //$NON-NLS-1$
+
+ /**
+ * Ending delimiter of a literal expression.
+ * <p>
+ * '...<b>'</b>
+ */
+ String LITERAL_END = "'"; //$NON-NLS-1$
+
+ /**
+ * Escape character in a literal expression.
+ * <p>
+ * ' <b>\ '</b> '
+ */
+ String LITERAL_ESCAPE = "\\\'"; //$NON-NLS-1$
+
+ /**
+ * Beginning delimiter of an area which is not static.
+ * <p>
+ * <b>[</b> ... ]
+ */
+ String DEFAULT_BEGIN = "["; //$NON-NLS-1$
+
+ /**
+ * Ending delimiter of an area which is not static.
+ * <p>
+ * [ ... <b>]</b>
+ */
+ String DEFAULT_END = "]"; //$NON-NLS-1$
+
+ /**
+ * Ending delimiter of the header and the body.
+ * <p>
+ * [ ... <b>/</b>]
+ */
+ String DEFAULT_END_BODY_CHAR = "/"; //$NON-NLS-1$
+
+ /**
+ * Beginning delimiter of an invocation.
+ * <p>
+ * <b>[</b> ... ]
+ */
+ String INVOCATION_BEGIN = DEFAULT_BEGIN;
+
+ /**
+ * Ending delimiter of an invocation.
+ * <p>
+ * [ ... <b>/]</b>
+ */
+ String[] INVOCATION_END = new String[] {DEFAULT_END_BODY_CHAR, DEFAULT_END};
+
+ /**
+ * Beginning delimiter of parenthesis.
+ * <p>
+ * <b>(</b> ... )
+ */
+ String PARENTHESIS_BEGIN = "("; //$NON-NLS-1$
+
+ /**
+ * Ending delimiter of parenthesis.
+ * <p>
+ * ( ... <b>)</b>
+ */
+ String PARENTHESIS_END = ")"; //$NON-NLS-1$
+
+ /**
+ * Beginning delimiter of brackets.
+ * <p>
+ * <b>{</b> ... }
+ */
+ String BRACKETS_BEGIN = "{"; //$NON-NLS-1$
+
+ /**
+ * Ending delimiter of brackets.
+ * <p>
+ * { ... <b>}</b>
+ */
+ String BRACKETS_END = "}"; //$NON-NLS-1$
+
+ /**
+ * Variable declaration separator between the name and the type.
+ * <p>
+ * c <b>:</b> Class
+ */
+ String VARIABLE_DECLARATION_SEPARATOR = ":"; //$NON-NLS-1$
+
+ /**
+ * Variable declaration separator between the type and the init expression.
+ * <p>
+ * i : Integer <b>=</b> 0
+ */
+ String VARIABLE_INIT_SEPARATOR = "="; //$NON-NLS-1$
+
+ /**
+ * Comma separator between variables.
+ * <p>
+ * c1:Class <b>,</b> c2:Class
+ */
+ String COMMA_SEPARATOR = ","; //$NON-NLS-1$
+
+ /**
+ * Semicolon separator between variables.
+ * <p>
+ * c1:Class<b>;</b>
+ * <p>
+ * c2:Class<b>;</b>
+ */
+ String SEMICOLON_SEPARATOR = ";"; //$NON-NLS-1$
+
+ /**
+ * Pipe separator between the local variable and the expression in a for statement.
+ * <p>
+ * [for (c:Class <b>|</b> p->allClasses()) ] ... [/for]
+ */
+ String PIPE_SEPARATOR = "|"; //$NON-NLS-1$
+
+ /**
+ * OCL : To invoke a method on each object of a list.
+ * <p>
+ * p.allClasses.name
+ */
+ String OCL_CALL_SIMPLE = "."; //$NON-NLS-1$
+
+ /**
+ * OCL : To invoke a method on the whole list.
+ * <p>
+ * p.allClasses->size()
+ */
+ String OCL_CALL_LIST = "->"; //$NON-NLS-1$
+
+ /**
+ * OCL : The 'self' keyword.
+ */
+ String SELF = "self"; //$NON-NLS-1$
+
+ /**
+ * OCL : The 'super' keyword.
+ */
+ String SUPER = "super"; //$NON-NLS-1$
+
+ /**
+ * Comment : The 'main' tag.
+ */
+ String TAG_MAIN = "@main"; //$NON-NLS-1$
+
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/acceleocommonmessages.properties b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/acceleocommonmessages.properties
new file mode 100644
index 0000000..1467165
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/acceleocommonmessages.properties
@@ -0,0 +1,35 @@
+################################################################################
+# Copyright (c) 2008, 2009 Obeo.
+# 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:
+# Obeo - initial API and implementation
+################################################################################
+## note : apostrophes need to be doubled in these messages or they'll be ignored
+# org.eclipse.acceleo.common
+AcceleoCommonPlugin.ElementNotFound = Required element not found.
+AcceleoCommonPlugin.JavaException = A java exception has been thrown.
+AcceleoCommonPlugin.LogNullStatus = Status to be logged cannot be null.
+AcceleoCommonPlugin.LogNullException = Exception to be logged cannot be null.
+AcceleoCommonPlugin.UnexpectedException = Unexpected Acceleo problem.
+
+AcceleoServicesRegistry.ServiceInstantiationFailure = Unexpected exception while initializing service {0} : {1}
+
+# org.eclipse.acceleo.common.internal.utils
+AcceleoServicesEclipseUtil.IllegalBundleState = Bundle {0} is in a wrong state : {1}
+AcceleoServicesEclipseUtil.UninstallationFailure = Unexpected exception while trying to uninstall workspace-defined bundle {0} : {1}
+AcceleoServicesEclipseUtil.InstallationFailure = Unexpected exception while trying to install workspace-defined bundle {0} : {1}
+
+# org.eclipse.acceleo.common.utils
+ModelUtils.LoadFailure = Unable to load model at {0}.
+ModelUtils.NullInputStream = Input Stream for the model to load cannot be null.
+ModelUtils.NullPath = Path cannot be null or empty.
+ModelUtils.NullSaveRoot = Cannot serialize null object.
+ModelUtils.NullRoot = Cannot attach ''null'' to a resource.
+
+AcceleoNonStandardLibrary.LoadFailure = Couldn''t load the Acceleo non-standard library.
+
+AcceleoStandardLibrary.LoadFailure = Couldn''t load the Acceleo standard library. \ No newline at end of file
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/internal/utils/AcceleoServicesEclipseUtil.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/internal/utils/AcceleoServicesEclipseUtil.java
new file mode 100644
index 0000000..7d695ed
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/internal/utils/AcceleoServicesEclipseUtil.java
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common.internal.utils;
+
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.acceleo.common.AcceleoCommonMessages;
+import org.eclipse.acceleo.common.AcceleoCommonPlugin;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.pde.core.plugin.IExtensions;
+import org.eclipse.pde.core.plugin.IPluginExtension;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * Eclipse-specific utilities for Acceleo services. It will be initialized with all services that could be parsed
+ * from the extension point if Eclipse is running and won't be used when outside of Eclipse.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public final class AcceleoServicesEclipseUtil {
+ /**
+ * Keeps track of all contributions to the services extension point. <b>Note</b> that this will be
+ * frequently changed as the registry's listener updates the list of available extensions.
+ */
+ private static final Set<Object> SERVICES = new LinkedHashSet<Object>();
+
+ /** Keeps track of all manually loaded workspace bundles. */
+ private static final Set<Bundle> WORKSPACE_INSTALLED_BUNDLES = new HashSet<Bundle>();
+
+ /**
+ * Utility classes don't need a default constructor.
+ */
+ private AcceleoServicesEclipseUtil() {
+ // hides constructor
+ }
+
+ /**
+ * Adds a given service to the list of available ones.
+ *
+ * @param service
+ * The actual service instance.
+ */
+ public static void addService(Object service) {
+ SERVICES.add(service);
+ }
+
+ /**
+ * Clears all registered extensions out of the eclipse registry.
+ */
+ public static void clearRegistry() {
+ // All manually loaded workspace contributions have to be unloaded here
+ for (Bundle bundle : WORKSPACE_INSTALLED_BUNDLES) {
+ try {
+ uninstallBundle(bundle);
+ } catch (BundleException e) {
+ AcceleoCommonPlugin.log(AcceleoCommonMessages.getString(
+ "AcceleoServicesEclipseUtil.UninstallationFailure", bundle.getSymbolicName(), e //$NON-NLS-1$
+ .getMessage()), true);
+ AcceleoCommonPlugin.log(e, true);
+ }
+ }
+ WORKSPACE_INSTALLED_BUNDLES.clear();
+ SERVICES.clear();
+ }
+
+ /**
+ * Returns all registered service classes.
+ *
+ * @return All registered service classes.
+ */
+ public static Set<Object> getRegisteredServices() {
+ loadWorkspaceContributions();
+ return new LinkedHashSet<Object>(SERVICES);
+ }
+
+ /**
+ * Removes a given services from the list of available ones.
+ *
+ * @param service
+ * The qualified class name of the service that is to be removed.
+ */
+ public static void removeService(String service) {
+ for (Object candidate : new ArrayList<Object>(SERVICES)) {
+ if (service.equals(candidate.getClass().getName())) {
+ SERVICES.remove(candidate);
+ }
+ }
+ }
+
+ /**
+ * Returns the bundle corresponding to the given location if any.
+ *
+ * @param pluginLocation
+ * The location of the bundle we seek.
+ * @return The bundle corresponding to the given location if any, <code>null</code> otherwise.
+ */
+ private static Bundle getBundle(String pluginLocation) {
+ Bundle[] bundles = AcceleoCommonPlugin.getDefault().getContext().getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ if (pluginLocation.equals(bundles[i].getLocation())) {
+ return bundles[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Installs the bundle corresponding to the given location. This will fail if the location doesn't point
+ * to a valid bundle.
+ *
+ * @param pluginLocation
+ * Location of the bundle to be installed.
+ * @return The installed bundle.
+ * @throws BundleException
+ * Thrown if the Bundle isn't valid.
+ * @throws IllegalStateException
+ * Thrown if the bundle couldn't be installed properly.
+ */
+ private static Bundle installBundle(String pluginLocation) throws BundleException, IllegalStateException {
+ Bundle target = AcceleoCommonPlugin.getDefault().getContext().installBundle(pluginLocation);
+ int state = target.getState();
+ if (state != Bundle.INSTALLED) {
+ throw new IllegalStateException(AcceleoCommonMessages.getString(
+ "AcceleoServicesEclipseUtil.IllegalBundleState", target, state)); //$NON-NLS-1$
+ }
+ refreshPackages(new Bundle[] {target});
+ return target;
+ }
+
+ /**
+ * This will search through workspace-defined plugins to check if any of them contributes a Java Service,
+ * then load them through OSGi.
+ */
+ private static void loadWorkspaceContributions() {
+ final IPluginModelBase[] workspaceModels = PluginRegistry.getWorkspaceModels();
+ final List<IPluginModelBase> javaServiceProvider = new ArrayList<IPluginModelBase>(
+ workspaceModels.length);
+ for (IPluginModelBase workspaceModel : workspaceModels) {
+ final IExtensions extensions = workspaceModel.getExtensions();
+ final IPluginExtension[] pluginExtensions = extensions.getExtensions();
+ for (IPluginExtension ext : pluginExtensions) {
+ if (AcceleoCommonPlugin.SERVICES_EXTENSION_POINT.equals(ext.getPoint())) {
+ javaServiceProvider.add(workspaceModel);
+ }
+ }
+ }
+
+ BundleContext context = AcceleoCommonPlugin.getDefault().getContext();
+ ServiceReference jobManagerReference = context.getServiceReference(IJobManager.class.getName());
+ IJobManager jobManager = null;
+ if (jobManagerReference != null) {
+ jobManager = (IJobManager)context.getService(jobManagerReference);
+ }
+ try {
+ final boolean[] flag = new boolean[] {false,};
+ for (IPluginModelBase candidate : javaServiceProvider) {
+ try {
+ final IResource candidateManifest = candidate.getUnderlyingResource();
+ final String candidateLocationReference = "reference:" //$NON-NLS-1$
+ + candidateManifest.getProject().getLocationURI().toURL().toExternalForm();
+
+ // Prepare the job listener so that we can wait for the end of all registry updates
+ Bundle bundle = getBundle(candidateLocationReference);
+ final int registryEventExpected;
+ if (bundle == null) {
+ registryEventExpected = 1;
+ } else {
+ // one event for the removal of old contributions, 1 for the addition
+ registryEventExpected = 2;
+ }
+ final IJobChangeListener listener = new JobChangeAdapter() {
+ private int expectedEvents = registryEventExpected;
+
+ @Override
+ public void done(IJobChangeEvent event) {
+ final IStatus result = event.getResult();
+ if ("org.eclipse.equinox.registry".equals(result.getPlugin())) { //$NON-NLS-1$
+ if (--expectedEvents == 0) {
+ synchronized(flag) {
+ flag[0] = true;
+ flag.notifyAll();
+ }
+ }
+ }
+ }
+ };
+ if (jobManager != null) {
+ jobManager.addJobChangeListener(listener);
+ }
+
+ // do the actual installation or refreshing of bundles
+ if (bundle == null) {
+ bundle = installBundle(candidateLocationReference);
+ WORKSPACE_INSTALLED_BUNDLES.add(bundle);
+ } else {
+ refreshPackages(new Bundle[] {bundle,});
+ }
+
+ // wait for all registry updates to end and remove listener
+ if (jobManager != null) {
+ synchronized(flag) {
+ while (!flag[0]) {
+ try {
+ flag.wait();
+ } catch (InterruptedException e) {
+ // discard
+ }
+ }
+ }
+ jobManager.removeJobChangeListener(listener);
+ }
+ } catch (BundleException e) {
+ AcceleoCommonPlugin.log(AcceleoCommonMessages.getString(
+ "AcceleoServicesEclipseUtil.installationFailure", candidate.getBundleDescription() //$NON-NLS-1$
+ .getName(), e.getMessage()), false);
+ AcceleoCommonPlugin.log(e, false);
+ } catch (MalformedURLException e) {
+ AcceleoCommonPlugin.log(e, false);
+ }
+ }
+ } finally {
+ context.ungetService(jobManagerReference);
+ }
+ }
+
+ /**
+ * Refreshes all exported packages of the given bundles. This must be called after installing the bundle.
+ *
+ * @param bundles
+ * Bundles which exported packages are to be refreshed.
+ */
+ private static void refreshPackages(Bundle[] bundles) {
+ BundleContext context = AcceleoCommonPlugin.getDefault().getContext();
+ ServiceReference packageAdminReference = context.getServiceReference(PackageAdmin.class.getName());
+ PackageAdmin packageAdmin = null;
+ if (packageAdminReference != null) {
+ packageAdmin = (PackageAdmin)context.getService(packageAdminReference);
+ }
+
+ if (packageAdmin != null) {
+ final boolean[] flag = new boolean[] {false,};
+ FrameworkListener listener = new FrameworkListener() {
+ public void frameworkEvent(FrameworkEvent event) {
+ if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+ synchronized(flag) {
+ flag[0] = true;
+ flag.notifyAll();
+ }
+ }
+ }
+ };
+
+ context.addFrameworkListener(listener);
+ packageAdmin.refreshPackages(bundles);
+ synchronized(flag) {
+ while (!flag[0]) {
+ try {
+ flag.wait();
+ } catch (InterruptedException e) {
+ // discard
+ }
+ }
+ }
+ context.removeFrameworkListener(listener);
+ context.ungetService(packageAdminReference);
+ }
+ }
+
+ /**
+ * Uninstalls the given bundle from the context.
+ *
+ * @param target
+ * The bundle that is to be uninstalled.
+ * @throws BundleException
+ * Thrown if a lifecycle issue arises.
+ */
+ private static void uninstallBundle(Bundle target) throws BundleException {
+ target.uninstall();
+ refreshPackages(null);
+ }
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoNonStandardLibrary.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoNonStandardLibrary.java
new file mode 100644
index 0000000..8a9e69d
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoNonStandardLibrary.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ * Jerome Benois - eInverse initial implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common.utils;
+
+import java.io.IOException;
+
+import org.eclipse.acceleo.common.AcceleoCommonMessages;
+import org.eclipse.acceleo.common.AcceleoCommonPlugin;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+
+/**
+ * This will define additional convenience operations on OCL types. Those were not defined in the
+ * specification.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public final class AcceleoNonStandardLibrary {
+ /**
+ * Name of the &quot;ancestors&quot; non-standard operation accessible on all objects.
+ * <p>
+ * <b>ancestors( ) : Sequence</b><br/> Returns a Sequence containing the full set of the receiver's
+ * ancestors.
+ * </p>
+ */
+ public static final String OPERATION_OCLANY_ANCESTORS = "ancestors"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;siblings&quot; non-standard operation accessible on all objects.
+ * <p>
+ * <b>siblings( ) : Sequence</b><br/> Returns a Sequence containing the full set of the receiver's
+ * siblings.
+ * </p>
+ */
+ public static final String OPERATION_OCLANY_SIBLINGS = "siblings"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;eAllContents&quot; non-standard operation accessible on all objects. This operation
+ * comes in two flavors :
+ * <p>
+ * <b>eAllContents( ) : Sequence</b><br/> Returns the whole content tree of the receiver as a Sequence.
+ * </p>
+ * <p>
+ * <b>eAllContents( OclAny ) : Sequence</b><br/> Returns the elements of the given type from the whole
+ * content tree of the receiver as a Sequence.
+ * </p>
+ */
+ public static final String OPERATION_OCLANY_EALLCONTENTS = "eAllContents"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;eInverse&quot; non-standard operation accessible on all objects.
+ * <p>
+ * <b>eInverse( ) : Sequence(T)</b><br/> Returns the inverse references of the receiver.
+ * </p>
+ */
+ public static final String OPERATION_OCLANY_EINVERSE = "eInverse"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;toString&quot; non-standard operation accessible on all objects.
+ * <p>
+ * <b>toString( ) : String</b><br/> Returns the String representation of the receiver.
+ * </p>
+ */
+ public static final String OPERATION_OCLANY_TOSTRING = "toString"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;endsWith&quot; non-standard String operation.
+ * <p>
+ * <b>endsWith( String substring ) : Boolean</b><br/> Returns <code>true</code> if self ends with the
+ * substring <code>substring</code>, <code>false</code> otherwise.
+ * </p>
+ */
+ public static final String OPERATION_STRING_ENDSWITH = "endsWith"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;replace&quot; non-standard String operation.
+ * <p>
+ * <b>replace( String substring, String replacement ) : String</b><br/> Substitutes the first occurence of
+ * substring <code>substring</code> in self by substring <code>replacement</code> and returns the
+ * resulting string. If there is no occurrence of the substring, The original string is returned.
+ * <code>substring</code> and <code>replacement</code> are treated as regular expressions.
+ * </p>
+ */
+ public static final String OPERATION_STRING_REPLACE = "replace"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;replaceAll&quot; non-standard String operation.
+ * <p>
+ * <b>replaceAll( String substring, String replacement ) : String</b><br/> Substitutes all substrings
+ * <code>substring</code> in self by substring <code>replacement</code> and returns the resulting string.
+ * If there is no occurrence of the substring, The original string is returned. <code>substring</code> and
+ * <code>replacement</code> are treated as regular expressions.
+ * </p>
+ */
+ public static final String OPERATION_STRING_REPLACEALL = "replaceAll"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;startsWith&quot; non-standard String operation.
+ * <p>
+ * <b>startsWith( String substring ) : Boolean</b><br/> Returns <code>true</code> if self starts with the
+ * substring <code>substring</code>, <code>false</code> otherwise.
+ * </p>
+ */
+ public static final String OPERATION_STRING_STARTSWITH = "startsWith"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;substituteAll&quot; non-standard String operation.
+ * <p>
+ * <b>substituteAll( String substring, String replacement ) : String</b><br/> Substitutes all substrings
+ * <code>substring</code> in self by substring <code>replacement</code> and returns the resulting string.
+ * If there is no occurrence of the substring, The original string is returned. <code>substring</code> and
+ * <code>replacement</code> are not treated as regular expressions.
+ * </p>
+ */
+ public static final String OPERATION_STRING_SUBSTITUTEALL = "substituteAll"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;tokenize&quot; non-standard String operation.
+ * <p>
+ * <b>tokenize( String delim ) : Sequence</b><br/> Returns a sequence containing all parts of self split
+ * around delimiters defined by the characters in String delim.
+ * </p>
+ */
+ public static final String OPERATION_STRING_TOKENIZE = "tokenize"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;trim&quot; non-standard String operation.
+ * <p>
+ * <b>trim( ) : String</b><br/> Removes all leading and trailing spaces of self.
+ * </p>
+ */
+ public static final String OPERATION_STRING_TRIM = "trim"; //$NON-NLS-1$
+
+ /** Name of the primitive type "String" as defined in the OCL standard library. */
+ public static final String PRIMITIVE_STRING_NAME = "String"; //$NON-NLS-1$
+
+ /** Name of the type "OclAny" used for common EOperations for all EObjects. */
+ public static final String TYPE_OCLANY_NAME = "OclAny"; //$NON-NLS-1$
+
+ /** This is the ecore package that will contain the Acceleo non-standard Library classifiers. */
+ private static EPackage nonStdLibPackage;
+
+ /** NS URI of the mtlnonstdlib.ecore which defines the Acceleo non-standard operation library. */
+ private static final String NS_URI = "http://www.eclipse.org/acceleo/mtl/0.8.0/mtlnonstdlib.ecore"; //$NON-NLS-1$
+
+ /** EClass for the Acceleo non-standard library's "OclAny" type. */
+ private static EClass oclAnyType;
+
+ /** EClass for the Acceleo non-standard library's "String" type. */
+ private static EClass stringType;
+
+ /**
+ * Initializes the non-standard library package along with its content.
+ */
+ public AcceleoNonStandardLibrary() {
+ final ResourceSet resourceSet = new ResourceSetImpl();
+
+ try {
+ nonStdLibPackage = (EPackage)ModelUtils.load(URI.createURI(NS_URI), resourceSet);
+ stringType = (EClass)nonStdLibPackage.getEClassifier(PRIMITIVE_STRING_NAME);
+ oclAnyType = (EClass)nonStdLibPackage.getEClassifier(TYPE_OCLANY_NAME);
+ } catch (IOException e) {
+ AcceleoCommonPlugin.log(AcceleoCommonMessages.getString("AcceleoNonStandardLibrary.LoadFailure"), false); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Obtains the operations declared on the specified type.
+ *
+ * @param type
+ * The type which operation are sought.
+ * @return The operations it declares. <code>null</code> if none.
+ */
+ public EList<EOperation> getExistingOperations(EClassifier type) {
+ return getExistingOperations(type.getName());
+ }
+
+ /**
+ * Obtains the operations declared on the specified type.
+ *
+ * @param classifierName
+ * The name of the classifier which operation are sought.
+ * @return The operations it declares. <code>null</code> if none.
+ */
+ public EList<EOperation> getExistingOperations(String classifierName) {
+ EList<EOperation> result = new BasicEList<EOperation>();
+
+ if (PRIMITIVE_STRING_NAME.equals(classifierName)) {
+ result.addAll(stringType.getEOperations());
+ } else if (TYPE_OCLANY_NAME.equals(classifierName)) {
+ result.addAll(oclAnyType.getEOperations());
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoStandardLibrary.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoStandardLibrary.java
new file mode 100644
index 0000000..e98bf82
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/AcceleoStandardLibrary.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common.utils;
+
+import java.io.IOException;
+
+import org.eclipse.acceleo.common.AcceleoCommonMessages;
+import org.eclipse.acceleo.common.AcceleoCommonPlugin;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+
+/**
+ * This will define additional operations on OCL types as defined in the Acceleo specification.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public final class AcceleoStandardLibrary {
+ /**
+ * Name of the &quot;toString&quot; standard Integer operation.
+ * <p>
+ * <b>toString( Integer i ) : String</b><br/> Converts the integer i to a string.
+ * </p>
+ * <p>
+ * <b>Note</b> that this has been replaced by the {@link AcceleoNonStandardLibrary#OPERATION_OCLANY_TOSTRING}.
+ * </p>
+ */
+ public static final String OPERATION_INTEGER_TOSTRING = "toString"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;toString&quot; standard Real operation.
+ * <p>
+ * <b>toString( Real r ) : String</b><br/> Converts the real r to a string.
+ * </p>
+ * <p>
+ * <b>Note</b> that this has been replaced by the {@link AcceleoNonStandardLibrary#OPERATION_OCLANY_TOSTRING}.
+ * </p>
+ */
+ public static final String OPERATION_REAL_TOSTRING = "toString"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;first&quot; standard String operation.
+ * <p>
+ * <b>first( Integer n ) : String</b><br/> Returns first n characters of self, or self if size of self is
+ * less than n.
+ * </p>
+ */
+ public static final String OPERATION_STRING_FIRST = "first"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;index&quot; standard String operation.
+ * <p>
+ * <b>index( String r ) : Integer</b><br/> Returns the index of substring r in self, or -1 if r is not in
+ * self.
+ * </p>
+ */
+ public static final String OPERATION_STRING_INDEX = "index"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;isAlpha&quot; standard String operation.
+ * <p>
+ * <b>isAlpha() : Boolean</b><br/> Returns <code>true</code> if self consists only of alphabetical
+ * characters, <code>false</code> otherwise.
+ * </p>
+ */
+ public static final String OPERATION_STRING_ISALPHA = "isAlpha"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;isAlphanum&quot; standard String operation.
+ * <p>
+ * <b>isAlphanum() : Boolean</b><br/> Returns <code>true</code> if self consists only of alphanumeric
+ * characters, <code>false</code> otherwise.
+ * </p>
+ */
+ public static final String OPERATION_STRING_ISALPHANUM = "isAlphanum"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;last&quot; standard String operation.
+ * <p>
+ * <b>last( Integer n ) : String</b><br/> Returns last n characters of self, or self if size of self is
+ * less than n.
+ * </p>
+ */
+ public static final String OPERATION_STRING_LAST = "last"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;strcmp&quot; standard String operation.
+ * <p>
+ * <b>strcmp( String s1 ) : Integer</b><br/> Returns an integer less than zero, equal to zero, or greater
+ * than zero depending on whether s1 is lexicographically less than, equal to, or greater than self.
+ * </p>
+ */
+ public static final String OPERATION_STRING_STRCMP = "strcmp"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;strstr&quot; standard String operation.
+ * <p>
+ * <b>strstr( String r ) : Boolean</b><br/> Searches for string r in self. Returns true if found, false
+ * otherwise.
+ * </p>
+ */
+ public static final String OPERATION_STRING_STRSTR = "strstr"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;strtok&quot; standard String operation.
+ * <p>
+ * <b>strtok( String s1, Integer flag ) : String</b><br/> Breaks the string self into a sequence of tokens
+ * each of which is delimited by any character in string s1. The parameter flag should be 0 when strtok is
+ * called for the first time, 1 subsequently.
+ * </p>
+ */
+ public static final String OPERATION_STRING_STRTOK = "strtok"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;substitute&quot; standard String operation.
+ * <p>
+ * <b>substitute( String r, String t ) : String</b><br/> Substitutes substring r in self by substring t
+ * and returns the resulting string. If there is no occurrence of the substring, it returns the original
+ * string.
+ * </p>
+ */
+ public static final String OPERATION_STRING_SUBSTITUTE = "substitute"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;toLowerFirst&quot; standard String operation.
+ * <p>
+ * <b>toLowerFirst() : String</b><br/> Creates a copy of self with first character converted to lowercase
+ * and returns it.
+ * </p>
+ */
+ public static final String OPERATION_STRING_TOLOWERFIRST = "toLowerFirst"; //$NON-NLS-1$
+
+ /**
+ * Name of the &quot;toUpperFirst&quot; standard String operation.
+ * <p>
+ * <b>toUpperFirst() : String</b><br/> Creates a copy of self with first character converted to uppercase
+ * and returns it.
+ * </p>
+ */
+ public static final String OPERATION_STRING_TOUPPERFIRST = "toUpperFirst"; //$NON-NLS-1$
+
+ /** Name of the primitive type "Integer" as defined in the OCL standard library. */
+ public static final String PRIMITIVE_INTEGER_NAME = "Integer"; //$NON-NLS-1$
+
+ /** Name of the primitive type "Real" as defined in the OCL standard library. */
+ public static final String PRIMITIVE_REAL_NAME = "Real"; //$NON-NLS-1$
+
+ /** Name of the primitive type "String" as defined in the OCL standard library. */
+ public static final String PRIMITIVE_STRING_NAME = "String"; //$NON-NLS-1$
+
+ /** EClass for the Acceleo standard library's "Integer" type. */
+ private static EClass integerType;
+
+ /** NS URI of the mtlstdlib.ecore which defines the Acceleo standard operation library. */
+ private static final String NS_URI = "http://www.eclipse.org/acceleo/mtl/0.8.0/mtlstdlib.ecore"; //$NON-NLS-1$
+
+ /** EClass for the Acceleo standard library's "Real" type. */
+ private static EClass realType;
+
+ /** This is the ecore package that will contain the Acceleo Standard Library classifiers. */
+ private static EPackage stdLibPackage;
+
+ /** EClass for the Acceleo standard library's "String" type. */
+ private static EClass stringType;
+
+ /**
+ * Initializes the standard library package along with its content.
+ */
+ public AcceleoStandardLibrary() {
+ final ResourceSet resourceSet = new ResourceSetImpl();
+
+ try {
+ stdLibPackage = (EPackage)ModelUtils.load(URI.createURI(NS_URI), resourceSet);
+ stringType = (EClass)stdLibPackage.getEClassifier(PRIMITIVE_STRING_NAME);
+ integerType = (EClass)stdLibPackage.getEClassifier(PRIMITIVE_INTEGER_NAME);
+ realType = (EClass)stdLibPackage.getEClassifier(PRIMITIVE_REAL_NAME);
+ } catch (IOException e) {
+ AcceleoCommonPlugin.log(AcceleoCommonMessages.getString("AcceleoStandardLibrary.LoadFailure"), false); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Obtains the operations declared on the specified type.
+ *
+ * @param type
+ * The type which operation are sought.
+ * @return The operations it declares. <code>null</code> if none.
+ */
+ public EList<EOperation> getExistingOperations(EClassifier type) {
+ return getExistingOperations(type.getName());
+ }
+
+ /**
+ * Obtains the operations declared on the specified type.
+ *
+ * @param classifierName
+ * The name of the classifier which operation are sought.
+ * @return The operations it declares. <code>null</code> if none.
+ */
+ public EList<EOperation> getExistingOperations(String classifierName) {
+ EList<EOperation> result = new BasicEList<EOperation>();
+
+ if (PRIMITIVE_STRING_NAME.equals(classifierName)) {
+ result.addAll(stringType.getEOperations());
+ } else if (PRIMITIVE_INTEGER_NAME.equals(classifierName)) {
+ result.addAll(integerType.getEOperations());
+ } else if (PRIMITIVE_REAL_NAME.equals(classifierName)) {
+ result.addAll(realType.getEOperations());
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/ModelUtils.java b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/ModelUtils.java
new file mode 100644
index 0000000..7c77200
--- /dev/null
+++ b/plugins/org.eclipse.acceleo.common/src/org/eclipse/acceleo/common/utils/ModelUtils.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007, 2008, 2009 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.common.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.acceleo.common.AcceleoCommonMessages;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
+
+/**
+ * Utility class for model loading/saving and serialization.
+ *
+ * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
+ */
+public final class ModelUtils {
+ /** Constant for the file encoding system property. */
+ private static final String ENCODING_PROPERTY = "file.encoding"; //$NON-NLS-1$
+
+ /**
+ * Utility classes don't need to (and shouldn't) be instantiated.
+ */
+ private ModelUtils() {
+ // prevents instantiation
+ }
+
+ /**
+ * Attaches the given {@link EObject} to a new resource created in a new {@link ResourceSet} with the
+ * given URI.
+ *
+ * @param resourceURI
+ * URI of the new resource to create.
+ * @param root
+ * EObject to attach to a new resource.
+ * @return The resource <tt>root</tt> has been attached to.
+ */
+ public static Resource attachResource(URI resourceURI, EObject root) {
+ if (root == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("ModelUtils.NullRoot")); //$NON-NLS-1$
+ }
+ final Resource newResource = createResource(resourceURI);
+ newResource.getContents().add(root);
+ return newResource;
+ }
+
+ /**
+ * Attaches the given {@link EObject} to a new resource created in the given {@link ResourceSet} with the
+ * given URI.
+ *
+ * @param resourceURI
+ * URI of the new resource to create.
+ * @param resourceSet
+ * ResourceSet in which to create the resource.
+ * @param root
+ * EObject to attach to a new resource.
+ * @return The resource <tt>root</tt> has been attached to.
+ */
+ public static Resource attachResource(URI resourceURI, ResourceSet resourceSet, EObject root) {
+ if (root == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("ModelUtils.NullRoot")); //$NON-NLS-1$
+ }
+ final Resource newResource = createResource(resourceURI, resourceSet);
+ newResource.getContents().add(root);
+ return newResource;
+ }
+
+ /**
+ * This will create a {@link Resource} given the model extension it is intended for.
+ *
+ * @param modelURI
+ * {@link org.eclipse.emf.common.util.URI URI} where the model is stored.
+ * @return The {@link Resource} given the model extension it is intended for.
+ */
+ public static Resource createResource(URI modelURI) {
+ return createResource(modelURI, new ResourceSetImpl());
+ }
+
+ /**
+ * This will create a {@link Resource} given the model extension it is intended for and a ResourceSet.
+ *
+ * @param modelURI
+ * {@link org.eclipse.emf.common.util.URI URI} where the model is stored.
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in.
+ * @return The {@link Resource} given the model extension it is intended for.
+ */
+ public static Resource createResource(URI modelURI, ResourceSet resourceSet) {
+ String fileExtension = modelURI.fileExtension();
+ if (fileExtension == null || fileExtension.length() == 0) {
+ fileExtension = Resource.Factory.Registry.DEFAULT_EXTENSION;
+ }
+
+ final Resource.Factory.Registry registry = Resource.Factory.Registry.INSTANCE;
+ final Object resourceFactory = registry.getExtensionToFactoryMap().get(fileExtension);
+ if (resourceFactory != null) {
+ resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(fileExtension,
+ resourceFactory);
+ } else {
+ resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(fileExtension,
+ new XMIResourceFactoryImpl());
+ }
+
+ return resourceSet.createResource(modelURI);
+ }
+
+ /**
+ * Loads the models contained by the given directory in the given ResourceSet.
+ * <p>
+ * If <code>resourceSet</code> is <code>null</code>, all models will be loaded in a new resourceSet.
+ * </p>
+ *
+ * @param directory
+ * The directory from which to load the models.
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in. If <code>null</code>, all models will be
+ * loaded in a new resourceSet.
+ * @return The models contained by the given directory.
+ * @throws IOException
+ * Thrown if an I/O operation has failed or been interrupted.
+ */
+ public static List<EObject> getModelsFrom(File directory, ResourceSet resourceSet) throws IOException {
+ return getModelsFrom(directory, null, resourceSet);
+ }
+
+ /**
+ * Loads the files with the given extension contained by the given directory as EObjects in the given
+ * ResourceSet.
+ * <p>
+ * If <code>resourceSet</code> is <code>null</code>, all models will be loaded in a new resourceSet.
+ * </p>
+ * <p>
+ * The argument <code>extension</code> is in fact the needed suffix for its name in order for a file to be
+ * loaded. If it is equal to &quot;rd&quot;, a file named &quot;model.aird&quot; will be loaded, but so
+ * would be a file named &quot;Shepherd&quot;.
+ * </p>
+ * <p>
+ * The empty String or <code>null</code> will result in all the files of the given directory to be loaded,
+ * and would then be equivalent to {@link #getModelsFrom(File)}.
+ * </p>
+ *
+ * @param directory
+ * The directory from which to load the models.
+ * @param extension
+ * File extension of the files to load. If <code>null</code>, will consider all extensions.
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in. If <code>null</code>, all models will be
+ * loaded in a new resourceSet.
+ * @return The models contained by the given directory.
+ * @throws IOException
+ * Thrown if an I/O operation has failed or been interrupted.
+ */
+ public static List<EObject> getModelsFrom(File directory, String extension, ResourceSet resourceSet)
+ throws IOException {
+ final List<EObject> models = new ArrayList<EObject>();
+ final String fileExtension;
+ if (extension != null) {
+ fileExtension = extension;
+ } else {
+ fileExtension = ""; //$NON-NLS-1$
+ }
+ final ResourceSet theResourceSet;
+ if (resourceSet == null) {
+ theResourceSet = new ResourceSetImpl();
+ } else {
+ theResourceSet = resourceSet;
+ }
+ if (directory.exists() && directory.isDirectory() && directory.listFiles() != null) {
+ final File[] files = directory.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ final File aFile = files[i];
+
+ if (!aFile.isDirectory() && aFile.getName().matches("[^.].*?\\Q" + fileExtension + "\\E")) { //$NON-NLS-1$ //$NON-NLS-2$
+ models.add(load(aFile, theResourceSet));
+ }
+ }
+ }
+
+ return models;
+ }
+
+ /**
+ * Loads a model from a {@link java.io.File File} in a given {@link ResourceSet}.
+ * <p>
+ * This will return the first root of the loaded model, other roots can be accessed via the resource's
+ * content.
+ * </p>
+ *
+ * @param file
+ * {@link java.io.File File} containing the model to be loaded.
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in.
+ * @return The model loaded from the file.
+ * @throws IOException
+ * If the given file does not exist.
+ */
+ public static EObject load(File file, ResourceSet resourceSet) throws IOException {
+ return load(URI.createFileURI(file.getPath()), resourceSet);
+ }
+
+ /**
+ * Load a model from an {@link java.io.InputStream InputStream} in a given {@link ResourceSet}.
+ * <p>
+ * This will return the first root of the loaded model, other roots can be accessed via the resource's
+ * content.
+ * </p>
+ *
+ * @param stream
+ * The inputstream to load from
+ * @param fileName
+ * The original filename
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in.
+ * @return The loaded model
+ * @throws IOException
+ * If the given file does not exist.
+ */
+ public static EObject load(InputStream stream, String fileName, ResourceSet resourceSet)
+ throws IOException {
+ if (stream == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("ModelUtils.NullInputStream")); //$NON-NLS-1$
+ }
+ EObject result = null;
+
+ final Resource modelResource = createResource(URI.createURI(fileName), resourceSet);
+ modelResource.load(stream, Collections.emptyMap());
+ if (modelResource.getContents().size() > 0) {
+ result = modelResource.getContents().get(0);
+ }
+ return result;
+ }
+
+ /**
+ * Loads a model from the String representing the location of a model.
+ * <p>
+ * This can be called with pathes of the form
+ * <ul>
+ * <li><code>/pluginID/path</code></li>
+ * <li><code>platform:/plugin/pluginID/path</code></li>
+ * <li><code>platform:/resource/pluginID/path</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * This will return the first root of the loaded model, other roots can be accessed via the resource's
+ * content.
+ * </p>
+ *
+ * @param path
+ * Location of the model.
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in.
+ * @return The model loaded from the path.
+ * @throws IOException
+ * If the path doesn't resolve to a reachable location.
+ */
+ public static EObject load(String path, ResourceSet resourceSet) throws IOException {
+ if (path == null || "".equals(path)) { //$NON-NLS-1$
+ throw new IllegalArgumentException(AcceleoCommonMessages.getString("ModelUtils.NullPath")); //$NON-NLS-1$
+ }
+ final EObject result;
+ // path is already defined with a platform scheme
+ if (path.startsWith("platform")) { //$NON-NLS-1$
+ result = load(URI.createURI(path), resourceSet);
+ } else {
+ EObject temp = null;
+ try {
+ // Will first try and load as if the model is in the plugins
+ temp = load(URI.createPlatformPluginURI(path, true), resourceSet);
+ } catch (IOException e) {
+ // Model wasn't in the plugins, try and load it within the workspace
+ try {
+ temp = load(URI.createPlatformResourceURI(path, true), resourceSet);
+ } catch (IOException ee) {
+ // Silently discarded, will fail later on
+ }
+ }
+ result = temp;
+ }
+ if (result == null) {
+ throw new IOException(AcceleoCommonMessages.getString("ModelUtils.LoadFailure", path)); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ /**
+ * Loads a model from an {@link org.eclipse.emf.common.util.URI URI} in a given {@link ResourceSet}.
+ * <p>
+ * This will return the first root of the loaded model, other roots can be accessed via the resource's
+ * content.
+ * </p>
+ *
+ * @param modelURI
+ * {@link org.eclipse.emf.common.util.URI URI} where the model is stored.
+ * @param resourceSet
+ * The {@link ResourceSet} to load the model in.
+ * @return The model loaded from the URI.
+ * @throws IOException
+ * If the given file does not exist.
+ */
+ public static EObject load(URI modelURI, ResourceSet resourceSet) throws IOException {
+ String fileExtension = modelURI.fileExtension();
+ if (fileExtension == null || fileExtension.length() == 0) {
+ fileExtension = Resource.Factory.Registry.DEFAULT_EXTENSION;
+ }
+ final Resource.Factory.Registry registry = Resource.Factory.Registry.INSTANCE;
+ final Object resourceFactory = registry.getExtensionToFactoryMap().get(fileExtension);
+ if (resourceFactory != null) {
+ resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(fileExtension,
+ resourceFactory);
+ } else {
+ resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(fileExtension,
+ new XMIResourceFactoryImpl());
+ }
+ EObject result = null;
+ final Resource modelResource = resourceSet.getResource(modelURI, true);
+ if (modelResource.getContents().size() > 0) {
+ result = modelResource.getContents().get(0);
+ }
+ return result;
+ }
+
+ /**
+ * Saves a model as a file to the given path.
+ *
+ * @param root
+ * Root of the objects to be serialized in a file.
+ * @param path
+ * File where the objects have to be saved.
+ * @throws IOException
+ * Thrown if an I/O operation has failed or been interrupted during the saving process.
+ */
+ public static void save(EObject root, String path) throws IOException {
+ if (root == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("ModelUtils.NullSaveRoot")); //$NON-NLS-1$
+ }
+ final Resource newModelResource = createResource(URI.createFileURI(path));
+ newModelResource.getContents().add(root);
+ final Map<String, String> options = new HashMap<String, String>();
+ options.put(XMLResource.OPTION_ENCODING, System.getProperty(ENCODING_PROPERTY));
+ newModelResource.save(options);
+ }
+
+ /**
+ * Serializes the given EObjet as a String.
+ *
+ * @param root
+ * Root of the objects to be serialized.
+ * @return The given EObjet serialized as a String.
+ * @throws IOException
+ * Thrown if an I/O operation has failed or been interrupted during the saving process.
+ */
+ public static String serialize(EObject root) throws IOException {
+ if (root == null) {
+ throw new NullPointerException(AcceleoCommonMessages.getString("ModelUtils.NullSaveRoot")); //$NON-NLS-1$
+ }
+ // Copies the root to avoid modifying it
+ final EObject copyRoot = EcoreUtil.copy(root);
+ attachResource(URI.createFileURI("resource.xml"), copyRoot); //$NON-NLS-1$
+
+ final StringWriter writer = new StringWriter();
+ final Map<String, String> options = new HashMap<String, String>();
+ options.put(XMLResource.OPTION_ENCODING, System.getProperty(ENCODING_PROPERTY));
+ // Should not throw ClassCast since uri calls for an xml resource
+ ((XMLResource)copyRoot.eResource()).save(writer, options);
+ final String result = writer.toString();
+ writer.flush();
+ return result;
+ }
+}