Java tutorial
/** * Copyright (c) 2006-2011 Floggy Open Source Group. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.floggy.persistence; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Vector; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import javassist.CtMethod; import javassist.CtNewMethod; import javassist.Modifier; import javassist.NotFoundException; import javassist.bytecode.AccessFlag; import javassist.bytecode.ClassFile; import javassist.bytecode.CodeAttribute; import javassist.bytecode.CodeIterator; import javassist.bytecode.ConstPool; import javassist.bytecode.MethodInfo; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import net.sourceforge.floggy.persistence.codegen.CodeGenerator; import net.sourceforge.floggy.persistence.codegen.strategy.JoinedStrategyCodeGenerator; import net.sourceforge.floggy.persistence.codegen.strategy.PerClassStrategyCodeGenerator; import net.sourceforge.floggy.persistence.codegen.strategy.SingleStrategyCodeGenerator; import net.sourceforge.floggy.persistence.impl.IndexMetadata; import net.sourceforge.floggy.persistence.impl.PersistableMetadata; import net.sourceforge.floggy.persistence.impl.PersistableMetadataManager; import net.sourceforge.floggy.persistence.impl.Utils; import net.sourceforge.floggy.persistence.pool.InputPool; import net.sourceforge.floggy.persistence.pool.OutputPool; import net.sourceforge.floggy.persistence.pool.PoolFactory; import net.sourceforge.floggy.persistence.strategy.PerClassStrategy; import net.sourceforge.floggy.persistence.strategy.SingleStrategy; import net.sourceforge.floggy.persistence.xstream.PersistableStrategyConverter; /** * DOCUMENT ME! * * @author <a href="mailto:thiago.moreira@floggy.org">Thiago Moreira</a> * @version $Revision$ */ public class Weaver { private static final Log LOG = LogFactory.getLog(Weaver.class); public static final String __PERSISTABLE_CLASSNAME = "net.sourceforge.floggy.persistence.impl.__Persistable"; public static final String PERSISTABLE_CLASSNAME = "net.sourceforge.floggy.persistence.Persistable"; /** * DOCUMENT ME! */ protected ClassPool classpathPool; /** * DOCUMENT ME! */ protected Configuration configuration = new Configuration(); /** * DOCUMENT ME! */ protected File configurationFile; /** * DOCUMENT ME! */ protected InputPool inputPool; /** * DOCUMENT ME! */ protected OutputPool embeddedClassesOutputPool; /** * DOCUMENT ME! */ protected OutputPool outputPool; /** * DOCUMENT ME! */ protected Set alreadyProcessedMetadatas = new HashSet(); /** * DOCUMENT ME! */ protected boolean invocationOfShutdownMethodFound = false; /** * Creates a new instance * * @param args */ public Weaver() { this(new ClassPool()); } /** * Creates a new instance * * @param args */ public Weaver(ClassPool classPool) { this.classpathPool = classPool; } /** * DOCUMENT ME! * * @param ctClass DOCUMENT ME! * * @return DOCUMENT ME! * * @throws NotFoundException DOCUMENT ME! */ public PersistableMetadata createPersistableMetadata(CtClass ctClass) throws NotFoundException { CtClass singleRecordStoreStrategy = classpathPool.get(SingleStrategy.class.getName()); CtClass recordStorePerClassStrategy = classpathPool.get(PerClassStrategy.class.getName()); int persistableStrategy = PersistableMetadata.JOINED_STRATEGY; if (ctClass.subtypeOf(singleRecordStoreStrategy)) { persistableStrategy = PersistableMetadata.SINGLE_STRATEGY; } else if (ctClass.subtypeOf(recordStorePerClassStrategy)) { persistableStrategy = PersistableMetadata.PER_CLASS_STRATEGY; } String className = ctClass.getName(); String superClassName = null; ClassVerifier superClassVerifier = new ClassVerifier(ctClass.getSuperclass(), classpathPool); if (superClassVerifier.isPersistable()) { superClassName = ctClass.getSuperclass().getName(); } CtField[] fields = ctClass.getDeclaredFields(); if (persistableStrategy != PersistableMetadata.JOINED_STRATEGY) { fields = ctClass.getFields(); } List fieldNames = new ArrayList(fields.length); List fieldTypes = new ArrayList(fields.length); Hashtable persistableImplementations = null; Vector indexMetadatas = null; for (int i = 0; i < fields.length; i++) { CtField field = (CtField) fields[i]; if (ignoreField(field)) { continue; } fieldNames.add(field.getName()); Integer type = buildFloggyFieldType(field.getType()); fieldTypes.add(type); if ((type.intValue() & PersistableMetadata.PERSISTABLE) == PersistableMetadata.PERSISTABLE) { if (persistableImplementations == null) { persistableImplementations = new Hashtable(); } persistableImplementations.put(field.getName(), field.getType().getName()); } } int[] temp = new int[fieldTypes.size()]; for (int i = 0; i < fieldTypes.size(); i++) { temp[i] = ((Integer) fieldTypes.get(i)).intValue(); } String recordStoreName = ctClass.getSimpleName() + className.hashCode(); if (persistableStrategy == PersistableMetadata.SINGLE_STRATEGY) { String tempSuperClassName = superClassName; PersistableMetadata oldSuperMetadata = null; while (tempSuperClassName != null) { PersistableMetadata superMetadata = configuration.getPersistableMetadata(tempSuperClassName); if (superMetadata != null) { oldSuperMetadata = superMetadata; tempSuperClassName = oldSuperMetadata.getSuperClassName(); } else { tempSuperClassName = null; } } if (oldSuperMetadata != null) { recordStoreName = oldSuperMetadata.getRecordStoreName(); } } if (recordStoreName.length() > 32) { LOG.warn("The recordStore name " + recordStoreName + " is bigger than 32 characters. It will be truncated to " + recordStoreName.substring(0, 32)); recordStoreName = recordStoreName.substring(0, 32); } PersistableMetadata metadata = new PersistableMetadata(Modifier.isAbstract(ctClass.getModifiers()), className, superClassName, (String[]) fieldNames.toArray(new String[fieldNames.size()]), temp, persistableImplementations, indexMetadatas, recordStoreName, persistableStrategy, null); return metadata; } /** * DOCUMENT ME! * * @throws WeaverException DOCUMENT ME! */ public void execute() throws WeaverException { long time = System.currentTimeMillis(); LOG.info("Floggy Persistence Weaver - " + PersistableMetadataManager.getBytecodeVersion()); LOG.info("CLDC version: " + ((isCLDC10()) ? "1.0" : "1.1")); try { URL fileURL = getClass() .getResource("/net/sourceforge/floggy/persistence/impl/PersistableMetadataManager.class"); classpathPool.makeClass(fileURL.openStream()); embeddedUnderlineCoreClasses(); adaptFrameworkToTargetCLDC(); List list = getClassThatImplementsPersistable(); excludeAbstractDescendents(); readConfiguration(); int classCount = list.size(); LOG.info("Processing " + classCount + " bytecodes!"); for (int i = 0; i < classCount; i++) { String className = (String) list.get(i); CtClass ctClass = this.classpathPool.get(className); LOG.info("Processing bytecode " + className + "!"); PersistableMetadata metadata = configuration.getPersistableMetadata(className); CodeGenerator codeGenerator = null; switch (metadata.getPersistableStrategy()) { case PersistableMetadata.SINGLE_STRATEGY: codeGenerator = new SingleStrategyCodeGenerator(ctClass, classpathPool, configuration); break; case PersistableMetadata.PER_CLASS_STRATEGY: codeGenerator = new PerClassStrategyCodeGenerator(ctClass, classpathPool, configuration); break; case PersistableMetadata.JOINED_STRATEGY: codeGenerator = new JoinedStrategyCodeGenerator(ctClass, classpathPool, configuration); break; } codeGenerator.generateCode(); if (configuration.isGenerateSource()) { byte[] source = codeGenerator.getSource().getBytes(); String fileName = className.replace('.', File.separatorChar) + ".txt"; outputPool.addResource(new ByteArrayInputStream(source), fileName); } this.outputPool.addClass(ctClass); if (LOG.isDebugEnabled()) LOG.debug("Bytecode modified."); } addPersistableMetadataManagerClass(); if (embeddedClassesOutputPool != outputPool) { embeddedClassesOutputPool.finish(); } outputPool.finish(); if (!invocationOfShutdownMethodFound) { LOG.warn( "-------------------------------------------------------------------------------------------------------------------"); LOG.warn( "The PersistableManager.shutdown() method is not being called. Please call it from MIDlet.destroyApp(boolean) method"); LOG.warn( "-------------------------------------------------------------------------------------------------------------------"); } } catch (Exception e) { LOG.error(e.getMessage(), e); throw new WeaverException(e.getMessage(), e); } time = System.currentTimeMillis() - time; LOG.info("Time elapsed: " + time + "ms"); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public XStream getXStream() { XStream stream = new XStream(new DomDriver()); stream.alias("floggy", Configuration.class); stream.useAttributeFor(Configuration.class, "generateSource"); stream.aliasAttribute("generate-source", "generateSource"); stream.useAttributeFor(Configuration.class, "addDefaultConstructor"); stream.aliasAttribute("add-default-constructor", "addDefaultConstructor"); stream.aliasType("persistables", ArrayList.class); stream.alias("persistable", PersistableMetadata.class); stream.omitField(PersistableMetadata.class, "isAbstract"); stream.omitField(PersistableMetadata.class, "fieldTypes"); stream.omitField(PersistableMetadata.class, "fieldNames"); stream.omitField(PersistableMetadata.class, "persistableImplementations"); stream.omitField(PersistableMetadata.class, "persistableStrategy"); stream.omitField(PersistableMetadata.class, "superClassName"); stream.omitField(PersistableMetadata.class, "recordId"); stream.aliasField("indexes", PersistableMetadata.class, "indexMetadatas"); stream.aliasField("persistable-strategy", PersistableMetadata.class, "persistableStrategy"); stream.registerLocalConverter(PersistableMetadata.class, "persistableStrategy", new PersistableStrategyConverter()); stream.useAttributeFor(PersistableMetadata.class, "className"); stream.aliasAttribute("class-name", "className"); stream.useAttributeFor(PersistableMetadata.class, "recordStoreName"); stream.aliasAttribute("record-store-name", "recordStoreName"); stream.useAttributeFor(PersistableMetadata.class, "suiteName"); stream.aliasAttribute("suite-name", "suiteName"); stream.useAttributeFor(PersistableMetadata.class, "vendorName"); stream.aliasAttribute("vendor-name", "vendorName"); stream.aliasType("indexes", Vector.class); stream.alias("index", IndexMetadata.class); stream.alias("field", String.class); stream.useAttributeFor(IndexMetadata.class, "name"); stream.aliasField("record-store-name", IndexMetadata.class, "recordStoreName"); stream.addImplicitCollection(IndexMetadata.class, "fields"); return stream; } /** * DOCUMENT ME! * * @param c1 DOCUMENT ME! * @param c2 DOCUMENT ME! * * @throws FloggyException DOCUMENT ME! */ public void mergeConfigurations(Configuration c1, Configuration c2) throws FloggyException { c1.setAddDefaultConstructor(c2.isAddDefaultConstructor()); c1.setGenerateSource(c2.isGenerateSource()); Iterator iterator = c2.getPersistableMetadatas().iterator(); while (iterator.hasNext()) { PersistableMetadata tempMetadata = (PersistableMetadata) iterator.next(); String className = tempMetadata.getClassName(); String suiteName = tempMetadata.getSuiteName(); String vendorName = tempMetadata.getVendorName(); PersistableMetadata currentMetadata = c1.getPersistableMetadata(className); if (((suiteName == null) && (vendorName != null)) || ((suiteName != null) && (vendorName == null))) { throw new FloggyException( "You must provide suite-name and vendor-name for persistable " + className); } if (currentMetadata != null) { String recordStoreName = tempMetadata.getRecordStoreName(); if (!Utils.isEmpty(recordStoreName)) { currentMetadata.setRecordStoreName(recordStoreName.trim()); } int persistableStrategy = tempMetadata.getPersistableStrategy(); if (persistableStrategy > 0) { currentMetadata.setPersistableStrategy(persistableStrategy); } Vector indexMetadatas = tempMetadata.getIndexMetadatas(); if (indexMetadatas != null) { int size = indexMetadatas.size(); for (int i = 0; i < size; i++) { IndexMetadata indexMetadata = (IndexMetadata) indexMetadatas.get(i); int hashCode = Math.abs(className.hashCode()); recordStoreName = "Index" + hashCode + indexMetadata.getName(); indexMetadata.setRecordStoreName(recordStoreName); Vector fields = indexMetadata.getFields(); for (int j = 0; j < fields.size(); j++) { String fieldName = (String) fields.get(j); if (!containsField(className, fieldName)) { throw new FloggyException("The field " + fieldName + " that compounds the index " + indexMetadata.getName() + " does not exist on persistable " + className); } else if (!isIndexableField(className, fieldName)) { throw new FloggyException("The field " + fieldName + " that compounds the index " + indexMetadata.getName() + " on persistable " + className + " it is not from a valid type"); } } } currentMetadata.setIndexMetadatas(indexMetadatas); } } } } /** * Sets the classpath. * * @param classpath DOCUMENT ME! */ public void setClasspath(String[] classpath) { if ((classpath != null) && (classpath.length > 0)) { for (int i = classpath.length - 1; i >= 0; i--) { try { this.classpathPool.insertClassPath(classpath[i]); } catch (NotFoundException e) { } } } } /** * DOCUMENT ME! * * @param configuration DOCUMENT ME! */ public void setConfiguration(Configuration configuration) { this.configuration = configuration; } /** * DOCUMENT ME! * * @param configurationFile DOCUMENT ME! */ public void setConfigurationFile(File configurationFile) { this.configurationFile = configurationFile; } /** * DOCUMENT ME! * * @param embeddedClassesOutputFile DOCUMENT ME! * * @throws WeaverException DOCUMENT ME! */ public void setEmbeddedClassesOutputPool(File embeddedClassesOutputFile) throws WeaverException { embeddedClassesOutputPool = PoolFactory.createOutputPool(embeddedClassesOutputFile); } /** * Sets the input file. * * @param inputFile DOCUMENT ME! * * @throws WeaverException DOCUMENT ME! */ public void setInputFile(File inputFile) throws WeaverException { this.inputPool = PoolFactory.createInputPool(inputFile); try { this.classpathPool.insertClassPath(inputFile.getCanonicalPath()); } catch (NotFoundException e) { } catch (IOException e) { } } /** * Sets the output file. * * @param outputFile * * @throws WeaverException DOCUMENT ME! */ public void setOutputFile(File outputFile) throws WeaverException { outputPool = PoolFactory.createOutputPool(outputFile); if (embeddedClassesOutputPool == null) { embeddedClassesOutputPool = outputPool; } } /** * DOCUMENT ME! * * @throws IOException DOCUMENT ME! * @throws CannotCompileException DOCUMENT ME! * @throws NotFoundException DOCUMENT ME! */ protected void adaptFrameworkToTargetCLDC() throws IOException, CannotCompileException, NotFoundException { URL fileURL = getClass().getResource("/net/sourceforge/floggy/persistence/impl/SerializationManager.class"); classpathPool.makeClass(fileURL.openStream()); CtClass ctClass = this.classpathPool.get("net.sourceforge.floggy.persistence.impl.SerializationManager"); if (isCLDC10()) { CtMethod[] methods = ctClass.getMethods(); for (int i = 0; i < methods.length; i++) { String methodName = methods[i].getName(); if ((methodName.indexOf("Float") != -1) || (methodName.indexOf("Double") != -1) || "readObject".equals(methodName) || "writeObject".equals(methodName)) { ctClass.removeMethod(methods[i]); } } for (int i = 0; i < methods.length; i++) { String methodName = methods[i].getName(); if ("readObjectCLDC10".equals(methodName)) { methods[i].setName("readObject"); } if ("writeObjectCLDC10".equals(methodName)) { methods[i].setName("writeObject"); } } } else { CtMethod[] methods = ctClass.getMethods(); for (int i = 0; i < methods.length; i++) { String methodName = methods[i].getName(); if (methodName.indexOf("CLDC10") != -1) { ctClass.removeMethod(methods[i]); } } } embeddedClassesOutputPool.addClass(ctClass); fileURL = getClass() .getResource("/net/sourceforge/floggy/persistence/impl/migration/AbstractEnumerationImpl.class"); classpathPool.makeClass(fileURL.openStream()); ctClass = this.classpathPool .get("net.sourceforge.floggy.persistence.impl.migration.AbstractEnumerationImpl"); if (isCLDC10()) { CtMethod[] methods = ctClass.getMethods(); for (int i = 0; i < methods.length; i++) { String methodName = methods[i].getName(); if ((methodName.indexOf("Float") != -1) || (methodName.indexOf("Double") != -1) || "createArray".equals(methodName) || "readArray".equals(methodName) || "readObject".equals(methodName) || "readPrimitive".equals(methodName)) { ctClass.removeMethod(methods[i]); } } for (int i = 0; i < methods.length; i++) { String methodName = methods[i].getName(); if ("createArrayCLDC10".equals(methodName)) { methods[i].setName("createArray"); } if ("readArrayCLDC10".equals(methodName)) { methods[i].setName("readArray"); } if ("readObjectCLDC10".equals(methodName)) { methods[i].setName("readObject"); } if ("readPrimitiveCLDC10".equals(methodName)) { methods[i].setName("readPrimitive"); } } } else { CtMethod[] methods = ctClass.getMethods(); for (int i = 0; i < methods.length; i++) { String methodName = methods[i].getName(); if (methodName.indexOf("CLDC10") != -1) { ctClass.removeMethod(methods[i]); } } } embeddedClassesOutputPool.addClass(ctClass); } /** * DOCUMENT ME! * * @throws CannotCompileException DOCUMENT ME! * @throws IOException DOCUMENT ME! * @throws NotFoundException DOCUMENT ME! */ protected void addPersistableMetadataManagerClass() throws CannotCompileException, IOException, NotFoundException { alreadyProcessedMetadatas.addAll(configuration.getPersistableMetadatas()); Set metadatas = alreadyProcessedMetadatas; StringBuffer buffer = new StringBuffer(); buffer.append("public static void init() throws Exception {\n"); buffer.append("rmsBasedMetadatas = new java.util.Hashtable();\n"); buffer.append("classBasedMetadatas = new java.util.Hashtable();\n"); buffer.append("java.util.Hashtable persistableImplementations = null;\n"); buffer.append("java.util.Vector indexMetadatas = null;\n"); buffer.append("java.util.Vector fields = null;\n"); for (Iterator iterator = metadatas.iterator(); iterator.hasNext();) { PersistableMetadata metadata = (PersistableMetadata) iterator.next(); boolean isAbstract = metadata.isAbstract(); String className = metadata.getClassName(); String superClassName = metadata.getSuperClassName(); String[] fieldNames = metadata.getFieldNames(); int[] fieldTypes = metadata.getFieldTypes(); Hashtable persistableImplementations = metadata.getPersistableImplementations(); String recordStoreName = metadata.getRecordStoreName(); int persistableStrategy = metadata.getPersistableStrategy(); Vector indexMetadatas = metadata.getIndexMetadatas(); String[] descendents = metadata.getDescendents(); StringBuffer fieldNamesBuffer = new StringBuffer("new String["); StringBuffer fieldTypesBuffer = new StringBuffer("new int["); boolean addHeader = true; for (int i = 0; i < fieldNames.length; i++) { if (addHeader) { fieldNamesBuffer.append("]{"); fieldTypesBuffer.append("]{"); addHeader = false; } fieldNamesBuffer.append("\""); fieldNamesBuffer.append(fieldNames[i]); fieldNamesBuffer.append("\","); fieldTypesBuffer.append(fieldTypes[i]); fieldTypesBuffer.append(","); } if (addHeader) { fieldNamesBuffer.append("0]"); fieldTypesBuffer.append("0]"); } else { fieldNamesBuffer.deleteCharAt(fieldNamesBuffer.length() - 1); fieldNamesBuffer.append("}"); fieldTypesBuffer.deleteCharAt(fieldTypesBuffer.length() - 1); fieldTypesBuffer.append("}"); } if ((persistableImplementations != null) && !persistableImplementations.isEmpty()) { buffer.append("persistableImplementations = new java.util.Hashtable();\n"); Enumeration enumeration = persistableImplementations.keys(); while (enumeration.hasMoreElements()) { String fieldName = (String) enumeration.nextElement(); String classNameOfField = (String) persistableImplementations.get(fieldName); buffer.append("persistableImplementations.put(\""); buffer.append(fieldName); buffer.append("\", \""); buffer.append(classNameOfField); buffer.append("\");\n"); } } else { buffer.append("persistableImplementations = null;\n"); } if ((indexMetadatas != null) && !indexMetadatas.isEmpty()) { buffer.append("indexMetadatas = new java.util.Vector();\n"); Enumeration enumeration = indexMetadatas.elements(); while (enumeration.hasMoreElements()) { IndexMetadata indexMetadata = (IndexMetadata) enumeration.nextElement(); buffer.append("fields = new java.util.Vector();\n"); Vector fields = indexMetadata.getFields(); for (int j = 0; j < fields.size(); j++) { buffer.append("fields.addElement(\""); buffer.append(fields.elementAt(j)); buffer.append("\");\n"); } buffer.append( "indexMetadatas.addElement(new net.sourceforge.floggy.persistence.impl.IndexMetadata(\""); buffer.append(indexMetadata.getRecordStoreName()); buffer.append("\", \""); buffer.append(indexMetadata.getName()); buffer.append("\", fields));\n"); } } else { buffer.append("indexMetadatas = null;\n"); } StringBuffer descendentsBuffer = new StringBuffer("new String["); addHeader = true; if (descendents != null) { for (int i = 0; i < descendents.length; i++) { if (addHeader) { descendentsBuffer.append("]{"); addHeader = false; } descendentsBuffer.append("\""); descendentsBuffer.append(descendents[i]); descendentsBuffer.append("\","); } } if (addHeader) { descendentsBuffer.append("0]"); } else { descendentsBuffer.deleteCharAt(descendentsBuffer.length() - 1); descendentsBuffer.append("}"); } buffer.append("classBasedMetadatas.put(\"" + className + "\", new net.sourceforge.floggy.persistence.impl.PersistableMetadata(" + isAbstract + ", \"" + className + "\", " + ((superClassName != null) ? ("\"" + superClassName + "\", ") : ("null, ")) + fieldNamesBuffer.toString() + ", " + fieldTypesBuffer.toString() + ", persistableImplementations, indexMetadatas, " + "\"" + recordStoreName + "\", " + persistableStrategy + ", " + descendentsBuffer.toString() + "));\n"); } buffer.append("load();\n"); buffer.append("}\n"); CtClass ctClass = this.classpathPool .get("net.sourceforge.floggy.persistence.impl.PersistableMetadataManager"); CtMethod[] methods = ctClass.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals("init")) { ctClass.removeMethod(methods[i]); } } ctClass.addMethod(CtNewMethod.make(buffer.toString(), ctClass)); embeddedClassesOutputPool.addClass(ctClass); } /** * DOCUMENT ME! * * @param ctClass DOCUMENT ME! * * @return DOCUMENT ME! * * @throws NotFoundException DOCUMENT ME! */ protected List buildClassTree(CtClass ctClass) throws NotFoundException { final CtClass persistable = classpathPool.get(Weaver.PERSISTABLE_CLASSNAME); List list = new ArrayList(); CtClass superClass = ctClass; String superName = ctClass.getName(); do { list.add(superName); superClass = superClass.getSuperclass(); superName = superClass.getName(); } while (!"java.lang.Object".equals(superName) && superClass.subtypeOf(persistable)); Collections.reverse(list); for (int i = 0; i < list.size(); i++) { String className = (String) list.get(i); PersistableMetadata metadata = configuration.getPersistableMetadata(className); if (metadata == null) { CtClass clazz = classpathPool.get(className); metadata = createPersistableMetadata(clazz); configuration.addPersistableMetadata(metadata); } String[] descendents = metadata.getDescendents(); if (descendents == null) { descendents = new String[0]; } Set temp = new HashSet(Arrays.asList(descendents)); temp.addAll(list.subList(i, list.size())); metadata.setDescendents((String[]) temp.toArray(new String[temp.size()])); } return list; } /** * DOCUMENT ME! * * @param fieldType DOCUMENT ME! * * @return DOCUMENT ME! * * @throws NotFoundException DOCUMENT ME! */ protected Integer buildFloggyFieldType(CtClass fieldType) throws NotFoundException { int floggyFieldType = 0; if (fieldType.isArray()) { fieldType = fieldType.getComponentType(); if (fieldType.isPrimitive()) { floggyFieldType = PersistableMetadata.PRIMITIVE | buildFloggyPrimitiveFieldType(fieldType); } else { floggyFieldType = buildFloggyObjectFieldType(fieldType); } floggyFieldType = floggyFieldType | PersistableMetadata.ARRAY; } else { if (fieldType.isPrimitive()) { floggyFieldType = PersistableMetadata.PRIMITIVE | buildFloggyPrimitiveFieldType(fieldType); } else { floggyFieldType = buildFloggyObjectFieldType(fieldType); } } if (floggyFieldType == 0) { throw new NotFoundException(fieldType.getName()); } return Integer.valueOf(floggyFieldType); } /** * DOCUMENT ME! * * @param fieldType DOCUMENT ME! * * @return DOCUMENT ME! * * @throws NotFoundException DOCUMENT ME! */ protected int buildFloggyObjectFieldType(CtClass fieldType) throws NotFoundException { int floggyFieldType = 0; String typeName = fieldType.getName(); if ("java.lang.Boolean".equals(typeName)) { floggyFieldType = PersistableMetadata.BOOLEAN; } if ("java.lang.Byte".equals(typeName)) { floggyFieldType = PersistableMetadata.BYTE; } if ("java.lang.Character".equals(typeName)) { floggyFieldType = PersistableMetadata.CHARACTER; } if ("java.lang.Double".equals(typeName)) { floggyFieldType = PersistableMetadata.DOUBLE; } if ("java.lang.Float".equals(typeName)) { floggyFieldType = PersistableMetadata.FLOAT; } if ("java.lang.Integer".equals(typeName)) { floggyFieldType = PersistableMetadata.INT; } if ("java.lang.Long".equals(typeName)) { floggyFieldType = PersistableMetadata.LONG; } if ("java.lang.Short".equals(typeName)) { floggyFieldType = PersistableMetadata.SHORT; } if ("java.lang.String".equals(typeName)) { floggyFieldType = PersistableMetadata.STRING; } if ("java.util.Calendar".equals(typeName)) { floggyFieldType = PersistableMetadata.CALENDAR; } if ("java.util.Date".equals(typeName)) { floggyFieldType = PersistableMetadata.DATE; } if ("java.util.Hashtable".equals(typeName)) { floggyFieldType = PersistableMetadata.HASHTABLE; } if (fieldType.subtypeOf(fieldType.getClassPool().get(Weaver.PERSISTABLE_CLASSNAME))) { floggyFieldType = PersistableMetadata.PERSISTABLE; } if ("java.lang.StringBuffer".equals(typeName)) { floggyFieldType = PersistableMetadata.STRINGBUFFER; } if ("java.util.Stack".equals(typeName)) { floggyFieldType = PersistableMetadata.STACK; } if ("java.util.TimeZone".equals(typeName)) { floggyFieldType = PersistableMetadata.TIMEZONE; } if ("java.util.Vector".equals(typeName)) { floggyFieldType = PersistableMetadata.VECTOR; } return floggyFieldType; } /** * DOCUMENT ME! * * @param fieldType DOCUMENT ME! * * @return DOCUMENT ME! */ protected int buildFloggyPrimitiveFieldType(CtClass fieldType) { int floggyFieldType = 0; if (CtClass.booleanType.equals(fieldType)) { floggyFieldType = PersistableMetadata.BOOLEAN; } if (CtClass.byteType.equals(fieldType)) { floggyFieldType = PersistableMetadata.BYTE; } if (CtClass.charType.equals(fieldType)) { floggyFieldType = PersistableMetadata.CHARACTER; } if (CtClass.doubleType.equals(fieldType)) { floggyFieldType = PersistableMetadata.DOUBLE; } if (CtClass.floatType.equals(fieldType)) { floggyFieldType = PersistableMetadata.FLOAT; } if (CtClass.intType.equals(fieldType)) { floggyFieldType = PersistableMetadata.INT; } if (CtClass.longType.equals(fieldType)) { floggyFieldType = PersistableMetadata.LONG; } if (CtClass.shortType.equals(fieldType)) { floggyFieldType = PersistableMetadata.SHORT; } return floggyFieldType; } /** * DOCUMENT ME! * * @param className DOCUMENT ME! * @param fieldName DOCUMENT ME! * * @return DOCUMENT ME! */ protected boolean containsField(String className, String fieldName) { try { CtClass ctClass = classpathPool.get(className); ctClass.getField(fieldName); return true; } catch (NotFoundException e) { return false; } } /** * DOCUMENT ME! * * @param fileName DOCUMENT ME! * * @throws IOException DOCUMENT ME! */ protected void embeddedClass(String fileName) throws IOException { URL fileURL = getClass().getResource(fileName); if (fileURL != null) { fileName = fileName.replace('/', File.separatorChar); embeddedClassesOutputPool.addFile(fileURL, fileName); classpathPool.makeClass(fileURL.openStream()); } } /** * DOCUMENT ME! * * @throws IOException DOCUMENT ME! */ protected void embeddedUnderlineCoreClasses() throws IOException { embeddedClass("/net/sourceforge/floggy/persistence/impl/FloggyOutputStream.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/FloggyProperties$1.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/IndexMetadata.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/IndexManager.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/Index.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/IndexEntry.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/ObjectComparator.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/ObjectSetImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/__Persistable.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/PersistableManagerImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/PersistableMetadata.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/PolymorphicObjectSetImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/PolymorphicObjectSetImpl$ObjectList.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/RecordStoreManager.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/RecordStoreManager$1.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/RecordStoreManager$RecordStoreReference.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/Utils.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/migration/MigrationManagerImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/migration/SingleStrategyEnumerationImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/migration/PerClassStrategyEnumerationImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/migration/JoinedStrategyEnumerationImpl.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/migration/HashtableValueNullable.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/strategy/JoinedStrategyObjectFilter.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/strategy/PerClassStrategyObjectFilter.class"); embeddedClass("/net/sourceforge/floggy/persistence/impl/strategy/SingleStrategyObjectFilter.class"); } /** * DOCUMENT ME! * * @throws NotFoundException DOCUMENT ME! */ protected void excludeAbstractDescendents() throws NotFoundException { List persistables = configuration.getPersistableMetadatas(); for (int i = 0; i < persistables.size(); i++) { PersistableMetadata metadata = (PersistableMetadata) persistables.get(i); String[] temp = metadata.getDescendents(); if (temp != null) { Set descendents = new HashSet(Arrays.asList(temp)); List toRemove = new LinkedList(); Iterator iterator = descendents.iterator(); while (iterator.hasNext()) { String className = (String) iterator.next(); CtClass ctClass = classpathPool.get(className); if (Modifier.isAbstract(ctClass.getModifiers())) { toRemove.add(className); } } if (descendents.removeAll(toRemove)) { metadata.setDescendents((String[]) descendents.toArray(new String[descendents.size()])); } } } } /** * DOCUMENT ME! * * @param ctClass DOCUMENT ME! */ protected void findInvocationOfShutdownMethod(CtClass ctClass) { if (!ctClass.isInterface()) { try { ClassFile classFile = ctClass.getClassFile2(); ConstPool constantPool = classFile.getConstPool(); List methods = classFile.getMethods(); for (Iterator iterator = methods.iterator(); iterator.hasNext();) { MethodInfo method = (MethodInfo) iterator.next(); if ((method.getAccessFlags() & AccessFlag.ABSTRACT) != AccessFlag.ABSTRACT) { CodeAttribute codeAttribute = method.getCodeAttribute(); if (codeAttribute != null) { byte[] code = codeAttribute.getCode(); CodeIterator codeIterator = codeAttribute.iterator(); while (codeIterator.hasNext()) { int index = codeIterator.next(); int opcode = codeIterator.byteAt(index); if (opcode == CodeAttribute.INVOKEVIRTUAL) { int temp = (code[index + 1] << 8) | code[index + 2]; String className = constantPool.getMethodrefClassName(temp); String methodName = constantPool.getMethodrefName(temp); if (PersistableManager.class.getName().equals(className) && "shutdown".equals(methodName)) { invocationOfShutdownMethodFound = true; } } } } } } } catch (Exception ex) { LOG.warn(ex.getMessage(), ex); } } } /** * Returns the class name given a file name. * * @param fileName * * @return */ protected String getClassName(String fileName) { if (fileName.endsWith(".class")) { String className = fileName.replace(File.separatorChar, '.'); return className.substring(0, className.length() - 6); } return null; } /** * DOCUMENT ME! * * @return DOCUMENT ME! * * @throws NotFoundException DOCUMENT ME! * @throws IOException DOCUMENT ME! */ protected List getClassThatImplementsPersistable() throws NotFoundException, IOException { int classCount = this.inputPool.getFileCount(); LOG.info("Look up for classes that implements Persistable!"); List list = new LinkedList(); final CtClass persistable = classpathPool.get(Weaver.PERSISTABLE_CLASSNAME); final CtClass __persistable = classpathPool.get(Weaver.__PERSISTABLE_CLASSNAME); for (int i = 0; i < classCount; i++) { String fileName = this.inputPool.getFileName(i); String className = getClassName(fileName); if (className == null) { this.outputPool.addFile(inputPool.getFileURL(i), fileName); continue; } CtClass ctClass = this.classpathPool.get(className); if (ctClass.subtypeOf(persistable) && !ctClass.subtypeOf(__persistable) && !ctClass.isInterface()) { List tree = buildClassTree(ctClass); for (int j = 0; j < tree.size(); j++) { Object object = tree.get(j); if (!list.contains(object)) { list.add(object); } } } else { LOG.debug("Bytecode NOT modified."); if (ctClass.subtypeOf(__persistable) && !ctClass.equals(__persistable)) { List temp = buildClassTree(ctClass); Iterator iterator = temp.iterator(); while (iterator.hasNext()) { className = (String) iterator.next(); PersistableMetadata metadata = configuration.getPersistableMetadata(className); alreadyProcessedMetadatas.add(metadata); } } findInvocationOfShutdownMethod(ctClass); this.outputPool.addFile(inputPool.getFileURL(i), fileName); } } return list; } /** * DOCUMENT ME! * * @param field DOCUMENT ME! * * @return DOCUMENT ME! */ protected boolean ignoreField(CtField field) { int modifier = field.getModifiers(); return field.getName().equals("__id") || field.getName().equals("__persistableMetadata") || Modifier.isTransient(modifier) || Modifier.isStatic(modifier); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected boolean isCLDC10() { try { CtClass ctClass = classpathPool.get("java.io.DataInput"); ctClass.getMethod("readFloat", "()F"); } catch (NotFoundException nfex) { return true; } return false; } /** * DOCUMENT ME! * * @param className DOCUMENT ME! * @param fieldName DOCUMENT ME! * * @return DOCUMENT ME! */ protected boolean isIndexableField(String className, String fieldName) { try { CtClass ctClass = classpathPool.get(className); CtField field = ctClass.getField(fieldName); CtClass fieldType = field.getType(); String fieldTypeClassName = fieldType.getName(); if ("boolean".equals(fieldTypeClassName) || "byte".equals(fieldTypeClassName) || "char".equals(fieldTypeClassName) || "double".equals(fieldTypeClassName) || "float".equals(fieldTypeClassName) || "int".equals(fieldTypeClassName) || "long".equals(fieldTypeClassName) || "short".equals(fieldTypeClassName) || "java.lang.Boolean".equals(fieldTypeClassName) || "java.lang.Byte".equals(fieldTypeClassName) || "java.lang.Character".equals(fieldTypeClassName) || "java.lang.Double".equals(fieldTypeClassName) || "java.lang.Float".equals(fieldTypeClassName) || "java.lang.Integer".equals(fieldTypeClassName) || "java.lang.Long".equals(fieldTypeClassName) || "java.lang.Short".equals(fieldTypeClassName) || "java.lang.String".equals(fieldTypeClassName) || "java.lang.StringBuffer".equals(fieldTypeClassName) || "java.util.Date".equals(fieldTypeClassName) || "java.util.TimeZone".equals(fieldTypeClassName)) { return true; } else { return false; } } catch (NotFoundException e) { return false; } } /** * DOCUMENT ME! * * @throws FloggyException DOCUMENT ME! * @throws IOException DOCUMENT ME! */ protected void readConfiguration() throws FloggyException, IOException { if ((configurationFile != null) && configurationFile.exists()) { XStream stream = getXStream(); Configuration temp = (Configuration) stream.fromXML(new FileReader(configurationFile)); mergeConfigurations(configuration, temp); } } }