Source Code Cross Referenced for HotSwapAdvancedClassWeaver.java in  » Byte-Code » PROSE » ch » ethz » inf » iks » jvmai » jvmdi » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Byte Code » PROSE » ch.ethz.inf.iks.jvmai.jvmdi 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        //
0002:        //  This file is part of the prose package.
0003:        //
0004:        //  The contents of this file are subject to the Mozilla Public License
0005:        //  Version 1.1 (the "License"); you may not use this file except in
0006:        //  compliance with the License. You may obtain a copy of the License at
0007:        //  http://www.mozilla.org/MPL/
0008:        //
0009:        //  Software distributed under the License is distributed on an "AS IS" basis,
0010:        //  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0011:        //  for the specific language governing rights and limitations under the
0012:        //  License.
0013:        //
0014:        //  Contributor(s):
0015:        //  $Id$
0016:        // =====================================================================
0017:        //
0018:        // (history at end)
0019:        //
0020:
0021:        package ch.ethz.inf.iks.jvmai.jvmdi;
0022:
0023:        import java.lang.reflect.Method;
0024:        import java.lang.reflect.Constructor;
0025:        import java.lang.reflect.Member;
0026:        import java.lang.reflect.Modifier;
0027:
0028:        import java.util.Collections;
0029:        import java.util.Collection;
0030:        import java.util.Map;
0031:        import java.util.HashMap;
0032:        import java.util.LinkedHashMap;
0033:        import java.util.ArrayList;
0034:        import java.util.Iterator;
0035:        import java.util.LinkedList;
0036:
0037:        import java.io.ByteArrayInputStream;
0038:        import java.io.IOException;
0039:
0040:        import org.apache.bcel.Constants;
0041:        import org.apache.bcel.Repository;
0042:        import org.apache.bcel.classfile.Attribute;
0043:        import org.apache.bcel.classfile.ClassParser;
0044:        import org.apache.bcel.classfile.ConstantValue;
0045:        import org.apache.bcel.classfile.JavaClass;
0046:        import org.apache.bcel.generic.*;
0047:        import org.apache.bcel.verifier.Verifier;
0048:        import org.apache.bcel.verifier.VerifierFactory;
0049:        import org.apache.bcel.verifier.VerificationResult;
0050:
0051:        import ch.ethz.jvmai.*;
0052:
0053:        /*
0054:         *  Modifies a given class to support advice execution.
0055:         *  Container for MethodWeavers, which does the code
0056:         *  manipulations. Use the static method {@link
0057:         *  #getWeaver(Method)} to get an instance of an 
0058:         *  {@link ch.ethz.jvmai.MethodWeaver}.
0059:         *  <P>
0060:         *  Optimized class weaver implementation. Holds a list with all
0061:         *  ClassWeavers that contains changes which are not yet commited.
0062:         *  On commit it iterates only over the ClassWeavers in this list.
0063:         *
0064:         *  The SimpleClassWeaver iterates over classweaver list.
0065:         *  The AdvancedClassWeaver iterates only over the last modified classweavers.
0066:         *  The advantage is that doesn't have to check for each class weaver if has been modified.
0067:         *
0068:         *	@author	 Angela Nicoara
0069:         *  @author  Gerald Linhofer
0070:         *  @version $Revision: 1.1.2.2 $
0071:         */
0072:        public class HotSwapAdvancedClassWeaver {
0073:
0074:            /**
0075:             *  String representation of the JVMAI class.
0076:             */
0077:            public static final String JVMAI_CLASS = "ch.ethz.inf.iks.jvmai.jvmdi.HotSwapAspectInterfaceImpl";
0078:
0079:            /**
0080:             * Set holding all class weavers, which hold uncommited modifications.
0081:             */
0082:            private static Collection modifiedClassWeavers = new LinkedList();
0083:            //	private static Collection<HotSwapClassWeaver> modifiedClassWeavers = new  LinkedList<HotSwapClassWeaver>();			// only JDK 1.5 or above
0084:
0085:            /**
0086:             *  Map with all class weaver. For each Class there
0087:             *  exists exactly one class weaver in the system.
0088:             */
0089:            private static Map classWeavers = new LinkedHashMap(1024);
0090:            //	private static Map<Class,HotSwapClassWeaver> classWeavers = new LinkedHashMap<Class,HotSwapClassWeaver>(1024);	// only JDK 1.5 or above
0091:
0092:            /**
0093:             *  Map with all method weavers. For each Method there
0094:             *  exists exactly one method weaver in the system.
0095:             */
0096:            private static Map methodWeavers = new LinkedHashMap(1024);
0097:            //	private static Map<Member,MethodWeaver> methodWeavers = new LinkedHashMap<Member,MethodWeaver>(1024);				// only JDK 1.5 or above
0098:
0099:            /**
0100:             *  Maps unique method ids to the method objects.
0101:             */
0102:            private static Member methodMap[] = new Member[1024];
0103:
0104:            /**
0105:             *  Manages unique method ids.
0106:             */
0107:            private static UniqueIdArrayManager idMgr = new UniqueIdArrayManager();
0108:
0109:            /**
0110:             *  The JVMAspectInterface.
0111:             */
0112:            private static HotSwapAspectInterfaceImpl aspectInterface = null;
0113:
0114:            /**
0115:             *  Is there anything to do for {@link #resetAll}
0116:             */
0117:            private static boolean anyWoven = false;
0118:
0119:            //----------------------------------------------------------------------
0120:
0121:            /**
0122:             *  Get a unique method weaver for 'target'.
0123:             * 
0124:             * @param target method for which a weaver will be returned.
0125:             * @return MethodWeaver associated to <CODE>target</CODE>.
0126:             */
0127:            static public MethodWeaver getWeaver(Member target) /*throws ClassNotFoundException*/{
0128:                if (null == target)
0129:                    throw new NullPointerException(
0130:                            "Parameter 'target' must not be null");
0131:
0132:                MethodWeaver result;
0133:                synchronized (methodWeavers) {
0134:                    result = (MethodWeaver) methodWeavers.get(target);
0135:                    if (null == result) {
0136:                        try {
0137:                            // get or create the ClassWeaver
0138:                            HotSwapAdvancedClassWeaver cw = getClassWeaver(target
0139:                                    .getDeclaringClass());
0140:                            // create a new MethodWeaver
0141:                            result = cw.getNewMethodWeaver(target);
0142:                        } catch (ClassNotFoundException e) {
0143:                            throw new JVMAIRuntimeException(
0144:                                    "Class weaver could not get the definition for "
0145:                                            + target.getDeclaringClass());
0146:                        }
0147:                    }
0148:                }
0149:                return result;
0150:            }
0151:
0152:            /**
0153:             *  Get a unique class weaver for 'target'.
0154:             */
0155:            static protected HotSwapAdvancedClassWeaver getClassWeaver(
0156:                    Class target) throws ClassNotFoundException {
0157:                if (null == target)
0158:                    throw new NullPointerException(
0159:                            "Parameter 'target' must not be null");
0160:
0161:                HotSwapAdvancedClassWeaver result;
0162:                synchronized (classWeavers) {
0163:                    result = (HotSwapAdvancedClassWeaver) classWeavers
0164:                            .get(target);
0165:                    if (null == result) {
0166:                        // create a new ClassWeaver
0167:                        result = new HotSwapAdvancedClassWeaver(target);
0168:                        classWeavers.put(target, result);
0169:                    }
0170:                }
0171:                return result;
0172:            }
0173:
0174:            /**
0175:             *  Re-Weaves all modified classes and activates them.
0176:             */
0177:            static public void commit() {
0178:                if (modifiedClassWeavers.isEmpty())
0179:                    return;
0180:
0181:                // synchronize commit and reset
0182:                synchronized (classWeavers) {
0183:                    Collection clazzes = new ArrayList();
0184:                    Collection definitions = new ArrayList();
0185:
0186:                    Iterator iter = modifiedClassWeavers.iterator();
0187:                    while (iter.hasNext()) {
0188:                        HotSwapAdvancedClassWeaver weaver = (HotSwapAdvancedClassWeaver) iter
0189:                                .next();
0190:                        try {
0191:                            weaver.prepareClassDefinition();
0192:                            definitions.add(weaver.getClassDefinition());
0193:                            clazzes.add(weaver.targetClass);
0194:                            // remove weaver if its not associated with an modified method.
0195:                            if (weaver.hasNoModifiedMethods())
0196:                                classWeavers.remove(weaver.targetClass);
0197:                            else {
0198:                                weaver.setWoven();
0199:                            }
0200:                        } catch (ClassNotFoundException e) {
0201:                            System.err
0202:                                    .println("ERROR HotSwapClassWeaver: Class redefinition failed: "
0203:                                            + e);
0204:                        } catch (IOException e) {
0205:                            System.err
0206:                                    .println("ERROR HotSwapClassWeaver: Class redefinition failed: "
0207:                                            + e);
0208:                        }
0209:                    }
0210:                    modifiedClassWeavers.clear();
0211:
0212:                    if (!clazzes.isEmpty()) {
0213:                        anyWoven = true;
0214:                        // redefine classes
0215:                        Class cls[] = new Class[clazzes.size()];
0216:                        clazzes.toArray(cls);
0217:                        byte defs[][] = new byte[definitions.size()][];
0218:                        definitions.toArray(defs);
0219:                        redefineClasses(cls, defs);
0220:                    }
0221:                }
0222:            }
0223:
0224:            /**
0225:             *  Resets all woven classes.
0226:             */
0227:            static public void resetAll() {
0228:                // synchronize commit() and resetAll()
0229:                synchronized (classWeavers) {
0230:                    if (anyWoven) {
0231:                        Collection clazzes = new ArrayList();
0232:                        Collection definitions = new ArrayList();
0233:                        Iterator it = classWeavers.values().iterator();
0234:
0235:                        // get classes and old class definitions
0236:                        while (it.hasNext()) {
0237:                            HotSwapAdvancedClassWeaver cw = (HotSwapAdvancedClassWeaver) it
0238:                                    .next();
0239:                            if (cw.isWoven() && null != cw.originalCode) {
0240:                                clazzes.add(cw.targetClass);
0241:                                definitions.add(cw.originalCode);
0242:                            }
0243:                        }
0244:
0245:                        if (!clazzes.isEmpty()) {
0246:                            // redefine classes
0247:                            Class cls[] = new Class[clazzes.size()];
0248:                            clazzes.toArray(cls);
0249:                            byte defs[][] = new byte[definitions.size()][];
0250:                            definitions.toArray(defs);
0251:                            redefineClasses(cls, defs);
0252:                        }
0253:                    }
0254:
0255:                    classWeavers.clear(); // = new LinkedHashMap();
0256:                    methodWeavers.clear(); // = new LinkedHashMap();
0257:                    modifiedClassWeavers.clear(); // = new LinkedList();
0258:                    methodMap = new Member[1024];
0259:                    idMgr.reset();
0260:                    anyWoven = false;
0261:                }
0262:            }
0263:
0264:            /**
0265:             * Returns an identifier for <CODE>method</CODE> and
0266:             * stores the association, so that {@link #idToMethod(int) idToMethod}
0267:             * may be used to get the <CODE>method</CODE> using the id.
0268:             * 
0269:             * Note: only the id is unique, if <CODE>createNewMethodId(Method)
0270:             * </CODE> is called more than one time with the same argument,
0271:             * each call will create a new id and a new map entry.
0272:             * 
0273:             * @param method that will be associated with a new identifier.
0274:             * @return new identifier for <CODE>method</CODE>.
0275:             */
0276:            private static int createNewMethodId(Member method) {
0277:                if (null == method)
0278:                    throw new NullPointerException();
0279:
0280:                int result;
0281:
0282:                synchronized (methodMap) {
0283:                    result = idMgr.newId();
0284:                    // check if map must be expanded
0285:                    int mapLength = methodMap.length;
0286:                    if (mapLength <= result) {
0287:                        Member newMap[] = new Member[2 * mapLength];
0288:                        System.arraycopy(methodMap, 0, newMap, 0, mapLength);
0289:                        methodMap = newMap;
0290:                    }
0291:                    // add method to the map
0292:                    methodMap[result] = method;
0293:                }
0294:                return result;
0295:            }
0296:
0297:            /**
0298:             * Returns the Member object associated to <CODE>methodId</CODE>
0299:             * or <CODE>null</CODE>, if <CODE>methodID</CODE> is not a valid
0300:             * id.
0301:             * 
0302:             * @param methodId id for the Method that will be returned.
0303:             * @return Method associated to  <CODE>methodID<CODE> or <CODE>null</CODE>.
0304:             * @throws ArrayOutOfBoundException
0305:             */
0306:            public static Member idToMethod(int methodId) {
0307:                return methodMap[methodId];
0308:            }
0309:
0310:            /**
0311:             * Sets the aspect interface, must be called before any call to
0312:             * {@link #commit commit}.
0313:             * 
0314:             * @param ai
0315:             */
0316:            public synchronized static void setAspectInterface(
0317:                    HotSwapAspectInterfaceImpl ai) {
0318:                aspectInterface = ai;
0319:            }
0320:
0321:            //---------------------------------------------------------------------
0322:
0323:            private boolean initialized;
0324:            private boolean modified;
0325:            private boolean woven;
0326:
0327:            /**
0328:             *  Class bound to this weaver
0329:             */
0330:            public final Class targetClass;
0331:
0332:            /**
0333:             *  Cached original (/unmodified) class file of {@link #targetClass}.
0334:             */
0335:            public final byte[] originalCode;
0336:
0337:            /**
0338:             *  BCEL class generator used during weaving processs.
0339:             *  holds the actual class definition during weaving process.
0340:             */
0341:            private ClassGen clGen;
0342:
0343:            /**
0344:             *  BCEL constant pool generator used during weaving process.
0345:             */
0346:            private ConstantPoolGen cpGen;
0347:
0348:            /**
0349:             *  BCEL instruction factory used during the weaving process.
0350:             */
0351:            private InstructionFactory instructionFactory;
0352:
0353:            /**
0354:             *  Collection of member MethodWeavers (of {@link #targetClass}) 
0355:             *  that will be redefined.
0356:             */
0357:            private Map methods;
0358:
0359:            // Used during weaving (introduced for verfyClassSchema)
0360:            private JavaClass bcelClass;
0361:
0362:            //-----------------------------------------------------------------------
0363:
0364:            /**
0365:             *  Creates a new class weaver. Use the static method
0366:             *  {@link #getClassWeaver(java.lang.Class) getClassWeaver} to obtain a weaver.
0367:             */
0368:            protected HotSwapAdvancedClassWeaver(Class target)
0369:                    throws ClassNotFoundException {
0370:                targetClass = target;
0371:                methods = new HashMap();
0372:
0373:                bcelClass = HotSwapAspectInterfaceImpl
0374:                        .getBCELClassDefinition(targetClass);
0375:                originalCode = bcelClass.getBytes();
0376:
0377:                initialized = false;
0378:                woven = false;
0379:                modified = false;
0380:
0381:                clGen = null;
0382:                cpGen = null;
0383:            }
0384:
0385:            /**
0386:             * Indicates if this class weaver holds any
0387:             * method weavers.
0388:             * 
0389:             * @return <CODE>true</CODE> if no method weavers are associated.
0390:             */
0391:            public boolean hasNoModifiedMethods() {
0392:                return methods.isEmpty();
0393:            }
0394:
0395:            /**
0396:             * Returns the class bound to this weaver.
0397:             * @return Class that is bound to this weaver
0398:             */
0399:            public Class getTargetClass() {
0400:                return targetClass;
0401:            }
0402:
0403:            public Collection getMethods() {
0404:                return methods.keySet();
0405:            }
0406:
0407:            /**
0408:             * Returns a collection of all method weavers for
0409:             * this class weaver.
0410:             * 
0411:             * @return Collection of <CODE>MethodWeaver</CODE>s associated to this
0412:             * 			<CODE>ClassWeaver</CODE>
0413:             */
0414:            public Collection getMethodWeavers() {
0415:                return methods.values();
0416:            }
0417:
0418:            /**
0419:             * Sets some internal variables to indicate
0420:             * that the target class was woven.
0421:             */
0422:            protected void setWoven() {
0423:                modified = false;
0424:                woven = true;
0425:                clGen = null;
0426:            }
0427:
0428:            /**
0429:             * Indicates if not yet woven modifications are registered
0430:             * for the target class.
0431:             * 
0432:             * @return <CODE>true</CODE> if weaver holds unwoven
0433:             * 		modifications for its target class.
0434:             */
0435:            public boolean isModified() {
0436:                return modified;
0437:            }
0438:
0439:            /**
0440:             * Indicates if the target class was woven (redefined).
0441:             * 
0442:             * @return <CODE>true</CODE> if the target class is redefined.
0443:             */
0444:            public boolean isWoven() {
0445:                return woven;
0446:            }
0447:
0448:            /**
0449:             *  Creates a new <CODE>MethodWeaver</CODE> and adds it to
0450:             *  this weaver.
0451:             *  This adds the new weaver also to the global methodWeavers
0452:             *  table.
0453:             *  Use {@link HotSwapAdvancedClassWeaver#getWeaver(java.lang.reflect.Member) getWeaver} to create a new MethodWeaver.
0454:             */
0455:            protected MethodWeaver getNewMethodWeaver(Member target) {
0456:                MethodWeaver result = new MethodWeaver(target);
0457:                methodWeavers.put(target, result);
0458:                methods.put(target, result);
0459:
0460:                return result;
0461:            }
0462:
0463:            /**
0464:             *  Prepares a class for weaving. This mean mainly
0465:             *  instrumenting the class file representation,
0466:             *  so that the new definition may be fetched with
0467:             *  {@link #getClassDefinition()}.
0468:             */
0469:            protected void prepareClassDefinition() throws java.io.IOException,
0470:                    ClassNotFoundException {
0471:                initPreparation();
0472:                weaveMethods();
0473:                //		verify();
0474:                //		verifyClassSchema();
0475:                finishWeaving();
0476:            }
0477:
0478:            /**
0479:             *  Prepare for weaving. Initializes some member field.
0480:             *  This method must only be called once (for each instance
0481:             *  of this class).
0482:             *  called by {@link #prepareClassDefinition()}.
0483:             */
0484:            private void initPreparation() throws java.io.IOException,
0485:                    ClassNotFoundException {
0486:                if (initialized) {
0487:                    // weaver was already used, so reset bcelClass to its original state
0488:                    ClassParser classParser = new ClassParser(
0489:                            new ByteArrayInputStream(originalCode), bcelClass
0490:                                    .getFileName());
0491:                    bcelClass = classParser.parse();
0492:                } else
0493:                    initialized = true;
0494:
0495:                // create bcel generator objects
0496:                clGen = new ClassGen(bcelClass);
0497:                cpGen = clGen.getConstantPool();
0498:                instructionFactory = new InstructionFactory(clGen, cpGen);
0499:            }
0500:
0501:            /**
0502:             *  Resets some member fields to the values they should have
0503:             *  after weaving.
0504:             *  Called by {@link #prepareClassDefinition()}-
0505:             */
0506:            private void finishWeaving() {
0507:                woven = true;
0508:                cpGen = null;
0509:                instructionFactory = null;
0510:            }
0511:
0512:            /**
0513:             *  Generate instrumented versions of the member methods
0514:             *  of {@link #targetClass}.
0515:             *  called by {@link #prepareClassDefinition()}.
0516:             */
0517:            private void weaveMethods() {
0518:                // Copy the methods to another collection to allow removal
0519:                // from the entire collection.
0520:                int numOfMethods = methods.size();
0521:                MethodWeaver[] mws = new MethodWeaver[numOfMethods];
0522:                methods.values().toArray(mws);
0523:                for (int i = 0; i < numOfMethods; i++) {
0524:                    mws[i].weaveMethod();
0525:                }
0526:            }
0527:
0528:            /**
0529:             *  Returns the instrumented class file.
0530:             *  {@link #prepareClassDefinition()} must be called first.
0531:             */
0532:            protected byte[] getClassDefinition() {
0533:                if (!initialized)
0534:                    throw new JVMAIRuntimeException("ClassWeaver for <"
0535:                            + targetClass + "> not initialized ");
0536:                return clGen.getJavaClass().getBytes();
0537:            }
0538:
0539:            private void reset() {
0540:                woven = false;
0541:                modified = false;
0542:
0543:                Iterator it = methods.values().iterator();
0544:                while (it.hasNext()) {
0545:                    MethodWeaver mw = (MethodWeaver) it.next();
0546:                    methodWeavers.remove(mw.target);
0547:                }
0548:                methods.clear();
0549:            }
0550:
0551:            /**
0552:             * Verifies if the new class definition doesn't change anything,
0553:             * which RedefineClasses can not handle (anything except 
0554:             * changing method bodies).
0555:             * 
0556:             * @return <CODE>false</CODE> if any incompabilities betwen
0557:             * 				the new and the old class definitions where found, 
0558:             * 				otherwise <CODE>true</CODE>.
0559:             */
0560:            private boolean verifyClassSchema() {
0561:                boolean retval = true;
0562:
0563:                if (null == clGen || null == bcelClass)
0564:                    throw new RuntimeException("nothing to verify");
0565:
0566:                //System.out.println( "Verifying " + oldClass.getClassName() );
0567:                // Get classes	
0568:                ClassParser cp = new ClassParser(new ByteArrayInputStream(
0569:                        originalCode), targetClass.getName().replace('.', '/'));
0570:                try {
0571:                    bcelClass = cp.parse();
0572:                } catch (java.io.IOException e) {
0573:                    throw new RuntimeException(e.getMessage());
0574:                }
0575:                JavaClass newClass = clGen.getJavaClass();
0576:
0577:                // Check class name
0578:                if (!bcelClass.getClassName().equals(newClass.getClassName())) {
0579:                    System.out.println("Class name changed ( old: "
0580:                            + bcelClass.getClassName() + ", new: "
0581:                            + newClass.getClassName() + ")");
0582:                    retval = false;
0583:                }
0584:                // Check class modifiers (access flags)
0585:                if (bcelClass.getAccessFlags() != newClass.getAccessFlags()) {
0586:                    System.out.println("Class modifiers changed (old: "
0587:                            + bcelClass.getAccessFlags() + ", new: "
0588:                            + newClass.getAccessFlags() + ")");
0589:                    retval = false;
0590:                }
0591:
0592:                // Methods
0593:                org.apache.bcel.classfile.Method oldMethods[] = bcelClass
0594:                        .getMethods();
0595:                org.apache.bcel.classfile.Method newMethods[] = newClass
0596:                        .getMethods();
0597:                int oldMethodsLength = oldMethods.length;
0598:                // number of methods
0599:                if (oldMethodsLength != newMethods.length) {
0600:                    System.out.println("Number of methods changed (old: "
0601:                            + oldMethodsLength + ", new: " + newMethods.length
0602:                            + ")");
0603:                    retval = false;
0604:                } else {
0605:                    for (int i = 0; i < oldMethodsLength; i++) {
0606:                        org.apache.bcel.classfile.Method oldMeth = oldMethods[i];
0607:                        org.apache.bcel.classfile.Method newMeth = newMethods[i];
0608:
0609:                        // method name
0610:                        String oldMName = oldMeth.getName();
0611:                        if (!oldMName.equals(newMeth.getName())) {
0612:                            System.out.println("Method name changed (old: "
0613:                                    + oldMName + ", new: " + newMeth.getName()
0614:                                    + ")");
0615:                            retval = false;
0616:                        }
0617:                        // method modifiers
0618:                        if (oldMeth.getAccessFlags() != newMeth
0619:                                .getAccessFlags()) {
0620:                            System.out.println("Method modifiers changed for"
0621:                                    + oldMName);
0622:                            retval = false;
0623:                        }
0624:                        // signature
0625:                        if (!oldMeth.getSignature().equals(
0626:                                newMeth.getSignature())) {
0627:                            System.out.println("Method signature changed for "
0628:                                    + oldMName);
0629:                            retval = false;
0630:                        }
0631:                    }
0632:                }
0633:
0634:                // Check for JVMDI_ERROR_SCHEMA_CHANGE... (Fields)
0635:                org.apache.bcel.classfile.Field newFields[] = newClass
0636:                        .getFields();
0637:                org.apache.bcel.classfile.Field oldFields[] = bcelClass
0638:                        .getFields();
0639:                int newFieldsLength = newFields.length;
0640:                if (newFieldsLength != oldFields.length) {
0641:                    System.out.println("Number of fields changed (old "
0642:                            + oldFields.length + ", new " + newFieldsLength
0643:                            + ")");
0644:                    retval = false;
0645:                } else {
0646:                    for (int i = 0; i < newFieldsLength; i++) {
0647:                        org.apache.bcel.classfile.Field nf = newFields[i];
0648:                        org.apache.bcel.classfile.Field of = oldFields[i];
0649:                        String oldName = of.getName();
0650:
0651:                        // Name				
0652:                        if (!nf.getName().equals(oldName)) {
0653:                            System.out.println("Field name changed ( new: "
0654:                                    + nf.getName() + ", old: " + oldName + ")");
0655:                            retval = false;
0656:                        }
0657:                        // Access flags
0658:                        if (nf.getAccessFlags() != of.getAccessFlags()) {
0659:                            System.out
0660:                                    .println("Field access flags changed for "
0661:                                            + oldName + "( old: "
0662:                                            + of.getAccessFlags() + ", new: "
0663:                                            + nf.getAccessFlags() + ")");
0664:                            retval = false;
0665:                        }
0666:                        // Signature
0667:                        if (!nf.getSignature().equals(of.getSignature())) {
0668:                            System.out.println("Field signature changed for "
0669:                                    + oldName + "( old: " + of.getSignature()
0670:                                    + ", new: " + nf.getSignature() + ")");
0671:                            retval = false;
0672:                        }
0673:                        // Constant value (may be 'null')
0674:                        ConstantValue oldConst = of.getConstantValue();
0675:                        ConstantValue newConst = nf.getConstantValue();
0676:                        if (oldConst != newConst) {
0677:                            if (null == oldConst) {
0678:                                System.out
0679:                                        .println("Changed constant field to modifiable field "
0680:                                                + oldName);
0681:                                retval = false;
0682:                            } else if (null == newConst) {
0683:                                System.out
0684:                                        .println("Changed modifiable field to constant field "
0685:                                                + oldName);
0686:                                retval = false;
0687:                            } else if (!oldConst.toString().equals(
0688:                                    newConst.toString())) {
0689:                                System.out.println("Changed "
0690:                                        + oldConst.toString() + " to "
0691:                                        + newConst.toString());
0692:                                retval = false;
0693:                            }
0694:                        }
0695:                        // Attributes
0696:                        Attribute newAttributes[] = nf.getAttributes();
0697:                        Attribute oldAttributes[] = of.getAttributes();
0698:                        int oldAttributesLength = oldAttributes.length;
0699:                        if (oldAttributesLength != newAttributes.length) {
0700:                            System.out
0701:                                    .println("Number of field attributes changend (old: "
0702:                                            + oldAttributesLength
0703:                                            + " new: "
0704:                                            + newAttributes.length + ")");
0705:                            retval = false;
0706:                        } else {
0707:                            for (int j = 0; j < oldAttributesLength; j++) {
0708:                                Attribute oldAttr = oldAttributes[j];
0709:                                Attribute newAttr = newAttributes[j];
0710:                            }
0711:                        }
0712:                    }
0713:                }
0714:                return retval;
0715:            }
0716:
0717:            /**
0718:             * Verify bytecodes with the BCEL verifier.
0719:             * <p>
0720:             * NOTE: Can't be used since even `normal' classes are rejected with Jikes
0721:             * RVM 2.3.0.1.
0722:             * 
0723:             */
0724:            private void verify() {
0725:                if (null == clGen)
0726:                    throw new RuntimeException("nothing to verify");
0727:
0728:                JavaClass jc = clGen.getJavaClass();
0729:                Repository.addClass(jc);
0730:
0731:                Verifier v = VerifierFactory.getVerifier(jc.getClassName());
0732:                checkVerificationResult(v.doPass1(), "1");
0733:                checkVerificationResult(v.doPass2(), "2");
0734:                MethodWeaver methodWeavers[] = new MethodWeaver[methods.size()];
0735:                methods.values().toArray(methodWeavers);
0736:                for (int i = 0; i < methods.size(); i++) {
0737:                    int method_index = methodWeavers[i].getTargetIndex();
0738:                    checkVerificationResult(v.doPass3a(method_index), "3a");
0739:                    checkVerificationResult(v.doPass3b(method_index), "3b");
0740:                }
0741:
0742:                try {
0743:                    String[] warnings = v.getMessages();
0744:                    if (warnings.length != 0)
0745:                        System.err.println("Messages:");
0746:                    for (int j = 0; j < warnings.length; j++)
0747:                        System.err.println(warnings[j]);
0748:                } catch (Exception e) {
0749:                    System.err.println("could not verify " + targetClass);
0750:                }
0751:            }
0752:
0753:            /**
0754:             * Check bytecode verification result.
0755:             * 
0756:             * @param vr verification result which must be checked
0757:             * @param pass verification pass
0758:             */
0759:            private void checkVerificationResult(VerificationResult vr,
0760:                    String pass) {
0761:                if (vr != VerificationResult.VR_OK) {
0762:                    System.err.println("Verification failed in pass " + pass
0763:                            + " for " + targetClass + ".");
0764:                    System.err.println(vr);
0765:                }
0766:            }
0767:
0768:            /**
0769:             * Redefines existing classes, actually only method bodies may be redefined,
0770:             * but the JVMDI and JVMTI functions requieres the whole class code. The parameters
0771:             * are two arrays of the same size, each entry of one array corresponds to the
0772:             * entry with the same index in the other array.
0773:             * The class that should be redefined must exist in the JVM (they must be loaded
0774:             * in advance).
0775:             * 
0776:             * Required for JVMDI/JVMTI HotSwap advice weaving.
0777:             *
0778:             * @param cls Array of Class objects that should get redefined
0779:             * @param definitions Array of class definitions, which are arrays of bytes,
0780:             *        the definition is in the same form like in a class file.
0781:             * @exception UnmodifiableClassException <CODE>cls</CODE> contains a not modifiable
0782:             *        class (for example an interface or a class that's not in the class path).
0783:             * @exception IlligalClassFormatException <CODE>definitions</CODE> contains a invalide
0784:             *        class definition
0785:             * @exception RuntimeException could not apply operation.
0786:             * @exception NullPointerException if <CODE>cls</CODE> is <CODE>null</CODE>.
0787:             * @exception IlligalArgumentExceptin <CODE>definitions</CODE> is <CODE>null</CODE>.
0788:             */
0789:            public static void redefineClasses(Class[] cls, byte[][] definitions) {
0790:                HotSwapClassWeaver.redefineClasses(cls, definitions);
0791:            }
0792:
0793:            /**
0794:             * Redefines an existing class, actually only method bodies may be redefined,
0795:             * but the JVMDI and JVMTI functions requieres the whole class code.
0796:             * The class that should be redefined must exist in the JVM (they must be loaded
0797:             * in advance).
0798:             *
0799:             * Required for JVMDI/JVMTI HotSwap advice weaving.
0800:             *
0801:             * @param cl Class objects that should get redefined
0802:             * @param definition class definition,
0803:             *        the definition is in the same form like in a class file.
0804:             * @exception UnmodifiableClassException <CODE>cl</CODE> is a not modifiable
0805:             *        class (for example an interface or a class that's not in the class path).
0806:             * @exception IlligalClassFormatException <CODE>definition</CODE> is a invalide
0807:             *        class definition
0808:             * @exception RuntimeException could not apply operation.
0809:             * @exception NullPointerException if <CODE>cl</CODE> is <CODE>null</CODE>.
0810:             * @exception IlligalArgumentExceptin <CODE>definition</CODE> is <CODE>null</CODE>.
0811:             */
0812:            public static void redefineClass(Class cl, byte[] definition) {
0813:                HotSwapClassWeaver.redefineClass(cl, definition);
0814:            }
0815:
0816:            //----------------------------------------------------------------------
0817:
0818:            /**
0819:             *  Implementation of MethodWeaver. Collects redefinition
0820:             *  requests and weaves them into the methods bytecode.
0821:             *
0822:             *  Based on MethodWeaver implementation by Johann Gyger.
0823:             * 
0824:             *  @see ch.ethz.jvmai.MethodWeaver
0825:             */
0826:            protected class MethodWeaver implements  ch.ethz.jvmai.MethodWeaver {
0827:
0828:                /**
0829:                 *  Method bound to this weaver.
0830:                 */
0831:                public final Member target;
0832:
0833:                /**
0834:                 *  Method identifier for {@link #target}.
0835:                 *  Generated with {@link HotSwapAdvancedClassWeaver#createNewMethodId ClassWeaver.createNewMethodId}.
0836:                 */
0837:                public final int targetId;
0838:
0839:                /**
0840:                 *  Method index (in the array of declared methods of the declaring 
0841:                 *  class {@link Class#getDeclaredMethods()}) or -1 if not initialized.
0842:                 */
0843:                private int targetIndex;
0844:
0845:                /**
0846:                 * Indicates how the method should be modified.
0847:                 * see {@link ch.ethz.jvmai.MethodWeaver}
0848:                 */
0849:                private int status;
0850:
0851:                /**
0852:                 *  Redefine advice method.
0853:                 */
0854:                private Member redefineAdvice;
0855:
0856:                //		/**
0857:                //		 *  Watched method calls (not implemented).
0858:                //		 */
0859:                //		private Map methodCalls;
0860:                //		
0861:                //		/**
0862:                //		 *  Watched method returns (not implemented).
0863:                //		 */
0864:                //		private Map methodReturns;
0865:
0866:                /**
0867:                 *  Watched field accesses
0868:                 */
0869:                private Map fieldAccessors;
0870:
0871:                /**
0872:                 *  Watched field modifications
0873:                 */
0874:                private Map fieldModifiers;
0875:
0876:                /**
0877:                 *  BCELs method generator
0878:                 */
0879:                private MethodGen methodGen;
0880:
0881:                /**
0882:                 *  BCEL instructions, used during weaving
0883:                 *  process (normalwise set to 'null').
0884:                 */
0885:                private InstructionList instructions;
0886:
0887:                /**
0888:                 * Create a new method weaver. Use the static method
0889:                 * {@link HotSwapAdvancedClassWeaver#getWeaver(java.lang.reflect.Member) ClassWeaver.getWeaver}to obtain a weaver.
0890:                 *
0891:                 * @param target method that will be woven
0892:                 */
0893:                public MethodWeaver(Member target) {
0894:                    this .target = target;
0895:
0896:                    targetId = createNewMethodId(target);
0897:                    targetIndex = -1;
0898:                    redefineAdvice = null;
0899:                    methodGen = null;
0900:                    instructions = null;
0901:
0902:                    //methodCalls 		= Collections.synchronizedMap(new LinkedHashMap());
0903:                    //methodReturns 		= Collections.synchronizedMap(new LinkedHashMap());
0904:                    fieldAccessors = Collections
0905:                            .synchronizedMap(new LinkedHashMap());
0906:                    fieldModifiers = Collections
0907:                            .synchronizedMap(new LinkedHashMap());
0908:
0909:                    status = MWEAVER_STATUS_UNCHANGED;
0910:                }
0911:
0912:                /**
0913:                 * Changes the status field to reflect that an watch
0914:                 * of type <code>'type'</code> is set.
0915:                 * 
0916:                 * @param type type of the watch (see ch.ethz.jvmai.MethodWeaver).
0917:                 */
0918:                private void addWatch(int type) {
0919:                    status |= type;
0920:                    setModified();
0921:                }
0922:
0923:                /**
0924:                 * Changes the status field to reflect that an watch
0925:                 * of type <code>'type'</code> has to be removed.
0926:                 * 
0927:                 * @param type type of the watch (see ch.ethz.jvmai.MethodWeaver).
0928:                 */
0929:                private void removeWatch(int type) {
0930:                    status &= ~type;
0931:                    setModified();
0932:                }
0933:
0934:                /**
0935:                 * Changes the status field to either add or remove a watch.
0936:                 * 
0937:                 * @param type type of the watch (see ch.ethz.jvmai.MethodWeaver).
0938:                 * @param flag <code>'true'</code> to add the watch, false to remove it.
0939:                 */
0940:                private void setWatch(int type, boolean flag) {
0941:                    status = flag ? (status | type) : (status & ~type);
0942:                    setModified();
0943:                }
0944:
0945:                /**
0946:                 * Indicates if a watch is set or not.
0947:                 * 
0948:                 * @param type type of the watch (see ch.ethz.jvmai.MethodWeaver).
0949:                 * @return <CODE>'true'</CODE> if the watch is set.
0950:                 */
0951:                public boolean hasWatch(int type) {
0952:                    return (status & type) > 0;
0953:                }
0954:
0955:                /**
0956:                 * Returns the method bound to this weaver.
0957:                 * @return Method bound to this weaver.
0958:                 */
0959:                public Member getTarget() {
0960:                    return target;
0961:                }
0962:
0963:                /**
0964:                 * Returns the identifier of the method bound to this weaver.
0965:                 * @return identifier of the method bound to this weaver
0966:                 */
0967:                public int getTargetId() {
0968:                    return targetId;
0969:                }
0970:
0971:                /**
0972:                 * Returns the index of the target method in the array, which
0973:                 * will be returned by its declaring classes <CODE>getDeclaredMethods()
0974:                 * </CODE> method.
0975:                 * @return index in the array of declared methods
0976:                 */
0977:                public int getTargetIndex() {
0978:                    return targetIndex;
0979:                }
0980:
0981:                /**
0982:                 * Returns the status of this weaver. The codes are defined
0983:                 * in {@link ch.ethz.jvmai.MethodWeaver MethodWeaver}.
0984:                 * 
0985:                 * @return int status of the weaver
0986:                 */
0987:                public int getStatus() {
0988:                    return status;
0989:                }
0990:
0991:                /**
0992:                 * Redefine the method in this weaver.
0993:                 *
0994:                 * @param advice method that will be called instead
0995:                 *               or null to reset a redefined method.
0996:                 */
0997:                public void setRedefineAdvice(Member advice) {
0998:                    if (null != redefineAdvice && null != advice)
0999:                        throw new RuntimeException(
1000:                                "Method is already redefined");
1001:
1002:                    redefineAdvice = advice;
1003:                    setWatch(MWEAVER_STATUS_REDEFINE, null != advice);
1004:                }
1005:
1006:                /**
1007:                 * Enable method entry join point.
1008:                 *
1009:                 * @param flag enable/disable
1010:                 */
1011:                public void setMethodEntryEnabled(boolean flag) {
1012:                    setWatch(MWEAVER_STATUS_ENTRY_ENABLED, flag);
1013:                }
1014:
1015:                /**
1016:                 * Enable method entry join point.
1017:                 *
1018:                 * @param flag enable/disable
1019:                 */
1020:                public void setMethodExitEnabled(boolean flag) {
1021:                    setWatch(MWEAVER_STATUS_EXIT_ENABLED, flag);
1022:                }
1023:
1024:                /**
1025:                 * Add a method for which a callback should be woven (before each call).
1026:                 *
1027:                 * @param m watched method
1028:                 */
1029:                public void addMethodCall(Method m) {
1030:                    throw new JVMAIRuntimeException(
1031:                            "Method HotSwapAdvancedClassWeaver.addMethodCall() not implemented");
1032:                    //			String key = m.getDeclaringClass().getName() + "#" + m.getName();
1033:                    //			if( ! methodCalls.containsKey( key ) ) {
1034:                    //				methodCalls.put( key, m );
1035:                    //				addWatch(MWEAVER_STATUS_HAS_METHOD_CALL_WATCH);
1036:                    //			}
1037:                }
1038:
1039:                /**
1040:                 * Remove a method for which a callback was woven (before each call).
1041:                 *
1042:                 * @param m watched method
1043:                 */
1044:                public void removeMethodCall(Method m) {
1045:                    throw new JVMAIRuntimeException(
1046:                            "Method HotSwapAdvancedClassWeaver.removeMethodCall() not implemented");
1047:                    //			String key = m.getDeclaringClass().getName() + "#" + m.getName();
1048:                    //			if( methodCalls.containsKey( key ) ) {
1049:                    //				methodCalls.remove( key );
1050:                    //				if( methodCalls.isEmpty() )
1051:                    //					removeWatch(MWEAVER_STATUS_HAS_METHOD_CALL_WATCH);
1052:                    //			    else
1053:                    //			        setModified();
1054:                    //			}
1055:                }
1056:
1057:                /**
1058:                 * Add a method for which a callback should be woven (after each call).
1059:                 *
1060:                 * @param m watched method
1061:                 */
1062:                public void addMethodReturn(Method m) {
1063:                    throw new JVMAIRuntimeException(
1064:                            "Method HotSwapAdvancedClassWeaver.addMethodReturn() not implemented");
1065:                    //			String key = m.getDeclaringClass().getName() + "#" + m.getName();
1066:                    //			if( ! methodReturns.containsKey( key ) ) {
1067:                    //				methodReturns.put( key, m );
1068:                    //				addWatch(MWEAVER_STATUS_HAS_METHOD_RETURN_WATCH);
1069:                    //			}
1070:                }
1071:
1072:                /**
1073:                 * Remove a method for which a callback was woven (after each call).
1074:                 *
1075:                 * @param m watched method
1076:                 */
1077:                public void removeMethodReturn(Method m) {
1078:                    throw new JVMAIRuntimeException(
1079:                            "Method HotSwapAdvancedClassWeaver.removeMethodReturn() not implemented");
1080:                    //			String key = m.getDeclaringClass().getName() + "#" + m.getName();
1081:                    //			if( methodReturns.containsKey( key ) ) {
1082:                    //				methodReturns.remove( key );
1083:                    //				if( methodReturns.isEmpty() )
1084:                    //					removeWatch(MWEAVER_STATUS_HAS_METHOD_RETURN_WATCH);
1085:                    //				else
1086:                    //					setModified();
1087:                    //			}
1088:                }
1089:
1090:                /**
1091:                 * Add a field for which a callback should be woven (for each access).
1092:                 *
1093:                 * @param fw weaver for the watched field
1094:                 */
1095:                public void addFieldAccessor(HotSwapFieldWeaver fw) {
1096:                    String f = fw.getKey();
1097:                    //System.out.println("HotSwapClassWeaver.addFieldAccessor(" + f + ") to " + target.getName() );
1098:                    if (!fieldAccessors.containsKey(f)) {
1099:                        fieldAccessors.put(f, fw);
1100:                        addWatch(MWEAVER_STATUS_HAS_FIELD_ACCESS_WATCH);
1101:                    }
1102:                }
1103:
1104:                /**
1105:                 * Remove a field for which a callback was woven (for each access).
1106:                 *
1107:                 * @param fw weaver for the watched field
1108:                 */
1109:                public void removeFieldAccessor(HotSwapFieldWeaver fw) {
1110:                    String f = fw.getKey();
1111:                    if (fieldAccessors.containsKey(f)) {
1112:                        fieldAccessors.remove(f);
1113:                        if (fieldAccessors.isEmpty())
1114:                            removeWatch(MWEAVER_STATUS_HAS_FIELD_ACCESS_WATCH);
1115:                        else
1116:                            setModified();
1117:                    }
1118:                }
1119:
1120:                /**
1121:                 * Add a field for which a callback should be woven (for each modification).
1122:                 *
1123:                 * @param fw weaver for the watched field
1124:                 */
1125:                public void addFieldModifier(HotSwapFieldWeaver fw) {
1126:                    String f = fw.getKey();
1127:                    //System.out.println("HotSwapClassWeaver.addFieldModifier(" + f + ") to " + target.getName() );
1128:                    if (!fieldModifiers.containsKey(f)) {
1129:                        fieldModifiers.put(f, fw);
1130:                        addWatch(MWEAVER_STATUS_HAS_FIELD_MODIFICATION_WATCH);
1131:                    }
1132:                }
1133:
1134:                /**
1135:                 * Remove a field for which a callback was woven (for each modification).
1136:                 *
1137:                 * @param fw weaver for the watched field
1138:                 */
1139:                public void removeFieldModifier(HotSwapFieldWeaver fw) {
1140:                    String f = fw.getKey();
1141:                    if (fieldModifiers.containsKey(f)) {
1142:                        fieldModifiers.remove(f);
1143:                        if (fieldModifiers.isEmpty())
1144:                            removeWatch(MWEAVER_STATUS_HAS_FIELD_MODIFICATION_WATCH);
1145:                        else
1146:                            setModified();
1147:                    }
1148:                }
1149:
1150:                /**
1151:                 * Weave all registered field accesses/modifications.
1152:                 */
1153:                private void weaveFieldAdvice() {
1154:                    for (InstructionHandle h = instructions.getStart(); h != null; h = h
1155:                            .getNext()) {
1156:                        Instruction instr = h.getInstruction();
1157:
1158:                        if (instr instanceof  FieldInstruction) {
1159:                            FieldInstruction fi = (FieldInstruction) instr;
1160:                            String key = fi.getReferenceType(cpGen).toString()
1161:                                    + "#" + fi.getName(cpGen) + "#"
1162:                                    + fi.getSignature(cpGen);
1163:                            if ((instr instanceof  GETSTATIC || instr instanceof  GETFIELD)
1164:                                    && fieldAccessors.containsKey(key)) {
1165:                                // Field Access
1166:                                HotSwapFieldWeaver fieldWeaver = (HotSwapFieldWeaver) fieldAccessors
1167:                                        .get(key);
1168:                                // check if this is a watched field access
1169:                                if (null != fieldWeaver) {
1170:                                    //System.out.println("MethodWeaver.weaveFieldAdvice(): " + target + " GET " + key);
1171:
1172:                                    // weave the callback function call
1173:                                    instructions
1174:                                            .insert(
1175:                                                    h,
1176:                                                    createFieldAccessAdviceCallback(fieldWeaver));
1177:                                }
1178:                            } else if ((instr instanceof  PUTSTATIC || instr instanceof  PUTFIELD)
1179:                                    && fieldModifiers.containsKey(key)) {
1180:                                // Field modification
1181:                                HotSwapFieldWeaver fieldWeaver = (HotSwapFieldWeaver) fieldModifiers
1182:                                        .get(key);
1183:                                // check if this is a watched field modification
1184:                                if (null != fieldWeaver) {
1185:                                    // Store new value to a local variable
1186:                                    Type field_type = fi.getFieldType(cpGen);
1187:                                    // The use of the LocalVariableGen is faster
1188:                                    // than just using max local + 1 (Dont no why, but meassurements showed it.
1189:                                    int local_index = methodGen.getMaxLocals() + 1;
1190:                                    instructions.insert(h, InstructionFactory
1191:                                            .createStore(field_type,
1192:                                                    local_index));
1193:
1194:                                    //System.out.println("MethodWeaver.weaveFieldAdvice(): " + target + " PUT " + key);
1195:                                    // weaver the callback function call
1196:                                    instructions
1197:                                            .insert(
1198:                                                    h,
1199:                                                    createFieldModificationAdviceCallback(
1200:                                                            "doOnFieldModification",
1201:                                                            fieldWeaver,
1202:                                                            local_index));
1203:                                    // Load new value
1204:                                    instructions.insert(h,
1205:                                            InstructionFactory.createLoad(
1206:                                                    field_type, local_index));
1207:                                    methodGen.setMaxLocals(local_index
1208:                                            + field_type.getSize() - 1);
1209:                                }
1210:                            }
1211:                        }
1212:                    }
1213:                }
1214:
1215:                /**
1216:                 * Weave method redefine advice callback into method body and remove original
1217:                 * code.
1218:                 */
1219:                private void weaveRedefineAdvice() {
1220:                    //System.out.println("MethodWeaver.weaveRedefineAdvice(): " + target + " / " + redefineAdvice);
1221:
1222:                    // get advices class generator
1223:                    Class advice_class = redefineAdvice.getDeclaringClass();
1224:                    String adviceClassName = advice_class.getName();
1225:                    ClassGen adviceGen;
1226:                    try {
1227:                        adviceGen = new ClassGen(HotSwapAspectInterfaceImpl
1228:                                .getBCELClassDefinition(advice_class));
1229:                    } catch (ClassNotFoundException e) {
1230:                        throw new JVMAIRuntimeException(
1231:                                "can not read class file " + advice_class);
1232:                    }
1233:
1234:                    // get advices constant pool generator
1235:                    ConstantPoolGen advice_cpg = adviceGen.getConstantPool();
1236:
1237:                    // get advices generator (method generator)		
1238:                    org.apache.bcel.classfile.Method[] methods = adviceGen
1239:                            .getMethods();
1240:                    String adviceName = redefineAdvice.getName();
1241:                    MethodGen advice_mg = null;
1242:                    for (int i = 0; i < methods.length; i++)
1243:                        if (adviceName.equals(methods[i].getName())) {
1244:                            advice_mg = new MethodGen(methods[i],
1245:                                    adviceClassName, advice_cpg);
1246:                            i = methods.length;
1247:                        }
1248:                    if (null == advice_mg)
1249:                        throw new JVMAIRuntimeException("can not find method "
1250:                                + adviceClassName + "." + adviceName);
1251:
1252:                    methodGen.removeExceptionHandlers();
1253:
1254:                    // set targets method generator
1255:                    instructions = advice_mg.getInstructionList();
1256:                    methodGen.setInstructionList(instructions);
1257:                    methodGen.setMaxLocals(advice_mg.getMaxLocals());
1258:
1259:                    for (InstructionHandle h = instructions.getStart(); h != null; h = h
1260:                            .getNext()) {
1261:                        Instruction instr = h.getInstruction();
1262:
1263:                        // Transform local variable (and parameter) access.
1264:                        // Decrement each index by 1 because the first parameter was stripped.
1265:                        if (instr instanceof  LocalVariableInstruction) {
1266:                            LocalVariableInstruction lv_instr = (LocalVariableInstruction) instr;
1267:                            if (lv_instr.getIndex() == 0)
1268:                                throw new JVMAIRuntimeException(
1269:                                        "No (implicit) `this' usage allowed in advice method: "
1270:                                                + redefineAdvice);
1271:                            lv_instr.setIndex(lv_instr.getIndex() - 1);
1272:                        }
1273:
1274:                        // Transform constant pool references to constant pool of target class.
1275:                        // Add missing constant pool entries in target class.
1276:                        if (instr instanceof  CPInstruction) {
1277:                            CPInstruction cp_instr = (CPInstruction) instr;
1278:                            org.apache.bcel.classfile.Constant c = advice_cpg
1279:                                    .getConstant(cp_instr.getIndex());
1280:                            int new_index = cpGen.addConstant(c, advice_cpg);
1281:                            cp_instr.setIndex(new_index);
1282:                        }
1283:                    }
1284:
1285:                    // Curb exception handlers
1286:                    CodeExceptionGen[] cegs = advice_mg.getExceptionHandlers();
1287:                    for (int i = 0; i < cegs.length; i++) {
1288:                        CodeExceptionGen ceg = cegs[i];
1289:                        methodGen.addExceptionHandler(ceg.getStartPC(), ceg
1290:                                .getEndPC(), ceg.getHandlerPC(), ceg
1291:                                .getCatchType());
1292:                    }
1293:                }
1294:
1295:                /**
1296:                 * Weave method entry advice callback into method body.
1297:                 */
1298:                private void weaveMethodEntryAdvice() {
1299:                    //System.out.println("MethodWeaver.weaveMethodEntryAdvice(): " + target);
1300:                    InstructionHandle start = instructions.getStart();
1301:
1302:                    if (target instanceof  Constructor) {
1303:
1304:                        // JVM requires call to super constructors, to be done first,
1305:                        // but this works also when the callback is called first.
1306:                        // check if the constructor calls another constructor
1307:                        InstructionHandle h = usesSuper();
1308:                        if (null != h) {
1309:                            // call must be woven after the other constructor was called.
1310:                            h = instructions.append(h,
1311:                                    new PUSH(cpGen, targetId));
1312:                            instructions.append(h, instructionFactory
1313:                                    .createInvoke(JVMAI_CLASS,
1314:                                            "doOnConstructor", Type.VOID,
1315:                                            new Type[] { Type.INT },
1316:                                            Constants.INVOKESTATIC));
1317:                        } else {
1318:                            // Push parameter: int methodId
1319:                            instructions.insert(start,
1320:                                    new PUSH(cpGen, targetId));
1321:
1322:                            // Call advice
1323:                            instructions.insert(start, instructionFactory
1324:                                    .createInvoke(JVMAI_CLASS,
1325:                                            "doOnConstructor", Type.VOID,
1326:                                            new Type[] { Type.INT },
1327:                                            Constants.INVOKESTATIC));
1328:                        }
1329:                    } else {
1330:
1331:                        // Push parameter: int methodId
1332:                        instructions.insert(start, new PUSH(cpGen, targetId));
1333:
1334:                        // Call advice
1335:                        instructions.insert(start, instructionFactory
1336:                                .createInvoke(JVMAI_CLASS, "doOnMethodEntry",
1337:                                        Type.VOID, new Type[] { Type.INT },
1338:                                        Constants.INVOKESTATIC));
1339:                    }
1340:                }
1341:
1342:                /**
1343:                 * Checks if another constructor is called by a constructor.
1344:                 * The call is the first thing that a constructor does.
1345:                 * @return InstructionHandle of the call or null if no call
1346:                 *                   to another constructor was found
1347:                 */
1348:                private InstructionHandle usesSuper() {
1349:                    //System.out.println("MethodWeaver.usesSuper(): " + target);
1350:                    InstructionHandle handle = instructions.getStart();
1351:                    while (handle != null) {
1352:                        Instruction inst = handle.getInstruction();
1353:                        if (inst instanceof  INVOKESPECIAL) {
1354:                            return handle;
1355:                        }
1356:                        if (!(inst instanceof  StackProducer))
1357:                            break;
1358:                        handle = handle.getNext();
1359:                    }
1360:                    return null;
1361:                }
1362:
1363:                /**
1364:                 * Weave method exit advice callback into method body.
1365:                 */
1366:                private void weaveMethodExitAdvice() {
1367:                    //System.out.println("MethodWeaver.weaveMethodExitAdvice(): " + target);
1368:                    InstructionHandle try_start = instructions.getStart();
1369:                    InstructionHandle try_end = instructions.getEnd();
1370:                    InstructionHandle real_end;
1371:
1372:                    // Weave method exit advice (in a finally block)
1373:                    int local_index = methodGen.getMaxLocals();
1374:                    InstructionHandle finally_start = instructions
1375:                            .append(new ASTORE(local_index));
1376:                    // Push parameter: int methodId
1377:                    instructions.append(new PUSH(cpGen, targetId));
1378:                    // Push parameter: int local value index of the return value
1379:                    // actual local index + 3 because two additional local variables
1380:                    // will be created below.
1381:                    instructions.append(new PUSH(cpGen, local_index + 3));
1382:                    // Call advice
1383:                    instructions.append(instructionFactory.createInvoke(
1384:                            JVMAI_CLASS, "doOnMethodExit", Type.VOID,
1385:                            new Type[] { Type.INT, Type.INT },
1386:                            Constants.INVOKESTATIC));
1387:
1388:                    real_end = instructions.append(new RET(local_index++));
1389:
1390:                    // Insert exception handler before finally block
1391:                    InstructionHandle catch_start = instructions.insert(
1392:                            finally_start, new ASTORE(local_index));
1393:                    instructions.insert(finally_start, new JSR(finally_start));
1394:                    instructions
1395:                            .insert(finally_start, new ALOAD(local_index++));
1396:                    instructions.insert(finally_start, new ATHROW());
1397:
1398:                    // Jump to finally block before each return
1399:                    JumpFinallyVisitor visitor = new JumpFinallyVisitor(
1400:                            instructions, try_start, catch_start,
1401:                            finally_start, local_index);
1402:                    visitor.go();
1403:                    local_index += visitor.getLocalSize();
1404:
1405:                    methodGen.setMaxLocals(local_index);
1406:                    methodGen.addExceptionHandler(try_start, catch_start
1407:                            .getPrev(), catch_start, null);
1408:                }
1409:
1410:                /**
1411:                 * Create a field access advice callback that can be woven.
1412:                 *
1413:                 * @param fieldWeaver weaver for the field.
1414:                 * @return List of instructions that make up the callback.
1415:                 */
1416:                private InstructionList createFieldAccessAdviceCallback(
1417:                        HotSwapFieldWeaver fieldWeaver) {
1418:                    InstructionList il = new InstructionList();
1419:
1420:                    // Push parameter: Object owner
1421:                    if (Modifier.isStatic(fieldWeaver.getTarget()
1422:                            .getModifiers()))
1423:                        il.append(InstructionConstants.ACONST_NULL);
1424:                    else
1425:                        il.append(InstructionConstants.DUP);
1426:
1427:                    // Push parameter: int fieldId
1428:                    il.append(new PUSH(cpGen, fieldWeaver.getTargetId()));
1429:
1430:                    // Call advice
1431:                    il.append(instructionFactory.createInvoke(JVMAI_CLASS,
1432:                            "doOnFieldAccess", Type.VOID, new Type[] {
1433:                                    Type.OBJECT, Type.INT },
1434:                            Constants.INVOKESTATIC));
1435:
1436:                    return il;
1437:                }
1438:
1439:                /**
1440:                 * Create a field advice callback that can be woven.
1441:                 *
1442:                 * @param callbackMethod method that will be called.
1443:                 * @param fieldWeaver weaver for the field.
1444:                 * @param slot variable table index of the new value for the field
1445:                 * @return List of instructions that make up the callback.
1446:                 */
1447:                private InstructionList createFieldModificationAdviceCallback(
1448:                        String callbackMethod, HotSwapFieldWeaver fieldWeaver,
1449:                        int slot) {
1450:                    InstructionList il = new InstructionList();
1451:
1452:                    // Push parameter: Object owner
1453:                    if (Modifier.isStatic(fieldWeaver.getTarget()
1454:                            .getModifiers()))
1455:                        il.append(InstructionConstants.ACONST_NULL);
1456:                    else
1457:                        il.append(InstructionConstants.DUP);
1458:
1459:                    // Push parameter: int fieldId
1460:                    int fieldId = fieldWeaver.getTargetId();
1461:                    il.append(new PUSH(cpGen, fieldId));
1462:
1463:                    // push parameter: local variable index of the field
1464:                    il.append(new PUSH(cpGen, slot));
1465:
1466:                    // Call advice
1467:                    il.append(instructionFactory.createInvoke(JVMAI_CLASS,
1468:                            callbackMethod, Type.VOID, new Type[] {
1469:                                    Type.OBJECT, Type.INT, Type.INT },
1470:                            Constants.INVOKESTATIC));
1471:
1472:                    return il;
1473:                }
1474:
1475:                /**
1476:                 * Weave advice that are associated with the method in this weaver.
1477:                 * 
1478:                 * Called by {@link HotSwapAdvancedClassWeaver#weaveMethods()}.
1479:                 */
1480:                protected void weaveMethod() {
1481:                    if (MWEAVER_STATUS_UNCHANGED == status) {
1482:                        // Remove this weaver from all maps
1483:                        //System.out.println("MethodWeaverImpl.weaveMethod(): remove " + this.target.getName());
1484:                        HotSwapAdvancedClassWeaver.methodWeavers
1485:                                .remove(this .target);
1486:                        methods.remove(this .target);
1487:                    } else {
1488:                        // 1. Prepare
1489:                        initMethodWeaving();
1490:                        // 2. Redefine method
1491:                        if (null != redefineAdvice)
1492:                            weaveRedefineAdvice();
1493:                        // 3. Weave field advices
1494:                        if (hasWatch(MWEAVER_STATUS_HAS_FIELD_ACCESS_WATCH
1495:                                | MWEAVER_STATUS_HAS_FIELD_MODIFICATION_WATCH))
1496:                            weaveFieldAdvice();
1497:                        // 4. Weave method entry advice
1498:                        if (hasWatch(MWEAVER_STATUS_ENTRY_ENABLED))
1499:                            weaveMethodEntryAdvice();
1500:                        // 5. Weaver method exit advice
1501:                        if (hasWatch(MWEAVER_STATUS_EXIT_ENABLED))
1502:                            weaveMethodExitAdvice();
1503:                        // 6. Finish method weaving
1504:                        finishMethodWeaving();
1505:                    }
1506:                }
1507:
1508:                /**
1509:                 * Prepare for weaving by initializing the corresponding fields.
1510:                 * 
1511:                 * Called by {@link #weaveMethod()}.
1512:                 */
1513:                private void initMethodWeaving() {
1514:                    // 1. Get the method name
1515:                    String methodName;
1516:                    String signature;
1517:                    if (target instanceof  Constructor) {
1518:                        // the name of constructors is alway <init>
1519:                        methodName = "<init>";
1520:                        signature = JNIUtil.jniSignature((Constructor) target);
1521:                    } else { // target is a method
1522:                        methodName = target.getName();
1523:                        signature = JNIUtil.jniSignature((Method) target);
1524:                    }
1525:
1526:                    // 2. Create the BCEL MethodGen object
1527:                    if (0 > targetIndex) {
1528:                        // 2.a Try to get the BCEL method object
1529:                        methodGen = null;
1530:                        org.apache.bcel.classfile.Method[] meths = clGen
1531:                                .getMethods();
1532:                        // Iterate over all member methods of the class
1533:                        for (int i = 0; i < meths.length; i++) {
1534:                            // Check for 
1535:                            if (methodName.equalsIgnoreCase(meths[i].getName())
1536:                                    && signature
1537:                                            .equals(meths[i].getSignature())) {
1538:                                targetIndex = i;
1539:                                methodGen = new MethodGen(meths[i], methodName,
1540:                                        cpGen);
1541:                                break;
1542:                            }
1543:                        }
1544:                    } else {
1545:                        methodGen = new MethodGen(clGen
1546:                                .getMethodAt(targetIndex), methodName, cpGen);
1547:                    }
1548:
1549:                    if (null == methodGen)
1550:                        throw new RuntimeException("Method " + methodName
1551:                                + " not found");
1552:
1553:                    // create BCEL instructions list
1554:                    instructions = methodGen.getInstructionList();
1555:
1556:                }
1557:
1558:                /**
1559:                 * Clean up weaving process and replaces the method definition in ClassWeavers
1560:                 * class definition.
1561:                 * 
1562:                 * Called by {@link #weaveMethod()}
1563:                 */
1564:                private void finishMethodWeaving() {
1565:                    methodGen.setMaxStack();
1566:                    methodGen.setMaxLocals();
1567:                    methodGen.removeLocalVariables();
1568:                    methodGen.removeLineNumbers();
1569:                    methodGen.removeCodeAttributes();
1570:
1571:                    clGen.setMethodAt(methodGen.getMethod(), targetIndex);
1572:
1573:                    // release instructions
1574:                    instructions.dispose();
1575:                    instructions = null;
1576:                    methodGen = null;
1577:                }
1578:
1579:                /**
1580:                 *  Sets some variables to indicate that the target class
1581:                 *  must be woven at the next call of 
1582:                 *  {@link HotSwapAdvancedClassWeaver#commit()}.
1583:                 *  <P>
1584:                 *  This does not set the {@link #status} variable, which must
1585:                 *  be managed too.
1586:                 */
1587:                private void setModified() {
1588:                    if (!modified) {
1589:                        // synchronize with commit and resetAll
1590:                        synchronized (classWeavers) {
1591:                            modifiedClassWeavers
1592:                                    .add(HotSwapAdvancedClassWeaver.this );
1593:                            modified = true;
1594:                        }
1595:                    }
1596:                }
1597:
1598:                /**
1599:                 * Removes all modifications of the target method, so that it
1600:                 * will be restored to its original state after the next commitment
1601:                 * ({@link HotSwapAdvancedClassWeaver#commit()}).
1602:                 */
1603:                private void resetMethod() {
1604:                    setModified();
1605:                    status = MWEAVER_STATUS_UNCHANGED;
1606:
1607:                    redefineAdvice = null;
1608:                    //methodCalls.clear();
1609:                    //methodReturns.clear();
1610:                    fieldAccessors.clear();
1611:                    fieldModifiers.clear();
1612:                }
1613:
1614:            }
1615:        }
1616:
1617:        //======================================================================
1618:        //
1619:        // $Log$
1620:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.