below the method and the unit test for that method.
The problem is that I'm not able to return the value of result from the Load method.
the unit test below fails!
I thought that by default JNA's object were ByRef by default so I tried instantiating and passing LoadResults "without" .ByReference ...
where is my mistake?
#Test
public void testLoad () {
MY_Processor proc = new MY_Processor();
// LoadResults result = new LoadResults ();
LoadResults.ByReference result = new LoadResults.ByReference();
ByteByReference [] pathToFile = new ByteByReference[256];
// fill pathToFile out ...
try {
proc.Load (pathToFile, result);
assertEquals(0, result.errorCode);
assertEquals(1, result.elaborationTime);
assertEquals(2, result.coreItem);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Integer Load ( ByteByReference[] pathToFile,
LoadResults.ByReference result ) throws Exception {
// here result is correctly filled out !
LoadResults result = null;
result = native.getResult (numCore);
}
added the native code.
UPDATE
// header
typedef struct
{
int errorCode;
int elaborationTime;
int coreItem;
} LoadResults;
//[in] path
//[out] result
int Load (char path[MY_BUFFER_DEFINE], LoadResults* result);
// implementation ...
LoadResults* getResult (int numCore)
{
// some check ...
LoadResults *localResult = new LoadResults();
// fill out ...
return localResult;
}
there is a "free" method exposed by the native code but I didn't show in order to keep the focus on my problem :-)
/UPDATE
thanks!
O.
The problem is that you're passing a Structure as a parameter, then reassigning that parameter within the function. That will have no effect whatsoever on the argument.
The pattern you need to follow is this:
Pointer p = mylib.getResult()
MyStructure m = new MyStructure(p);
// ....
mylib.free(p);
I'd recommend you pass in a native string (const char*) as your path rather than a fixed-size buffer of native char.
UPDATE
If you want to copy a result into the argument, then you'll need to copy the structure's contents, e.g.
public int Load(LoadResults arg) throws Exception {
// Effectively copy memory from result into arg
LoadResults result = native.getResult(numCore);
if (alternative_1) {
// Copy result's native memory into arg's memory, then sync Java fields
result.useMemory(arg.getPointer());
result.write();
arg.read();
}
else {
// Sync result's native memory with arg's Java fields
Pointer p = arg.getPointer();
arg.useMemory(result.getPointer());
arg.read();
arg.useMemory(p);
}
}
Just solved ...
1) I don't need to use LoadResults.ByReference.
2) the problem was that into the Load method I updated the reference passed in input with another one:
public Integer Load ( ByteByReference[] pathToFile, LoadResults result ) throws Exception
{
// that's the problem!!!! storing the value into another object with another "address"
// and not the original "results".
// result = native.getResult (numCore);
// solved with this:
native.getResult (numCore, result);
}
Related
I am trying to understand why a synchronized block is used in this method from the vertx handlebars library io.vertx.ext.web.templ.handlebars.impl.HandlebarsTemplateEngineImpl class:
#Override
public void render(Map<String, Object> context, String templateFile, Handler<AsyncResult<Buffer>> handler) {
try {
int idx = templateFile.lastIndexOf('/');
String prefix = "";
String basename = templateFile;
if (idx != -1) {
prefix = templateFile.substring(0, idx);
basename = templateFile.substring(idx + 1);
}
Template template = isCachingEnabled() ? cache.get(templateFile) : null;
if (template == null) {
synchronized (this) {
loader.setPrefix(prefix);
// Strip leading slash from Utils##normalizePath
template = handlebars.compile(basename);
if (isCachingEnabled()) {
cache.put(templateFile, template);
}
}
}
Context engineContext = Context.newBuilder(context).resolver(getResolvers()).build();
handler.handle(Future.succeededFuture(Buffer.buffer(template.apply(engineContext))));
} catch (Exception ex) {
handler.handle(Future.failedFuture(ex));
}
}
Please explain it to me like I'm an idiot!
First, synchronization questions are never "idiot" questions.
I spent some time looking at this code too, and still not 100% sure it's totally correct.
The main reason to have synchronized block here is to protect the following two methods from executing out of order:
loader.setPrefix(prefix);
...
template = handlebars.compile(basename);
You see, Handlebars has a reference to loader:
loader = new Loader(vertx);
...
handlebars = new Handlebars(loader);
Possible scenario without sync block would be
T1 sets prefix to A and switches
T2 sets prefix to B and switches
T1 compiles template with prefix set to B, while thinking it's still A
Here is an example of an issue I am having using reflection. This is a simple case, but what I eventually need is to dynamically build the method name on the fly... but even this simple case I can not get to work!
Client1 cData = (Client1) session.get(Client1.class, 1);
int cType = cData.getClientType();
int cType2 = -1;
Method method[] = null;
Method getCTypeMethod = null;
try {
method = cData.getClass().getMethods();
for (Method m : method){
System.out.println(m.getName()); // displays getClientType
}
getCTypeMethod = cData.getClass().getMethod("getClientType", int.class);
if (getCTypeMethod != null){
cType2 = (int) getCTypeMethod.invoke(cData, int.class);
}
} catch (Exception e) {
e.printStackTrace();
}
assertEquals(cType, cType2);
The line:
getCTypeMethod = cData.getClass().getMethod("getClientType", int.class);
Always throws an exception:
java.lang.NoSuchMethodException: Client1.getClientType(int)
The method getMethod receives the param classes, not the return type, your getClientType receive a int?
If not, try:
cData.getClass().getMethod("getClientType");
I've been using a system in which I could tack on as many parameters as I want and the method determines the data-type based on the object, this methods skeleton is as follows:
public void sendPacket(int id, Object... data) {
....
}
This has allowed me to easily send packets with all sorts of information, by just supplying the ID and then the data in the order that I wanted it to be sent over the network.
This became a problem when I needed to dynamically call sendPacket(Integer, Object);
Usually I know exactly how much data I need to pass to the sendPacket method, and I pass it manually, however in this case I don't know how many parameters I'm going to send, thus the amount of data I'm sending over the network is unknown.
The method I used to try to do this was to create an Object[] buffer which isn't doing what I wanted it to, example below:
Object[] buffer = new Object[list.size() * 3];
int bufferIndex = 0;
for(int i = 0; i < list.size(); i++) {
buffer[bufferIndex++] = list.get(i).getId();
buffer[bufferIndex++] = list.get(i).getName();
buffer[bufferIndex++] = list.get(i).getLevel();
}
sendPacket(5, true, list.size(), buffer);
This presents the following [DEBUG] output.
[DEBUG]: Packet ID: 5 Data Passed[Boolean]: true
[DEBUG]: Packet ID: 5 Data Passed[Integer]: 1
[Ljava.lang.Object;
The [Ljava.lang.Object output is because I have it setup to tell me the class-name of the Object that failed to be converted into usable data.
Here's an example as to how I'm currently interpreting the data being passed to sendPacket
for(Object o : data) {
if(o.getClass().getName().endsWith("Integer")) {
out.writeInt((int)o);
}
}
There's probably more efficient ways to figure out which type to cast the data to, so if you know one, that information would also be beneficial to myself.
Thanks for any help.
public class ConvertUtil {
private ConvertUtil() {}
private final static Map<Class<?>, Method> METHOD_MAP = new HashMap<Class<?>, Method>();
private static Logger log = LoggerFactory.getLogger(ConvertUtil.class);
static {
try {
METHOD_MAP.put(Byte.class, Byte.class.getMethod("valueOf", String.class));
METHOD_MAP.put(Short.class, Short.class.getMethod("valueOf", String.class));
METHOD_MAP.put(Integer.class, Integer.class.getMethod("valueOf", String.class));
METHOD_MAP.put(Long.class, Long.class.getMethod("valueOf", String.class));
METHOD_MAP.put(Boolean.class, Boolean.class.getMethod("valueOf", String.class));
METHOD_MAP.put(Float.class, Float.class.getMethod("valueOf", String.class));
METHOD_MAP.put(Double.class, Double.class.getMethod("valueOf", String.class));
METHOD_MAP.put(String.class, String.class.getMethod("valueOf", Object.class));
} catch (Exception e) {
log.error("ConvertUtil static is error" + e.getLocalizedMessage());
}
}
#SuppressWarnings("unchecked")
public static <T> T castValue(Object val, T defaultVal) {
Method method = METHOD_MAP.get(defaultVal.getClass());
try {
if (val != null && val instanceof String) {
defaultVal = (T) method.invoke(defaultVal.getClass(), val.toString());
}
if (val != null && val.getClass().getName().equals(defaultVal.getClass().getName())) {
defaultVal = (T) val;
}
} catch (Exception e) {
log.error("ConvertUtil castValue is error" + e.getLocalizedMessage());
}
return defaultVal;
}
}
using Jsoup, I extract JavaScript part in html file. and store it as java String Object.
and I want to extract function list, variables list in js's function using javax.script.ScriptEngine
JavaScript part has several function section.
ex)
function a() {
var a_1;
var a_2
...
}
function b() {
var b_1;
var b_2;
...
}
function c() {
var c_1;
var c_2;
...
}
My Goals is right below.
List funcList
a
b
c
List varListA
a_1
a_2
...
List varListB
b_1
b_2
...
List varListC
c_1
c_2
...
How can I extract function list and variables list(or maybe values)?
I think you can do this by using javascript introspection after having loaded the javascript in the Engine - e.g. for functions:
ScriptEngine engine;
// create the engine and have it load your javascript
Bindings bind = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Set<String> allAttributes = bind.keySet();
Set<String> allFunctions = new HashSet<String>();
for ( String attr : allAttributes ) {
if ( "function".equals( engine.eval("typeof " + attr) ) ) {
allFunctions.add(attr);
}
}
System.out.println(allFunctions);
I haven't found a way to extract the variables inside functions (local variables) without delving in internal mechanics (and thus unsafe to use) of the javascript scripting engine.
It is pretty tricky. ScriptEngine API seems not good for inspecting the code. So, I have such kind of pretty ugly solution with instance of and cast operators.
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
for (Map.Entry<String, Object> scopeEntry : bindings.entrySet()) {
Object value = scopeEntry.getValue();
String name = scopeEntry.getKey();
if (value instanceof NativeFunction) {
log.info("Function -> " + name);
NativeFunction function = NativeFunction.class.cast(value);
DebuggableScript debuggableFunction = function.getDebuggableView();
for (int i = 0; i < debuggableFunction.getParamAndVarCount(); i++) {
log.info("First level arg: " + debuggableFunction.getParamOrVarName(i));
}
} else if (value instanceof Undefined
|| value instanceof String
|| value instanceof Number) {
log.info("Global arg -> " + name);
}
}
I had similar issue. Maybe it will be helpfull for others.
I use groove as script lang. My Task was to retrive all invokable functions from the script. And then filter this functions by some criteria.
Unfortunately this approach is usefull only for groovy...
Get script engine:
public ScriptEngine getEngine() throws Exception {
if (engine == null)
engine = new ScriptEngineManager().getEngineByName(scriptType);
if (engine == null)
throw new Exception("Could not find implementation of " + scriptType);
return engine;
}
Compile and evaluate script:
public void evaluateScript(String script) throws Exception {
Bindings bindings = getEngine().getBindings(ScriptContext.ENGINE_SCOPE);
bindings.putAll(binding);
try {
if (engine instanceof Compilable)
compiledScript = ((Compilable)getEngine()).compile(script);
getEngine().eval(script);
} catch (Throwable e) {
e.printStackTrace();
}
}
Get functions from script. I did not found other ways how to get all invokable methods from script except Reflection. Yeah, i know that this approach depends on ScriptEngine implementation, but it's the only one :)
public List getInvokableList() throws ScriptException {
List list = new ArrayList();
try {
Class compiledClass = compiledScript.getClass();
Field clasz = compiledClass.getDeclaredField("clasz");
clasz.setAccessible(true);
Class scrClass = (Class)clasz.get(compiledScript);
Method[] methods = scrClass.getDeclaredMethods();
clasz.setAccessible(false);
for (int i = 0, j = methods.length; i < j; i++) {
Annotation[] annotations = methods[i].getDeclaredAnnotations();
boolean ok = false;
for (int k = 0, m = annotations.length; k < m; k++) {
ok = annotations[k] instanceof CalculatedField;
if (ok) break;
}
if (ok)
list.add(methods[i].getName());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
}
return list;
}
In my task i don't need all functions, for this i create custom annotation and use it in the script:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CalculatedField {
}
Script example:
import com.vssk.CalculatedField;
def utilFunc(s) {
s
}
#CalculatedField
def func3() {
utilFunc('Testing func from groovy')
}
Method to invoke script function by it's name:
public Object executeFunc(String name) throws Exception {
return ((Invocable)getEngine()).invokeFunction(name);
}
In Javascript i have the following code:
var r=applet.foo({var0:99,var1:'foo',var2:applet});
In my Java applet i have the following:
public JSObject foo(JSObject args){
System.out.println("The function is correctly invoked");
//In fact, the following works perfectly:
System.out.println("var1 is:"+(String)args.getMember("var1"));
JSObject w=JSObject.getWindow(this);
JSObject j=(JSObject)w.eval("new Object();");
Map m=new Hashmap();
//TODO here all the keys and values of args should be added to m
m.put("hello","world");
//TODO here all the keys and values of m should be added to j
return j;
}
How can this be done? (TODOs)
Reading http://docstore.mik.ua/orelly/web/jscript/ch19_06.html, i noticed theres a getSlot method for JSObject but if i do
args.getSlot(0)
all i have is one Exception:
netscape.javascript.JSException: No such slot 0 on JavaScript object
...
Unfortunately, Errandir's solution works only when you know a name of global variable that can be used to access an object you want to get properties' names of. You need to know this name to be able to add keys method to the object, and invoke it using JSObject's call method later. Of course, you can pass a global name of your object to Java if you have it. This solution doesn't look so good especially when you can't refer to your object in global context.
As an alternative, I proposed to use this of JSObject's eval method in the comment supposing that it will do all the work. And it does. But a big disappointent was that it works as expected only in Mozilla Firefox and Opera. In Internet Explorer 9 and Google Chrome (tested under Windows 7 and Ubuntu 12.04 LTS) this of eval method always refers to applet's document window ignoring which JavaScript object JSObject instance actually represents. I don't know whether it's a bug or simply LiveConnect is supported in these browsers very poorly.
The good news is that call method of JSObject executes specified function on the proper context. Keeping that in mind I finally found a solution how a list of names of JavaScript object's properties can be retrieved. The idea is to define a temporary function in global context using eval method. This function has to receive a JavaScript object we want to get properties of and to return names of these properties as an array. After that we can invoke the temporary function through JSObject's call method passing a Java representation of concerned JavaScript object (jsObject in my method below or args as it sounds in the question). At last, temporary function can be removed.
public static ArrayList<String> getJsObjectPropertiesNames(Applet applet, JSObject jsObject) {
if (applet == null || jsObject == null)
return null;
// Retrieving global context - a JSObject representing a window applet belongs to
JSObject globalContext;
try {
globalContext = JSObject.getWindow(applet);
}
catch (JSException ex) {
return null;
}
// Checking whether passed object is not an array
try {
jsObject.getSlot(0);
return null;
}
catch (JSException e) {
}
String keysFunctionName = String.format("_getKeys%d", Calendar.getInstance().getTimeInMillis());
jsObject.eval("window['" + keysFunctionName + "'] = function(jsObject) { return Object.keys(jsObject) }");
JSObject propertiesNamesJsObject = (JSObject)globalContext.call(keysFunctionName, new Object[] { jsObject });
jsObject.eval("delete(window['" + keysFunctionName + "'])");
ArrayList<String> propertiesNames = new ArrayList<>();
try {
int slotIndex = 0;
while (true) {
Object propertyName = propertiesNamesJsObject.getSlot(slotIndex);
if (propertyName instanceof String)
propertiesNames.add((String)propertyName);
slotIndex++;
}
}
catch (JSException e) {
}
return propertiesNames;
}
As a solution, you could define method keys as proposed here (You can do it within your java-code using JSObject.eval(...)). Then you could get keys like:
JSObject keys = (JSObject)args.call("keys", Collections.EMPTY_LIST);
keys.getSlot(0);
Here below I print a String, please modify it to get whatever you need.
public final static String getKeys = "{var keys = [];for (var key in this) {keys.push(key);} keys;}";
private static String printProperties(final Object o,
final boolean printType,
final int level,
final String tab) {
final StringBuilder sb = new StringBuilder(100);
if (printType) {
sb.append("(");
sb.append(o.getClass().getSimpleName());
sb.append(") ");
}
if (o instanceof JSObject) {
sb.append("{\n");
final JSObject js = (JSObject) o;
final JSObject keys = (JSObject) js.eval(getKeys);
boolean needComma = false;
for (int i = 0;; i++) {
final String key = (String) keys.getSlot(i);
if ((key != null) && !(key.equals("undefined"))) {
final Object val = js.getMember(key);
if (!needComma) {
needComma = true;
} else {
sb.append(",\n");
}
sb.append(multitab(tab, level));
sb.append(key);
sb.append(":");
sb.append(printProperties(val, printType, level + 1, tab));
} else {
break;
}
}
sb.append("\n");
sb.append(multitab(tab, level - 1));
sb.append("}");
} else {
sb.append(o);
}
return sb.toString();
}
private final static String tab = " ";
private static String multitab(final String tab,
int i) {
final StringBuilder sb = new StringBuilder();
while (i-- > 0) {
sb.append(tab);
}
return sb.toString();
}