We have developed a COM Object which is an .exe file and runs as a service in background. We are trying to connect to the object using JACOB.
Introduction:
On start up create an activeXcomponent and call Connect method of the object. Connect method returns instance of the class (which is written inside COM object) by reference, here referred as "handle"
component=new ActiveXComponent("ServiceName.className");
Dispatch.call(component,FN_CONNECT,sourceType,additionalParams,handle);
This handle is stored in a class level variable. Instance of this JAVA Class is stored in a connection pool and is later used for future function calls. This is to ensure that the next calls are called on objects/pointers which are already initialized.
When data fetch call is to be initiated, it calls another method named fetchData and takes request as input. It returns error code and response by reference. The component object is referred through the instance of a JAVA class that was stored in the connection pool
Variant response = new Variant("", true); //String
Variant errorCode = new Variant(0, true);
Dispatch.call(component,FETCH_DATA,handle,functionCode,request,response,errorCode);
Problem statement:
Now while testing in local enviroment we found out that everthing works fine as expected and no exception is thrown. However in client enviroment we are getting following error:
Caused by: com.jacob.com.ComFailException: Can't map name to dispid: fetchData
at com.jacob.com.Dispatch.invokev(Native Method)
at com.jacob.com.Dispatch.invokev(Dispatch.java:625)
at com.jacob.com.Dispatch.callN(Dispatch.java:453)
at com.jacob.com.Dispatch.call(Dispatch.java:541)
We managed to notice that same code works fine at one attempt and fails in next restart. This behavior is completely random hence difficult to trace.
Points to note:
fetchData function exists with exactly same signature at both side.
Code runs fine at one point and misbehaves after restart.
We read somewhere, JACOB Library misbehaves in a multi-threaded enviroment. Is this true?
If yes, what should be done in order to make it work as expected.
If not, then why is this exception thrown randomly ?
Any idea/help/lead is useful. Thanks in advance!
This is not an answer to this specific situation, since the question is very old anyway - but just since I see it unanswered and I saw it in one of my searches, I'd like to give some pointers.
In my own experience, JACOB is okay when you use it correctly - so it can't be called "misbehaving".
In my specific scenario, again, since I am using JACOB to automate Microsoft Word, most of the problems we have been having stem from the fact that Office is not made to be automated on backend, window-less environments.
Link to a Microsoft article on early and late binding in COM automation
Other related threads on StackOverflow are:
JACOB library fails when used in multiple threads
Java - Jacob Multitheading
JACOB doesn't release the objects properly
In one of the above threads they mention an old archived article about JACOB and how they suggest to use it in multi-threaded environments.
Related
This question already has answers here:
Real time updates from database using JSF/Java EE
(3 answers)
Closed 7 years ago.
The normal way is calling database from java. But as per my scenario some third party application is doing inserts and my application is just reading. In that case is it possible to do something so that whenever there is new data or db data gets updated I want my java to get that data. i.e. any change in db would trigger my java class. By not running any process or threads i.e. like run a process every 2-5 mins to check db that would increase unnecessary load on server and also it wont be live that means anything comes to the db in mean time is missed.
There might be other good solutions to this problem (see my comment), but one possible quick & dirty trick is to write an insert/update trigger that writes the new inserted/updated data to a file.
Now, in order to make things synchronous, you can make that 'file' a named pipe (a FIFO), providing that you run on a *nix system. In this way, you can have the Java code doing a blocking read on the pipe and, every time there is a new insert/update, the MySQL will write to the pipe (be careful to avoid EOFs) and the consumer (your Java code) will unblock itself, process the new data, and then block again, avoiding unnecessary load.
I think there would be no way to do that.
(And belows may not be an answer but a recommend.)
It seems that java and other application connect DB simultaneiusly. I think the problem comes from here.
3rd party app should notify to my app ..
and my app should insert to DB and do what I want. Then there will be no problem like this and more flexible work we can do. And more safe..
There may be some other reason... but I hope you to consider this also..
I'm trying to change the page persistence in our XPages application, intending to move from "Keep pages in memory" to "Keep only the current page in memory". And of course I get run-time errors telling me that XPages cannot serialize a JavaScript function. But which function? The stack trace only shows the standard Java error stuff, but nothing about which variable or function cannot be serialized?
I had similar issues before, and it always cost me a lot of time to dig deep in the code and solve the problem. It takes ages... and I've really had it by now.
Is there a clever way to find out which function cannot be serialized??
UPDATE
What OpenLog Logger comes up with:
Client Version
Release 9.0.1FP3
January 12, 2015
Database aalto803.nsf
Agent /aASK.xsp
Method class java.lang.StackTraceElement.writeValue
Error Num -
Error Line 364
Error Msg Impossible de sérialiser une fonction JavaScript
Language Java
Stack Trace
java.io.IOException: Impossible de sérialiser une fonction JavaScript
at com.ibm.jscript.types.FBSValue.writeValue(FBSValue.java:364)
at com.ibm.jscript.types.FBSDefaultObject.writeExternal(FBSDefaultObject.java:746)
at com.ibm.jscript.std.ObjectObject.writeExternal(ObjectObject.java:106)
at java.io.ObjectOutputStream.writeExternalData(ObjectOutputStream.java:1462)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1179)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at java.util.HashMap.writeObject(HashMap.java:942)
at sun.reflect.GeneratedMethodAccessor51.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1020)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1502)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1433)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1179)
at java.io.ObjectOutputStream.writeUnshared(ObjectOutputStream.java:413)
at com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectOutputStream.writeObjectEx(AbstractSerializingStateManager.java:438)
at com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectOutputStream.writeObjectEx(AbstractSerializingStateManager.java:417)
at com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectOutputStream.writeObjectEx(AbstractSerializingStateManager.java:417)
at com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectOutputStream.writeObjectEx(AbstractSerializingStateManager.java:417)
at com.ibm.xsp.application.AbstractSerializingStateManager$FastObjectOutputStream.writeObjectEx(AbstractSerializingStateManager.java:417)
at com.ibm.xsp.application.AbstractSerializingStateManager.saveSerializedView(AbstractSerializingStateManager.java:294)
at com.ibm.xsp.application.AbstractSerializingStateManager.doSaveSerializedView(AbstractSerializingStateManager.java:269)
at com.ibm.xsp.application.FileStateManager.doSaveSerializedView(FileStateManager.java:290)
at com.ibm.xsp.application.FileStateManager.doSaveSerializedView(FileStateManager.java:270)
at com.ibm.xsp.application.AbstractStateManager.saveSerializedView(AbstractStateManager.java:114)
at com.ibm.xsp.application.StateManagerImpl.saveSerializedView(StateManagerImpl.java:152)
at com.ibm.xsp.application.ViewHandlerExImpl._saveViewState(ViewHandlerExImpl.java:455)
at com.ibm.xsp.application.ViewHandlerExImpl.saveViewState(ViewHandlerExImpl.java:449)
at com.ibm.xsp.application.ViewHandlerExImpl._renderView(ViewHandlerExImpl.java:324)
at com.ibm.xsp.application.ViewHandlerExImpl.renderView(ViewHandlerExImpl.java:336)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:103)
XPages OpenLog Logger not only catches uncaught exceptions (it sounds like this is one of those), but also catches which component triggered the problem. It needs an error XPage in the application (otherwise after the error occurs there is no Render Response phase run, from which XPages OpenLog Logger retrieves the details). That might help you track it down.
Otherwise, check what functions you're storing in viewScope etc. That might help you narrow things down. SSJS is not really designed for object orientated programming, which I think is where issues arise when storing functions in scope.
The answer to your question is not so much WHICH function can't be serialized, its that NONE of your functions can be serialized. OR if you want to get very technical, none can be expected to persist in any way reliably. SSJS is not meant to be serialized. In this blog post here: http://xomino.com/2014/03/26/why-learning-javascript-is-more-critical-to-xpage-developers-than-java/ there is a good discussion in the comments about why and where serialization is toxic, specifically with SSJS (you can sort of disregard the actual discussion surrounding the blog post of java vs JavaScript - just concentrate on the bits concerning serialization).
A recent discovery of mine answers this question too IMHO, see XPages: how to put a Java Date value in an ObjectObject . A few years back, I started with moving my code from SSJS to Java, and I had some (better: a lot of) trouble with the ObjectObject and ArrayObject classes, mostly with the rather ugly way values have to be converted using a class called FBSUtility.
My main issue was with the fact that I couldn't manage to store a Date in an ObjectObject object. In a later stage, I was happy to have found a call with a JSContext parameter, FBSUtility.wrap(jsContext, someDate), which permits storing a Date value. Call me clueless, about what the JSContext actually does here (which I am), but I thought that was the end to it.
Recently, in order to test our application, I changed the Persistence Mode, from a few pages in memory to everything on disk, hence forcing the serialization of all objects. I found out that a specific element of my application no longer worked, always stopping on a Serialization error. Further tests proved that there were no errors when I removed all Date values from the OO object.
Earlier, I had already adopted JsonJavaObject and JsonJavaArray classes for some other parts of the application (yeah I know, messy coding, big application, never time to do things right, 50 Mb template db, etc.). I rewrote the code to remove all use of the classes JSContext, FBSUtility, ObjectObject and ArrayObject, to replace them with the JsonJava classes, and there's no longer the dreaded message that a JS function cannot be serialized.
So, what I learned is: if your Persistence Mode is set to Keep pages on Disk or Keep only the current page in memory, try avoid ObjectObject objects and never use FBSUtility in combination with JSContext.
I'm running a multi-threaded Java application which gets requests to classify instances. In order to be able to run many threads concurrently my application shares a Classifier object and an Instances object among the threads. The Instances object contains only attributes' related data and does not have any instance associated with it.
When my application gets a classification request, I create an Instance object with the request's attributes data and set the pre-generated Instances object as the dataset using Instance.setDataset(), e.g.:
myNewInstance.setDataset(sharedInstances);
Then myNewInstance is sent to the shared Classifier.
It seems to work well in most cases. However sometimes when 2 concurrent requests occur, an exception is thrown from Classifier.distributionForInstance(). Unfortunately the error message is not clear, however these are 2 different exceptions I see:
Caused by: java.lang.RuntimeException: Queue is empty
at weka.core.Queue.pop(Queue.java:194)
at weka.filters.Filter.output(Filter.java:563)
at weka.filters.unsupervised.attribute.PrincipalComponents.convertInstance(PrincipalComponents.java:626)
at weka.filters.unsupervised.attribute.PrincipalComponents.input(PrincipalComponents.java:812)
at weka.classifiers.meta.RotationForest.convertInstance(RotationForest.java:1114)
at weka.classifiers.meta.RotationForest.distributionForInstance(RotationForest.java:1147)
Caused by: java.lang.NullPointerException
at weka.filters.unsupervised.attribute.Standardize.convertInstance(Standardize.java:238)
at weka.filters.unsupervised.attribute.Standardize.input(Standardize.java:142)
at weka.filters.unsupervised.attribute.PrincipalComponents.convertInstance(PrincipalComponents.java:635)
at weka.filters.unsupervised.attribute.PrincipalComponents.input(PrincipalComponents.java:812)
at weka.classifiers.meta.RotationForest.convertInstance(RotationForest.java:1114)
at weka.classifiers.meta.RotationForest.distributionForInstance(RotationForest.java:1147)
As you can see, when the latest happens it comes with an empty message string.
To my understanding I can't make the objects immutable, and I'd rather not wrap this part in a critical section in order to utilize the most out of the concurrency.
I've tried creating a different 'Instances' object per each classification request by using the constructor Instances(Instances dataset), however, it did not yield different results. Using a different Classifier is not an option since it takes too much time to construct the object and it needs to respond fast (10 to 20 milliseconds at most), and to my understanding the problem does not rely there.
I assume that the problem comes from using the same Instances object. Based on the documentation of Instances the constructor only copies the references to the header information which explains why the problem was not solved by creating another object. Is there an option to create a completely different Instances object based on a previous object without going over all attributes in realtime?
Any other performance-oriented solution will also be highly appreciated.
thanks!
Probably you have solved this issue by now. This is just for those who face a similar issue. I was testing instances in a multi-threaded Java application, and I faced the same exception. To break down the problem, there are two issues in your case:
The first one is that you are using the same Instances object where you are setting the data for each request. With this, you will most probably run into concurrency issues that might not break the code, but will yield wrong results. Because the data from different requests could get mixed up. Your best bet is to create a new Instances object for each request. However, this is not what is producing the exception you are facing. It is the second issue.
The second issue is that you are using the same Classifier, and this is what is producing the exception. In my case I had the classifiers built and serialized and written to a file since I constructed them. Once I need to classify a test set, I used to deserialize the object in each thread, giving me a new instance. However, a proper way to solve this issue would be to use the weka.classifiers.Classifier.makeCopy(model) static method to make a copy for each request, which internally uses serialization.
I work with Domino server and develop java agents. Usually i put external jar files into script library, but periodically get OutOfMemory. I extracted jar's from script library to jvm/lib/ext. I can get classes via ClassLoader, but can't via import statement.
What should i do to get it works via import statement?
Close Lotus Notes client and Designer.
Place the JARs to your local jvm/lib/ext.
Open Lotus Notes Client and Designer.
Now you can import the classes.
You can actually add the jar's to the Java Agent explicitly. Be aware that a Java Agent has no package name by default, and you'll need to quote the correct package name when quoting the package in the import statement. Importing jar's into agents is described here, and for version 8.5 here and here
Also, I suspect that you're not explicitly cleaning up you're java objects. The connection between the JVM and Domino memory heap is "weak". So you have to do you're own garbage collection on Domino objects in order to keep the server's memory clean. It's still black magic to me, but my understanding is that even though agents are supposed to "contain" the session and then release memory at termination, Domino objects not properly recycled can bleed Domino's heap memory. Below are my simple tips for keeping your memory clean:
1/ Keep the session object in a wrapper object. Create a class that has the Domino session object within it, (I called it SessionWrapper). Then declare the SessionWrapper object within the NotesMain method only, don't declare it at the class level. This SessionWrapper class will need to have it's own recycle method that calls Session.recycle(), and you'll need to call it at the end of NotesMain. The reason for this is explained in point #2. If you don't call any other methods within NotesMain, then you don't really need this wrapper. See point #4 about recycling the session.
2/ Pass the SessionWrapper to all methods where you require Domino access. Basically you're passing the session around in this wrapper class as a parameter. This is because we don't want to declare the session object at the class level. This is not ideal, but it will prevent memory leaks caused from keeping the session class at the class level.
3/ Agressive recycling. This has never made much sense to me until I saw this example loop
ViewEntryCollection vec = view.getAllEntries();
ViewEntry ve = vec.getFirstEntry();
While (ve!=null) {
ViewEntry veNext = vec.getNextEntry(ve);
// do stuff
ve.recycle;
ve = null;
ve = veNext;
}
See how the "ve" object is getting recycled and veNext is getting the next object. Basically you need to recycle every object once you're finished working with it, the "getNext" methods doesn't actually recycle the object in the Domino heap memory, if you don't recycle it, it's orphaned and Domino won't clean it up, and the server will eventually run out of memory for Domino objects. Note that I am not recycling veNext. I don't need to because I assign ve => veNext. "ve" will have a link to the same Domino object and I call recycle ve at the end of the loop. From this, you can see that many java objects can point to the same Domino instance object in the back end. If I tried to call veNext.recycle after ve.recycle, I would get an "Object has been removed or recycle" error.
4/ Recylce session at the end of the NotesMain. Make sure you call SessionWrapper.recycle() at the end of NotesMain to ensure you're releasing that bit of memory back to the server.
5/ Ensure that you're providing enough memory for the JVM on the server. See this technote. Also be aware of "HTTPJVMMaxHeapSizeSet=1" which is a strange setting to ensure memory settings "stick".. More about it here.
For many years IBM hasn't provided the internal cleanup tasks of objects that is so deperately needed to eliminate this overhead on developers. You're then required to explicitly deallocate memory which is also a performance hit to, but it's a necessary compromise for stability. These points are by no means exhaustive, but I found that stability with agents and servlets greatly improved when observing these rules.
I know that to interact from Javascript to Java you have to inject a Java object using the addjavascriptInterface method in webview.
Here is the problem I am facing.
I register a java object using addJavascriptInterface method to be available in my JS.
I inject few JS in the webview using webview.loadURL("javascript:XXX");
I send a JS event when I am done with injecting the JS.
The problem is that if immediately after step 1, if I execute the following Javascript:
mWebView.loadUrl("javascript:if(window.myobject) console.log('myobject found---------'); else {console.log('myobject not found----');}");
I get "myobject not found" in my console's log.
I want to know that if there is some time before I can access my object and if so, how do I get to know how much time should I wait to call my object?
I want to know that if there is some time before i can access my object
Yes, I think there is a delay, because WebView.addJavascriptInterface will run in the WebView's internal worker thread. Perhaps you've thought about this, and realized that WebView has to maintain at least one worker thread to do asynchronous network IO. Maybe you also noticed these threads in DDMS while using a WebView.
It turns out that it also uses a thread to do work for a number of other public methods. I really wish the docs from Google made this clearer! But I hope I can help and show you how I tried to confirm this for myself.
Follow me as I take a look at the source for WebView. It's reasonably readable, even if you can't follow exactly what's going on, it's possible to trace through answer some questions with respect to threads.
You can download the Android framework source through the SDK manager tool, but it's also mirrored on Github, so that's what I've linked to here. I guessed and picked a tag that's close to some version of ICS. It's not hard to find WebView.addJavascriptInterface. I just Googled "WebView.java site:github.com/android".
The method WebView.addJavascriptInterface sends a message to an instance of WebViewCore:
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
In WebViewCore.java there are a bunch of overloaded methods called sendMessage, but we don't really need to know which exactly is being called, since they do pretty much the same thing. There's even a nice comment to give us a hint that we're in the right place! All of them are delegating to an instance of EventHub which is some inner class. This method turns out to be synchronized, and is sending a message to an instance of Handler, which is a good indication that this is probably running in another thread, but for completeness sake, let's find out!
That Handler is instantiated in EventHub.transferMessages which is called from WebViewCore.initialize. There are a few more hops here, but eventually I found out that this is called from run in WebCoreThread (subclass of Runnable), which is instantiated along with a new Thread right here.
What an adventure! So, even though I really can't say for sure what's going on with all these moving parts, I am pretty confident to say that this method is not synchronous, and sends a message to the WebView's worker thread. I hope that makes sense!
if so, how do i get to know how much time should i wait to call my object?
Unfortunately, I don't know the answer to this. I was researching this exact issue and found this question on StackOverflow in the course of my Googling. I think you have the following options, some of which are nicer or easier than others:
1) Just Thread.sleep for 100 ms or something between addJavascriptInterface and loadUrl("javascript:..."). Blech, I don't like this, but it is potentially the easiest.
2) Another possibility is that you could call WebView.loadUrl with a snippet of JavaScript that specifically tests if the interface is set, and catches the ReferenceError that is thrown if it's not set yet. However, as you might have guessed, this kind of involves adding a JavaScript interface to the WebView!
3) Call WebView.setWebChromeClient instead, and catch JavaScript's alert() or console.log instead. From my experiments, this method is synchronous, so there is no delay. (I have confirmed this in source, but I'll leave details as an exercise for the reader) You should probably come up with some special string to call alert with and check for it inside onJsAlert, so you aren't just catching all alert()s.
Sorry for the length of this answer, I hope that helps. Good luck!
Ensure your Javascript objects declared in your HTML / Javascript that you need to access from Java are declared global otherwise they will most likely be collected. I have code that does this (where Android is my interface added with addJavascriptInterface):
<script>
var cb = function(location) {
alert('location is ' + location);
}
Android.getLocation('cb');
</script>
The getLocation method invokes Android's LocationManager.requestSingleUpdate which then invokes the callback when the LocationListener fires.
Without the "var" I find that by the time the location lookup invokes the callback the callback function has been garbage collected.
(copied from my response on a similar question)
I've taken Jason Shah's and Mr S's implementation as the building block for my fix and improved upon it greatly.
There's just far too much code to put into this comment I'll just link to it.
Details: http://twigstechtips.blogspot.com/2013/09/android-webviewaddjavascriptinterface.html
Source: https://github.com/twig/twigstechtips-snippets/blob/master/GingerbreadJSFixExample.java
Key points are:
Applies to all versions of Gingerbread (2.3.x)
Calls from JS to Android are now synchronous
No longer have to map out interface methods manually
Fixed possibility of string separators breaking code
Much easier to change JS signature and interface names