move to native ptql impl

This commit is contained in:
Doug MacEachern 2007-04-16 01:35:12 +00:00
parent 3ffa2335c3
commit ff7fd11fac
17 changed files with 9 additions and 1594 deletions

View File

@ -3,12 +3,10 @@
<classpathentry kind="src" path="build/src"/>
<classpathentry kind="src" path="hyperic_jni/src"/>
<classpathentry kind="src" path="src"/>
<classpathentry sourcepath="/usr/src/jakarta/bcel-5.1/src/java/" kind="lib" path="lib/bcel-5.1.jar"/>
<classpathentry kind="lib" path="lib/junit.jar"/>
<classpathentry kind="lib" path="hyperic_jni/lib/cpptasks.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="/Developer/Java/Ant/lib/ant.jar"/>
<classpathentry kind="lib" path="lib/log4j.jar"/>
<classpathentry kind="lib" path="sigar-bin/lib/sigar.jar"/>
<classpathentry kind="output" path="build/classes"/>
</classpath>

Binary file not shown.

View File

@ -39,7 +39,6 @@ public class Runner {
private static final String JAR_EXT = ".jar";
static {
wantedJars.put("bcel", Boolean.FALSE);
wantedJars.put("junit", Boolean.FALSE);
wantedJars.put("log4j", Boolean.FALSE);
}

View File

@ -36,9 +36,8 @@ import org.hyperic.sigar.ProcStat;
*
* Example to display java processes only:<br>
* <code>% java -jar sigar-bin/lib/sigar.jar Top State.Name.eq=java</code>
*
* @see org.hyperic.sigar.ptql.ProcessQueryBuilder
*/
public class Top {
private static final int SLEEP_TIME = 1000 * 5;

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.hyperic.sigar.SigarException;
public class PidFileQuery extends PidQuery {
File file;
long modified = -1;
public PidFileQuery(String file) {
this.file = new File(file);
}
public long getPid()
throws SigarException {
if (!file.exists()) {
throw new SigarException(this.file + " does not exist");
}
long lastMod = file.lastModified();
if (lastMod == this.modified) {
return this.pid;
}
this.modified = lastMod;
String line;
try {
BufferedReader in =
new BufferedReader(new FileReader(this.file));
while ((line = in.readLine()) != null) {
line = line.trim();
if (line.length() != 0) {
break;
}
}
} catch (FileNotFoundException e) {
throw new SigarException(e.getMessage());
} catch (IOException e) {
throw new SigarException(e.getMessage());
}
int len = line.length();
StringBuffer number = new StringBuffer(len);
char[] chars = line.toCharArray();
for (int i=0; i<len; i++) {
char c = chars[i];
if (!Character.isDigit(c)) {
break;
}
number.append(c);
}
try {
this.pid = Long.parseLong(number.toString());
} catch (NumberFormatException e) {
throw new SigarException("Not a number: " + line);
}
return this.pid;
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarProxy;
public class PidQuery implements ProcessQuery {
protected long pid;
protected PidQuery() { }
public PidQuery(long pid) {
this.pid = pid;
}
public PidQuery(String pid) {
this.pid = Long.parseLong(pid);
}
public long getPid()
throws SigarException {
return this.pid;
}
public boolean match(SigarProxy sigar, long pid)
throws SigarException {
return pid == getPid();
}
}

View File

@ -45,18 +45,16 @@ public class ProcessFinder {
return findSingleProcess(processQuery);
} catch (MalformedQueryException e) {
throw new SigarException(e.getMessage());
} catch (QueryLoadException e) {
throw new SigarException(e.getMessage());
}
}
public long findSingleProcess(ProcessQuery query)
throws SigarException, SigarNotImplementedException,
MalformedQueryException {
if (query instanceof PidQuery) {
return ((PidQuery)query).getPid();
}
//XXX bring back in another form
//if (query instanceof PidQuery) {
// return ((PidQuery)query).getPid();
//}
int i, matches = 0;
@ -109,8 +107,6 @@ public class ProcessFinder {
try {
return finder.find(ProcessQueryFactory.getInstance(query));
} catch (QueryLoadException e) {
throw new SigarException(e.getMessage());
} catch (MalformedQueryException e) {
throw new SigarException(e.getMessage());
}
@ -127,8 +123,6 @@ public class ProcessFinder {
try {
return find(ProcessQueryFactory.getInstance(query));
} catch (QueryLoadException e) {
throw new SigarException(e.getMessage());
} catch (MalformedQueryException e) {
throw new SigarException(e.getMessage());
}

View File

@ -1,880 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.hyperic.sigar.NetFlags;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarProxy;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.BranchInstruction;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;
/**
* Build a Process Query using a PTQL string.
*
* Queries must be in the following format:
* <pre>
* Class.Attribute.operator=value
* </pre>
* Where:
* <ul>
* <li> <b>Class</b> is the name of the Sigar class minus the Proc prefix.
* <li> <b>Attribute</b> is an attribute of the given <b>Class</b>,
* index into an array or key in a Map class.
* <li> <b>operator</b> is one of the following for String values:
* <ul>
* <li> <b>eq</b> - Equal to <b>value</b>
* <li> <b>ne</b> - Not Equal to <b>value</b>
* <li> <b>ew</b> - Ends with <b>value</b>
* <li> <b>sw</b> - Starts with <b>value</b>
* <li> <b>ct</b> - Contains <b>value</b> (substring)
* <li> <b>re</b> - Regular expression <b>value</b> matches
* </ul>
* <li> <b>operator</b> is one of the following for numeric values:
* <ul>
* <li> <b>eq</b> - Equal to <b>value</b>
* <li> <b>ne</b> - Not Equal to <b>value</b>
* <li> <b>gt</b> - Greater than <b>value</b>
* <li> <b>ge</b> - Greater than or equal <b>value</b>
* <li> <b>lt</b> - Less than <b>value</b>
* <li> <b>le</b> - Less than or equal <b>value</b>
* </ul>
* </ul>
* Multiple queries must delimited by a comma.
* <p>
* Examples can be found in the sigar-bin/lib/.sigar_shellrc file of
* the Sigar distribution.
*/
public class ProcessQueryBuilder {
//set true during development to dump generated
//.class files to disk.
private static final boolean dumpClasses =
"true".equals(System.getProperty("sigar.ptql.dumpClasses"));
private static int generation = 0;
private static final String SIGAR_PACKAGE =
"org.hyperic.sigar.";
private static final String PROC_PREFIX =
SIGAR_PACKAGE + "Proc";
private static final String PROXY_CLASS =
SIGAR_PACKAGE + "SigarProxy";
private static final String PROXY_HELPER =
SIGAR_PACKAGE + "ptql.ProcessQueryHelper";
private static final String GENERATION_PACKAGE =
SIGAR_PACKAGE + "ptql.GENERATED.";
private static final String[] GENERATION_IMPL =
new String[] { ProcessQuery.class.getName() };
public static final Class[] NOPARAM =
new Class[] {};
static final char MOD_CLONE = 'C';
static final char MOD_PARENT = 'P';
static final char MOD_VALUE = 'V';
private static final HashMap INUMOPS;
private static final HashMap LNUMOPS;
private static final HashMap STROPS;
private static final HashMap IFMETHODS;
private InstructionFactory factory;
private ConstantPoolGen pool;
private ClassGen generator;
private String className;
//ProcessQuery.match method impl
private MethodGen query;
//query instructions (match method body)
private InstructionList qi = new InstructionList();
//branches of query method
private ArrayList branches = new ArrayList();
static final boolean COMPAT_1_4;
static {
//long
HashMap lnops = new HashMap();
lnops.put("eq", new Short(Constants.IFNE));
lnops.put("ne", new Short(Constants.IFEQ));
lnops.put("gt", new Short(Constants.IFGE));
lnops.put("ge", new Short(Constants.IFGT));
lnops.put("lt", new Short(Constants.IFLE));
lnops.put("le", new Short(Constants.IFLT));
LNUMOPS = lnops;
//int
HashMap inops = new HashMap();
inops.put("eq", new Short(Constants.IF_ICMPNE));
inops.put("ne", new Short(Constants.IF_ICMPEQ));
inops.put("gt", new Short(Constants.IF_ICMPGE));
inops.put("ge", new Short(Constants.IF_ICMPGT));
inops.put("lt", new Short(Constants.IF_ICMPLE));
inops.put("le", new Short(Constants.IF_ICMPLT));
INUMOPS = inops;
HashMap sops = new HashMap();
sops.put("ew", new StringOp("endsWith", Constants.IFEQ));
sops.put("sw", new StringOp("startsWith", Constants.IFEQ));
sops.put("eq", new StringOp("equals", Constants.IFEQ));
sops.put("ne", new StringOp("equals", Constants.IFNE));
sops.put("re", new StringOp("matches", Constants.IFEQ));
sops.put("ct", new StringOp("indexOf", Constants.IF_ICMPEQ));
STROPS = sops;
HashMap iftab = new HashMap();
Method[] methods = SigarProxy.class.getMethods();
for (int i=0; i<methods.length; i++) {
String name = methods[i].getName();
if (!name.startsWith("getProc")) {
continue;
}
Class[] params = methods[i].getParameterTypes();
//getProcFoo(long pid)
if (!((params.length == 1) &&
(params[0] == Long.TYPE)))
{
continue;
}
iftab.put(name.substring(7), methods[i]);
}
IFMETHODS = iftab;
boolean isCompat;
try {
Class.forName("java.net.SocketAddress");
isCompat = true;
} catch (ClassNotFoundException e) {
isCompat = false;
}
COMPAT_1_4 = isCompat;
}
public ProcessQueryBuilder() {
init();
}
public static Map getMethods() {
return IFMETHODS;
}
public static Set getMethodOpNames(Method method) {
if (method == null) {
return STROPS.keySet();
}
Class rtype = method.getReturnType();
if ((rtype == Character.TYPE) ||
(rtype == Double.TYPE) ||
(rtype == Integer.TYPE) ||
(rtype == Long.TYPE))
{
return LNUMOPS.keySet();
}
return STROPS.keySet();
}
public static boolean isSigarClass(Class type) {
return type.getName().startsWith(SIGAR_PACKAGE);
}
class QueryOp {
String op;
int flags;
boolean isParent = false;
boolean isClone = false;
boolean isValue = false;
public QueryOp(String val)
throws MalformedQueryException {
int i=0;
char c;
while (Character.isUpperCase((c = val.charAt(i)))) {
switch (c) {
case MOD_CLONE:
this.isClone = true;
break;
case MOD_PARENT:
this.isParent = true;
break;
case MOD_VALUE:
this.isValue = true;
break;
default:
String msg = "Unsupported modifier: " + c;
throw new MalformedQueryException(msg);
}
i++;
}
this.op = val.substring(i);
}
}
private void init() {
String name = genClassName();
this.className = GENERATION_PACKAGE + name;
this.generator =
new ClassGen(this.className,
"java.lang.Object",
className + ".java",
Constants.ACC_PUBLIC|Constants.ACC_SUPER,
GENERATION_IMPL);
this.pool = this.generator.getConstantPool();
this.factory = new InstructionFactory(this.generator,
this.pool);
createConstructor();
this.query =
new MethodGen(Constants.ACC_PUBLIC,
Type.BOOLEAN,
new Type[] { new ObjectType(PROXY_CLASS), Type.LONG },
new String[] { "sigar", "pid" }, "match", getClassName(),
this.qi, this.pool);
}
//arg 1 passed to ProcessQuery.match
private void loadSigarArg() {
this.qi.append(InstructionFactory.createLoad(Type.OBJECT, 1));
}
//arg 2 passed to ProcessQuery.match
private void loadPidArg() {
this.qi.append(InstructionFactory.createLoad(Type.LONG, 2));
}
private static synchronized String genClassName() {
return "PTQL" + generation++;
}
public String getClassName() {
return this.className;
}
private void createConstructor() {
InstructionList il = new InstructionList();
MethodGen method =
new MethodGen(Constants.ACC_PUBLIC,
Type.VOID, Type.NO_ARGS,
new String[] {}, "<init>",
getClassName(),
il, this.pool);
il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
il.append(this.factory.createInvoke("java.lang.Object",
"<init>",
Type.VOID, Type.NO_ARGS,
Constants.INVOKESPECIAL));
il.append(InstructionFactory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
this.generator.addMethod(method.getMethod());
il.dispose();
}
private void loadStandardArgs(QueryOp qop) {
if (qop.isParent) {
loadSigarArg();
}
loadSigarArg();
loadPidArg();
if (!qop.isParent) {
return;
}
//e.g. sigar.getProcState(pid).getName() is converted to:
// sigar.getProcState(sigar.getProcState(pid).getPpid()).getName()
final String procState = SIGAR_PACKAGE + "ProcState";
this.qi.append(this.factory.createInvoke(PROXY_CLASS,
"getProcState",
new ObjectType(procState),
new Type[] { Type.LONG },
Constants.INVOKEINTERFACE));
this.qi.append(this.factory.createInvoke(procState,
"getPpid",
Type.LONG, Type.NO_ARGS,
Constants.INVOKEVIRTUAL));
}
//e.g. sigar.getProcState(pid).getName()
//attrClass == "State"
//attr == "Name"
//type == Type.STRING (return type)
private void createStandardInvoker(String attrClass, String attr, Type type) {
this.qi.append(this.factory.createInvoke(PROXY_CLASS,
"getProc" + attrClass,
new ObjectType(PROC_PREFIX + attrClass),
new Type[] { Type.LONG },
Constants.INVOKEINTERFACE));
this.qi.append(this.factory.createInvoke(PROC_PREFIX + attrClass,
"get" + attr,
type, Type.NO_ARGS,
Constants.INVOKEVIRTUAL));
}
private MalformedQueryException unsupportedOp(String name) {
return new MalformedQueryException("Unsupported operator: " +
name);
}
private MalformedQueryException unsupportedMethod(String name) {
return new MalformedQueryException("Unsupported method: " +
name);
}
private MalformedQueryException unsupportedAttribute(String name) {
return new MalformedQueryException("Unsupported attribute: " +
name);
}
private StringOp getStringOp(String op)
throws QueryLoadException,
MalformedQueryException {
StringOp sop = (StringOp)STROPS.get(op);
if (sop == null) {
throw unsupportedOp(op);
}
if (!COMPAT_1_4) {
if (op.equals("re")) {
throw new QueryLoadException(op + " requires jdk 1.4+");
}
}
return sop;
}
private void createStringInvoker(String op)
throws QueryLoadException,
MalformedQueryException {
StringOp sop = getStringOp(op);
this.qi.append(this.factory.createInvoke("java.lang.String", sop.name,
sop.returnType, new Type[] { sop.type },
Constants.INVOKEVIRTUAL));
if (op.equals("ct")) {
this.qi.append(new PUSH(this.pool, -1));
}
BranchInstruction branch =
InstructionFactory.createBranchInstruction(sop.opcode, null);
this.qi.append(branch);
this.branches.add(branch);
}
//special case
public void appendProcPortOp(String flags, String op,
int protocol, long val)
throws MalformedQueryException {
//XXX flags current unused; could be used to narrow search scope.
QueryOp qop = new QueryOp(op);
loadSigarArg();
this.qi.append(new PUSH(this.pool, protocol));
this.qi.append(new PUSH(this.pool, val)); //port
this.qi.append(this.factory.createInvoke(PROXY_CLASS,
"getProcPort",
Type.LONG,
new Type[] {
Type.INT,
Type.LONG
},
Constants.INVOKEINTERFACE));
loadPidArg();
this.qi.append(InstructionConstants.LCMP);
Short sop = (Short)LNUMOPS.get(qop.op);
if (sop == null) {
throw unsupportedOp(qop.op);
}
BranchInstruction branch =
InstructionFactory.createBranchInstruction(sop.shortValue(), null);
this.qi.append(branch);
this.branches.add(branch);
}
//special case
public void appendEnvOp(String key, String op, String val)
throws QueryLoadException,
MalformedQueryException {
QueryOp qop = new QueryOp(op);
loadStandardArgs(qop);
this.qi.append(new PUSH(this.pool, key));
this.qi.append(this.factory.createInvoke(PROXY_HELPER,
"getProcEnv", Type.STRING,
new Type[] {
new ObjectType(PROXY_CLASS),
Type.LONG, Type.STRING
},
Constants.INVOKESTATIC));
this.qi.append(new PUSH(this.pool, val));
createStringInvoker(qop.op);
}
//special case
public void appendArgsOp(int idx, String op, String val)
throws QueryLoadException,
MalformedQueryException {
QueryOp qop = new QueryOp(op);
loadStandardArgs(qop);
this.qi.append(new PUSH(this.pool, idx));
this.qi.append(this.factory.createInvoke(PROXY_HELPER,
"getProcArg", Type.STRING,
new Type[] {
new ObjectType(PROXY_CLASS),
Type.LONG, Type.INT
},
Constants.INVOKESTATIC));
this.qi.append(new PUSH(this.pool, val));
createStringInvoker(qop.op);
}
public void appendArgsMatch(String op, String val)
throws QueryLoadException,
MalformedQueryException {
QueryOp qop = new QueryOp(op);
getStringOp(qop.op); //validate
loadStandardArgs(qop);
this.qi.append(new PUSH(this.pool, val));
this.qi.append(new PUSH(this.pool, qop.op));
this.qi.append(this.factory.createInvoke(PROXY_HELPER,
"argsMatch", Type.BOOLEAN,
new Type[] {
new ObjectType(PROXY_CLASS),
Type.LONG,
Type.STRING,
Type.STRING
},
Constants.INVOKESTATIC));
BranchInstruction branch =
InstructionFactory.createBranchInstruction(Constants.IFEQ, null);
this.qi.append(branch);
this.branches.add(branch);
}
public void appendStringOp(String attrClass, String attr,
String op, String val)
throws QueryLoadException,
MalformedQueryException {
QueryOp qop = new QueryOp(op);
loadStandardArgs(qop);
createStandardInvoker(attrClass, attr, Type.STRING);
if (qop.isValue) {
return;
}
if (qop.isClone) {
append(val, null);
}
else {
this.qi.append(new PUSH(this.pool, val));
}
createStringInvoker(qop.op);
}
public void appendNumberOp(String attrClass, String attr,
String op, int val)
throws MalformedQueryException {
appendNumberOp(attrClass, attr, op, Type.INT,
0, 0.0, val);
}
public void appendNumberOp(String attrClass, String attr,
String op, long val)
throws MalformedQueryException {
appendNumberOp(attrClass, attr, op, Type.LONG,
val, 0.0, 0);
}
public void appendNumberOp(String attrClass, String attr,
String op, double val)
throws MalformedQueryException {
appendNumberOp(attrClass, attr, op, Type.DOUBLE,
0, val, 0);
}
private void appendNumberOp(String attrClass, String attr,
String op, Type type,
long val, double dval, int ival)
throws MalformedQueryException {
HashMap nops;
if ((type == Type.INT) ||
(type == Type.CHAR))
{
nops = INUMOPS;
this.qi.append(new PUSH(this.pool, ival));
}
else if (type == Type.DOUBLE) {
nops = LNUMOPS;
this.qi.append(new PUSH(this.pool, dval));
}
else {
nops = LNUMOPS;
this.qi.append(new PUSH(this.pool, val));
}
QueryOp qop = new QueryOp(op);
loadStandardArgs(qop);
createStandardInvoker(attrClass, attr, type);
Short sop = (Short)nops.get(qop.op);
if (sop == null) {
throw unsupportedOp(qop.op);
}
if (type == Type.LONG) {
this.qi.append(InstructionConstants.LCMP);
}
else if (type == Type.DOUBLE) {
this.qi.append(InstructionConstants.DCMPL);
}
BranchInstruction branch =
InstructionFactory.createBranchInstruction(sop.shortValue(), null);
this.qi.append(branch);
this.branches.add(branch);
}
private void appendPidOp(String op, String val)
throws MalformedQueryException {
long longVal;
HashMap nops = LNUMOPS;
if (val.equals("$$")) {
loadSigarArg();
this.qi.append(this.factory.createInvoke(PROXY_CLASS,
"getPid",
Type.LONG, Type.NO_ARGS,
Constants.INVOKEINTERFACE));
}
else {
try {
longVal = Long.parseLong(val);
} catch (NumberFormatException e) {
String msg = "Pid value '" + val + "' is not a number";
throw new MalformedQueryException(msg);
}
this.qi.append(new PUSH(this.pool, longVal));
}
loadPidArg();
QueryOp qop = new QueryOp(op);
Short sop = (Short)nops.get(qop.op);
if (sop == null) {
throw unsupportedOp(qop.op);
}
this.qi.append(InstructionConstants.LCMP);
BranchInstruction branch =
InstructionFactory.createBranchInstruction(sop.shortValue(), null);
this.qi.append(branch);
this.branches.add(branch);
}
public void append(String branch, String val)
throws QueryLoadException,
MalformedQueryException {
QueryBranch qb = new QueryBranch(branch);
String attrClass=qb.attrClass, attr=qb.attr, op=qb.op;
if (attrClass.equals("Env")) {
appendEnvOp(attr, op, val);
}
else if (attrClass.equals("Args")) {
if (attr.equals("*")) {
//run op against all args
appendArgsMatch(op, val);
}
else {
int idx;
try {
idx = Integer.parseInt(attr);
} catch (NumberFormatException e) {
String msg = "Array index '" + attr + "' is not a number";
throw new MalformedQueryException(msg);
}
appendArgsOp(idx, op, val);
}
}
else if (attrClass.equals("Port")) {
int protocol;
long port;
try {
port = Long.parseLong(val);
} catch (NumberFormatException e) {
String msg = "Port value '" + val + "' is not a number";
throw new MalformedQueryException(msg);
}
try {
protocol = NetFlags.getConnectionProtocol(attr);
} catch (SigarException e) {
throw new MalformedQueryException(e.getMessage());
}
appendProcPortOp(attr, op, protocol, port);
}
else if (attrClass.equals("Pid")) {
appendPidOp(op, val);
}
else {
Method method = (Method)IFMETHODS.get(attrClass);
if (method == null) {
throw unsupportedMethod(attrClass);
}
Class subtype = method.getReturnType();
boolean isStringType = false;
if (isSigarClass(subtype)) {
try {
method = subtype.getMethod("get" + attr,
NOPARAM);
} catch (NoSuchMethodException e) {
throw unsupportedAttribute(attr);
}
if (method.getReturnType() == String.class) {
isStringType = true;
}
else if (method.getReturnType() == Character.TYPE) {
if (val.length() != 1) {
String msg = val + " is not a char";
throw new MalformedQueryException(msg);
}
int c = (int)val.charAt(0);
appendNumberOp(attrClass, attr, op, Type.CHAR,
0, 0.0, c);
return;
}
else if (method.getReturnType() == Double.TYPE) {
try {
double doubleVal = Double.parseDouble(val);
appendNumberOp(attrClass, attr, op, doubleVal);
return;
} catch (NumberFormatException e) {
String msg = val + " is not a double";
throw new MalformedQueryException(msg);
}
}
}
else {
isStringType = true;
}
if (!isStringType && Character.isDigit(val.charAt(0))) {
try {
long longVal = Long.parseLong(val);
appendNumberOp(attrClass, attr, op, longVal);
return;
} catch (NumberFormatException e) {
}
}
appendStringOp(attrClass, attr, op, val);
}
}
String addModifier(String key, char modifier)
throws MalformedQueryException {
int ix;
if ((ix = key.lastIndexOf(".")) < 0) {
throw new MalformedQueryException();
}
return key.substring(0, ix+1) + modifier +
key.substring(ix+1, key.length());
}
public void finish() {
this.qi.append(new PUSH(this.pool, 1));
BranchInstruction gotoBranch =
InstructionFactory.createBranchInstruction(Constants.GOTO, null);
this.qi.append(gotoBranch);
InstructionHandle target =
this.qi.append(new PUSH(this.pool, 0));
InstructionHandle retval =
this.qi.append(InstructionFactory.createReturn(Type.INT));
for (int i=0; i<this.branches.size(); i++) {
BranchInstruction branch =
(BranchInstruction)this.branches.get(i);
branch.setTarget(target);
}
gotoBranch.setTarget(retval);
this.query.setMaxStack();
this.query.setMaxLocals();
this.generator.addMethod(this.query.getMethod());
this.qi.dispose();
}
public ProcessQuery load()
throws QueryLoadException {
if (dumpClasses) {
try {
FileOutputStream os =
new FileOutputStream(getClassName() + ".class");
dump(os);
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] bytecode = this.generator.getJavaClass().getBytes();
ClassLoader parent = this.getClass().getClassLoader();
ClassLoader cl = new ProcessQueryClassLoader(parent, bytecode);
Class genclass;
try {
genclass = cl.loadClass(getClassName());
} catch (ClassNotFoundException e) {
throw new QueryLoadException("ClassNotFoundException: " +
e.getMessage());
}
try {
return (ProcessQuery)genclass.newInstance();
} catch (InstantiationException e) {
throw new QueryLoadException("InstantiationException: " +
e.getMessage());
} catch (IllegalAccessException e) {
throw new QueryLoadException("IllegalAccessException: " +
e.getMessage());
}
}
public void dump(OutputStream os) throws IOException {
this.generator.getJavaClass().dump(os);
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
class ProcessQueryClassLoader extends ClassLoader {
private byte[] bytecode;
ProcessQueryClassLoader(ClassLoader parent, byte[] bytecode) {
super(parent);
this.bytecode = bytecode;
}
public Class findClass(String name) throws ClassNotFoundException {
try {
return defineClass(name, this.bytecode, 0, this.bytecode.length);
} catch (ClassFormatError e) {
throw new ClassNotFoundException("Class Format Error", e);
}
}
}

View File

@ -18,131 +18,18 @@
package org.hyperic.sigar.ptql;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.StringTokenizer;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.util.ReferenceMap;
public class ProcessQueryFactory implements Comparator {
//for testing until native port is completed
private static final boolean useNative =
"true".equals(System.getProperty("sigar.ptql.native"));
public class ProcessQueryFactory {
private static Map cache =
ReferenceMap.synchronizedMap();
public ProcessQueryFactory() {}
//sort what will become instruction branches.
//so the cheapest are executed first.
private int getOrder(String s) {
if (s.startsWith("Port.")) {
return 11;
}
else if (s.startsWith("Env.")) {
return 10;
}
else if (s.startsWith("Args.")) {
return 9;
}
else if (s.startsWith("Exe.")) {
return 8;
}
else if (s.startsWith("State.")) {
return 7;
}
return 1;
}
public int compare(Object o1, Object o2) {
return getOrder((String)o1) -
getOrder((String)o2);
}
public ProcessQuery prepare(QueryBranchMap map)
throws MalformedQueryException,
QueryLoadException {
ProcessQueryBuilder builder = new ProcessQueryBuilder();
String[] keys =
(String[])map.keySet().toArray(new String[0]);
Arrays.sort(keys, this);
for (int i=0; i<keys.length; i++) {
String key = keys[i];
String val = (String)map.get(key);
if (val.charAt(0) == '$') {
String var = val.substring(1);
try {
int ix = Integer.parseInt(var);
//$1..n references
ix--;
if ((ix < 0) || (ix >= map.branches.size())) {
String msg = "Variable out of range " + var;
throw new MalformedQueryException(msg);
}
var = (String)map.branches.get(ix);
var = builder.addModifier(var,
ProcessQueryBuilder.MOD_VALUE);
key = builder.addModifier(key,
ProcessQueryBuilder.MOD_CLONE);
} catch (NumberFormatException e) {
var = System.getProperty(var, val);
}
val = var;
}
builder.append(key, val);
}
builder.finish();
return builder.load();
}
private static ProcessQuery getPidInstance(String query)
throws MalformedQueryException {
if (query.indexOf(",") > 0) {
throw new MalformedQueryException("Invalid Pid query");
}
String[] vals = QueryBranch.split(query);
QueryBranch branch = new QueryBranch(vals[0]);
String val = vals[1];
if (!branch.op.equals("eq")) {
throw new MalformedQueryException("Invalid Pid operator");
}
if (branch.attr.equals("PidFile")) {
return new PidFileQuery(val);
}
else if (branch.attr.equals("Service")) {
return new WindowsServiceQuery(val);
}
throw new MalformedQueryException("Unsupported method: " +
branch.attr);
}
public static ProcessQuery getInstance(String query)
throws MalformedQueryException,
QueryLoadException {
throws MalformedQueryException {
if (query == null) {
throw new MalformedQueryException("null query");
@ -158,36 +45,9 @@ public class ProcessQueryFactory implements Comparator {
return pQuery;
}
if (useNative) {
pQuery = new SigarProcessQuery();
((SigarProcessQuery)pQuery).create(query);
cache.put(query, pQuery);
return pQuery;
}
if (query.startsWith("Pid.PidFile.") ||
query.startsWith("Pid.Service."))
{
pQuery = getPidInstance(query);
cache.put(query, pQuery);
return pQuery;
}
QueryBranchMap queries = new QueryBranchMap();
StringTokenizer st = new StringTokenizer(query, ",");
while (st.hasMoreTokens()) {
String[] vals = QueryBranch.split(st.nextToken());
queries.put(vals[0], vals[1]);
}
ProcessQueryFactory factory = new ProcessQueryFactory();
pQuery = factory.prepare(queries);
cache.put(query, pQuery);
return pQuery;
}
}

View File

@ -1,148 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import java.util.Map;
import java.util.HashMap;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarNotImplementedException;
import org.hyperic.sigar.SigarProxy;
public class ProcessQueryHelper {
static HashMap stringMatchers = new HashMap();
static {
stringMatchers.put("eq", new StringEqMatcher());
stringMatchers.put("ne", new StringNeMatcher());
stringMatchers.put("sw", new StringSwMatcher());
stringMatchers.put("ew", new StringEwMatcher());
stringMatchers.put("re", new StringReMatcher());
stringMatchers.put("ct", new StringCtMatcher());
}
//avoid NPE if key does not exist.
public static String getProcEnv(SigarProxy proxy, long pid, String key)
throws SigarException, SigarNotImplementedException {
Map vars;
try {
vars = proxy.getProcEnv(pid);
} catch (SigarNotImplementedException e) {
throw e;
} catch (SigarException e) {
return "";
}
String val = (String)vars.get(key);
if (val == null) {
return "";
}
return val;
}
//avoid ArrayOutOfBoundsException
public static String getProcArg(SigarProxy proxy, long pid, int num)
throws SigarException, SigarNotImplementedException {
String[] args;
try {
args = proxy.getProcArgs(pid);
} catch (SigarNotImplementedException e) {
throw e;
} catch (SigarException e) {
return "";
}
//e.g. find last element of args: Args.-1.eq=weblogic.Server
if (num < 0) {
num += args.length;
}
if ((num >= args.length) ||
(num < 0)) {
return "";
}
return args[num];
}
public interface StringMatcher {
public boolean match(String left, String right);
}
static class StringEqMatcher implements StringMatcher {
public boolean match(String left, String right) {
return left.equals(right);
}
}
static class StringNeMatcher implements StringMatcher {
public boolean match(String left, String right) {
return !left.equals(right);
}
}
static class StringEwMatcher implements StringMatcher {
public boolean match(String left, String right) {
return left.endsWith(right);
}
}
static class StringSwMatcher implements StringMatcher {
public boolean match(String left, String right) {
return left.startsWith(right);
}
}
static class StringCtMatcher implements StringMatcher {
public boolean match(String left, String right) {
return left.indexOf(right) != -1;
}
}
static class StringReMatcher implements StringMatcher {
public boolean match(String left, String right) {
return StringPattern.matches(left, right);
}
}
public static boolean argsMatch(SigarProxy proxy, long pid,
String value, String op)
throws SigarException, SigarNotImplementedException {
String[] args = proxy.getProcArgs(pid);
StringMatcher matcher =
(StringMatcher)stringMatchers.get(op);
for (int i=0; i<args.length; i++) {
if (matcher.match(args[i], value)) {
return true;
}
}
return false;
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
class QueryBranch {
String attrClass;
String attr;
String op;
QueryBranch(String query)
throws MalformedQueryException {
StringTokenizer st = new StringTokenizer(query, ".");
try {
this.attrClass = st.nextToken();
} catch (NoSuchElementException e) {
throw new MalformedQueryException("Empty query");
}
try {
this.attr = st.nextToken();
} catch (NoSuchElementException e) {
throw new MalformedQueryException("Missing attribute");
}
try {
this.op = st.nextToken();
} catch (NoSuchElementException e) {
throw new MalformedQueryException("Missing operator");
}
}
static String[] split(String query)
throws MalformedQueryException {
String[] vals = new String[2];
int ix = query.indexOf('=');
if (ix < 0) {
throw new MalformedQueryException("Missing '='");
}
vals[0] = query.substring(0, ix);
vals[1] = query.substring(ix+1, query.length());
return vals;
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import java.util.ArrayList;
import java.util.HashMap;
public class QueryBranchMap extends HashMap {
ArrayList branches = new ArrayList();
public Object put(Object key, Object value) {
branches.add(key);
return super.put(key, value);
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
/**
* Exception for process queries which were
* parsed ok but whos class generation failed.
*/
public class QueryLoadException extends Exception {
public QueryLoadException() {
}
public QueryLoadException(String message) {
super(message);
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import org.apache.bcel.generic.Type;
class StringOp {
String name;
short opcode;
Type type = Type.STRING;
Type returnType = Type.BOOLEAN;
StringOp(String name, short opcode) {
this.name = name;
this.opcode = opcode;
if (name.equals("equals")) {
this.type = Type.OBJECT;
}
else if (name.equals("indexOf")) {
this.returnType = Type.INT;
}
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.sigar.ptql;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarProxy;
import org.hyperic.sigar.SigarException;
public class WindowsServiceQuery implements ProcessQuery {
private String name;
public WindowsServiceQuery(String name) {
this.name = name;
}
public boolean match(SigarProxy sigar, long pid)
throws SigarException {
return pid == sigar.getServicePid(this.name);
}
public static void main(String[] args) throws Exception {
Sigar sigar = new Sigar(); //load the .dll
System.out.println(sigar.getServicePid(args[0]));
}
}

View File

@ -27,7 +27,6 @@ import org.hyperic.sigar.ptql.ProcessQuery;
import org.hyperic.sigar.ptql.ProcessQueryFactory;
import org.hyperic.sigar.ptql.ProcessFinder;
import org.hyperic.sigar.ptql.MalformedQueryException;
import org.hyperic.sigar.ptql.QueryLoadException;
public class TestPTQL extends SigarTestCase {
@ -101,16 +100,12 @@ public class TestPTQL extends SigarTestCase {
//"Pid.Service.ne=Eventlog",
};
private static final String[] LOAD_FAIL_QUERIES = {
};
public TestPTQL(String name) {
super(name);
}
private int runQuery(SigarProxy proxy, String qs)
throws MalformedQueryException,
QueryLoadException,
SigarException {
ProcessQuery query;
@ -169,19 +164,6 @@ public class TestPTQL extends SigarTestCase {
}
}
private void testLoadFailure(SigarProxy proxy) throws Exception {
for (int i=0; i<LOAD_FAIL_QUERIES.length; i++) {
String qs = LOAD_FAIL_QUERIES[i];
try {
runQuery(proxy, qs);
fail(qs + " did not throw QueryLoadException");
} catch (QueryLoadException e) {
traceln(qs + ": " + e.getMessage());
assertTrue(qs + " QueryLoad", true);
}
}
}
public void testCreate() throws Exception {
SigarProxy proxy =
SigarProxyCache.newInstance(getSigar());
@ -193,7 +175,6 @@ public class TestPTQL extends SigarTestCase {
}
testMalformed(proxy);
testLoadFailure(proxy);
}
}