cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

We are happy to announce the new Windchill Customization board! Learn more.

How to run background task periodically

akosolapov-2
14-Alexandrite

How to run background task periodically

Hi.

I need run some code in Windchill to update objects. I need start this task at specified time and rerun it in some period.

So i tried to use java.util.TimerTask implementation.

Some code example i used:


public class MyServiceManager extends wt.services.StandardManager {

    private static Logger LOGGER = LogR.getLogger(MyServiceManager .class.getName());

    public static MyServiceManager newMyServiceManager () throws WTException {

        MyServiceManager instance = new MyServiceManager ();

        instance.initialize();

        return instance;

    }

    @Override

    protected synchronized void performStartupProcess() throws ManagerException {

        try {

            /*some code to init firstTime and period*/

            Timer timer = new Timer();

            timer.scheduleAtFixedRate(new MyTimerTask(), firstTime, period);

        } catch (Exception e) {

            LOGGER.error(e.getMessage(), e);

        }

    }

}

public class MyTimerTask extends java.util.TimerTask {

    private static Logger LOGGER = LogR.getLogger(MyTimerTask.class.getName());

    public MyTimerTask() {

        //

    }

    @Override

    public void run() {

        try {

            QuerySpec querySpec = new QuerySpec();

            //fill query spec with conditions

            QueryResult qr = PersistenceHelper.manager.find((StatementSpec) querySpec); // and i get exception here

            //

        } catch (Exception e) {

            LOGGER.error(e.getMessage(), e);

        }

    }

}

In PersistenceHelper.manager.find i get exception:

Message:  Resource bundle/Message key = wt.pom.pomResource/0

(wt.pom.pomResource/0) wt.pom.POMInitException: A persistence error occurred. System message follows:

Nested exception is: wt.method.MethodServerException: No active method context

    at wt.method.MethodContext.getContext(MethodContext.java:1725)

    at wt.pom.PersistentObjectManager.getPom(PersistentObjectManager.java:289)

    at wt.fc.StandardPersistenceManager._query(StandardPersistenceManager.java:1993)

    at wt.fc.StandardPersistenceManager._find(StandardPersistenceManager.java:2022)

    at wt.fc.StandardPersistenceManager.find(StandardPersistenceManager.java:681)

    at sun.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

    at java.lang.reflect.Method.invoke(Method.java:606)

    at wt.services.ServiceFactory$ServerInvocationHandler.invoke(ServiceFactory.java:399)

    at com.sun.proxy.$Proxy9.find(Unknown Source)

What shouild i do to fix this? Or is there more appropriate way to run same task in Windchill?

I expect get java code example.

Thanks.

6 REPLIES 6

I wouldn't do it manually with a timer. Windchill has the ability to schedule jobs.

Have a look at the customization guide and search for the chapter: Procedure – Creating Custom Schedule Jobs

It works.

But is there a way to solve by background queue?

Yes, the task will probably running in the Methodserver. I don't have any solution to run it in the BMS. Perhaps somebody else can help...?

If you wan't to use a time, you need to create a Windchill context :

import wt.method.MethodContext

import wt.method.RemoteMethodServer

import wt.session.SessionContext

import wt.session.SessionHelper

new MethodContext(null, null)

SessionContext.newContext()

SessionHelper.manager.setPrincipal("wcadmin")

RemoteMethodServer rms = RemoteMethodServer.getDefault()

rms.setUserName("wcadmin")

rms.setPassword("wcadmin")

But as Bjorg said, it's not the best way. In fact, if you have several MS & a BGMS, the thread would run everywhere, and it would probably raise stranges issues.

I had to do something similar, and I used wt.queue.ScheduleQueue and its associated entry wt.queue.ScheduleQueueEntry

ScheduleQueueEntries have a "processAt" parameter.

The algorithm is :

  • In a service, check that the custom schedule queue exists
  • if no create it
  • Is there an entry in the queue ?
  • if yes, do nothing
  • if no, add a new one, scheduled to execute at a specific date

And iat the end of the code launched by the ScheduleQueueEntry, you add a new entry in the queue. So there is always a pending job.

Some code :

The starting point is to call addQueueEntry(); in the performStartupProcess method.

Everyhting is done from this method.

Of course you need to define some constants, like HAGER_QUEUE_NAME

private static ScheduleQueue initialiseQueue(String qname)

   throws WTException {

  ScheduleQueue q = (ScheduleQueue) QueueHelper.manager.getQueue(qname, wt.queue.ScheduleQueue.class);

   if (q == null) {

  q = createScheduleQueue(qname);

   //QueueHelper.manager.setInterval(q, interval);
  // q = (ScheduleQueue)PersistenceHelper.manager.save(q); Voila qui ne m'a plus l'air ncessaire.....
   if (logger.isDebugEnabled()) {

  logger.debug("initialiseQueue() - " + CLASSNAME + ".initialiseQueue() Creating Queue " + qname); //$NON-NLS-1$ //$NON-NLS-2$
   }

  }

   if (logger.isDebugEnabled()) {

  logger.debug("initialiseQueue() - " + CLASSNAME + ".initialiseQueue() Starting Queue " + qname); //$NON-NLS-1$ //$NON-NLS-2$
   }

  QueueHelper.manager.startQueue(q);

   return q;

}

//##begin newStandardHagerService%newStandardHagerServicef.doc preserve=no

private static ScheduleQueue createScheduleQueue(String qname)

   throws WTException {

  ScheduleQueue schedulequeue = null;

   try {

  schedulequeue = QueueHelper.manager.createScheduleQueue(qname);

  } catch (ObjectIsStaleException objectisstaleexception) {

  schedulequeue = (ScheduleQueue) QueueHelper.manager.getQueue(qname, wt.queue.ScheduleQueue.class);

  } catch (UniquenessException uniquenessexception) {

  schedulequeue = (ScheduleQueue) QueueHelper.manager.getQueue(qname, wt.queue.ScheduleQueue.class);

  }

   return schedulequeue;

}

//##begin getAllSigleService%3BF8E35000FAg.doc preserve=no

public static void addQueueEntry() {

  ScheduleQueue queue = null;

// Check existing entries
   try {

  QuerySpec qs = new QuerySpec(wt.queue.ScheduleQueueEntry.class);

  ClassAttribute theClassAttribute = new ClassAttribute(wt.queue.ScheduleQueueEntry.class, "targetClass");

  RelationalExpression theExpression = ConstantExpression.newExpression("ext.hager.services.StandardHagerService", theClassAttribute.getColumnDescriptor().getJavaType());

  SearchCondition theCondition = new SearchCondition(theClassAttribute, SearchCondition.EQUAL, theExpression);

  qs.appendWhere(theCondition);

  qs.appendAnd();

  theClassAttribute = new ClassAttribute(wt.queue.ScheduleQueueEntry.class, "statusInfo.code");

  theExpression = ConstantExpression.newExpression("READY", theClassAttribute.getColumnDescriptor().getJavaType());

  theCondition = new SearchCondition(theClassAttribute, SearchCondition.EQUAL, theExpression);

  qs.appendWhere(theCondition);

  QueryResult qr = PersistenceServerHelper.manager.query(qs);

   if (qr.size() > 0) {

  // Found something
   if (logger.isDebugEnabled()) {

  logger.debug("addQueueEntry() - " + CLASSNAME + ".addQueueEntry() No need to add an entry. "); //$NON-NLS-1$ //$NON-NLS-2$
   }

   return;

  }

  } catch (WTException wte) {

   if (logger.isDebugEnabled()) {

  logger.debug("addQueueEntry() - " + CLASSNAME + ".addQueueEntry() Exception caught " + wte.toString()); //$NON-NLS-1$ //$NON-NLS-2$
   }

  logger.error("addQueueEntry()", wte); //$NON-NLS-1$
   return;

  }

   try {

  queue = initialiseQueue(HAGER_QUEUE_NAME);

  GregorianCalendar cDate = new GregorianCalendar();

  cDate.add(Calendar.DAY_OF_YEAR, NB_JOURS_SCHED_QUEUE);

  cDate.set(Calendar.HOUR, HEURE_TACHE_ARCHIVAGE);

  cDate.set(Calendar.MINUTE, 0);

  cDate.set(Calendar.SECOND, 0);

  Timestamp processAt = new Timestamp(cDate.getTime().getTime());

   //processAt = new Timestamp((new java.util.Date()).getTime()+10000);

   WTPrincipal user = SessionContext.getEffectivePrincipal();

  WTPrincipal admin = SessionHelper.manager.getAdministrator();

  WTPrincipal admin2 = SessionContext.setEffectivePrincipal(admin);



   queue.addEntry(

  admin,

   "archiveDocuments",

  CLASSNAME,

   new Class[]{},

   new Object[]{},

  processAt);

   if (logger.isDebugEnabled()) {

  logger

  .debug("addQueueEntry() - " + CLASSNAME + ".addQueueEntry() Prochaine recherche des documents oboltes   " + cDate.getTime()); //$NON-NLS-1$ //$NON-NLS-2$
   }

  SessionContext.setEffectivePrincipal(user);

  } catch (WTException wte) {

   if (logger.isDebugEnabled()) {

  logger

  .debug("addQueueEntry() - " + CLASSNAME + ".addQueueEntry() Exception caught " + wte.toString()); //$NON-NLS-1$ //$NON-NLS-2$
   }

  logger.error("addQueueEntry()", wte); //$NON-NLS-1$
   return;

  }

}

//-------------------------------------- code executed by the queue :

public static void archiveDocuments() throws WTException {

  // all the hthings you need goes here...

// And here we go again.

  addQueueEntry();

}


Will this code run only once at a specified time "processAt" ?

Yes, and the keey is to call

addQueueEntry();

at the end of your task, in "archiveDocuments" in this example


Top Tags