Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java
41161 views
/*1* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package nsk.share.aod;2324import java.lang.instrument.*;25import java.io.*;26import nsk.share.*;2728/*2930AbstractJarAgent is base class for java agents used in AttachOnDemand tests31(tests against Attach API, API from package com.sun.tools.attach).3233In all AttachOnDemand tests the same algorithm is used:34- java application where agent is loaded to (target application) based on35class nsk.share.aod.TargetApplicationWaitingAgents starts and waits when36test agents will be loaded3738- special application (nsk.share.jvmti.aod.AgentsAttacher) loads test agents39in the target application using Attach API4041- when agent is loaded it notifies target application about that and executes42test-specific actions. When agent execution is completed it also notifies43target application about that4445- when all test agents finish execution target application checks its status46(passed or failed) and also finishes4748Each java agent should have method 'agentmain' where only agent initialization should be done,49main agent's actions should be executed in special thread started from 'agentmain'.50Class AbstractJarAgent incapsulates actions common for all java agents: agent initialization,51starting thread executing agent's actions and communication with target application.5253In most cases test agents should override only method 'agentActions' and its 'agentmain'54should contain only call of the method 'AbstractJarAgent.runJarAgent'.5556Typical agent class looks like this:5758public class agentExample extends AbstractJarAgent {5960protected void init(String[] args) {61// parse agent's options and do test-specific initialization62}6364protected void agentActions() {65// do test specific actions66}6768public static void agentmain(final String options, Instrumentation inst) {69new agentExample().runJarAgent(options, inst);70}71}72*/73abstract public class AbstractJarAgent {7475private boolean finishedSuccessfully = true;7677private Log log;7879protected void display(String message) {80log.display(outputPrefix + message);81}8283protected void complain(String message) {84log.complain(outputPrefix + message);85}8687protected void logThrowable(Throwable t) {88t.printStackTrace(log.getOutStream());89}9091/*92* Instrumentation object passed to the 'agentmain' method93*/94protected Instrumentation inst;9596private String name;9798private String outputPrefix;99100private String pathToNewByteCode;101102protected String pathToNewByteCode() {103return pathToNewByteCode;104}105106/*107* Subclasses should report about test failures using this method108*/109protected void setStatusFailed(String errorMessage) {110finishedSuccessfully = false;111complain("ERROR: " + errorMessage);112}113114/*115* Initialization method, called from agentmain before method agentActions is called116* (it introduced for overriding in subclasses)117*/118protected void init(String[] args) {119}120121protected static class AgentOption {122public String name;123public String value;124public AgentOption(String name, String value) {125this.name = name;126this.value = value;127}128}129130protected AgentOption parseAgentArgument(String arg) {131int index = arg.indexOf('=');132if (index <= 0) {133throw new TestBug("Invalid agent parameters format");134}135return new AgentOption(arg.substring(0, index), arg.substring(index + 1));136}137138static protected final String agentNameOption = "-agentName";139140static protected final String pathToNewByteCodeOption = "-pathToNewByteCode";141142/*143* Parse agent's options, initialize common parameters144*/145private void defaultInit(String[] args) {146for (int i = 0; i < args.length; i++) {147AgentOption option = parseAgentArgument(args[i]);148if (option.name.equals(agentNameOption)) {149name = option.value;150outputPrefix = name + ": ";151} else if (option.name.equals(pathToNewByteCodeOption)) {152pathToNewByteCode = option.value;153}154}155156if (name == null)157throw new TestBug("Agent name wasn't specified");158159log = new Log(System.out, true);160}161162/*163* Special thread which is started from agentmain method and executing main164* agent's actions. When agent completes execution AgentThread notifies165* target application about that.166*/167class AgentThread extends Thread {168169AgentThread() {170super("Jar agent thread (agent: " + name + ")");171}172173public void run() {174try {175agentActions();176} catch (Throwable t) {177setStatusFailed("Unexpected exception in the JarAgent: " + t);178logThrowable(t);179} finally {180TargetApplicationWaitingAgents.agentFinished(name, finishedSuccessfully);181}182}183}184185/*186* This methods parses agent's options, initializes agent, notifies target application187* that agent is started and starts thread executing main agent's actions.188* Agents used in AttachOnDemand tests should call this method from its agentmain methods.189*/190public final void runJarAgent(String options, Instrumentation inst) {191if (options == null)192throw new TestBug("Agent options weren't specified");193194this.inst = inst;195196String[] args = options.split(" ");197198// initialize common parameters199defaultInit(args);200201// test-specific initialization202init(args);203204// notify target application that agent was loaded and initialized205TargetApplicationWaitingAgents.agentLoaded(name);206207// start special thread executing test-specific actions208new AgentThread().start();209}210211/*212* Actions specific for test should be realized in this method.213* This method is called from special thread started from agentmain method214* after agent initialization215*/216abstract protected void agentActions() throws Throwable;217218219/*220* Create ClassDefinition object for given class, path to the new class file221* is specified in the parameter 'pathToByteCode'222*/223protected static ClassDefinition createClassDefinition(Class<?> klass,224String pathToByteCode) throws IOException {225File classFile = new File(pathToByteCode + File.separator +226klass.getName().replace(".", File.separator) +227".class");228229if (classFile.length() > Integer.MAX_VALUE)230throw new Failure("Class file '" + classFile.getName() + " 'too large");231232byte data[] = new byte[(int)classFile.length()];233234DataInputStream in = null;235try {236in = new DataInputStream(new FileInputStream(classFile));237in.readFully(data);238} finally {239if (in != null)240in.close();241}242243return new ClassDefinition(klass, data);244}245246/*247* Redefine given class using path to byte code specified with options -pathToNewByteCode248*/249protected void redefineClass(Class<?> klass) throws Throwable {250if (pathToNewByteCode() == null)251throw new TestBug("Path to new class files wasn't specified");252253ClassDefinition newClassDef = createClassDefinition(klass, pathToNewByteCode());254inst.redefineClasses(newClassDef);255}256}257258259