PrepareInvokerJavaDynamic.java :  » UML » model-analysis-framework » de » uniAugsburg » MAF » core » invoker » javadyn » Java Open Source

Java Open Source » UML » model analysis framework 
model analysis framework » de » uniAugsburg » MAF » core » invoker » javadyn » PrepareInvokerJavaDynamic.java
/**
 * File: PrepareInvokerJavaDynamic Created: 02.03.2010
 * 
 * /****************************************************************************
 * *** Copyright (c) 2009-2010 University of Augsburg, Germany <www.ds-lab.org>
 * 
 * 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: Christian Saad, Programming distributed Systems Lab, University
 * of Augsburg - initial API and implementation
 *******************************************************************************/
package de.uniAugsburg.MAF.core.invoker.javadyn;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.emf.ecore.EClass;

import de.uniAugsburg.MAF.core.MAFCore;
import de.uniAugsburg.MAF.core.MAFLevel;
import de.uniAugsburg.MAF.core.Messages;
import de.uniAugsburg.MAF.core.adapter.attribution.AttributionAdapter;
import de.uniAugsburg.MAF.core.exceptions.InvokerException;
import de.uniAugsburg.MAF.core.invoker.APrepareInvoker;
import de.uniAugsburg.MAF.core.util.GeneralUtils;
import de.uniAugsburg.MAF.core.util.compiler.EclipseMemoryCompiler;
import de.uniAugsburg.MAF.models.attrmm.attributes.AttrDefinition;
import de.uniAugsburg.MAF.models.attrmm.attributes.AttrExtension;
import de.uniAugsburg.MAF.models.attrmm.semanticrules.AttrSemanticRule;


/**
 * Prepares java rules which are read as strings and compiled at run time.
 */
public class PrepareInvokerJavaDynamic extends APrepareInvoker
{

  /**
   * Class for logger.
   */
  private static Class<?> cl = PrepareInvokerJavaDynamic.class;

  /**
   * A lookup map for methods.
   */
  private Map<String, Object[]> methodMap;

  /**
   * Class name for dynamic compilation.
   */
  private String CLASS_NAME;

  /**
   * Class body for dynamic compilation.
   */
  private StringBuffer CLASS_BODY;

  /**
   * Indicates whether rules have been added.
   */
  private boolean dynamicMethodsPresent;

  /**
   * Compiler for java classes.
   */
  private EclipseMemoryCompiler emc;


  /**
   * The constructor.
   * 
   * @param core
   * @param aadapter
   * @param invokerType
   */
  public PrepareInvokerJavaDynamic(MAFCore core, AttributionAdapter aadapter, String invokerType)
  {
    super(core, aadapter, invokerType);
  }


  /*
   * (non-Javadoc)
   * 
   * @see
   * de.uniAugsburg.MAF.core.invoker.IPrepareInvoker#initRulePreparation(java
   * .util.Map, java.util.Map)
   */
  @Override
  protected void resetRulePreparationInternal(Map<Integer, EClass> metaModelMap,
      Map<Integer, AttrExtension> attributeExtensionMap)
  {
    methodMap = new HashMap<String, Object[]>();

    // set class name to attribution id
    CLASS_NAME = aadapter != null ? aadapter.getAttributionRepoID() : "attr_temp_class";//$NON-NLS-1$

    // init body
    CLASS_BODY = new StringBuffer();

    for (String imp : getDefaultImports())
      CLASS_BODY.append(imp + "\n"); //$NON-NLS-1$

    CLASS_BODY.append("public class " + CLASS_NAME + " implements IJavaRules\n{\n"); //$NON-NLS-1$ //$NON-NLS-2$

    // indicate
    dynamicMethodsPresent = false;
  }


  /*
   * (non-Javadoc)
   * 
   * @see
   * de.uniAugsburg.MAF.core.invoker.APrepareInvoker#addRuleInternal(org.eclipse
   * .emf.ecore.EClass, de.uniAugsburg.MAF.models.attrmm.AttrDefinition,
   * de.uniAugsburg.MAF.models.attrmm.AttrSemanticRule)
   */
  @Override
  protected void addRuleInternal(EClass contextClass, AttrDefinition attrDefinition,
      AttrSemanticRule semanticRule)
  {
    dynamicMethodsPresent = true;

    // attribute identifier as method name
    String methodName = GeneralUtils.getAttributeID(contextClass, attrDefinition);

    String rule = semanticRule.getRule() != null ? semanticRule //$NON-NLS-1$
        .getRule() : "return null;";
    rule = GeneralUtils.deserializeString(rule);

    // add rule to body
    if (rule.contains("private") || rule.contains("protected") || rule.contains("public")) //$NON-NLS-1$ //$NON-NLS-2$  //$NON-NLS-3$
    {
      // replace generic rule name with context-specific rule name
      rule = rule.replace("public Object " + semanticRule.getId().toLowerCase(),
          "public Object " + methodName); //$NON-NLS-1$ //$NON-NLS-2$

      // rule already has signature
      CLASS_BODY.append("\n" + rule + "\n\n"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    else
    {
      // rule has no signature
      CLASS_BODY
          .append("public Object " //$NON-NLS-1$
              + methodName
              + "(IAttributeAccessor accessor, AttrDefinition attrDefinition, EObject localObject) throws InstantiatorException, VisualizerException, InvokerException, EvaluatorException\n{\n"); //$NON-NLS-1$

      CLASS_BODY.append("\n" + rule + "\n}\n\n"); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }


  /*
   * (non-Javadoc)
   * 
   * @see
   * de.uniAugsburg.MAF.core.invoker.APrepareInvoker#finishRulePreparationInternal
   * ()
   */
  protected void finishRulePreparationInternal() throws InvokerException
  {
    if (!dynamicMethodsPresent)
    {
      // return if no rules have been added
      return;
    }

    try
    {
      core.logStatus(cl, MAFLevel.INFO, Messages.invokjava_info_compilerules);

      // init java compiler
      if (emc == null)
        emc = new EclipseMemoryCompiler();

      // finish and compile class
      CLASS_BODY.append("\n}"); //$NON-NLS-1$

      // move method-local imports to the beginning
      String classText = sanitizeImports(CLASS_BODY.toString());
      CLASS_BODY.delete(0, CLASS_BODY.length());
      CLASS_BODY.append(classText);

      Class<?> compiledClass = emc.compile(CLASS_NAME, CLASS_BODY.toString());

      Object compiledClassInstance = compiledClass.newInstance();

      List<String> objectMethods = new ArrayList<String>();
      for (Method method : Object.class.getMethods())
        objectMethods.add(method.getName());

      // put all generated methods into map
      for (Method javaRule : compiledClass.getMethods())
      {
        String javaRuleName = javaRule.getName();
        if (objectMethods.contains(javaRuleName))
          continue;
        methodMap.put(javaRuleName, new Object[] { compiledClassInstance, javaRule });
      }

      core.logStatus(cl, MAFLevel.INFO,
          Messages.bind(Messages.invokjava_info_initrules, methodMap.size()));

    }
    catch (Exception e)
    {
      String logString = Messages.bind(Messages.invokjava_error_compile, new Object[] {
          getInvokerType(), emc.getResultMessages().toString() });
      core.logStatus(cl, MAFLevel.ERROR,e,  logString);
      throw new InvokerException(logString, e);
    }
  }


  /**
   * @return the moduleContents
   */
  @Override
  public Object getCompileUnit()
  {
    return CLASS_BODY;
  }


  /**
   * The result messages from the EclipseMemoryCompiler.
   * 
   * @return
   */
  public String getCompileMessages()
  {
    if (emc != null)
      return emc.getResultMessages().toString();

    return "";
  }


  /**
   * @return the default imports.
   */
  public static List<String> getDefaultImports()
  {
    List<String> result = new ArrayList<String>();
    result.add("import java.util.ArrayList;"); //$NON-NLS-1$
    result.add("import java.util.HashMap;"); //$NON-NLS-1$
    result.add("import java.util.HashSet;"); //$NON-NLS-1$
    result.add("import java.util.List;"); //$NON-NLS-1$
    result.add("import java.util.Map;"); //$NON-NLS-1$
    result.add("import java.util.Set;"); //$NON-NLS-1$
    result.add("import org.eclipse.emf.common.util.BasicEList;"); //$NON-NLS-1$
    result.add("import org.eclipse.emf.common.util.EList;"); //$NON-NLS-1$
    result.add("import org.eclipse.emf.ecore.EObject;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.core.exceptions.InstantiatorException;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.core.exceptions.InvokerException;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.core.exceptions.EvaluatorException;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.core.exceptions.VisualizerException;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.core.instantiation.IAttributeAccessor;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.core.invoker.java.IJavaRules;"); //$NON-NLS-1$
    result.add("import de.uniAugsburg.MAF.models.attrmm.attributes.AttrDefinition;"); //$NON-NLS-1$

    return result;
  }


  /**
   * Extracts the non-default imports in a java rule text.
   * 
   * @param ruleText
   * @return
   */
  public static Set<String> getNewImports(String ruleText)
  {
    List<String> defaultImports = getDefaultImports();
    Set<String> newImports = new HashSet<String>();
    while (true)
    {
      int index = ruleText.indexOf("import"); //$NON-NLS-1$

      if (index == -1)
        break;

      // remove whitespace from start
      ruleText = ruleText.substring(index, ruleText.length());

      // extract import
      index = ruleText.indexOf(";"); //$NON-NLS-1$
      String impString = ruleText.substring(0, index + 1);

      // remove import from text
      ruleText = ruleText.substring(index + 1, ruleText.length());

      if (!defaultImports.contains(impString))
        newImports.add(impString);
    }

    return newImports;
  }


  /**
   * If imports are stored before a method's signature, they must be moved
   * into the main import section of the class.
   * 
   * @param ruleText
   * @return
   */
  public static String sanitizeImports(String classText)
  {
    String result = classText;

    // remove default imports from class text
    int startIndex = classText.indexOf("{"); //$NON-NLS-1$
    classText = classText.substring(startIndex, classText.length());

    // get all new imports in between the methods
    Set<String> newImports = getNewImports(classText);

    // remove new imports from result
    for (String imp : newImports)
    {
      while (result.contains(imp))
        result = result.replace(imp, "");

      result = imp + "\n" + result;
    }

    return result;
  }


  /*
   * (non-Javadoc)
   * 
   * @see
   * de.uniAugsburg.MAF.core.invoker.APrepareInvoker#getRuleInternal(org.eclipse
   * .emf.ecore.EClass, de.uniAugsburg.MAF.models.attrmm.AttrDefinition)
   */
  @Override
  protected Object getRuleInternal(EClass contextClass, AttrDefinition attrDefinition)
  {
    // lookup the rule
    return methodMap.get(GeneralUtils.getAttributeID(contextClass, attrDefinition));
  }


  /*
   * (non-Javadoc)
   * 
   * @see de.uniAugsburg.MAF.core.invoker.APrepareInvoker#disposeInternal()
   */
  @Override
  protected void disposeInternal()
  {
    if (methodMap != null)
    {
      methodMap.clear();
      methodMap = null;
    }

    emc = null;
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.