[465576] Performances improvements for java services

Bug: 465576
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=465576
Change-Id: I6d6d496b914d37ce9dfd6750da74f38419ba06ef
Signed-off-by: Philippe DUL <philippe.dul@thalesgroup.com>
diff --git a/plugins/org.eclipse.sirius.query.legacy/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.query.legacy/META-INF/MANIFEST.MF
index a296e6b..2c0c9cf 100644
--- a/plugins/org.eclipse.sirius.query.legacy/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.sirius.query.legacy/META-INF/MANIFEST.MF
@@ -30,6 +30,7 @@
  org.eclipse.sirius.query.legacy.gen.template.scripts.imports,
  org.eclipse.sirius.query.legacy.gen.template.scripts.imports.services,
  org.eclipse.sirius.query.legacy.gen.template.statements,
+ org.eclipse.sirius.query.legacy.preferences,
  org.eclipse.sirius.query.legacy.tools,
  org.eclipse.sirius.query.legacy.tools.classloaders,
  org.eclipse.sirius.query.legacy.tools.format,
diff --git a/plugins/org.eclipse.sirius.query.legacy/plugin.xml b/plugins/org.eclipse.sirius.query.legacy/plugin.xml
index d3049f5..455d549 100644
--- a/plugins/org.eclipse.sirius.query.legacy/plugin.xml
+++ b/plugins/org.eclipse.sirius.query.legacy/plugin.xml
@@ -2,7 +2,7 @@
 <?eclipse version="3.2"?>
 
 <!--
-  Copyright (c) 2005-2014 Obeo
+  Copyright (c) 2005-2015 Obeo and others
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Public License v1.0
   which accompanies this distribution, and is available at
@@ -10,6 +10,7 @@
 
   Contributors:
        Obeo - Initial API and implementation
+       Thales - Add eclipse preferences
 -->
 
 <plugin>
@@ -30,5 +31,11 @@
       <extension point="org.eclipse.help.toc">
       <toc file="doc/toc.xml" primary="false" />
    </extension>
+   <extension
+      point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.eclipse.sirius.query.legacy.preferences.PreferenceInitializer">
+      </initializer>
+   </extension>
 
 </plugin>
diff --git a/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/gen/template/scripts/SpecificScript.java b/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/gen/template/scripts/SpecificScript.java
index 448a41a..0f53826 100644
--- a/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/gen/template/scripts/SpecificScript.java
+++ b/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/gen/template/scripts/SpecificScript.java
@@ -1,15 +1,15 @@
 /*******************************************************************************
- * Copyright (c) 2005-2014 Obeo
- *  
+ * Copyright (c) 2005-2015 Obeo and others
+ *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * 
+ *
  * Contributors:
  *    Obeo - initial API and implementation
+ *    Thales - Add a preference to use specific scripts first
  *******************************************************************************/
-
 package org.eclipse.sirius.query.legacy.gen.template.scripts;
 
 import java.io.File;
@@ -42,8 +42,7 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
-import org.osgi.framework.Bundle;
-
+import org.eclipse.sirius.query.legacy.AcceleoInterpreterPlugin;
 import org.eclipse.sirius.query.legacy.ecore.factories.FactoryException;
 import org.eclipse.sirius.query.legacy.ecore.tools.ETools;
 import org.eclipse.sirius.query.legacy.gen.AcceleoGenMessages;
@@ -63,11 +62,13 @@
 import org.eclipse.sirius.query.legacy.gen.template.scripts.imports.EvalModel;
 import org.eclipse.sirius.query.legacy.gen.template.scripts.imports.JavaServiceNotFoundException;
 import org.eclipse.sirius.query.legacy.gen.template.statements.TemplateFeatureStatement;
+import org.eclipse.sirius.query.legacy.preferences.AcceleoPreferenceConstants;
 import org.eclipse.sirius.query.legacy.tools.plugins.AcceleoMetamodelProvider;
 import org.eclipse.sirius.query.legacy.tools.plugins.AcceleoModuleProvider;
 import org.eclipse.sirius.query.legacy.tools.resources.Resources;
 import org.eclipse.sirius.query.legacy.tools.strings.Int2;
 import org.eclipse.sirius.query.legacy.tools.strings.TextSearch;
+import org.osgi.framework.Bundle;
 
 /**
  * Model specific generator configuration. A script file contains this
@@ -151,6 +152,11 @@
     protected ISpecificScriptContext scriptContext = null;
 
     /**
+     * The preference to use specific imports first
+     */
+    protected Boolean useSpecificImportsFirst = null;
+
+    /**
      * Constructor.
      */
     public SpecificScript() {
@@ -258,6 +264,17 @@
         reset(new ArrayList());
     }
 
+    /**
+     * Returns whether specific imports will be loaded first.
+     * @see org.eclipse.sirius.query.legacy.preferences.AcceleoPreferenceConstants.PREF_USE_SPECIFIC_SCRIPTS_FIRST
+     */
+    protected boolean useSpecificImportsFirst() {
+      if (useSpecificImportsFirst == null) {
+        useSpecificImportsFirst = Boolean.valueOf(Platform.getPreferencesService().getBoolean(AcceleoInterpreterPlugin.PLUGIN_ID, AcceleoPreferenceConstants.PREF_USE_SPECIFIC_SCRIPTS_FIRST, AcceleoPreferenceConstants.PREF_USE_SPECIFIC_SCRIPTS_FIRST_DEFAULT_VALUE, null));
+      }
+      return useSpecificImportsFirst.booleanValue();
+    }
+
     private void reset(List fileHierarchy) throws TemplateSyntaxExceptions {
         if (file != null) {
             final String content = Resources.getFileContent(file).toString();
@@ -1006,54 +1023,25 @@
      *            is the number of the import
      * @throws TemplateSyntaxException
      */
-    private void newImport(List fileHierarchy, String value, Int2 valuePos, int num) throws TemplateSyntaxException {
+    protected void newImport(List fileHierarchy, String value, Int2 valuePos, int num) throws TemplateSyntaxException {
         boolean isMetamodelImport = parseMetamodelImport(value, valuePos, num);
         if (scriptContext == null || scriptContext.getMaxLevel() == -1 || fileHierarchy.size() < scriptContext.getMaxLevel()) {
             if (!isMetamodelImport) {
                 if (file != null) {
                     boolean service = false;
                     boolean specificExists = false;
-                    // Specific script file
-                    final String[] specificExtensions = getSpecificImportExtensions();
-                    for (String specificExtension : specificExtensions) {
-                        final File specificFile = resolveScriptFile(file, value, specificExtension);
-                        if (specificFile != null && specificFile.exists()) {
-                            // Is recursive import?
-                            IScript genSpecific = this;
-                            do {
-                                if (genSpecific.getFile() != null && genSpecific.getFile().equals(specificFile)) {
-                                    throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.RecursiveImport"), this, valuePos); //$NON-NLS-1$
-                                }
-                                genSpecific = genSpecific.getSpecific();
-                            } while (genSpecific != null);
-                            // Add import
-                            try {
-                                if (!tryOptimizedImport(fileHierarchy, specificFile)) {
-                                    final SpecificScript newImport = createSpecificImport(specificFile);
-                                    newImport.setInitProfiling(initProfiling);
-                                    newImport.reset(new ArrayList(fileHierarchy));
-                                    newImport.setSpecific(this);
-                                    addImport(newImport);
-                                }
-                            } catch (final TemplateSyntaxExceptions e) {
-                                String message = AcceleoGenMessages.getString("SpecificScript.ErroneousTemplate"); //$NON-NLS-1$
-                                if (e.getProblems().size() == 1) {
-                                    message += " : " + ((TemplateSyntaxException) e.getProblems().get(0)).getMessage(); //$NON-NLS-1$
-                                }
-                                throw new TemplateSyntaxException(message, this, valuePos);
-                            }
-                            specificExists = true;
+
+                    if (useSpecificImportsFirst()) {
+                        specificExists = newImportFromSpecificImports(fileHierarchy, value, valuePos, num);
+                        service = newImportFromJavaServices(value);
+
+                    } else {
+                        service = newImportFromJavaServices(value);
+                        if (!service) {
+                          specificExists = newImportFromSpecificImports(fileHierarchy, value, valuePos, num);
                         }
                     }
-                    // Java service
-                    try {
 
-                        addImportForJavaService(file, value);
-                        service = true;
-                    } catch (final JavaServiceNotFoundException e) {
-                        // throw new
-                        // TemplateSyntaxException(e.getMessage(),this,valuePos);
-                    }
                     if (!service && !specificExists) {
                         throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.UnresolvedImport", new Object[] { value, }), this, valuePos); //$NON-NLS-1$
                     }
@@ -1063,6 +1051,65 @@
     }
 
     /**
+     * Try to load the given class.
+     * @return whether a class has been loaded
+     */
+    protected boolean newImportFromJavaServices(String qualifiedName) {
+
+      boolean service = false;
+      try {
+          addImportForJavaService(file, qualifiedName);
+          service = true;
+      } catch (final JavaServiceNotFoundException e) {
+          // throw new
+          // TemplateSyntaxException(e.getMessage(),this,valuePos);
+      }
+      return service;
+    }
+
+    /**
+     * Try to load specific imports for the given name
+     * @return whether a specific script has been loaded
+     */
+    protected boolean newImportFromSpecificImports(List fileHierarchy, String value, Int2 valuePos, int num) throws TemplateSyntaxException {
+      boolean specificExists = false;
+
+      // Specific script file
+      final String[] specificExtensions = getSpecificImportExtensions();
+      for (String specificExtension : specificExtensions) {
+          final File specificFile = resolveScriptFile(file, value, specificExtension);
+          if ((specificFile != null) && specificFile.exists()) {
+              // Is recursive import?
+              IScript genSpecific = this;
+              do {
+                  if ((genSpecific.getFile() != null) && genSpecific.getFile().equals(specificFile)) {
+                      throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.RecursiveImport"), this, valuePos); //$NON-NLS-1$
+                  }
+                  genSpecific = genSpecific.getSpecific();
+              } while (genSpecific != null);
+              // Add import
+              try {
+                  if (!tryOptimizedImport(fileHierarchy, specificFile)) {
+                      final SpecificScript newImport = createSpecificImport(specificFile);
+                      newImport.setInitProfiling(initProfiling);
+                      newImport.reset(new ArrayList(fileHierarchy));
+                      newImport.setSpecific(this);
+                      addImport(newImport);
+                  }
+              } catch (final TemplateSyntaxExceptions e) {
+                  String message = AcceleoGenMessages.getString("SpecificScript.ErroneousTemplate"); //$NON-NLS-1$
+                  if (e.getProblems().size() == 1) {
+                      message += " : " + ((TemplateSyntaxException) e.getProblems().get(0)).getMessage(); //$NON-NLS-1$
+                  }
+                  throw new TemplateSyntaxException(message, this, valuePos);
+              }
+              specificExists = true;
+          }
+      }
+      return specificExists;
+    }
+
+    /**
      * Add a java service to import list.
      * 
      * @param file
diff --git a/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/preferences/AcceleoPreferenceConstants.java b/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/preferences/AcceleoPreferenceConstants.java
new file mode 100644
index 0000000..8dbf8b9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/preferences/AcceleoPreferenceConstants.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2015 THALES GLOBAL SERVICES.
+ * 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 - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.query.legacy.preferences;
+
+/**
+ * Constants for preferences
+ */
+public interface AcceleoPreferenceConstants {
+
+  /**
+   * This preference ensures that specific scripts are loaded before java extensions while evaluating Acceleo expressions with the interpreter.
+   * If set to false, Interpreter will try to load java classes for IJavaExtensions then will load specific scripts if a java class hasn't been found for the qualified name.
+   *
+   * One of side effect of this behavior is that if a script has same name than an existing java class, it will not be loaded
+   */
+  String PREF_USE_SPECIFIC_SCRIPTS_FIRST = "PREF_USE_SPECIFIC_SCRIPTS_FIRST";
+
+  boolean PREF_USE_SPECIFIC_SCRIPTS_FIRST_DEFAULT_VALUE = true;
+}
diff --git a/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/preferences/PreferenceInitializer.java b/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/preferences/PreferenceInitializer.java
new file mode 100644
index 0000000..0eff7ef
--- /dev/null
+++ b/plugins/org.eclipse.sirius.query.legacy/src/org/eclipse/sirius/query/legacy/preferences/PreferenceInitializer.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2015 THALES GLOBAL SERVICES.
+ * 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 - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.query.legacy.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.sirius.query.legacy.AcceleoInterpreterPlugin;
+
+/**
+ * Class used to initialize default preference values.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+  public PreferenceInitializer() {
+  }
+
+  @Override
+  public void initializeDefaultPreferences() {
+    IEclipsePreferences preferences = DefaultScope.INSTANCE.getNode(AcceleoInterpreterPlugin.PLUGIN_ID);
+    preferences.putBoolean(AcceleoPreferenceConstants.PREF_USE_SPECIFIC_SCRIPTS_FIRST, AcceleoPreferenceConstants.PREF_USE_SPECIFIC_SCRIPTS_FIRST_DEFAULT_VALUE);
+  }
+
+}