PeopleSoft Component Interfaces: Create Method Doesn't Persist The New Object - java

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();
}

Related

How to get the current substate and the parent state out of the Spring Statemachine?

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...

Java InvocationTargetException

I have used EMC Documentum Foundation Classes to perform some actions in documentum repository. The code was working fine. I exported the project as a runnable JAR and then tried to run it. However I got following error and I am not able to understand it.
And here is the code for DocMovementHandler.getSession()
Actually this is no new code but regular code for obtaining documentum session
public IDfSession getSession(String userName, String password)
{
DfClientX clientx = null;
IDfClient client = null;
IDfSession session = null;
try {
// create a client object using a factory method in DfClientX
clientx = new DfClientX();
client = clientx.getLocalClient(); //takes time
// call a factory method to create the session manager
IDfSessionManager sessionMgr = client.newSessionManager();
// create an IDfLoginInfo object and set its fields
IDfLoginInfo loginInfo = clientx.getLoginInfo();
loginInfo.setUser(userName);
loginInfo.setPassword(password);
// set single identity for all docbases
sessionMgr.setIdentity("xyz_repo", loginInfo);
session = sessionMgr.getSession("xyz_repo"); //takes time
//sessionMgr.beginTransaction();
System.out.println("Session obtaied.");
}
catch (DfServiceException dse)
{
DfLogger.debug(this, "Error while beginning transaction. ", null, dse);
dse.printStackTrace();
}
catch (Exception e)
{
DfLogger.debug(this, "Error while creating a new session. ", null, e);
e.printStackTrace();
}
return session;
}
And that line 38 is client = clientx.getLocalClient();
InvocationTargetException is a wrapper. It says, "an exception occurred behind this reflection call", and you use getCause() to get at the inner exception.
The stack trace contains the inner exception. It's an ExceptionInInitializerError. That's another wrapper. It says, "whatever you did caused a new class to be loaded, and that class's static initializer threw an exception".
The final exception in this chain is the NullPointerException. That's the one you need to solve. Which means you need to debug this com.documentum thing. As the comments pointed out, that's not going to be easy.
Here is the most likely problem:
The static initializer in one of the classes whose names you have struck is adding an entry with either a null key or a null value to a Hashtable, which does not allow null keys or values.
It is using the Hashtable as a place to store a bunch of persistent properties and all that, and my guess is that the value for one of the entries was the null (which is a perfectly reasonable way to indicate that some feature is unavailable or something like that).
The now deprecated Hashtable needs to be replaced with the more modern HashMap.
If it is a library, that you can't just modify, you should replace the whole library with an updated version.
Here are some clues may be helpful.
The NullPointerException is thrown by Hashtable#put, and this is normally because either the key or the value is null.
Hashtable#put is called by PreferenceManager.readPersistenceProperties, so most likely it's because something is missing in a properties file so the value is null.
This NPE caused the DfClient class could not be loaded.
DfPreferences is the class loading the DFC configuration file dfc.properties. There must be something wrong with it.
Ohkay I did not pin pointed the root cause, but found the solution that will definitely work everytime.
EMC provides a flavor of Eclipse called Documentum Composer to work with Documentum Projects. Since Eclipse variation we can create other types of projects like normal Java project, dynamic web project, web services in this. So I recreated my project in Documetnum Composer and exported it as JAR and whoaaaa it worked.
I tried this many times and this worked all time.
Some points to note:
You have to replace dfc.properties file in Composer installation folder with one in Content Server
The Export to JAR wizard in Composer is a bit different than one in Eclipse
This is usually caused by dfc.properties being incorrect.
Preferences are stored on the global registry repository and the connection details should be specified in dfc.properties. If not, this (or a similar error can occur).
Also, always try to clear cache and use the correct version of the dfc jar's (v6.7 content server requires 6.7 jars, etc...).

Any Java API in Azure to get existing ServiceBusContract?

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.

Play Framework Multi-Tenant Filter

I'm attempting to build a multi-tenant application using Play Framework 2.2 and have run into a problem. I want to set a session key in the global onRouteRequest (or onRequest in Java) that identifies the site ID for the domain the user is requesting. In literally dozens of other frameworks this type of thing is painless (e.g. Django), but I'm learning that the session object in Play is apparently immutable, however.
So, right now, I have something like this:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteUIDFromURL(request.host.toLowerCase()).toString()
if (!id.isEmpty){
//what goes here to set the session?
}else{
//not found - redirect to a general notFound page
}
}
super.onRouteRequest(request)
}
And, although it's not the most efficient way using a database lookup, it works for testing right now. I need to be able to set a session key in the global but am completely lost on how to do that. If there are any better methods I am all ears (perhaps wrapping my controllers?).
I'm open to solution examples in either Java or Scala.
Think of actions in Play as being function calls, the input is the request, the output is the result. If you want to change the result of a wrapped function call, then you must first invoke the function, and then apply your change. Adding a key to a session is changing the result, since the session is sent to the client in the session cookie. In the code above, you're trying to do the change before you have a result to change, ie, before you call super.onRouteRequest.
If you don't need to modify routing at all, then don't do this in onRouteRequest, do it in a filter, much easier there. But assuming you do need to modify routing, then you need to apply a filter to handler returned. This is what it might look like:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
val maybeSite: Option[String] = request.session.get("site").orElse {
// Let's just assume that getSiteUIDFromUrl returns Option[String], always use Option if you're returning values that might not exist.
models.Site.getSiteUIDFromURL(request.host.toLowerCase())
}
maybeSite.flatMap { site =>
super.onRouteRequest(request).map {
case e: EssentialAction => EssentialAction { req =>
e(req).map(_.withSession("site" -> site))
}
case other => other
}
}
}
Check the source code for the CSRFFilter to see examples of how to add things to the session in a filter.

Why is my Com4J interface hanging during iteration?

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.

Categories