1 /*
   2  * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  *  @test
  26  *  @bug 4287595
  27  *  @bug 4462989
  28  *  @bug 4531511
  29  *  @summary Test class redefinition
  30  *
  31  *  @author Robert Field
  32  *
  33  *  @library ..
  34  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  35  *  @run compile -g RedefineTest.java
  36  *  @run shell RedefineSetUp.sh
  37  *  @run driver RedefineTest
  38  */
  39 import com.sun.jdi.*;
  40 import com.sun.jdi.event.*;
  41 import com.sun.jdi.request.*;
  42 import java.util.*;
  43 import java.io.*;
  44 
  45     /********** target program **********/
  46 
  47 class RedefineTarg {
  48     public static void show(String where){
  49         System.out.println("Returned: " + where);
  50     }
  51 
  52     public static void lastly(String where){
  53     }
  54 
  55     public static void main(String[] args){
  56         RedefineSubTarg sub = new RedefineSubTarg();
  57         String where = "";
  58         for (int i = 0; i < 5; ++i) {
  59             where = sub.foo(where);
  60             show(where);
  61         }
  62         lastly(where);
  63     }
  64 }
  65 
  66     /********** test program **********/
  67 
  68 public class RedefineTest extends TestScaffold {
  69     ReferenceType targetClass;
  70     static final String expected ="Boring Boring Different Boring Different ";
  71     int repetitionCount = 0;
  72     boolean beforeRedefine = true;
  73 
  74     RedefineTest (String args[]) {
  75         super(args);
  76     }
  77 
  78     public static void main(String[] args)      throws Exception {
  79         new RedefineTest(args).startTests();
  80     }
  81 
  82     /********** event handlers **********/
  83 
  84     public void methodEntered(MethodEntryEvent event) {
  85         Method meth = event.location().method();
  86         ThreadReference thread = event.thread();
  87 
  88         if (meth.name().equals("foo")) {
  89             ++repetitionCount;
  90             beforeRedefine = true;
  91             try {
  92                 expectNonObsolete(thread);
  93                 inspectLineNumber(event, thread.frame(0));
  94 
  95                 doRedefine(thread);
  96                 beforeRedefine = false;
  97 
  98                 switch (repetitionCount) {
  99                 case 1:
 100                 case 5:
 101                     expectNonObsolete(thread);
 102                     inspectLineNumber(event, thread.frame(0));
 103                     break;
 104                 case 2:
 105                 case 3:
 106                 case 4:
 107                     expectObsolete(thread);
 108                     inspectLineNumber(event, thread.frame(0));
 109                     break;
 110                 }
 111 
 112 
 113             } catch (Exception exc) {
 114                 failure("Test Failure: unexpected exception - " + exc);
 115                 exc.printStackTrace();
 116             }
 117         }
 118     }
 119 
 120     public void breakpointReached(BreakpointEvent event) {
 121         ThreadReference thread = event.thread();
 122         try {
 123             StackFrame frame = thread.frame(0);
 124             LocalVariable lv = frame.visibleVariableByName("where");
 125             Value vWhere = frame.getValue(lv);
 126             String remoteWhere = ((StringReference)vWhere).value();
 127             println("Value of where: " + remoteWhere);
 128             if (!remoteWhere.equals(expected)) {
 129                 failure("FAIL: expected result string: '" + expected +
 130                         "' got: '" + remoteWhere + "'");
 131             }
 132         } catch (Exception thr) {
 133             failure("Test Failure: unexpected exception: " + thr);
 134         }
 135     }
 136 
 137     /********** test assists **********/
 138 
 139     void expectNonObsolete(ThreadReference thread) throws Exception {
 140         if (isObsolete(thread)) {
 141             failure("FAIL: Method should NOT be obsolete");
 142         } else {
 143             println("as it should be, not obsolete");
 144         }
 145     }
 146 
 147     void expectObsolete(ThreadReference thread) throws Exception {
 148         if (isObsolete(thread)) {
 149             println("obsolete like it should be");
 150         } else {
 151             failure("FAIL: Method should be obsolete");
 152         }
 153     }
 154 
 155     void inspectLineNumber(LocatableEvent event, StackFrame frame) throws Exception {
 156         /*
 157          * For each value of repetitionCount, use the beforeRedefine
 158          * boolean to distinguish the time before and after the actual
 159          * redefinition takes place.  Line numbers are inspected both
 160          * before and after each redefine.
 161          */
 162         int n = -1;
 163         int expectedLine = -1;
 164         switch (repetitionCount) {
 165         case 1:
 166             expectedLine = 4;
 167             break;
 168         case 2:
 169             expectedLine = beforeRedefine ? 4:21;
 170             break;
 171         case 3:
 172             expectedLine = beforeRedefine ? 21:4;
 173             break;
 174         case 4:
 175             expectedLine = beforeRedefine ? 4:21;
 176             break;
 177         case 5:
 178             /* The class won't be redefined on this iteration (look
 179              * for a java.lang.UnsupportedOperationException instead)
 180              * so expected line stays the same as last successful
 181              * redefine.
 182              */
 183             expectedLine = 21;
 184             break;
 185         }
 186         Method method = event.location().method();
 187         if (frame.location().method().isObsolete()) {
 188             /*
 189              * Then skip. Obsolete methods are not interesting to
 190              * inspect.
 191              */
 192             println("inspectLineNumber skipping obsolete method " + method.name());
 193         } else {
 194             n = method.location().lineNumber();
 195             int m = frame.location().lineNumber();
 196             if ((n != expectedLine) || (n != m)) {
 197                 failure("Test Failure: line number disagreement: " +
 198                         n + " (event) versus " + m + " (frame) versus " + expectedLine +
 199                         " (expected)");
 200             } else {
 201                 println("inspectLineNumber in method " + method.name() + " at line " + n);
 202             }
 203         }
 204     }
 205 
 206     boolean isObsolete(ThreadReference thread) throws Exception {
 207         StackFrame frame = thread.frame(0);
 208         Method meth = frame.location().method();
 209         return meth.isObsolete();
 210     }
 211 
 212     void doRedefine(ThreadReference thread) throws Exception {
 213         Exception receivedException = null;
 214         String fileName = "notThis";
 215 
 216         switch (repetitionCount) {
 217         case 1:
 218             fileName = "RedefineSubTarg.class";
 219             break;
 220         case 2:
 221             fileName = "Different_RedefineSubTarg.class";
 222             break;
 223         case 3:
 224             fileName = "RedefineSubTarg.class";
 225             break;
 226         case 4:
 227             fileName = "Different_RedefineSubTarg.class";
 228             break;
 229         case 5:
 230             fileName = "SchemaChange_RedefineSubTarg.class";
 231             break;
 232         }
 233         File phyl = new File(fileName);
 234         byte[] bytes = new byte[(int)phyl.length()];
 235         InputStream in = new FileInputStream(phyl);
 236         in.read(bytes);
 237         in.close();
 238 
 239         Map map = new HashMap();
 240         map.put(findReferenceType("RedefineSubTarg"), bytes);
 241 
 242         println(System.getProperty("line.separator") + "Iteration # " + repetitionCount +
 243                 " ------ Redefine as: " + fileName);
 244         try {
 245             vm().redefineClasses(map);
 246         } catch (Exception thr) {
 247             receivedException = thr;
 248         }
 249         switch (repetitionCount) {
 250         case 5:
 251             if (receivedException == null) {
 252                 failure("FAIL: no exception; expected: UnsupportedOperationException");
 253             } else if (receivedException instanceof UnsupportedOperationException) {
 254                 println("Received expected exception: " + receivedException);
 255             } else {
 256                 failure("FAIL: got exception: " + receivedException +
 257                         ", expected: UnsupportedOperationException");
 258             }
 259             break;
 260         default:
 261             if (receivedException != null) {
 262                 failure("FAIL: unexpected exception: " +
 263                         receivedException);
 264             }
 265             break;
 266         }
 267         return;
 268     }
 269 
 270     /********** test core **********/
 271 
 272     protected void runTests() throws Exception {
 273 
 274         BreakpointEvent bpe = startToMain("RedefineTarg");
 275         targetClass = bpe.location().declaringType();
 276         EventRequestManager erm = vm().eventRequestManager();
 277 
 278         /*
 279          * Method entry in sub targ
 280          */
 281         MethodEntryRequest mee = erm.createMethodEntryRequest();
 282         mee.addClassFilter("RedefineSubTarg");
 283         mee.enable();
 284 
 285         /*
 286          * BP at end to get value
 287          */
 288         List lastlys = targetClass.methodsByName("lastly");
 289         if (lastlys.size() != 1) {
 290             throw new Exception ("TestFailure: Expected one 'lastly' method, found: " +
 291                                  lastlys);
 292         }
 293         Location loc = ((Method)(lastlys.get(0))).location();
 294         EventRequest req = erm.createBreakpointRequest(loc);
 295         req.enable();
 296 
 297         // Allow application to complete and shut down
 298         listenUntilVMDisconnect();
 299 
 300         /*
 301          * deal with results of test
 302          * if anything has called failure("foo") testFailed will be true
 303          */
 304         if (!testFailed) {
 305             println("RedefineTest: passed");
 306         } else {
 307             throw new Exception("RedefineTest: failed");
 308         }
 309     }
 310 }