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