Creating Service Requests
Along with the developing a service processor, creating a service request is an essential part of the process of implementing custom functionality into Tribefire.
For more information on service processors and their relations to service requests and responses, see Service Processor. For information on creating service models, see Creating a Service Model - Best Practices.
In this example, we will create a service request and a service processor programmatically and later trigger the request from Control Center. The service request will, when triggered, populate the cortex
access with a list of User
instances. For reasons of efficiency we will not focus on creating a separate cartridge to host the service request code in, but will use the simple cartridge instead.
For information how to develop cartridges, see Developing Cartridges.
On this page
Prerequisites
- prepared environment as per the instructions on Setting Up IDE for Cartridge Development
Creating a Service Processor Denotation Type
It is a good idea to create your service processor first - this way you will know what exact types and properties you must implement in your service request. Let's start with creating the denotation type for your service processor.
- In your IDE, go to the
simple-deployment-model
project and, in thecom.braintribe.tribefire.cartridge.simple.model.deployment.service
package, create a newPopulateAccessService
interface. - Make sure your interface extends the
AccessRequestProcessor
and provide your service access to reflection:
package com.braintribe.tribefire.cartridge.simple.model.deployment.service;
import com.braintribe.model.extensiondeployment.access.AccessRequestProcessor;
import com.braintribe.model.generic.reflection.EntityType;
import com.braintribe.model.generic.reflection.EntityTypes;
public interface PopulateAccessService extends AccessRequestProcessor {
EntityType<PopulateAccessService> T = EntityTypes.T(PopulateAccessService.class);
}
For more information on reflection, see Reflection
Creating a Service Processor Expert
Now that you have your denotation type, it is time to implement the expert. Experts in Tribefire are always Java classes that implement the actual business logic.
- In your IDE, go to the
simple-cartridge
project and, in thecom.braintribe.tribefire.cartridge.simple.deployables.service
package, create a newPopulateAccessService
class. - Make sure your service implements the
AccessRequestProcessor<REQUEST, RESPONSE>
interface. Note that you must specify the service request and the service response in the class header.
package com.braintribe.tribefire.cartridge.simple.deployables.service;
import java.util.List;
import com.braintribe.model.processing.accessrequest.api.AccessRequestProcessor;
import com.braintribe.model.user.User;
import com.braintribe.tribefire.cartridge.simple.model.service.PopulateAccessWithDataRequest;
public class PopulateAccessService implements AccessRequestProcessor<PopulateAccessWithDataRequest, List<User>> {
// your logic goes here
}
Note that your IDE will produce errors here because you have not yet implemented the
PopulateAccessWithDataRequest
. You will implement it later.
- As you are implementing the
AccessRequestProcessor
, you must add its methods to your class and implement them. The processor you are implementing has only one method:process()
, which provides the appropriate context for your logic (and the context takes your service request as an argument). What's more, theprocess()
method returns the exact type you specified in the class header as the second argument:AccessRequestProcessor<PopulateAccessWithDataRequest, List<User>>
.
Below you can find an example implementation of the method:
@Override
public List<User> process(AccessRequestContext<PopulateAccessWithDataRequest> context) {
PersistenceGmSession session = context.getSession();
List<User> usersToCreate = context.getRequest().getUsers();
List<User> createdUsers = new ArrayList<User>();
for (User user: usersToCreate) {
User createdUser = session.create(User.T);
createdUser.setFirstName(user.getFirstName());
createdUser.setName(user.getName());
createdUsers.add(createdUser);
}
session.commit();
return createdUsers;
}
The first thing we do is get the current session. Then we specify the usersToCreate
list variable and assign it the value of the (not existing yet) service request's getUsers()
method. At this point you already know that your service request must have a getUsers()
method whose return type is a List<User>
.
Once we have the list of users to create, we loop over the items of that list and create a new User
instance within the session for every item found in the list. Moreover, we assign the values of the name
and firstName
properties to the new User
entities inside the session. The loop finishes with adding a new User
instance to the previously created list referenced by the createdUsers
variable. Once the loop has finished, all the changes are committed to the session and the list of created users is returned.
Creating a Service Request Denotation Type
You coded your processor so you know exactly what properties and methods your request must have.
- In your IDE, go to the
simple-service-model
project and create a newPopulateAccessWithDataRequest
interface. - Make sure your interface extends the
AccessDataRequest
andAuthorizedRequest
interfaces.
public interface PopulateAccessWithDataRequest extends AccessDataRequest, AuthorizedRequest {
}
- Add a dependency to
user-model
to this project's POM and refresh the projects in the IDE:
<dependency>
<groupId>com.braintribe.gm</groupId>
<artifactId>user-model</artifactId>
<version>${V.com.braintribe.gm}</version>
<?tag asset?>
</dependency>
- Provide your service request denotation type access to reflection and define its necessary methods. You already know what method your service processor will use - now it's time to define them:
package com.braintribe.tribefire.cartridge.simple.model.service;
import java.util.List;
import com.braintribe.model.accessapi.AccessDataRequest;
import com.braintribe.model.generic.reflection.EntityType;
import com.braintribe.model.generic.reflection.EntityTypes;
import com.braintribe.model.service.api.AuthorizedRequest;
import com.braintribe.model.user.User;
public interface PopulateAccessWithDataRequest extends AccessDataRequest, AuthorizedRequest {
EntityType<PopulateAccessWithDataRequest> T = EntityTypes.T(PopulateAccessWithDataRequest.class);
//list of Users to populate the access with - you used this method in the service processor
List<User> getUsers();
void setUsers(List<User> users);
}
- Go to the the
simple-cartridge
project and, in thecom.braintribe.tribefire.cartridge.simple.deployables.service
package, open thePopulateAccessService
class and import the service request denotation type you just created.
Wiring the Service Processor Denotation Type to the Expert
Now that you have all the necessary elements of your service request, it is time to wire them together.
For more information on Wire, see Wire and Wire in Detail.
- In your IDE, go to the
simple-cartridge
project and open theDeployablesSpace
class. - Register your service processor as a deployable by creating the appropriate method:
public PopulateAccessService populateAccessService(ExpertContext<com.braintribe.tribefire.cartridge.simple.model.deployment.service.PopulateAccessService> context) {
return new PopulateAccessService();
}
This method's return type com.braintribe.tribefire.cartridge.simple.deployables.service.PopulateAccessService
so the expert type. Note that it is the denotation type (com.braintribe.tribefire.cartridge.simple.model.deployment.service.PopulateAccessService
) that is provided as the parameter of the populateAccessService()
method.
- Go to the
CustomCartridgeSpace
class and find the definition of theextensions()
method. - Bind your service processor denotation type to its deployable supplier:
@Managed
public DenotationTypeBindingsConfig extensions() {
DenotationTypeBindingsConfig bean = new DenotationTypeBindingsConfig();
//other bean bindings
bean.bind(PopulateAccessService.T)
.component(commonComponents.accessRequestProcessor())
.expertFactory(deployables::populateAccessService);
Configuring the Initializer
- In your IDE, go to the
simple-cartridge-initializer
project and, in theSimpleCartridgeInitializer
class, add a newconfigurePopulateAccessService()
method. This project is an asset of the typePluginPriming
which means that is incrementally adds programmatic information to Tribefire. You must add and configure your new service processor there.
For more information about
PluginPriming
see Platform Assets
- Implement the method as follows:
private void configurePopulateAccessService() {
PopulateAccessService service = session.create(PopulateAccessService.T);
service.setExternalId("populateAccessService");
service.setGlobalId("custom:" + service.getExternalId());
service.setId(service.getGlobalId());
service.setName(PopulateAccessService.T.getShortName());
service.setCartridge(cartridge);
ProcessWith processWithMetadata = session.create(ProcessWith.T);
processWithMetadata.setGlobalId("custom:md/processWith:" + service.getExternalId());
processWithMetadata.setId(processWithMetadata.getGlobalId());
processWithMetadata.setProcessor(service);
new BasicModelMetaDataEditor(serviceModel).onEntityType(PopulateAccessWithDataRequest.T).addMetaData(processWithMetadata);
}
It is worth to note the existence of the ProcessWith
metadata which binds the processor to the request type: new BasicModelMetaDataEditor(serviceModel).onEntityType(PopulateAccessWithDataRequest.T).addMetaData(processWithMetadata);
.
- Find the definition of the
initializeData()
method and call theconfigurePopulateAccessService()
method you just created from within its body.
Metadata Validation
You might want to validate the values for certain metadata that introduce constraints before the service processor is triggered. Current metadata where validation is supported include:
To enable basic validation against those metadata you must attach the com.braintribe.model.cortex.preprocessor.RequestValidatorPreProcessor
service preprocessor to the main entity in your service request (the one that derives from ServiceRequest
) using a PreProcessWith
metadata.
You can use the following information to find the RequestValidatorPreProcessor
:
Property | Value |
---|---|
globalId | default:preprocessor/requestValidator |
externalId | preProcessor.requestValidator.default |
name | Default Request Validator |
type | com.braintribe.model.cortex.preprocessor.RequestValidatorPreProcessor |
declaredModel | cortex-deployment-model |
For more information about the
PreProcessWith
metadata, see ProcessWith as both metadata work in a similar fashion.
This metadata (and the validation it introduces) is automatically propagated to requests derived from that entity type so you can use an abstract supertype for all your requests that you want to have validated.
The validation might increase the total time of evaluating a service request.
Building and Setting Up Tribefire
When you have all your code in place, it is time to build the software and set up your tribefire based on the enhanced simple cartridge. To do so:
- From within the folder which contains all the simple cartridge projects, run
mvn clean install
. - When you see BUILD SUCCESSFUL, create a new directory and set up tribefire based on the cartridge you just built using Jinni:
jinni setup-local-tomcat-platform setupDependency=tribefire.extension.enablement-maven.simple:simple-cartridge-setup#2.0 installationPath=PATH_TO_A_DIRECTORY deletePackageBaseDir=true
.
Do not forget to change the value of the
installationPath
parameter.
Testing
- Start the server (
runtime/bin/startup.bat
), open Control Center and, using the Quick Access search bar, search forPopulateAccessWithDataRequest
. - Click the Add link and create several instances of
User
. Remember that the name parameter is mandatory. - Click Evaluate. Your service request has been called.
- In the Quick Access search box, search for
User
. You will see a list of all instances ofUser
, including the ones you added as a part of the service request.