7.8. Custom extensions

Apache Unomi is a pluggeable server that may be extended in many ways. This document assumes you are familiar with theApache Unomi concepts . This document is mostly a reference document on the different things that maybe used inside an extension. If you are looking for complete samples, please see the samples page.

7.8.1. Creating an extension

An extension is simply a Maven project, with a Maven pom that looks like this:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  2. <parent>
  3. <groupId>org.apache.unomi</groupId>
  4. <artifactId>unomi-extensions</artifactId>
  5. <version>${project.version}</version>
  6. </parent>
  7. <modelVersion>4.0.0</modelVersion>
  8. <artifactId>unomi-extension-example</artifactId>
  9. <name>Apache Unomi :: Extensions :: Example</name>
  10. <description>Service implementation for the Apache Unomi Context Server extension that integrates with the Geonames database</description>
  11. <version>${project.version}</version>
  12. <packaging>bundle</packaging>
  13. <dependencies>
  14. <!-- This dependency is not required but generally used in extensions -->
  15. <dependency>
  16. <groupId>org.apache.unomi</groupId>
  17. <artifactId>unomi-api</artifactId>
  18. <version>${project.version}</version>
  19. <scope>provided</scope>
  20. </dependency>
  21. </dependencies>
  22. <build>
  23. <plugins>
  24. <plugin>
  25. <groupId>org.apache.felix</groupId>
  26. <artifactId>maven-bundle-plugin</artifactId>
  27. <extensions>true</extensions>
  28. <configuration>
  29. <instructions>
  30. <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
  31. <Import-Package>
  32. sun.misc;resolution:=optional,
  33. *
  34. </Import-Package>
  35. </instructions>
  36. </configuration>
  37. </plugin>
  38. </plugins>
  39. </build>
  40. </project>

An extension may contain many different kinds of Apache Unomi objects, as well as custom OSGi services or anything thatis needed to build your application.

7.8.2. Deployment and custom definition

When you deploy a custom bundle with a custom definition (see "Predefined xxx" chapters under) for the first time, the definition will automatically be deployed at your bundle start event if it does not exist, after that if you redeploy the same bundle there are two cases:1. Your bundle is a SNAPSHOT then every time you redeploy it the definition will be redeployed2. Your bundle is NOT a SNAPSHOT then the definition will not be redeployed, but you can redeploy it manually using the command unomi:deploy-definition <bundleId> <fileName>

7.8.3. Predefined segments

You may provide pre-defined segments by simply adding a JSON file in the src/main/resources/META-INF/cxs/segments directory ofyour Maven project. Here is an example of a pre-defined segment:

  1. {
  2. "metadata": {
  3. "id": "leads",
  4. "name": "Leads",
  5. "scope": "systemscope",
  6. "description": "You can customize the list below by editing the leads segment.",
  7. "readOnly":true
  8. },
  9. "condition": {
  10. "parameterValues": {
  11. "subConditions": [
  12. {
  13. "parameterValues": {
  14. "propertyName": "properties.leadAssignedTo",
  15. "comparisonOperator": "exists"
  16. },
  17. "type": "profilePropertyCondition"
  18. }
  19. ],
  20. "operator" : "and"
  21. },
  22. "type": "booleanCondition"
  23. }
  24. }

Basically this segment uses a condition to test if the profile has a property leadAssignedTo that exists. All profilesthat match this condition will be part of the pre-defined segment.

7.8.4. Predefined rules

You may provide pre-defined rules by simply adding a JSON file in the src/main/resources/META-INF/cxs/rules directory ofyour Maven project. Here is an example of a pre-defined rule:

  1. {
  2. "metadata" : {
  3. "id": "evaluateProfileSegments",
  4. "name": "Evaluate segments",
  5. "description" : "Evaluate segments when a profile is modified",
  6. "readOnly":true
  7. },
  8. "condition" : {
  9. "type": "profileUpdatedEventCondition",
  10. "parameterValues": {
  11. }
  12. },
  13. "actions" : [
  14. {
  15. "type": "evaluateProfileSegmentsAction",
  16. "parameterValues": {
  17. }
  18. }
  19. ]
  20. }

In this example we provide a rule that will execute when a predefined composed condition of type"profileUpdatedEventCondition" is received. See below to see how predefined composed conditions are declared.Once the condition is matched, the actions will be executed in sequence. In this example there is only a singleaction of type "evaluateProfileSegmentsAction" that is defined so it will be executed by Apache Unomi’s rule engine.You can also see below how custom actions may be defined.

7.8.5. Predefined properties

By default Apache Unomi comes with a set of pre-defined properties, but in many cases it is useful to add additionalpredefined property definitions. You can create property definitions for session or profile properties by creating themin different directories.

For session properties you must create a JSON file in the following directory in your Maven project:

  1. src/main/resources/META-INF/cxs/properties/sessions

For profile properties you must create the JSON file inside the directory in your Maven project:

  1. src/main/resources/META-INF/cxs/properties/profiles

Here is an example of a property definition JSON file

  1. {
  2. "metadata": {
  3. "id": "city",
  4. "name": "City",
  5. "systemTags": ["properties", "profileProperties", "contactProfileProperties"]
  6. },
  7. "type": "string",
  8. "defaultValue": "",
  9. "automaticMappingsFrom": [ ],
  10. "rank": "304.0"
  11. }

7.8.6. Predefined child conditions

You can define new predefined conditions that are actually conditions inheriting from a parent condition and settingpre-defined parameter values. You can do this by creating a JSON file in:

  1. src/main/resources/META-INF/cxs/conditions

Here is an example of a JSON file that defines a profileUpdateEventCondition that inherits from a parent condition oftype eventTypeCondition.

  1. {
  2. "metadata": {
  3. "id": "profileUpdatedEventCondition",
  4. "name": "profileUpdatedEventCondition",
  5. "description": "",
  6. "systemTags": [
  7. "event",
  8. "eventCondition"
  9. ],
  10. "readOnly": true
  11. },
  12. "parentCondition": {
  13. "type": "eventTypeCondition",
  14. "parameterValues": {
  15. "eventTypeId": "profileUpdated"
  16. }
  17. },
  18. "parameters": [
  19. ]
  20. }

7.8.7. Predefined personas

Personas may also be pre-defined by creating JSON files in the following directory:

  1. src/main/resources/META-INF/cxs/personas

Here is an example of a persona definition JSON file:

  1. {
  2. "persona": {
  3. "itemId": "usVisitor",
  4. "properties": {
  5. "description": "Represents a visitor browsing from inside the continental US",
  6. "firstName": "U.S.",
  7. "lastName": "Visitor"
  8. },
  9. "segments": []
  10. },
  11. "sessions": [
  12. {
  13. "itemId": "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d9",
  14. "profileId": "usVisitor",
  15. "properties": {
  16. "operatingSystemName": "OS X 10.9 Mavericks",
  17. "sessionCountryName": "United States",
  18. "location": {
  19. "lat":37.422,
  20. "lon":-122.084058
  21. },
  22. "userAgentVersion": "37.0.2062.120",
  23. "sessionCountryCode": "US",
  24. "deviceCategory": "Personal computer",
  25. "operatingSystemFamily": "OS X",
  26. "userAgentName": "Chrome",
  27. "sessionCity": "Mountain View"
  28. },
  29. "timeStamp": "2014-09-18T11:40:54Z",
  30. "lastEventDate": "2014-09-18T11:40:59Z",
  31. "duration": 4790
  32. }
  33. ]
  34. }

You can see that it’s also possible to define sessions for personas.

7.8.8. Custom actions

Custom actions are a powerful way to integrate with external systems by being able to define custom logic that willbe executed by an Apache Unomi rule. An action is defined by a JSON file created in the following directory:

  1. src/main/resources/META-INF/cxs/actions

Here is an example of a JSON action definition:

  1. {
  2. "metadata": {
  3. "id": "addToListsAction",
  4. "name": "addToListsAction",
  5. "description": "",
  6. "systemTags": [
  7. "demographic",
  8. "availableToEndUser"
  9. ],
  10. "readOnly": true
  11. },
  12. "actionExecutor": "addToLists",
  13. "parameters": [
  14. {
  15. "id": "listIdentifiers",
  16. "type": "string",
  17. "multivalued": true
  18. }
  19. ]
  20. }

The actionExecutor identifier refers to a service property that is defined in the OSGi Blueprint service registration.Note that any OSGi service registration may be used, but in these examples we use OSGi Blueprint. The definition for theabove JSON file will be found in a file called src/main/resources/OSGI-INF/blueprint/blueprint.xml with the followingcontent:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <blueprint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
  3. xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
  4. <reference id="profileService" interface="org.apache.unomi.api.services.ProfileService"/>
  5. <reference id="eventService" interface="org.apache.unomi.api.services.EventService"/>
  6. <!-- Action executors -->
  7. <service interface="org.apache.unomi.api.actions.ActionExecutor">
  8. <service-properties>
  9. <entry key="actionExecutorId" value="addToLists"/>
  10. </service-properties>
  11. <bean class="org.apache.unomi.lists.actions.AddToListsAction">
  12. <property name="profileService" ref="profileService"/>
  13. <property name="eventService" ref="eventService"/>
  14. </bean>
  15. </service>
  16. </blueprint>

You can note here the actionExecutorId that corresponds to the actionExecutor in the JSON file.

The implementation of the action is available here : org.apache.unomi.lists.actions.AddToListsAction

7.8.9. Custom conditions

Custom conditions are different from predefined child conditions because they implement their logic using Java classes.They are also declared by adding a JSON file into the conditions directory:

  1. src/main/resources/META-INF/cxs/conditions

Here is an example of JSON custom condition definition:

  1. {
  2. "metadata": {
  3. "id": "matchAllCondition",
  4. "name": "matchAllCondition",
  5. "description": "",
  6. "systemTags": [
  7. "logical",
  8. "profileCondition",
  9. "eventCondition",
  10. "sessionCondition",
  11. "sourceEventCondition"
  12. ],
  13. "readOnly": true
  14. },
  15. "conditionEvaluator": "matchAllConditionEvaluator",
  16. "queryBuilder": "matchAllConditionESQueryBuilder",
  17. "parameters": [
  18. ]
  19. }

Note the conditionEvaluator and the queryBuilder values. These reference OSGi service properties that are declaredin an OSGi Blueprint configuration file (other service definitions may also be used such as Declarative Services or evenJava registered services). Here is an example of an OSGi Blueprint definition corresponding to the above JSON conditiondefinition file.

  1. src/main/resources/OSGI-INF/blueprint/blueprint.xml
  2. <blueprint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
  3. xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
  4. <service
  5. interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilder">
  6. <service-properties>
  7. <entry key="queryBuilderId" value="matchAllConditionESQueryBuilder"/>
  8. </service-properties>
  9. <bean class="org.apache.unomi.plugins.baseplugin.conditions.MatchAllConditionESQueryBuilder"/>
  10. </service>
  11. <service interface="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluator">
  12. <service-properties>
  13. <entry key="conditionEvaluatorId" value="matchAllConditionEvaluator"/>
  14. </service-properties>
  15. <bean class="org.apache.unomi.plugins.baseplugin.conditions.MatchAllConditionEvaluator"/>
  16. </service>
  17. </blueprint>

You can find the implementation of the two classes here :