-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
269 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
yourkit-probes/src/main/java/org/daisy/pipeline/yourkit/probes/XPath.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package org.daisy.pipeline.yourkit.probes; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import com.yourkit.probes.ObjectRowIndexMap; | ||
import com.yourkit.probes.OnEnterResult; | ||
import com.yourkit.probes.ReturnValue; | ||
import com.yourkit.probes.StringColumn; | ||
import com.yourkit.probes.Table; | ||
|
||
import com.yourkit.probes.MethodPattern; | ||
import com.yourkit.probes.Param; | ||
import com.yourkit.probes.This; | ||
|
||
public final class XPath { | ||
|
||
@MethodPattern("net.sf.saxon.lib.ExtensionFunctionDefinition:<init>()") | ||
public static final class ExtensionFunctionProbe { | ||
public static void onReturn(@This Object definition) { | ||
String qName = invoke(definition, "net.sf.saxon.lib.ExtensionFunctionDefinition", "getFunctionQName").toString(); | ||
EXTENSION_FUNCTIONS.createRow(definition, qName); | ||
} | ||
} | ||
|
||
@MethodPattern("*:makeCallExpression()") | ||
public static final class ExtensionFunctionCallExpressionProbe { | ||
public static void onReturn(@This Object definition, | ||
@ReturnValue Object call) { | ||
if (isInstanceOf(definition, "net.sf.saxon.lib.ExtensionFunctionDefinition")) | ||
EXTENSION_FUNCTIONS.assocCall(definition, call); | ||
} | ||
} | ||
|
||
@MethodPattern("*:call(*)") | ||
public static final class ExtensionFunctionCallProbe { | ||
public static int onEnter(@This Object call, | ||
@Param(1) Object context, | ||
@Param(2) Object arguments) { | ||
if (isInstanceOf(call, "net.sf.saxon.lib.ExtensionFunctionCall")) | ||
return EXTENSION_FUNCTION_CALLS.createRow(call, Arrays.toString((Object[])arguments)); | ||
else | ||
return Table.NO_ROW; | ||
} | ||
public static void onReturn(@OnEnterResult int row) { | ||
if (row != Table.NO_ROW) | ||
EXTENSION_FUNCTION_CALLS.closeRow(row); | ||
} | ||
} | ||
|
||
private static final ExtensionFunctionTable EXTENSION_FUNCTIONS = new ExtensionFunctionTable(); | ||
private static class ExtensionFunctionTable extends Table { | ||
public ExtensionFunctionTable() { | ||
super("XPath Extension Functions", Table.MASK_FOR_GENERIC_LASTING_EVENTS); | ||
} | ||
public final StringColumn QNAME = new StringColumn("QName"); | ||
private final ObjectRowIndexMap rows = new ObjectRowIndexMap(); | ||
public void createRow(Object definition, String qName) { | ||
int row = createRow(); | ||
rows.put(definition, row); | ||
QNAME.setValue(row, qName); | ||
} | ||
public int getRow(Object definition) { | ||
return rows.get(definition); | ||
} | ||
private final Map callToDefinition = new HashMap(); | ||
public void assocCall(Object definition, Object call) { | ||
callToDefinition.put(call, definition); | ||
} | ||
public int getRowForCall(Object call) { | ||
return getRow(callToDefinition.get(call)); | ||
} | ||
} | ||
|
||
private static final ExtensionFunctionCallTable EXTENSION_FUNCTION_CALLS = new ExtensionFunctionCallTable(); | ||
private static class ExtensionFunctionCallTable extends Table { | ||
public ExtensionFunctionCallTable() { | ||
super(EXTENSION_FUNCTIONS, "Calls", Table.MASK_FOR_SINGLE_METHOD_CALL_LASTING_EVENTS); | ||
} | ||
private final StringColumn INPUT = new StringColumn("Input"); | ||
public int createRow(Object call, String input) { | ||
int row = createRow(EXTENSION_FUNCTIONS.getRowForCall(call)); | ||
INPUT.setValue(row, input); | ||
return row; | ||
} | ||
} | ||
|
||
private static Object invoke(Object obj, String className, String methodName, Object... params) { | ||
Class c = obj.getClass(); | ||
while (!c.getName().equals(className)) | ||
c = c.getSuperclass(); | ||
Method method; | ||
Class[] paramTypes = new Class[params.length]; | ||
int i = 0; | ||
for (Object o : params) | ||
paramTypes[i++] = o.getClass(); | ||
try { | ||
method = c.getMethod(methodName, paramTypes); | ||
return method.invoke(obj, params); } | ||
catch (Exception e) { | ||
throw new RuntimeException(e); } | ||
} | ||
|
||
private static boolean isInstanceOf(Object obj, String className) { | ||
Class c = obj.getClass(); | ||
while (c != null) { | ||
if (c.getName().equals(className)) | ||
return true; | ||
c = c.getSuperclass(); } | ||
return false; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import javax.inject.Inject; | ||
|
||
import java.io.File; | ||
|
||
import java.util.Collections; | ||
import java.util.Hashtable; | ||
import java.util.Iterator; | ||
|
||
import javax.xml.namespace.NamespaceContext; | ||
import javax.xml.xpath.XPath; | ||
import javax.xml.xpath.XPathConstants; | ||
import javax.xml.xpath.XPathFactory; | ||
|
||
import net.sf.saxon.expr.XPathContext; | ||
import net.sf.saxon.lib.ExtensionFunctionCall; | ||
import net.sf.saxon.lib.ExtensionFunctionDefinition; | ||
import net.sf.saxon.om.Sequence; | ||
import net.sf.saxon.om.StructuredQName; | ||
import net.sf.saxon.trans.XPathException; | ||
import net.sf.saxon.value.SequenceType; | ||
import net.sf.saxon.value.StringValue; | ||
|
||
import org.daisy.pipeline.braille.liblouis.Liblouis; | ||
|
||
import static org.daisy.pipeline.pax.exam.Options.brailleModule; | ||
import static org.daisy.pipeline.pax.exam.Options.felixDeclarativeServices; | ||
import static org.daisy.pipeline.pax.exam.Options.forThisPlatform; | ||
import static org.daisy.pipeline.pax.exam.Options.logbackBundles; | ||
import static org.daisy.pipeline.pax.exam.Options.logbackConfigFile; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
|
||
import org.ops4j.pax.exam.Configuration; | ||
import org.ops4j.pax.exam.junit.PaxExam; | ||
import org.ops4j.pax.exam.Option; | ||
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; | ||
import org.ops4j.pax.exam.spi.reactors.PerClass; | ||
import org.ops4j.pax.exam.util.PathUtils; | ||
|
||
import static org.ops4j.pax.exam.CoreOptions.bootDelegationPackage; | ||
import static org.ops4j.pax.exam.CoreOptions.junitBundles; | ||
import static org.ops4j.pax.exam.CoreOptions.mavenBundle; | ||
import static org.ops4j.pax.exam.CoreOptions.options; | ||
import static org.ops4j.pax.exam.CoreOptions.vmOption; | ||
|
||
import org.osgi.framework.BundleContext; | ||
|
||
import org.xml.sax.InputSource; | ||
|
||
@RunWith(PaxExam.class) | ||
@ExamReactorStrategy(PerClass.class) | ||
public class ProbesTest { | ||
|
||
@Inject | ||
Liblouis liblouis; | ||
|
||
@Test | ||
public void testLiblouisTranslation() { | ||
assertEquals("foobar", | ||
liblouis.translate("file:" + PathUtils.getBaseDir() + "/target/test-classes/foobar.cti", | ||
"foobar", false, null)); | ||
} | ||
|
||
@Inject | ||
BundleContext context; | ||
|
||
@Test | ||
public void testCustomXPathFunction() throws Exception { | ||
context.registerService( | ||
ExtensionFunctionDefinition.class.getName(), | ||
new ExtensionFunctionDefinition() { | ||
public StructuredQName getFunctionQName() { | ||
return new StructuredQName("ex", "http://example.net/ns", "foo"); | ||
} | ||
public SequenceType[] getArgumentTypes() { | ||
return new SequenceType[] {}; | ||
} | ||
public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { | ||
return SequenceType.SINGLE_STRING; | ||
} | ||
public ExtensionFunctionCall makeCallExpression() { | ||
return new ExtensionFunctionCall() { | ||
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { | ||
return new StringValue("foobar"); | ||
} | ||
}; | ||
} | ||
}, | ||
new Hashtable<String,Object>()); | ||
|
||
// Don't use @Inject here because the ExtensionFunctionDefinition binding on | ||
// org.daisy.common.xpath.saxon.XPathFactoryImpl is static, which means that the injected xpathFactory | ||
// would not have the custom function registered. | ||
XPathFactory xpathFactory = (XPathFactory)context.getService(context.getServiceReference(XPathFactory.class.getName())); | ||
XPath xpath = xpathFactory.newXPath(); | ||
xpath.setNamespaceContext( | ||
new NamespaceContext() { | ||
public String getNamespaceURI(String prefix) { | ||
return "ex".equals(prefix) ? "http://example.net/ns" : null; } | ||
public String getPrefix(String namespaceURI) { | ||
return null; } | ||
public Iterator<String> getPrefixes(String namespaceURI) { | ||
return Collections.emptyIterator(); } | ||
} | ||
); | ||
assertEquals("foobar", xpath.compile("ex:foo()").evaluate(null, XPathConstants.STRING)); | ||
} | ||
|
||
@Configuration | ||
public Option[] config() { | ||
File probeClasspath = new File(PathUtils.getBaseDir() + "/target/classes"); | ||
return options( | ||
vmOption("-agentpath:${yourkit.home}/bin/mac/libyjpagent.jnilib=" | ||
+ "dir=" + PathUtils.getBaseDir() + "/target/yourkit" | ||
+ ",onexit=memory" | ||
+ ",probeclasspath=" + probeClasspath | ||
+ ",probe=org.daisy.pipeline.yourkit.probes.Liblouis" | ||
+ ",probe=org.daisy.pipeline.yourkit.probes.XPath" | ||
), | ||
vmOption("-Xbootclasspath/a:" + probeClasspath), | ||
bootDelegationPackage("org.daisy.pipeline.yourkit.probes"), | ||
logbackConfigFile(), | ||
logbackBundles(), | ||
felixDeclarativeServices(), | ||
mavenBundle().groupId("com.google.guava").artifactId("guava").versionAsInProject(), | ||
mavenBundle().groupId("net.java.dev.jna").artifactId("jna").versionAsInProject(), | ||
mavenBundle().groupId("org.liblouis").artifactId("liblouis-java").versionAsInProject(), | ||
brailleModule("common-java"), | ||
brailleModule("liblouis-core"), | ||
forThisPlatform(brailleModule("liblouis-native")), | ||
mavenBundle().groupId("org.daisy.libs").artifactId("saxon-he").versionAsInProject(), | ||
mavenBundle().groupId("org.daisy.pipeline").artifactId("saxon-adapter").versionAsInProject(), | ||
junitBundles() | ||
); | ||
} | ||
} |