com.sun.btrace.api.impl.BTraceTaskImpl Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.btrace.api.impl;
import com.sun.btrace.comm.Command;
import java.io.File;
import java.io.PrintWriter;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sun.btrace.api.BTraceEngine;
import com.sun.btrace.api.BTraceTask;
import com.sun.btrace.comm.ErrorCommand;
import com.sun.btrace.comm.GridDataCommand;
import com.sun.btrace.comm.MessageCommand;
import com.sun.btrace.comm.NumberDataCommand;
import com.sun.btrace.comm.NumberMapDataCommand;
import com.sun.btrace.comm.RetransformClassNotification;
import com.sun.btrace.comm.StringMapDataCommand;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*
* @author Jaroslav Bachorik
*/
public class BTraceTaskImpl extends BTraceTask implements BTraceEngineImpl.StateListener {
final private static Pattern NAMED_EVENT_PATTERN = Pattern.compile("@OnEvent\\s*\\(\\s*\\\"(\\w.*)\\\"\\s*\\)", Pattern.MULTILINE);
final private static Pattern ANONYMOUS_EVENT_PATTERN = Pattern.compile("@OnEvent(?!\\s*\\()");
final private static Pattern UNSAFE_PATTERN = Pattern.compile("@BTrace\\s*\\(.*unsafe\\s*=\\s*(true|false).*\\)", Pattern.MULTILINE);
final private static Pattern NAME_ANNOTATION_PATTERN = Pattern.compile("@BTrace\\s*\\(.*name\\s*=\\s*\"(.*)\".*\\)", Pattern.MULTILINE);
final private static Pattern NAME_PATTERN = Pattern.compile("@BTrace.*?class\\s+(.*?)\\s+", Pattern.MULTILINE);
final private AtomicReference currentState = new AtomicReference(State.NEW);
final private Set stateListeners = new HashSet();
final private Set messageDispatchers = new HashSet();
final private static ExecutorService dispatcher = Executors.newSingleThreadExecutor();
private PrintWriter consoleWriter = new PrintWriter(System.out, true);
private String script;
private int numInstrClasses;
private boolean unsafe;
final private BTraceEngineImpl engine;
final private int pid;
public BTraceTaskImpl(int pid, BTraceEngine engine) {
this.pid = pid;
this.engine = (BTraceEngineImpl)engine;
this.engine.addListener(this);
}
@Override
public String getScript() {
return script != null ? script : "";
}
@Override
public String getName() {
Matcher m = NAME_ANNOTATION_PATTERN.matcher(getScript());
if (m.find()) {
return m.group(1);
} else {
m = NAME_PATTERN.matcher(getScript());
if (m.find()) {
return m.group(1);
}
}
return null;
}
@Override
public void setScript(String newValue) {
script = newValue;
Matcher m = UNSAFE_PATTERN.matcher(getScript());
if (m.find()) {
unsafe = Boolean.parseBoolean(m.group(1));
}
}
@Override
public void sendEvent(String event) {
engine.sendEvent(this, event);
}
@Override
public void sendEvent() {
engine.sendEvent(this);
}
@Override
public Set getNamedEvents() {
Set events = new HashSet();
Matcher matcher = NAMED_EVENT_PATTERN.matcher(getScript());
while (matcher.find()) {
events.add(matcher.group(1));
}
return events;
}
@Override
public boolean hasAnonymousEvents() {
Matcher matcher = ANONYMOUS_EVENT_PATTERN.matcher(getScript());
return matcher.find();
}
@Override
public boolean hasEvents() {
return getScript() != null && getScript().contains("@OnEvent");
}
public int getPid() {
return pid;
}
/**
* Property getter
* @return Returns the current state
*/
protected State getState() {
return currentState.get();
}
@Override
public int getInstrClasses() {
return EnumSet.of(State.INSTRUMENTING, State.RUNNING).contains(getState()) ? numInstrClasses : -1;
}
/**
* Listener management (can use {@linkplain WeakListeners} to create a new listener)
* @param listener {@linkplain StateListener} instance to add
*/
@Override
public void addStateListener(StateListener listener) {
synchronized (stateListeners) {
stateListeners.add(listener);
}
}
/**
* Listener management
* @param listener {@linkplain StateListener} instance to remove
*/
@Override
public void removeStateListener(StateListener listener) {
synchronized (stateListeners) {
stateListeners.remove(listener);
}
}
/**
* Dispatcher management (can use {@linkplain WeakListeners} to create a new listener)
* @param dispatcher {@linkplain StateListener} instance to add
*/
@Override
public void addMessageDispatcher(MessageDispatcher dispatcher) {
synchronized (messageDispatchers) {
messageDispatchers.add(dispatcher);
}
}
/**
* Dispatcher management
* @param dispatcher {@linkplain StateListener} instance to remove
*/
@Override
public void removeMessageDispatcher(MessageDispatcher dispatcher) {
synchronized (messageDispatchers) {
messageDispatchers.remove(dispatcher);
}
}
/**
* Starts the injected code using the attached {@linkplain BTraceEngine}
*/
@Override
public void start() {
setState(State.STARTING);
if (!engine.start(this)) {
setState(State.FAILED);
}
}
/**
* Stops the injected code running on the attached {@linkplain BTraceEngine}
*/
@Override
public void stop() {
if (getState() == State.RUNNING) {
if (!engine.stop(this)) {
setState(State.RUNNING);
}
}
}
/**
* @see BTraceEngine.StateListener#onTaskStart(net.java.visualvm.btrace.api.BTraceTask)
*/
@Override
public void onTaskStart(BTraceTask task) {
if (task.equals(this)) {
setState(State.RUNNING);
}
}
/**
* @see BTraceEngine.StateListener#onTaskStop(net.java.visualvm.btrace.api.BTraceTask)
*/
@Override
public void onTaskStop(BTraceTask task) {
if (task.equals(this)) {
setState(State.FINISHED);
}
}
@Override
public String getClassPath() {
StringBuilder sb = new StringBuilder();
for(String cpEntry : engine.getClasspathProvider().getClasspath(this)) {
if (sb.length() > 0) {
sb.append(File.pathSeparator);
}
sb.append(cpEntry);
}
return sb.toString();
}
@Override
public boolean isUnsafe() {
return unsafe;
}
void setState(State newValue) {
currentState.set(newValue);
fireStateChange();
}
void setInstrClasses(int value) {
numInstrClasses = value;
}
private void fireStateChange() {
Set toProcess = null;
synchronized (stateListeners) {
toProcess = new HashSet(stateListeners);
}
for (StateListener listener : toProcess) {
listener.stateChanged(getState());
}
}
void dispatchCommand(final Command cmd) {
final Set dispatchingSet = new HashSet();
synchronized(messageDispatchers) {
dispatchingSet.addAll(messageDispatchers);
}
dispatcher.submit(new Runnable() {
@Override
public void run() {
for(MessageDispatcher listener : dispatchingSet) {
switch (cmd.getType()) {
case Command.MESSAGE: {
listener.onPrintMessage(((MessageCommand)cmd).getMessage());
break;
}
case Command.RETRANSFORM_CLASS: {
listener.onClassInstrumented(((RetransformClassNotification)cmd).getClassName());
break;
}
case Command.NUMBER: {
NumberDataCommand ndc = (NumberDataCommand)cmd;
listener.onNumberMessage(ndc.getName(), ndc.getValue());
break;
}
case Command.NUMBER_MAP: {
NumberMapDataCommand nmdc = (NumberMapDataCommand)cmd;
listener.onNumberMap(nmdc.getName(), nmdc.getData());
break;
}
case Command.STRING_MAP: {
StringMapDataCommand smdc = (StringMapDataCommand)cmd;
listener.onStringMap(smdc.getName(), smdc.getData());
break;
}
case Command.GRID_DATA: {
GridDataCommand gdc = (GridDataCommand)cmd;
listener.onGrid(gdc.getName(), gdc.getData());
break;
}
case Command.ERROR: {
ErrorCommand ec = (ErrorCommand)cmd;
listener.onError(ec.getCause());
break;
}
}
}
}
});
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final BTraceTaskImpl other = (BTraceTaskImpl) obj;
if (this.pid != other.pid) {
return false;
}
if (this.getName() != other.getName() && (this.getName() == null || !this.getName().equals(other.getName()))) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 19 * hash + pid;
hash = 19 * hash + (this.getName() != null ? this.getName().hashCode() : 0);
return hash;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy