Creating Workers
In this tutorial, you're going to create a simple worker which changes data on Person entity type instances (in this particular case, it changes the first and last name to Big Boss) based on their current position (CEO in this tutorial). Your worker will also periodically check for changes, utilizing the JobScheduling extension point.
On this page
Prerequisites
- Prepared development environment as per the instructions on Setting Up IDE for Cartridge Development. In order to follow this tutorial to the letter, please use the **Demo Cartridge.
Implementation Steps
The following is a brief overview of worker implementation:
- Create a denotation type extending the abstract type Jobto depict the actual implementation.
- Implement the Jobexpert (this is where you define the actual logic).
- Declare the deployable in Wire.
- Bind the deployable to the expert in Wire.
- Create an instance of a Joband deploy it.
- Create an instance of a JobScheduler(subtype of Worker), assign the Job instance to it, and deploy it.
Creating a Worker Denotation Type
Let's begin with creating the denotation type, following the normal workflow of cartridge development.
- Find the tribefire-demo-deployment-modelproject in your IDE, then create theChangeNameJobinterface in thetribefire.demo.model.deployment package.
- Make sure that your interface extends the Jobinterface, as in the snippet below:
package tribefire.demo.model.deployment;
import com.braintribe.model.accessdeployment.IncrementalAccess;
import com.braintribe.model.extensiondeployment.scheduling.Job;
import com.braintribe.model.generic.reflection.EntityType;
import com.braintribe.model.generic.reflection.EntityTypes;
public interface ChangeNameJob extends Job {
	EntityType<ChangeNameJob> T = EntityTypes.T(ChangeNameJob.class);
	IncrementalAccess getAccess();
	void setAccess(IncrementalAccess demoAccess);
	
}
Implementing the Job Expert
This is the most important part of the whole process, where we define the logic of our expert. We will use a left-join select query to retrieve all CEOs from all Company instances, make a list of all CEOs, and finally iterate through the list to change their names.
For more information about the query syntax, see GMQL
- Find and open the tribefire-demo-cartridgeproject.
- In the tribefire.demo.impl.extensionspackage, create theChangeNameJobclass, implementing theJobinterface. Use the snippet below for reference.
Note that this interface requires to override the
processmethod.
package tribefire.demo.impl.extensions;
import java.util.List;
import com.braintribe.cfg.Required;
import com.braintribe.model.job.api.JobRequest;
import com.braintribe.model.job.api.JobResponse;
import com.braintribe.model.processing.query.fluent.SelectQueryBuilder;
import com.braintribe.model.processing.service.api.Job;
import com.braintribe.model.processing.service.api.ServiceRequestContext;
import com.braintribe.model.processing.session.api.persistence.PersistenceGmSession;
import com.braintribe.model.processing.session.api.persistence.PersistenceGmSessionFactory;
import com.braintribe.model.query.SelectQuery;
import com.braintribe.model.record.ListRecord;
import tribefire.demo.model.data.Company;
import tribefire.demo.model.data.Person;
public class ChangeNameJob implements Job {
	
	
	// Declaration and getters of configurable access-property and session factory
    private String accessId;
    private PersistenceGmSessionFactory sessionFactory;
    @Required
    public void setAccessId(String accessId) {
        this.accessId = accessId;
    }
    @Required
    public void setSessionFactory(PersistenceGmSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
    @Override
    public JobResponse process(ServiceRequestContext context, JobRequest request) {
    	
    	PersistenceGmSession session = sessionFactory.newSession(accessId);
        //Finding all CEOs across all companies...		
    	SelectQuery ceoQuery = new SelectQueryBuilder()
                .from(Company.T,"c")
                    .leftJoin("c", Company.ceo, "ceo")
                .select("c", Company.id)
                .select("ceo")
                .distinct()
                .done();
    	
        // ...making a list of CEOs...
    	List<ListRecord> listRecords = session.query().select(ceoQuery).list();
    	
        // ...and iterating through it to change the names
    	for (ListRecord l : listRecords ) {
    		
    		Person p = (Person) l.getValues().get(1);
    		
    		p.setFirstName("Big");
    		p.setLastName("Boss");
    		
    	}
    	
    	session.commit();
    	
    	return JobResponse.T.create();
    }
    
}
Declaring the Deployable in Wire
Now that we have both our Denotation Type and Expert (logic), it's time to link them together using Wire, in accordance with the cartridge development standard. First, we need to declare our expert type as a bean in the DeployablesSpace class.
- Open the DeployablesSpaceclass from thecom.braintribe.cartridge.extension.wire.space.DeployablesSpacepackage, found in thetribefire-demo-cartridgeproject.
- Declare your expert as a bean. The actual instantiation takes place during deployment due to its managed nature. The passing of the configured values is defined here by:
- using the ExpertContextas a parameter
- getting the Deployablefrom the context object
- getting the accessobject from thedeployable
- getting the sessionFactoryfrom theclientBaseContract
- setting both on the expert
 
- using the 
@Managed
	public ChangeNameJob changeNameJob(ExpertContext<tribefire.demo.model.deployment.ChangeNameJob> context) {
		
		tribefire.demo.model.deployment.ChangeNameJob deployable = context.getDeployable();
		
		ChangeNameJob bean = new ChangeNameJob();
		bean.setAccessId(deployable.getAccess().getExternalId());
	    bean.setSessionFactory(clientBaseContract.persistenceGmSessionFactory());
	    return bean;
		
	}
Expert Binding in Wire
Now we're going to bind the denotation type to the expert.
- Open the CustomCartridgeSpaceclass from thecom.braintribe.cartridge.extension.wire.space.DeployablesSpacepackage, found in thetribefire-demo-cartridgeproject.
- Pass the denotation type's Tvalue to thebind()method of theDenotationTypeBindingsConfiginstance.
- Follow with a component declaration taken from a component contract. The component declaration is the interface your denotation type extends. In this tutorial, it is Job.
- Finish the binding by providing the expert from the DeployablesSpaceclass, which is where you declared your expert type as a bean in the first place. As we use the context object to pass values, we have to use anexpertFactoryhere.
@Managed
private DenotationTypeBindings extensions() {
	DenotationTypeBindingsConfig bean = new DenotationTypeBindingsConfig();
    //...other bindings...
    //...your binding
    bean.bind(ChangeNameJob.T)
		.component(commonComponents.job())
		.expertFactory(deployables::changeNameJob);
return bean;
}
Testing
That's it in terms of programming - now it's time to see your worker in action!
- 
Set up a local environment with your changes. When in doubt, follow the Developing Cartridges document, starting with step 5. 
- 
Start the server ( runtime/bin/startup.bat) and open Control Center.
- 
Navigate to the Workersentry point and create a new instance ofJobScheduler.
- 
Provide the necessary information: Property Value externalIdscheduling.name.changesnameName Change Schedulercartridgenull coalescingtruecronExpression0/10 0/1 * 1/1 * ? *jobNew instance of ChangeNameJobIn the likely event of not knowing what a cron expression is, you can rely on the Cron Maker to convert your frequency value into cron.
- 
Configure the just created Jobas follows:Property Value externalIdjob.name.changesnameName Change Watch JobaccessDemo Accesscartridgetribefire.demo.cartridge
- 
Commit your changes and deploy both instances. 
- 
Switch to Demo Access.
- 
In explorer, search for Persons. After 10 seconds (or whatever interval you set in the cron expression), all CEO names should read Big Boss.