/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2005 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
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S.Chassande-Barrioz.
*
*/
package org.objectweb.speedo.generation.enhancer.pc;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.attrs.Attributes;
import org.objectweb.jorm.lib.PBindingImpl;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.generation.enhancer.common.AbstractEnhancerComponent;
import org.objectweb.speedo.generation.enhancer.common.DuplicatedMethodVerifier;
import org.objectweb.speedo.generation.enhancer.common.InterfaceAgregatorVisitor;
import org.objectweb.speedo.generation.enhancer.common.MergedClassModifier;
import org.objectweb.speedo.generation.enhancer.oid.PNameEnhancer;
import org.objectweb.speedo.generation.enhancer.oid.UserIdEnhancer;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoIdentity;
import org.objectweb.speedo.metadata.SpeedoPackage;
import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Enhances a set of Java classes.
*
* @author S.Chassande-Barrioz
*/
public class PersistentClassEnhancer extends AbstractEnhancerComponent {
public final static String LOGGER_NAME
= SpeedoProperties.LOGGER_NAME + ".generation.enhancer";
int processedClasses;
public PersistentClassEnhancer(Personality p) {
super(p);
}
/**
* Initializes this PersistentClassEnhancer
*/
public boolean init() {
logger = scp.loggerFactory.getLogger(LOGGER_NAME);
//TODO: manage classes located in a jar file
isSrcJar = false;
processedClasses = 0;
return !scp.getXmldescriptor().isEmpty();
}
public String getTitle() {
return "Enhancing Persistent classes...";
}
public String getSummary() {
return processedClasses + " enhanced";
}
/**
* Loads all binary classes described by the Object Model and applies
* revelant modification to each of them.
*/
public void process() throws SpeedoException {
if (scp.getXmldescriptor().isEmpty())
return;
ArrayList except = new ArrayList();
Collection xmls = scp.getXmldescriptor().values();
for (Iterator itDesc = xmls.iterator(); itDesc.hasNext();) {
SpeedoXMLDescriptor desc = (SpeedoXMLDescriptor) itDesc.next();
for (Iterator itPack = desc.packages.values().iterator(); itPack.hasNext();) {
SpeedoPackage sp = (SpeedoPackage) itPack.next();
for (Iterator itclass = sp.classes.values().iterator(); itclass.hasNext();) {
SpeedoClass sc = (SpeedoClass) itclass.next();
Logger log = scp.loggerFactory.getLogger(LOGGER_NAME + '.' + sc.getFQName());
treatPC(sc, log);
treatOID(sc, log);
processedClasses ++;
}
}
}
// Displays thrown exceptions
if (!except.isEmpty() && logger.isLoggable(BasicLevel.WARN)) {
for (Iterator it = except.iterator(); it.hasNext();) {
Exception e = (Exception) it.next();
logger.log(BasicLevel.WARN, e.getLocalizedMessage());
}
}
}
protected ClassVisitor getFirstVisitors(ClassWriter cw,
Logger log,
String classToWrite,
Map ctx) {
ClassVisitor current = new InterfaceAgregatorVisitor(cw, log, classToWrite, personality);
current = new DuplicatedMethodVerifier(current, log, personality);
return current;
}
protected ClassVisitor getParentVisitors(ClassVisitor current,
Logger log,
String classToWrite,
SpeedoClass sc,
Map ctx) {
final String bindingName = PBindingImpl.class.getName();
current = new CacheEntryAdder(current, log, classToWrite, personality);
current = new MergedClassModifier(current, classToWrite, bindingName.replace('.', '/'), log, personality);
return current;
}
protected ClassVisitor getVisitors(ClassVisitor current,
Logger log,
String classToWrite,
SpeedoClass sc,
Map ctx) {
// add the accessor (static and not)
current = new FieldAccessorsAdder(current, log, sc, scp, personality);
// add the PO methods
current = new POAdder(current, log, sc, scp, personality);
// modifies the original code
current = new FieldAccessModifier(current, sc, log, personality);
//Add or modifiy the no arg constructor
current = new NoArgConstructorAdder(current, log, sc.noArgConstructorStatus, personality);
//Remove the persistent fields
current = new FieldRemover(current, sc, log, personality);
return current;
}
/**
* Enhances the .class of a persistent class.
* @param sc is the Speedo meta object representing the persistent
* class
* @param xmls is the
* @param log
* @throws SpeedoException
*/
private void treatPC(final SpeedoClass sc, final Logger log) throws SpeedoException {
final String name = sc.getFQName();
log.log(BasicLevel.DEBUG, "Enahncing the class: " + name);
final String classToWrite = name.replace('.', '/');
final ClassWriter cw = new ClassWriter(true);
Map ctx = new HashMap();
ClassVisitor current = getFirstVisitors(cw, log, classToWrite, ctx);
final ClassVisitor common = current;
if (sc.getSuperClassName() == null) {
log.log(BasicLevel.DEBUG, "Add shared methods (no super class)");
final String bindingName = PBindingImpl.class.getName();
current = common;
current = getParentVisitors(current, log, classToWrite, sc, ctx);
final ClassReader cr = loadJavaClass(false, bindingName, scp.output, true);
//This is not the last branch of the visitor tree. So the visitor
// regAdder register only the static area only
cr.accept(current, Attributes.getDefaultAttributes(), false);
}
current = common;
current = getVisitors(current, log, classToWrite, sc, ctx);
//Read the original code
ClassReader cr = loadJavaClass(false, name, scp.output, false);
cr.accept(current, Attributes.getDefaultAttributes(), false);
//write the .class file
writeJavaClass(name, cw, scp.output);
}
/**
* It enhances the userid class and the XXXPName class in case of the
* ideentifier of the persistent class are based on a user objectid class.
* @param sc is the Speedo meta object of the persistent class
*/
private void treatOID(final SpeedoClass sc, final Logger log) throws SpeedoException {
if (sc.getIdentityType() == SpeedoIdentity.USER_ID
&& sc.identity.objectidClass != null
&& !sc.identity.oidClassAutoCalculated
&& (sc.getSuperClassName() == null //I have not a parent
|| !sc.identity.objectidClass.equals(sc.getSuper().identity.objectidClass)) ) {
ClassWriter cw;
ClassVisitor current;
//Modifies the User id class
cw = new ClassWriter(true);
current = new UserIdEnhancer(cw, sc, log, personality);
String cn = sc.identity.objectidClass;
ClassReader cr = loadJavaClass(false, cn, scp.output, true);
cr.accept(current, Attributes.getDefaultAttributes(), false);
writeJavaClass(cn, cw, scp.output);
//Modify the generated XXXPName class (by JORM)
cw = new ClassWriter(false);
cn = NamingRules.pnameName(sc.identity.objectidClass);
cr = loadJavaClass(false, cn, scp.output, true);
current = new PNameEnhancer(cw, sc, log, personality);
cr.accept(current, Attributes.getDefaultAttributes(), false);
writeJavaClass(cn, cw, scp.output);
}
}
}