Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X
Hello Gurus.
I am trying to retrieve the global Process variables of a Change Notice from a Change Activity.
Running the code below I get the following error:
CA is 07138
CN is 06489
Reference is wt.change2.WTChangeOrder2>671258721
Object is wt.change2.WTChangeOrder2:671258722
qrWfProc wt.fc.QueryResult@5039f4d3
WARNING: The ManagerService is not initialized! This can be caused by:
1) Attempting to invoke a server only method from a remote client
2) Attempting to invoke a method on a service from the constructor or static initializer of another service
Exception in thread "main" java.lang.ExceptionInInitializerError
at wt.workflow.engine.WfProcess.getName(WfProcess.java:1425)
at wt.workflow.engine.WfExecutionObject.toString(WfExecutionObject.java:710)
at wt.workflow.engine.WfProcess.toString(WfProcess.java:296)
at java.lang.String.valueOf(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at ext.ChangeNotice2.main(ChangeNotice2.java:47)
Caused by: java.lang.NullPointerException
at wt.access.AccessControlServerHelper.<clinit>(AccessControlServerHelper.java:77)
... 6 more
The code that I used is:
package ext;
import wt.change2.ChangeHelper2;
import wt.change2.WTChangeActivity2;
import wt.change2.WTChangeOrder2;
import wt.fc.ObjectIdentifier;
import wt.fc.PersistenceHelper;
import wt.fc.QueryResult;
import wt.fc.ReferenceFactory;
import wt.fc.WTReference;
import wt.method.RemoteAccess;
import wt.method.RemoteMethodServer;
import wt.util.WTException;
import wt.workflow.engine.WfProcess;
import wt.workflow.engine.WfVariable;
public class ChangeNotice2 implements RemoteAccess {
public static void main(String[] args) throws WTException {
// TODO Auto-generated method stub
RemoteMethodServer rms = RemoteMethodServer.getDefault();
rms.setUserName("wcadmin");
rms.setPassword("wcadmin");
ObjectIdentifier oid = ObjectIdentifier.newObjectIdentifier("wt.change2.WTChangeActivity2:671258847");
WTChangeActivity2 ecaOID = (WTChangeActivity2) PersistenceHelper.manager.refresh(oid);
System.out.println("CA is " + ecaOID.getNumber());
QueryResult qr = ChangeHelper2.service.getChangeOrder(ecaOID);
while (qr.hasMoreElements()) {
Object obj = qr.nextElement();
if (obj instanceof WTChangeOrder2) {
WTChangeOrder2 ecn = (WTChangeOrder2) obj;
System.out.println("CN is " + ecn.getNumber());
ReferenceFactory rf = new ReferenceFactory();
WTReference ref = (WTReference) rf.getReference(ecn);
System.out.println("Reference is " + ref);
System.out.println("Object is " + ref.getObject());
WTChangeOrder2 wtChangeOrder = (WTChangeOrder2) ref.getObject();
QueryResult qrWfProc = wt.workflow.engine.WfEngineHelper.service.getAssociatedProcesses(wtChangeOrder, null, wtChangeOrder.getContainerReference());
System.out.println("qrWfProc " + qrWfProc);
while (qrWfProc.hasMoreElements()) {
WfProcess process = (WfProcess) qrWfProc.nextElement();
System.out.println("Process is " + process);
WfVariable vars[] = process.getContext().getVariableList();
for (WfVariable var : vars) {
System.out.println("Printing Variable " + var.getName() + "---value---" + var.getValue());
}
}
}
}
}
}
Any help will be appreciated
Thanks
Antonio
Solved! Go to Solution.
Hi Antonio,
The code is supposed to be executed in the Method Server, though in your code you have created the instance of the method server, but you are not using it.
String argType={String.class};
String argValue={"wt.change2.WTChangeActivity2:671258847"}; // pass oid as string
RemoteMethodServer.getDefault().invoke( "<method_name>", "<class_name>", null, argType, argValue);
Note:- this class must implement RemoteAccess interface.
Place the following code in a separate method, and invoke that method from mains, using RMI call as mentioned above.
ObjectIdentifier oid = ObjectIdentifier.newObjectIdentifier("wt.change2.WTChangeActivity2:671258847");
WTChangeActivity2 ecaOID = (WTChangeActivity2) PersistenceHelper.manager.refresh(oid);
System.out.println("CA is " + ecaOID.getNumber());
QueryResult qr = ChangeHelper2.service.getChangeOrder(ecaOID);
while (qr.hasMoreElements()) {
Object obj = qr.nextElement();
if (obj instanceof WTChangeOrder2) {
WTChangeOrder2 ecn = (WTChangeOrder2) obj;
System.out.println("CN is " + ecn.getNumber());
ReferenceFactory rf = new ReferenceFactory();
WTReference ref = (WTReference) rf.getReference(ecn);
System.out.println("Reference is " + ref);
System.out.println("Object is " + ref.getObject());
WTChangeOrder2 wtChangeOrder = (WTChangeOrder2) ref.getObject();
QueryResult qrWfProc = wt.workflow.engine.WfEngineHelper.service.getAssociatedProcesses(wtChangeOrder, null, wtChangeOrder.getContainerReference());
System.out.println("qrWfProc " + qrWfProc);
while (qrWfProc.hasMoreElements()) {
WfProcess process = (WfProcess) qrWfProc.nextElement();
System.out.println("Process is " + process);
WfVariable vars[] = process.getContext().getVariableList();
for (WfVariable var : vars) {
System.out.println("Printing Variable " + var.getName() + "---value---" + var.getValue());
}
}
}
Thanks,
Aditya
Hi Antonio,
The code is supposed to be executed in the Method Server, though in your code you have created the instance of the method server, but you are not using it.
String argType={String.class};
String argValue={"wt.change2.WTChangeActivity2:671258847"}; // pass oid as string
RemoteMethodServer.getDefault().invoke( "<method_name>", "<class_name>", null, argType, argValue);
Note:- this class must implement RemoteAccess interface.
Place the following code in a separate method, and invoke that method from mains, using RMI call as mentioned above.
ObjectIdentifier oid = ObjectIdentifier.newObjectIdentifier("wt.change2.WTChangeActivity2:671258847");
WTChangeActivity2 ecaOID = (WTChangeActivity2) PersistenceHelper.manager.refresh(oid);
System.out.println("CA is " + ecaOID.getNumber());
QueryResult qr = ChangeHelper2.service.getChangeOrder(ecaOID);
while (qr.hasMoreElements()) {
Object obj = qr.nextElement();
if (obj instanceof WTChangeOrder2) {
WTChangeOrder2 ecn = (WTChangeOrder2) obj;
System.out.println("CN is " + ecn.getNumber());
ReferenceFactory rf = new ReferenceFactory();
WTReference ref = (WTReference) rf.getReference(ecn);
System.out.println("Reference is " + ref);
System.out.println("Object is " + ref.getObject());
WTChangeOrder2 wtChangeOrder = (WTChangeOrder2) ref.getObject();
QueryResult qrWfProc = wt.workflow.engine.WfEngineHelper.service.getAssociatedProcesses(wtChangeOrder, null, wtChangeOrder.getContainerReference());
System.out.println("qrWfProc " + qrWfProc);
while (qrWfProc.hasMoreElements()) {
WfProcess process = (WfProcess) qrWfProc.nextElement();
System.out.println("Process is " + process);
WfVariable vars[] = process.getContext().getVariableList();
for (WfVariable var : vars) {
System.out.println("Printing Variable " + var.getName() + "---value---" + var.getValue());
}
}
}
Thanks,
Aditya
Hi Aditya,
Thank you so very much!
That helped a lot to find the issue!!
I do have additional question for you.
1) If I place the code inside an expression robot in a workflow, I imagine I can remove the remote method server call, correct?
2) If I use an expression robot to call the class with my code, do I still need to have the instantiation of the MS or can I call the code method directly?
Sorry for the silly questions..
I am very new to java and customization, even though I am long time Windchill Admin.
Thank you very much for your help!
Antonio
Hi Antonio,
You are correct, its not required to instantiate MS for both the cases you have mentioned.
Expression robot has limitions on number of line of code, so its always recommended to make a method call to a custom workflow helper class(Use case 2) from the expression.
thanks,
Aditya
More generally if your code is being invoked within a method server, whether it is by a workflow, a JSP page (in 10.0 or higher where Tomcat is embedded in the method server), or whatever, then you not only do not need to use RemoteMethodServer.invoke(), but you should not use it -- as it causes a loopback RMI request which is wasteful. Moreover, you'll get warnings in recent Windchill versions if you do this.
If you have code which may or may not be in the method server you can use *Helper.manager.* or *Helper.service.* methods or you can logic like they do internally:
if (RemoteMethodServer.ServerFlag) {
// call code directly, you're in a method server
} else {
// do RemoteMethodServer.invoke() -- as you're not in a method server
}
Finally, I should note that if you have code that may be running in a server manager, then you should not blithely assume you can do RemoteMethodServer.invoke() -- at least not if you have any cluster nodes that do not have (and should not have) a foreground method server -- as RemoteMethodServer.invoke() requires a foreground method server. This issue most frequently comes up from custom wt.cache.CacheManager subclasses that do not consider how their methods are called in server managers.
Aditya,
Thanks again for your help, I really appreciate it.
Jess,
awesome explanation.
Thank you!