/* Copyright 2004, Carnegie Mellon, All Rights Reserved */ package edu.cmu.minorthird.text; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; /** * AnnotatorLoader which contains locally a list of Annotator * definitions, in the form of a list of class files, and/or mixup * files. */ public class EncapsulatingAnnotatorLoader extends AnnotatorLoader implements Serializable{ static private final long serialVersionUID=20080303L; // special serialization code private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{ System.out.println("Reading EncapsulatingAnnotatorLoader"); in.defaultReadObject(); for(Iterator<String> i=fileNameToContentsMap.keySet().iterator();i .hasNext();){ String fileName=i.next(); if(fileName.endsWith(".class")){ String className= fileName.substring(0,fileName.length()-".class".length()); try{ System.out.println("loading class "+className); myClassLoader.loadClass(className); //ClassLoader.getSystemClassLoader().loadClass(className); }catch(ClassNotFoundException ex){ ex.printStackTrace(); log.warn("error recovering class: "+ex); } } } } static private Logger log= Logger.getLogger(EncapsulatingAnnotatorLoader.class); private Map<String,byte[]> fileNameToContentsMap; private ClassLoader myClassLoader; /** * @param path Filenames, separated by the current value of * File.pathSeparator, which should be "encapsulated". Encapsulated * files should be .mixup files or .class files, which will be read * in when the AnnotatorLoader is created. Their contents will * serialized along with it. When finding annotators (for a * TextLabels object, in a require call) an * EncapsulatingAnnotatorLoader will load these files in preference * to anything on the current classpath. */ public EncapsulatingAnnotatorLoader(String path){ this(true,path); } /** * * @param asFiles if true, elements of the path are file names. If * false, elements of the path should be resources that can be found * with getResourceAsStream(). The 'asFiles=false' option was * mostly provided so that file-system-independent unit tests * could be written. * */ public EncapsulatingAnnotatorLoader(boolean asFiles,String path){ fileNameToContentsMap=new HashMap<String,byte[]>(); String[] fileName=path.split(File.pathSeparator); for(int i=0;i<fileName.length;i++){ try{ File file=new File(fileName[i]); InputStream s=null; if(asFiles){ s=new FileInputStream(file); } else{ s=EncapsulatingAnnotatorLoader.class.getClassLoader().getResourceAsStream(fileName[i]); } byte[] contents=new byte[s.available()]; s.read(contents); fileNameToContentsMap.put(file.getName(),contents); if(file.getName().endsWith(".mixup")){ redirectionProps.put(file.getName().substring(0,file.getName().length()-6),file.getName()); //fileNameToContentsMap.put(file.getName().substring(0,file.getName().length()-6),contents); } }catch(IOException e){ throw new IllegalArgumentException("can't open file '"+fileName[i]+"': "+e); } } myClassLoader=new EncapsulatingClassLoader(); } /** Find the named resource file - usually a dictionary or trie for mixup. */ @Override public InputStream findFileResource(String fileName){ log.info("Looking for file resource: "+fileName); byte[] contents=fileNameToContentsMap.get(fileName); if(contents!=null){ log.info("Encapsulated resource found containing "+contents.length+" bytes"); return new ByteArrayInputStream(contents); }else{ log.info("Calling Java class loader to find resource: "+fileName); return this.getClass().getClassLoader().getResourceAsStream(fileName); } } /** Find the named resource class - usually an annotator. */ @Override public Class<?> findClassResource(String className){ try{ Class<?> clazz=myClassLoader.loadClass(className); return clazz; }catch(ClassNotFoundException e){ return null; } } public class EncapsulatingClassLoader extends ClassLoader implements Serializable{ static private final long serialVersionUID=20080303L; @Override public Class<?> findClass(String className) throws ClassNotFoundException{ log.info("Looking for class "+className+" with encapsulated loader"); byte[] contents=fileNameToContentsMap.get(className+".class"); if(contents!=null){ log.info("Encapsulated class definition found containing "+ contents.length+" bytes"); try{ return defineClass(className,contents,0,contents.length); }catch(NoClassDefFoundError e){ // try again, interpreting the wrong name error message and just name it accordingly Pattern msgPat=Pattern.compile("\\(wrong name\\: (.+?)\\)"); String message=e.getMessage(); Matcher m=msgPat.matcher(message); if(m.find()){ String realClassName=m.group(1).replaceAll("[\\/]+","."); Class<?> clazz=Class.forName(realClassName); return clazz; } else{ return null; } } }else{ log.info("calling default class loader to find class"); //for some reason the EncapsulatingAnnotatorLoader doesn't seem to work; just use Class.forName return Class.forName(className); //return EncapsulatingAnnotatorLoader.class.getClassLoader().loadClass(className+".class"); } } } }