001: /**
002: * Speedo: an implementation of JDO compliant personality on top of JORM generic
003: * I/O sub-system.
004: * Copyright (C) 2001-2005 France Telecom R&D
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: *
021: *
022: * Contact: speedo@objectweb.org
023: *
024: * Authors: S.Chassande-Barrioz.
025: *
026: */package org.objectweb.speedo.generation.enhancer.pc;
027:
028: import org.objectweb.asm.ClassReader;
029: import org.objectweb.asm.ClassVisitor;
030: import org.objectweb.asm.ClassWriter;
031: import org.objectweb.asm.attrs.Attributes;
032: import org.objectweb.jorm.lib.PBindingImpl;
033: import org.objectweb.speedo.api.SpeedoException;
034: import org.objectweb.speedo.api.SpeedoProperties;
035: import org.objectweb.speedo.generation.enhancer.common.AbstractEnhancerComponent;
036: import org.objectweb.speedo.generation.enhancer.common.DuplicatedMethodVerifier;
037: import org.objectweb.speedo.generation.enhancer.common.InterfaceAgregatorVisitor;
038: import org.objectweb.speedo.generation.enhancer.common.MergedClassModifier;
039: import org.objectweb.speedo.generation.enhancer.oid.PNameEnhancer;
040: import org.objectweb.speedo.generation.enhancer.oid.UserIdEnhancer;
041: import org.objectweb.speedo.generation.lib.NamingRules;
042: import org.objectweb.speedo.lib.Personality;
043: import org.objectweb.speedo.metadata.SpeedoClass;
044: import org.objectweb.speedo.metadata.SpeedoIdentity;
045: import org.objectweb.speedo.metadata.SpeedoPackage;
046: import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
047: import org.objectweb.util.monolog.api.BasicLevel;
048: import org.objectweb.util.monolog.api.Logger;
049:
050: import java.util.ArrayList;
051: import java.util.Collection;
052: import java.util.HashMap;
053: import java.util.Iterator;
054: import java.util.Map;
055:
056: /**
057: * Enhances a set of Java classes.
058: *
059: * @author S.Chassande-Barrioz
060: */
061: public class PersistentClassEnhancer extends AbstractEnhancerComponent {
062: public final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME
063: + ".generation.enhancer";
064: int processedClasses;
065:
066: public PersistentClassEnhancer(Personality p) {
067: super (p);
068: }
069:
070: /**
071: * Initializes this PersistentClassEnhancer
072: */
073: public boolean init() {
074: logger = scp.loggerFactory.getLogger(LOGGER_NAME);
075: //TODO: manage classes located in a jar file
076: isSrcJar = false;
077: processedClasses = 0;
078: return !scp.getXmldescriptor().isEmpty();
079: }
080:
081: public String getTitle() {
082: return "Enhancing Persistent classes...";
083: }
084:
085: public String getSummary() {
086: return processedClasses + " enhanced";
087: }
088:
089: /**
090: * Loads all binary classes described by the Object Model and applies
091: * revelant modification to each of them.
092: */
093: public void process() throws SpeedoException {
094: if (scp.getXmldescriptor().isEmpty())
095: return;
096: ArrayList except = new ArrayList();
097: Collection xmls = scp.getXmldescriptor().values();
098: for (Iterator itDesc = xmls.iterator(); itDesc.hasNext();) {
099: SpeedoXMLDescriptor desc = (SpeedoXMLDescriptor) itDesc
100: .next();
101: for (Iterator itPack = desc.packages.values().iterator(); itPack
102: .hasNext();) {
103: SpeedoPackage sp = (SpeedoPackage) itPack.next();
104: for (Iterator itclass = sp.classes.values().iterator(); itclass
105: .hasNext();) {
106: SpeedoClass sc = (SpeedoClass) itclass.next();
107: Logger log = scp.loggerFactory
108: .getLogger(LOGGER_NAME + '.'
109: + sc.getFQName());
110: treatPC(sc, log);
111: treatOID(sc, log);
112: processedClasses++;
113: }
114: }
115: }
116: // Displays thrown exceptions
117: if (!except.isEmpty() && logger.isLoggable(BasicLevel.WARN)) {
118: for (Iterator it = except.iterator(); it.hasNext();) {
119: Exception e = (Exception) it.next();
120: logger.log(BasicLevel.WARN, e.getLocalizedMessage());
121: }
122: }
123: }
124:
125: protected ClassVisitor getFirstVisitors(ClassWriter cw, Logger log,
126: String classToWrite, Map ctx) {
127: ClassVisitor current = new InterfaceAgregatorVisitor(cw, log,
128: classToWrite, personality);
129: current = new DuplicatedMethodVerifier(current, log,
130: personality);
131: return current;
132: }
133:
134: protected ClassVisitor getParentVisitors(ClassVisitor current,
135: Logger log, String classToWrite, SpeedoClass sc, Map ctx) {
136: final String bindingName = PBindingImpl.class.getName();
137: current = new CacheEntryAdder(current, log, classToWrite,
138: personality);
139: current = new MergedClassModifier(current, classToWrite,
140: bindingName.replace('.', '/'), log, personality);
141: return current;
142: }
143:
144: protected ClassVisitor getVisitors(ClassVisitor current,
145: Logger log, String classToWrite, SpeedoClass sc, Map ctx) {
146: // add the accessor (static and not)
147: current = new FieldAccessorsAdder(current, log, sc, scp,
148: personality);
149: // add the PO methods
150: current = new POAdder(current, log, sc, scp, personality);
151: // modifies the original code
152: current = new FieldAccessModifier(current, sc, log, personality);
153: //Add or modifiy the no arg constructor
154: current = new NoArgConstructorAdder(current, log,
155: sc.noArgConstructorStatus, personality);
156: //Remove the persistent fields
157: current = new FieldRemover(current, sc, log, personality);
158: return current;
159: }
160:
161: /**
162: * Enhances the .class of a persistent class.
163: * @param sc is the Speedo meta object representing the persistent
164: * class
165: * @param xmls is the
166: * @param log
167: * @throws SpeedoException
168: */
169: private void treatPC(final SpeedoClass sc, final Logger log)
170: throws SpeedoException {
171: final String name = sc.getFQName();
172: log.log(BasicLevel.DEBUG, "Enahncing the class: " + name);
173: final String classToWrite = name.replace('.', '/');
174: final ClassWriter cw = new ClassWriter(true);
175: Map ctx = new HashMap();
176: ClassVisitor current = getFirstVisitors(cw, log, classToWrite,
177: ctx);
178: final ClassVisitor common = current;
179: if (sc.getSuperClassName() == null) {
180: log.log(BasicLevel.DEBUG,
181: "Add shared methods (no super class)");
182: final String bindingName = PBindingImpl.class.getName();
183: current = common;
184: current = getParentVisitors(current, log, classToWrite, sc,
185: ctx);
186: final ClassReader cr = loadJavaClass(false, bindingName,
187: scp.output, true);
188: //This is not the last branch of the visitor tree. So the visitor
189: // regAdder register only the static area only
190: cr
191: .accept(current, Attributes.getDefaultAttributes(),
192: false);
193: }
194: current = common;
195: current = getVisitors(current, log, classToWrite, sc, ctx);
196:
197: //Read the original code
198: ClassReader cr = loadJavaClass(false, name, scp.output, false);
199: cr.accept(current, Attributes.getDefaultAttributes(), false);
200:
201: //write the .class file
202: writeJavaClass(name, cw, scp.output);
203:
204: }
205:
206: /**
207: * It enhances the userid class and the XXXPName class in case of the
208: * ideentifier of the persistent class are based on a user objectid class.
209: * @param sc is the Speedo meta object of the persistent class
210: */
211: private void treatOID(final SpeedoClass sc, final Logger log)
212: throws SpeedoException {
213: if (sc.getIdentityType() == SpeedoIdentity.USER_ID
214: && sc.identity.objectidClass != null
215: && !sc.identity.oidClassAutoCalculated
216: && (sc.getSuperClassName() == null //I have not a parent
217: || !sc.identity.objectidClass
218: .equals(sc.getSuper().identity.objectidClass))) {
219: ClassWriter cw;
220: ClassVisitor current;
221: //Modifies the User id class
222: cw = new ClassWriter(true);
223: current = new UserIdEnhancer(cw, sc, log, personality);
224: String cn = sc.identity.objectidClass;
225: ClassReader cr = loadJavaClass(false, cn, scp.output, true);
226: cr
227: .accept(current, Attributes.getDefaultAttributes(),
228: false);
229: writeJavaClass(cn, cw, scp.output);
230:
231: //Modify the generated XXXPName class (by JORM)
232: cw = new ClassWriter(false);
233: cn = NamingRules.pnameName(sc.identity.objectidClass);
234: cr = loadJavaClass(false, cn, scp.output, true);
235: current = new PNameEnhancer(cw, sc, log, personality);
236: cr
237: .accept(current, Attributes.getDefaultAttributes(),
238: false);
239: writeJavaClass(cn, cw, scp.output);
240: }
241: }
242: }
|