I have to interface a third party COM API into an Java application. So I decided to use Com4j, and so far I've been satisfied, but now I've run into a problem.
After running the tlbgen I have an object called IAddressCollection which according to the original API documentation conforms to the IEnum interface definition. The object provides an iterator() function that returns a java.util.Iterator<Com4jObject>. The object comes from another object called IMessage when I want to find all the addresses for the message. So I would expect the code to work like this:
IAddressCollection adrCol = IMessage.getAddressees();
Iterator<Com4jObject> adrItr = adrCol.iterator();
while(adrItr.hasNext()){
Com4jObject adrC4j = adrItr.next();
// normally here I would handle the queryInterface
// and work with the rest of the API
}
My problem is that when I attempt the adrItr.next() nothing happens, the code stops working but hangs. No exception is thrown and I usually have to kill it through the task manager. So I'm wondering is this a problem that is common with Com4j, or am I handling this wrong, or is it possibly a problem with the API?
Ok, I hate answering my own question but in this case I found the problem. The issue was the underlying API. The IAddressCollection uses a 1 based indexing instead of a 0 based as I would have expected. It didn't provide this information in the API documentation. There is an item function where I can pull the object this way and so I can handle this with
IAddressCollection adrCol = IMessage.getAddressees();
for(int i = 1; i <= adrCol.count(); i++){
IAddress adr = adrCol.item(i);
// IAddress is the actual interface that I wanted and this works
}
So sorry for the annoyance on this.
Related
I am running a hierachical Spring Statemachine and - after walking through the inital transitions into state UP with the default substate STOPPED - want to use statemachine.getState(). Trouble is, it gives me only the parent state UP, and I cannot find an obvious way to retrieve both the parent state and the sub state.
The machine has states constructed like so:
StateMachineBuilder.Builder<ToolStates, ToolEvents> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial(ToolStates.UP)
.state(ToolStates.UP, new ToolUpEventAction(), null)
.state(ToolStates.DOWN
.and()
.withStates()
.parent(ToolStates.UP)
.initial(ToolStates.STOPPED)
.state(ToolStates.STOPPED,new ToolStoppedEventAction(), null )
.state(ToolStates.IDLE)
.state(ToolStates.PROCESSING,
new ToolBeginProcessingPartAction(),
new ToolDoneProcessingPartAction());
...
builder.build();
ToolStates and ToolEvents are just enums. In the client class, after running the builder code above, the statemachine is started with statemachine.start(); When I subsequently call statemachine.getState().getId(); it gives me UP. No events sent to statemachine before that call.
I have been up and down the Spring statemachine docs and examples. I know from debugging that the entry actions of both states UP and STOPPED have been invoked, so I am assuming they are both "active" and would want to have both states presented when querying the statemachine. Is there a clean way to achieve this ? I want to avoid storing the substate somewhere from inside the Action classes, since I believe I have delegated all state management issues to the freakin Statemachine in the first place and I would rather like to learn how to use its API for this purpose.
Hopefully this is something embarrasingly obvious...
Any advice most welcome!
The documentation describes getStates():
https://docs.spring.io/spring-statemachine/docs/current/api/org/springframework/statemachine/state/State.html
java.util.Collection<State<S,E>> getStates()
Gets all possible states this state knows about including itself and substates.
stateMachine.getState().getStates();
to wrap it up after SMA's most helpful advice: turns out the stateMachine.getState().getStates(); does in my case return a list of four elements:
a StateMachineState instance containing UP and STOPPED
three ObjectState instances containing IDLE, STOPPED and PROCESSING,
respectively.
this leads me to go forward for the time being with the following solution:
public List<ToolStates> getStates() {
List<ToolStates> result = new ArrayList<>();
Collection<State<ToolStates, ToolEvents>> states = this.stateMachine.getState().getStates();
Iterator<State<ToolStates, ToolEvents>> iter = states.iterator();
while (iter.hasNext()) {
State<ToolStates, ToolEvents> candidate = iter.next();
if (!candidate.isSimple()) {
Collection<ToolStates> ids = candidate.getIds();
Iterator<ToolStates> i = ids.iterator();
while (i.hasNext()) {
result.add(i.next());
}
}
}
return result;
}
This maybe would be more elegant with some streaming and filtering, but does the trick for now. I don't like it much, though. It's a lot of error-prone logic and I'll have to see if it holds in the future - I wonder why there isn't a function in the Spring Statemachine that gives me a list of the enum values of all the currently active states, rather than giving me everything possible and forcing me to poke around in it with external logic...
I'm working with the PSJOA library. I have a Java app, and I'm testing each of the standard operations using the CI_PERSONAL_DATA. Everything works fine with the Get, Find and Save. But not with the Create, even though when I invoke the method, I get an OK response, with no apparent errors. The input parameter I'm sending (taken from the CreateKeys) is the KEYPROP_EMPLID.
The odd thing here is that, if instead I call the Create method using Web Services (through SoapUI), the new instances is correctly created. However, in this scenario, passing just the primary key KEYPROP_EMPLID is not enough and I have to fill more fields (as it I was performing an update).
Can someone point to me what might be happening? Is there some missing data? Maybe I misunderstood the creation behavior?
Thanks.
What exactly goes awry when you call create? That will create a new entry in the personal data component in PeopleSoft for the person with the supplied emplid. It will be editable, so you can fill in other information, but it will not persist until/unless you call save() afterwards.
Does the emplid already exist in the personal data component? If so, you should be calling get() instead.
Does the emplid already exist in the peoplesoft instance? If not, you should make sure it is in the system prior to using it.
Regarding the lack of error behavior, I have found the peoplesoft component interface APIs for java are notoriously unreliable. You can test them in real time through Application Designer (Via the "Test Component Interface" option in the drop-down menu), which I often find helpful.
Finally, calling session.checkMessages() on your session after performing a method on a CI can often generate error messages that otherwise will not be displayed.
EDIT: Here is a snippet of how we typically call/use it in our PeopleSoft HR instance:
ICiPersonalData wh = (ICiPersonalData)ses.getComponent("CI_PERSONAL_DATA");
if (wh == null) throw new UpdateException("Failed to get component");
wh.setInteractiveMode(true);
wh.setGetHistoryItems(true);
wh.setEditHistoryItems(true);
wh.setKeypropEmplid(emplid);
if (!existsInHR(emplid)) { // Direct database check
LOG.debug("Creating a new HR person.");
if ( ! wh.create() )
LOG.warn("wh.create returned false for emplid ="+emplid);
ses.checkMessages(); // will throw exception if errors exist
wh.setPropDerivedEmp("Y");
rs.put("NEW","Y");
setKeyPersonalData(wh, emplid, rs); // Sets name, etc.
} else {
if (!wh.get())
LOG.warn("wh.get returned false for emplid ="+emplid);
ses.checkMessages();
}
I am trying to use JACOB 1.17 (latest stable version) to access a 64-bit in-process COM server, i.e. MyObject-x64.dll .
My CoClass has two dualinterfaces: IFoo (default), and IBar. IFoo contains foo_method(), and IBar contains bar_method(). Both methods have dispatch ID of 1.
My Java code is:
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.LibraryLoader;
import com.jacob.com.Variant;
// ...
ActiveXComponent my_object = new ActiveXComponent("MyObject.MyClass"); // OK
Dispatch.call(my_object, "foo_method"); // OK
Dispatch ibar = my_object.QueryInterface("{DE3FF217-120B-4F1E-BEF5-098B8ABDEC1F}"); // OK
Dispatch.call(ibar, "bar_method"); // Exception - "Can't map names to dispid:bar_method"
Dispatch.getIDOfName(ibar, "bar_method"); // Exception - "Can't map names to dispid:bar_method"
Dispatch.call(ibar, "foo_method"); // OK, executes foo_method
Dispatch.call(ibar, 1); // OK, executes foo_method
So, it seems that either the QueryInterface has returned the wrong interface, or the call function on ibar is calling the default interface instead of the result of the QueryInterface.
I have had a quick look through the JNI source code for jacob-1.17-x64.dll and can't see any obvious problem with the QueryInterface implementation or with the call implementation, although I haven't looked at JNI code before so I may be missing something obvious.
There is a sample that comes with JACOB, samples/com/jacob/samples/atl which accesses multiple interfaces, and it uses QueryInterface the same as I have. However I can't run this sample as it requires a MultiFace.dll which is not provided. (Source is provided but it is MSVC++-specific source, and I don't use MSVC++).
The IID in QueryInterface is definitely correct , and my object definitely isn't broken; I can access IBar fine using a free trial of one of the commercial Java-COM bridges, as well as from Visual Basic.
Is JACOB bugged or am I doing something wrong?
Using JRE 1.7.0_51-b13 .
Actually, Jacob is OK. The problem is that C++Builder XE5 has bugged implementation of IDispatch. If you QueryInterface for IDispatch plus the IID of the interface you want, then you get a valid pointer, however it actually points to the original interface you queried from, not the new one.
The other access methods all must be using vtable binding, so they did not encounter a problem.
Leaving this answer here in case anyone else has the same issue and searches.
So far, I have not discovered a workaround.
I am using the tutorial here for pushing data and consuming, data from Azure Service Bus. When I run the example the second time, I get back an error PUT https://asbtest.servicebus.windows.net/TestQueue?api-version=2012-08 returned a response status of 409 Conflict, which is way of saying you have already a configuration with that name, so do not create it another time. Most probably, this is the guilty code
Configuration config =
ServiceBusConfiguration.configureWithWrapAuthentication(
"HowToSample",
"your_service_bus_owner",
"your_service_bus_key",
".servicebus.windows.net",
"-sb.accesscontrol.windows.net/WRAPv0.9");
ServiceBusContract service = ServiceBusService.create(config);
QueueInfo queueInfo = new QueueInfo("TestQueue");
That is recalling create() is causing the problem, I would guess. But all methods in com.microsoft.windowsazure.services.serviceBus.ServiceBusService from http://dl.windowsazure.com/javadoc/ are only create, and I am unable to find a method like
ServiceBusContract service = A_class_that_finds_existing_bus_contract.find(config);
Am I thinking the wrong way, or is there another way out. Any pointers are appreciated.
EDIT:
I realized my code example for what I was asking was config, not service bus contract. Updated it, to reflect so.
Turns out I was wrong. The create() function in ServiceBusService does not throw any exception, as I gathered from Javadocs. Also, you can create the service bus contracts multiple times, as it being only a connection. The exception arises, when you attempt to create a queue with a name that already exists. That is this line.
String path = "TestQueue";
QueueInfo queueInfo = new QueueInfo(path);
To overcome this, you can go this way.
import com.microsoft.windowsazure.services.serviceBus.Util;
...
...
Iterable<QueueInfo> iqnf = Util.iterateQueues(service);
boolean queue_created = false;
for( QueueInfo qi : iqnf )
{
if( path.toLowerCase().equals( qi.getPath() ))
{
System.out.println(" Queue already exists. Do not create one.");
queue_created = true;
}
}
if ( !queue_created ) {
service.createQueue(queueInfo);
}
Hope, this helps anybody who may be stuck on create conflicts for queue on Azure.
EDIT: Even after I got the path code, my code refused to work. Turns out there is another caveat. Azure makes all queue names in lower case. I have edited the code to use toLower() for this work around.
I upvoted Soham's Question and Answer. I did not know about lowercase though I have not verified it. It did confirm the problem I am having right now as well.
The way #Soham has addressed it is good but not good for large ServicebUs where we may have tons of Queues it's added overhead to iterate it. The only way is to catch the ServiceException which is very generic and ignore that Exception.
Example:
QueueInfo queueInfo = new QueueInfo(queName);
try {
CreateQueueResult qr = service.createQueue(queueInfo);
} catch (ServiceException e) {
//Silently ignore for now.
}
The right way would be for the Azure library to extend the ServiceException and throw "ConcflictException" for e.g. which is present in httpStatusCode of ServiceException but unfortunately it's set to Private.
Since it is not We would have to extend the ServiceException and override the httpStatusCode setter.
Again, not the best way but the library can improve if we list as feedback on their Github issues.
Note: ServiceBus is still in preview phase.
I work on windows but I am stuck here on Mac. I have the Canon SDK and have built a JNA wrapper over it. It works well on windows and need some help with Mac.
In the sdk, there is a function where one can register a callback function. Basically when an event occurs in camera, it calls the callback function.
On windows, after registering, I need to use User32 to get the event and to dispatch the event by:
private static final User32 lib = User32.INSTANCE;
boolean hasMessage = lib.PeekMessage( msg, null, 0, 0, 1 ); // peek and remove
if( hasMessage ){
lib.TranslateMessage( msg );
lib.DispatchMessage( msg ); //message gets dispatched and hence the callback function is called
}
In the api, I do not find a similar class in Mac. How do I go about this one??
PS: The JNA api for unix is extensive and I could not figure out what to look for. The reference might help
This solution is using the Cocoa framework. Cocoa is deprecated and I am not aware of any other alternative solution. But the below works like charm.
Finally I found the solution using Carbon framework. Here is my MCarbon interface which defines calls I need.
public interface MCarbon extends Library {
MCarbon INSTANCE = (MCarbon) Native.loadLibrary("Carbon", MCarbon.class);
Pointer GetCurrentEventQueue();
int SendEventToEventTarget(Pointer inEvent, Pointer intarget);
int RemoveEventFromQueue(Pointer inQueue, Pointer inEvent);
void ReleaseEvent(Pointer inEvent);
Pointer AcquireFirstMatchingEventInQueue(Pointer inQueue,NativeLong inNumTypes,EventTypeSpec[] inList, NativeLong inOptions);
//... so on
}
The solution to the problem is solved using the below function:
NativeLong ReceiveNextEvent(NativeLong inNumTypes, EventTypeSpec[] inList, double inTimeout, byte inPullEvent, Pointer outEvent);
This does the job. As per documentation -
This routine tries to fetch the next event of a specified type.
If no events in the event queue match, this routine will run the
current event loop until an event that matches arrives, or the
timeout expires. Except for timers firing, your application is
blocked waiting for events to arrive when inside this function.
Also if not ReceiveNextEvent, then other functions as mentioned in MCarbon class above would be useful.
I think Carbon framework documentation would give more insights and flexibilities to solve the problem. Apart from Carbon, in forums people have mentioned about solving using Cocoa, but none I am aware of.
Edit: Thanks to technomarge, more information here