Package gov.nasa.jpf.conformanceChecker.providers

Source Code of gov.nasa.jpf.conformanceChecker.providers.ModelClassProvider

//
// Copyright (C) 2012 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA).  All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3.  The NOSA has been approved by the Open Source
// Initiative.  See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.conformanceChecker.providers;

import gov.nasa.jpf.Config;
import gov.nasa.jpf.JPF;
import gov.nasa.jpf.classfile.ClassFile;
import gov.nasa.jpf.classfile.ClassFileException;
import gov.nasa.jpf.jvm.ClassInfo;
import gov.nasa.jpf.jvm.JVM;
import gov.nasa.jpf.util.MethodSpec;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Random;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;

/**
* The purpose of this class is similar to {@link StandardClassProvider}
* but instead of the standard version of the class it loads
* the model one.
*
* Properties used from jpf config file:
*
*   - conformance-checker.modelPaths
*  
* that specifies a ':' separated list of the directories/jars
* that build up the set of model classes
*
* The directories specified _must_ be roots of package hierarchies.
*
* @author Matteo Ceccarello <matteo.ceccarello AT gmail.com>
*
*/
public class ModelClassProvider {
 
  static {
    // FIXME the hack used to avoid null pointers
    if(JVM.getVM() == null)
      new JVM(null, new Config(new String[0]));
  }
 
  private static Logger logger = JPF.getLogger(ModelClassProvider.class.getName());
 
  public static final char[] delims = {':', ','};
  public static final String MODEL_PATHS_PROP = "conformance-checker.modelPaths";
 
  /* To generate random IDs for classes */
  private Random rnd = new Random();
 
  File[] files;
 
  public ModelClassProvider() {
    this(new Config(new String[]{}));
  }
 
  public ModelClassProvider(Config config) {
    String[] fileNames = config.getStringArray(MODEL_PATHS_PROP, delims);
    if (fileNames != null) {
      files = new File[fileNames.length];
      for (int i = 0; i < fileNames.length; i++) {
        files[i] = new File(fileNames[i]);
      }
    } else {
      files = new File[0];
      logger.severe("No path to model classes specified in jpf configuration file.\n" +
          "No comparison will be made.\n" +
          "Please specify a model class path with the property " + MODEL_PATHS_PROP);
    }
  }
 
  /**
   * Returns a list of all {@link ClassInfo} objects retrieved from the jar
   * files and directories specified in the configuration file via the
   * property {@value #MODEL_PATHS_PROP}.
   *
   * @return a {@link Iterable} of all {@link ClassInfo}s of the model.
   */
  public Iterable<ClassInfo> loadClassInfos() {
    return loadClassInfos(new LinkedList<MethodSpec>());
  }
 
  /**
   * Returns a list of {@link ClassInfo} objects retrieved from the jar
   * files and directories specified in the configuration file via the
   * property {@value #MODEL_PATHS_PROP}. Only the classes matching
   * one of the given {@link MethodSpec}s are loaded
   *
   * @return a {@link Iterable} of all {@link ClassInfo}s of the model.
   */
  public Iterable<ClassInfo> loadClassInfos(Collection<MethodSpec> specs) {
   
    LinkedList<ClassInfo> classInfos = new LinkedList<ClassInfo>();
    for (File f : files) {
      if (f.isFile() && f.getName().endsWith(".jar")) {
        classInfos.addAll(loadClassInfosFromJar(f, specs));
      } else if (f.isDirectory()) {
        classInfos.addAll(loadClassInfosFromDir(f, specs));
      }
    }
    return classInfos;
  }

  Collection<ClassInfo> loadClassInfosFromDir(File f, Collection<MethodSpec> specs) {   
    return retrieveClassInfos(f, "", specs);
  }
 
  Collection<ClassInfo> retrieveClassInfos(File f, String baseName, Collection<MethodSpec> specs) {
    LinkedList<ClassInfo> classInfos = new LinkedList<ClassInfo>();
    String fileName = f.getName();
      if(f.isFile() && fileName.endsWith(".class")) {
        try {
          // to avoid things like .ClassName for classes in the default package
          String name = (!"".equals(baseName))? baseName + "." : "";
          name += fileName.substring(fileName.lastIndexOf('.'));
          byte[] classBytes = Util.getClassBytes(new FileInputStream(f));
          ClassFile cf = new ClassFile(name, classBytes);
          ClassInfo ci = new UnregisteredClassInfo(cf);
          // FIXME it would be better to be able to perform this check earlier
          if(matchesSpecs(ci.getName(), specs)) {
            classInfos.add(ci);
          }
        } catch (FileNotFoundException e) {
          logger.warning("file " + f + " does not exist");
        } catch (IOException e) {
          logger.warning("error reading file " + f + "\n" + e.getMessage());
        } catch (ClassFileException e) {
          logger.warning(e.getMessage() + "\n" + e.getStackTrace());
        }
      } else if(f.isDirectory()) {
        String name = (!"".equals(baseName))? baseName + "." : "";
        name += fileName;
        for(File content : f.listFiles()) {
          classInfos.addAll(retrieveClassInfos(content, name, specs));
        }
      }
    return classInfos;
  }
 
  static boolean matchesSpecs(String name, Collection<MethodSpec> specs) {
    if(specs.size() == 0)
      return true;
    for (MethodSpec spec : specs) {
      if(spec.matchesClass(name))
        return true;
    }
    return false;
  }

  Collection<ClassInfo> loadClassInfosFromJar(File f, Collection<MethodSpec> specs) {
    LinkedList<ClassInfo> classInfos = new LinkedList<ClassInfo>();
    try {
      JarFile jar = new JarFile(f);
      Enumeration<JarEntry> entries = jar.entries();
      while(entries.hasMoreElements()) {
        JarEntry entry = entries.nextElement();
        String name = entry.getName();
        if(name.endsWith(".class")) {
          // FIXME: check if on Windows the file separator inside jar files
          // is / or \
          name = name.substring(0, name.lastIndexOf('.')).replace('/', '.');
          if(matchesSpecs(name, specs)) {
            byte[] classBytes = Util.getClassBytes(jar.getInputStream(entry));
            ClassFile cf = new ClassFile(name, classBytes);
            classInfos.add(new UnregisteredClassInfo(cf));
          }
        }
      }
    } catch (IOException e) {
      logger.warning("error while loading classes from " + f +
          "\n" + e.getMessage());
    } catch (ClassFileException e) {
      logger.warning("error while loading class from " + f +
          "\n" + e.getMessage());
    }
    return classInfos;
  }

  /**
   * Loads a specified {@link ClassInfo} from the jars and directories
   * specified in the configuration file with the {@value #MODEL_PATHS_PROP}
   * property
   *
   * @param className the desired class
   * @return the {@link ClassInfo} object for the desired class.
   */
  public ClassInfo loadClassInfo(String className) {
    ClassInfo ci = null;
    for (File f : files) {
      if (f.isFile() && f.getName().endsWith(".jar")) {
        ci = loadFromJar(f, className);
      } else if (f.isDirectory()) {
        ci = loadFromDir(f, className);
      }
      if (ci != null)
        return ci;
    }
    return null;
  }

  /**
   * Loads from a directory tree the specified class
   * returns null of the class is not found
   */
  ClassInfo loadFromDir(File f, String className) {
    String[] fileNames = className.split("\\.");
    fileNames[fileNames.length-1] += ".class";
    File file = getFile(f, 0, fileNames);
    if(file != null) {
      try {
        byte[] data = Util.getClassBytes(new FileInputStream(file));
        ClassFile cf = new ClassFile(className, data);
//        return new UnregisteredClassInfo(cf);
        return new ClassInfo(cf, rnd.nextInt(1000));
      } catch (FileNotFoundException e) {
        logger.warning(e.getMessage());
      } catch (IOException e) {
        logger.warning(e.getMessage());
      } catch (ClassFileException e) {
        logger.warning(e.getMessage());
      }
    }
    return null;
  }
 
  File getFile(File f, int i, String[] names) {
    for(File content : f.listFiles()) {
      if(content.getName().equals(names[i])) {
        if (i == names.length-1)
          return content;
        return getFile(content, i+1, names);
      }
    }
    return null;
  }

  /**
   * Loads from the given jar the requested class.
   * Returns null if the class is not found
   */
  ClassInfo loadFromJar(File f, String className) {
    // FIXME: check if on Windows the file separator inside jar files
    // is / or \
    String fileName = className.replace('.', '/') + ".class";
    try {
      JarFile jar = new JarFile(f);
      JarEntry entry = jar.getJarEntry(fileName);
      if (entry != null) {
        byte[] classBytes = Util.getClassBytes(jar.getInputStream(entry));
        ClassFile cf = new ClassFile(className, classBytes);
        return new UnregisteredClassInfo(cf);
      }
    } catch (IOException e) {
      logger.warning("error while loading class " + className +
          " from jar file " + f + "\n" + e.getMessage());
      return null;
    } catch (ClassFileException e) {
      logger.warning("error while loading class " + className +
          " from jar file " + f + "\n" + e.getMessage());
      return null;
    }
    return null;
  }
 
  public static void main(String[] args) {
    ModelClassProvider mcp = new ModelClassProvider();
    ClassInfo ci = mcp.loadClassInfo("gov.nasa.jpf.jvm.AtomicFieldUpdater");
    System.out.println(ci);
    System.out.println(mcp.loadClassInfos());
  }
 
}
TOP

Related Classes of gov.nasa.jpf.conformanceChecker.providers.ModelClassProvider

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.