Package org.objectweb.speedo.genclass.merger

Source Code of org.objectweb.speedo.genclass.merger.GenClassMerger

/**
* Copyright (C) 2001-2004 France Telecom R&D
*
* 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
*/
package org.objectweb.speedo.genclass.merger;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.jorm.util.lib.StringReplace;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.genclass.GenClass;
import org.objectweb.speedo.generation.enhancer.common.DuplicatedMethodVerifier;
import org.objectweb.speedo.generation.enhancer.common.InterfaceAgregatorVisitor;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
*
* @author S.Chassande-Barrioz
*/
public class GenClassMerger extends MatchingTask {
  public final static String LOGGER_NAME =
    SpeedoProperties.LOGGER_NAME + ".genclassmerger";
  public final static String GEN_CLASS_NAME =
    GenClass.class.getName().replace('.', '/');
  private File src = null;
  protected Logger logger = null;
  protected Personality personality;

  public GenClassMerger() {
    personality = null;
  }
 
  public GenClassMerger(Personality p) {
    personality = p;
  }
 
  public File getSrc() {
    return src;
  }

  public void setSrc(File src) {
    this.src = src;
  }
 
    protected String getLoggerName() {
        return LOGGER_NAME;
    }
   
  public void execute() throws BuildException {
    if (logger == null) {
      logger = Monolog.initialize().getLogger(getLoggerName());
    }
    String[] pdFiles = super.getDirectoryScanner(src).getIncludedFiles();
    for(int i=0; i<pdFiles.length; i++) {
      try {
        mergeGenClass(newGCInfo(pdFiles[i]));
      } catch (SpeedoException e) {
        String msg = "Error while merging the file " + pdFiles[i]
                                     + " merged" ;
        Exception ie = ExceptionHelper.getNested(e);
        throw new BuildException(msg, ie);
            } catch (RuntimeException e) {
                logger.log(BasicLevel.ERROR, e.getMessage(), e);
                throw new BuildException("Error", e);
      }
    }
  }

  public void mergeGenClass(GCInfo gc) throws SpeedoException {
        logger.log(BasicLevel.DEBUG, "Treat the class " + gc.classToWrite);
        ClassReader cr = loadJavaClass(gc.classToWrite, false);
        if (cr != null) {
            //The file exists ==> analyze it.
            logger.log(BasicLevel.DEBUG, "Analyze the class " + gc.classToWrite);
            GenClassAnalyzer gcInfo = new GenClassAnalyzer(logger, gc);
            cr.accept(gcInfo, false);
        if (!requireEnhancement(gc)) {
          return;
            }
    }
    logger.log(BasicLevel.INFO, "Enhance the generic class " + gc.classToWrite);
    ClassWriter cw = new ClassWriter(false);
        ClassVisitor current = cw;
        current = new InterfaceAgregatorVisitor(current, logger, gc.classToWrite, personality);
        current = new DuplicatedMethodVerifier(current, logger, personality);
       
        writeFirstClass(gc, current);
        writeSecondClass(gc, current);
    writeJavaClass(gc.classToWrite, cw);
   
    checkAfter(gc);
  }
 
    protected void writeFirstClass(final GCInfo gc, ClassVisitor current)
        throws SpeedoException {
        //Write the code of the first class
        GenClassAdapter gca = new GenClassAdapter(current, logger, gc, personality);
        loadJavaClass(gc.firstClass, false).accept(gca, false);
    }

    protected void writeSecondClass(final GCInfo gc, ClassVisitor current)
        throws SpeedoException {
        //Write the code of the second class
        GenClassAdapter gca = new GenClassAdapter(current, logger, gc, personality);
        gca.setVisitConstructor(false);
        loadJavaClass(gc.secondClass, false).accept(gca, false);
    }   
  protected String getClassToWrite(String gcn) {
        return StringReplace.replaceChar('\\', '/',
                gcn.substring(0, gcn.length()-6));
  }

    protected String getFirstClass(String gcn) {
        return getClassToWrite(gcn);
    }

    protected String getSecondClass(String gcn) {
        return GEN_CLASS_NAME;
    }
 
  protected boolean requireEnhancement(GCInfo gc) {
    if (!gc.isAbstract) {
            //do nothing
            logger.log(BasicLevel.DEBUG, "Class " + gc.gcn + " already complete.");
      return false;
    }
    return true;
  }
 
  protected void checkAfter(GCInfo gc) throws SpeedoException {
        //Test the class loading
        logger.log(BasicLevel.DEBUG, "check after the class " + gc.classToWrite);
        String cn = StringReplace.replaceChar('/','.', gc.classToWrite);
        cn = StringReplace.replaceChar('\\','.', cn);
    try {
      Class.forName(cn);
    } catch (Throwable e) {
      String msg = "Merged class '" + gc.classToWrite
                + "' cannot be loaded: " + e.getMessage();
      logger.log(BasicLevel.ERROR, msg, e);
            if (e instanceof Exception) {
                throw new SpeedoException(msg, (Exception) e);
            } else {
                throw new SpeedoException(msg);
            }
    }
  }

  /**
   * Loads a specified class.
   * @param fn is the file name of the .class to load. the file name is
   * a relative patht to the 'src' directory.
   * @param remove indicates if the .class must be removed
   * @return the JavaClass loaded
   * @exception SpeedoException if the file cannot be loaded
   */
  protected ClassReader loadJavaClass(final String fn,
      final boolean remove) throws SpeedoException {
        String filename = fn;
        if (!filename.endsWith(".class")) {
            filename = filename + ".class";
        }
        logger.log(BasicLevel.DEBUG, "Load the class " + filename);
    try {
      File f = new File(src, filename);
            if (!f.exists()) {
                return null;
            }
      FileInputStream fis = new FileInputStream(f);
      ClassReader jclass = new ClassReader(fis);
      fis.close();
      if (remove) {
        f.delete();
      }
      return jclass;
    } catch (IOException e) {
      throw new SpeedoException("Error during loading " + filename, e);
    }
  }

    public GCInfo newGCInfo(String gcn) {
        return new GCInfo(gcn,
                getFirstClass(gcn),
                getSecondClass(gcn),
                getClassToWrite(gcn));
    }
   
  /**
   * Saves the new bytecode of the specified Java class under a specified base
   * directory.
   *
   * @param jclass the Java class that has to be saved
   * @exception SpeedoException if the file cannot be written
   */
  protected void writeJavaClass(final String fn,
      final ClassWriter jclass)
  throws SpeedoException {
        String filename = fn;
        if (!filename.endsWith(".class")) {
            filename = filename + ".class";
        }
        logger.log(BasicLevel.DEBUG, "Write the class " + filename);
    try {
      File outputFile = new File(src, filename);
            if (!outputFile.getParentFile().exists()) {
                outputFile.getParentFile().mkdirs();
            }
      outputFile.createNewFile();
      FileOutputStream fos = new FileOutputStream(outputFile);
      fos.write(jclass.toByteArray());
      fos.close();
    } catch (IOException e) {
      throw new SpeedoException("Cannot write " + filename, e);
    }
  }
}
TOP

Related Classes of org.objectweb.speedo.genclass.merger.GenClassMerger

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.