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