Skip to main content
1-Visitor
May 10, 2016
Solved

remote method server exception querying WfProcess

  • May 10, 2016
  • 3 replies
  • 5327 views

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

Best answer by asingh

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

3 replies

asingh1-VisitorAnswer
1-Visitor
May 10, 2016

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

1-Visitor
May 10, 2016

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

1-Visitor
May 11, 2016

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

12-Amethyst
May 11, 2016

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.

1-Visitor
May 11, 2016

Aditya,

Thanks again for your help, I really appreciate it.

Jess,

awesome explanation.

Thank you!