All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.frascati.implementation.script.FrascatiImplementationScriptProcessor Maven / Gradle / Ivy

The newest version!
/**
 * OW2 FraSCAti: SCA Implementation Script
 * Copyright (C) 2009-2010 INRIA, University of Lille 1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Contact: [email protected]
 *
 * Author: Philippe Merle
 *
 * Contributors: Nicolas Dolet, Christophe Demarey
 *
 */

package org.ow2.frascati.implementation.script;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashMap;

import javax.script.Invocable;
import javax.script.ScriptException;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

import org.eclipse.stp.sca.domainmodel.frascati.FrascatiPackage;
import org.eclipse.stp.sca.domainmodel.frascati.ScriptImplementation;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.factory.GenericFactory;
import org.objectweb.fractal.api.type.ComponentType;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.fractal.api.type.TypeFactory;
import org.objectweb.fractal.util.Fractal;
import org.objectweb.fractal.julia.Julia;

import org.osoa.sca.annotations.Reference;
import org.ow2.frascati.assembly.factory.api.CompositeManager;
import org.ow2.frascati.assembly.factory.api.ProcessingContext;
import org.ow2.frascati.assembly.factory.api.ProcessorException;
import org.ow2.frascati.assembly.factory.processor.AbstractCompositeBasedImplementationProcessor;

/**
 * OW2 FraSCAti SCA Implementation Script processor class.
 *
 * @author Philippe Merle
 * @version 1.3
 */
public class FrascatiImplementationScriptProcessor
     extends AbstractCompositeBasedImplementationProcessor {

  // ======================================================================
  // Internal state.
  // ======================================================================

  /**
   * The script engine manager.
   */
  private ScriptEngineManager scriptEngineManager;

  /**
   * The required composite manager.
   */
  @Reference(name = "composite-manager")
  private CompositeManager compositeManager;

  // ======================================================================
  // Internal methods.
  // ======================================================================

  /**
   * @see org.ow2.frascati.assembly.factory.processor.AbstractProcessor#toStringBuilder(EObjectType, StringBuilder)
   */
  @Override
  protected final void toStringBuilder(ScriptImplementation scriptImplementation, StringBuilder sb) {
    sb.append("frascati:implementation.script");
    append(sb, "script", scriptImplementation.getScript());
    append(sb, "language", scriptImplementation.getLanguage());
    super.toStringBuilder(scriptImplementation, sb);
  }

  /**
   * Initialize the script engine manager.
   */
  private void initializeScriptEngineManager(ClassLoader classLoader) {
    // Create the script engine manager with the runtime classloader.
    // Let's note that this can't be done before (e.g., at the instantiation time
    // of this component) because the runtime classloader could not be initialized too.
    // Christophe pointed this when applying the FraSCAti MOJO plugin to execute
    // 'mvn -Prun' on examples/helloworld-script/
    scriptEngineManager = new ScriptEngineManager(classLoader);

    // Log currently supported scripting engines.
    StringBuffer buffer = new StringBuffer();
    buffer.append("OW2 FraSCAti - Supported scripting engines:\n");
    for(ScriptEngineFactory factory : scriptEngineManager.getEngineFactories()) {
      buffer.append("* ");
      buffer.append(factory.getEngineName());
      buffer.append(' ');
      buffer.append(factory.getEngineVersion());
      buffer.append(' ');
      buffer.append(factory.getExtensions());
      buffer.append(' ');
      buffer.append(factory.getNames());
      buffer.append(' ');
      buffer.append(factory.getLanguageName());
      buffer.append(' ');
      buffer.append(factory.getLanguageVersion());
      buffer.append('\n');
    }
    log.info(buffer.toString());
  }

  /**
   * @see org.ow2.frascati.assembly.factory.api.Processor#check(ElementType, ProcessingContext)
   */
  @Override
  protected final void doCheck(ScriptImplementation scriptImplementation, ProcessingContext processingContext)
	      throws ProcessorException
  {
    String scriptImplementationScript = scriptImplementation.getScript();
    if(isNullOrEmpty(scriptImplementationScript)) {
      error(processingContext, scriptImplementation, "The attribute 'script' must be set");
    } else {
      if(processingContext.getResource(scriptImplementationScript) == null) {
        error(processingContext, scriptImplementation, "Script '", scriptImplementationScript, "' not found");
      }
    }

    // TODO check that the required script engine is available?
    // TODO evaluate the script to see it is correct

    // check attributes 'policySets' and 'requires'.
    checkImplementation(scriptImplementation, processingContext);
  }

  /**
   * @see org.ow2.frascati.assembly.factory.api.Processor#instantiate(ElementType, ProcessingContext)
   */
  @Override
  protected final void doInstantiate(ScriptImplementation scriptImplementation, ProcessingContext processingContext)
      throws ProcessorException
  {
    // Initialize the script engine manager if not already done.
    // At this moment the FraSCAti assembly factory runtime classloader
    // is initialized.
    //
    // TODO: Perhaps the script engine manager should be instantiated
    // each time a ScriptEngine is instantiated in order to be sure that
    // all script engines present in the runtime classloader are useable.
    // For instance, we could imagine a reconfiguration scenario where
    // we dynamically add a new script engine at runtime.
    if(scriptEngineManager == null) {
      initializeScriptEngineManager(processingContext.getClassLoader());
    }

    // Get the script.
    String script = scriptImplementation.getScript();

    log.info("Create an SCA component for  and the Fractal component type "
        + getFractalComponentType(scriptImplementation, processingContext).toString());

    // Obtain an input stream reader to the script.
    // TODO: Could 'script' contain a url or filename, and not just a resource in the classpath?
    // TODO move into check()
    URL scriptUrl = processingContext.getResource(script);
    if(scriptUrl == null) {
      severe(new ProcessorException(scriptImplementation, "Script '" + script + "' not found"));
      return;
    }
    InputStream scriptInputStream = null;
    try {
      scriptInputStream = scriptUrl.openStream();
    } catch (IOException ioe) {
      severe(new ProcessorException(scriptImplementation, "Script '" + script + "' not found", ioe));
      return;
    }
    InputStreamReader scriptReader = new InputStreamReader(scriptInputStream);

    // Obtain a scripting engine for evaluating the script.
    // TODO: Use scriptImplementation.getLanguage() if not null
    // TODO move into check
    String scriptExtension = script.substring(script.lastIndexOf('.') + 1);
    ScriptEngine scriptEngine = scriptEngineManager.getEngineByExtension(scriptExtension);
    if(scriptEngine == null) {
      severe(new ProcessorException(scriptImplementation, "ScriptEngine for '" + script + "' not found"));
      return;
    }
    // Add a reference to the SCA domain into the script engine
    scriptEngine.put("domain", compositeManager.getTopLevelDomainComposite());

    // Switch the current thread class loader to the processing context class loader
    // in order to be sure that the script will be evaluated into the right class loader.
    ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(processingContext.getClassLoader());

    // Evaluate the script.
    try {
      scriptEngine.eval(scriptReader);
	} catch(ScriptException se) {
      severe(new ProcessorException(scriptImplementation, "Error when evaluating '" + script + "'", se));
      return;
    } finally {
      // Restore the previous class loader.
      Thread.currentThread().setContextClassLoader(previousClassLoader);
    }

    // Create the Fractal component as a composite.
	Component component = doInstantiate(scriptImplementation, processingContext, scriptEngine);

    // Create a primitive component encapsulating the scripting engine.
    try {
      ScriptEngineComponent scriptEngineContent = new ScriptEngineComponent(component, scriptEngine);

      // TODO Will not using Tinfi instead of Julia?
      // TODO init the Fractal bootstrap component just one time.
      HashMap hints = new HashMap();
      hints.put("fractal.provider", Julia.class.getCanonicalName());
      Component bootstrap = Fractal.getBootstrapComponent(hints);
	  TypeFactory typeFactory = Fractal.getTypeFactory(bootstrap);
	  GenericFactory genericFactory = Fractal.getGenericFactory(bootstrap);

      ComponentType scriptEngineType = typeFactory.createFcType(new InterfaceType[] {
            // type for attribute-controller
            typeFactory.createFcItfType("attribute-controller",
                ScriptEngineAttributes.class.getCanonicalName(),
                false, false, false) });
      Component scriptEngineComponent = genericFactory.newFcInstance(scriptEngineType,
                "primitive", scriptEngineContent);

      // add the scripting engine component as a sub component of the SCA composite.
      addFractalSubComponent(component, scriptEngineComponent);
    } catch(Exception exc) {
      // This should not happen!
      severe(new ProcessorException(scriptImplementation, "Internal Fractal error!", exc));
	  return;
    }
  }

  /**
   * AbstractCompositeBasedImplementationProcessor#getService(ContentType, String, Class)
   */
  @Override
  protected final Object getService(ScriptEngine scriptEngine, String name, Class interfaze) throws Exception
  {
    // Get a typed proxy from the script engine.
    return ((Invocable)scriptEngine).getInterface(interfaze);
  }

  /**
   * AbstractCompositeBasedImplementationProcessor#setReference(ContentType, String, Object, Class)
   */
  @Override
  protected final void setReference(ScriptEngine scriptEngine, String name, Object delegate, Class interfaze) throws Exception
  {
    // Put the reference into the script engine.
    scriptEngine.put(name, delegate);
  }

  // ======================================================================
  // Public methods.
  // ======================================================================

  /**
   * @see org.ow2.frascati.assembly.factory.api.Processor#getProcessorID()
   */
  public final String getProcessorID() {
    return getID(FrascatiPackage.Literals.SCRIPT_IMPLEMENTATION);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy