Community Tip - Need to share some code when posting a question or reply? Make sure to use the "Insert code sample" menu option. Learn more! X
A student in the Axeda Groovy course had some good questions. Instead of answering via email, I thought I'd answer here, so we could share the knowledge.
Domain Objects - How can I customize or extend Axeda provided domain objects? (Eg., I need to store whether a user is external or internal user) How can I achieve this?
This is a perfect use case for the Axeda Extended Data API. Documentation on the API can be found in the Axeda Platform v1 API Developer's Reference Guide. A good, "Getting Started," topic is available on Axeda Mentor - Getting Started With the Axeda Extended Data API.
To customize/extend/decorate Axeda-provided domain objects, use Extended Objects. Extended Objects can be thought of in the abstract as a collection of custom database table rows. The analogy isn't perfect, but it helps with understanding.
The use case in the question is very common. Extended Objects can stand on their own, or they can be associated with an Axeda domain object with the setInternalID() method. In the following sample code, we "decorate" an Axeda User object with two new fields, isExternalUser and companyID:
private void updateAdditionalFieldsForUser(User user, boolean isExternalUser, String companyID) { // GET OBJECT TYPE - This example assumes the ExtendedObjectType has already been created ExtendedObjectType extObjectType = extendedObjectService.findExtendedObjectTypeByClassname("com.axeda.drm.sdk.user.User") // GET PROPERTY TYPES PropertyType isExternalUserPropertyType = findOrCreatePropertyType(extObjectType, "IS_EXTERNAL_USER") PropertyType companyIdPropertyType = findOrCreatePropertyType(extObjectType, "COMPANY_ID") /* GET THE EXTENDED OBJECT * Note - the example provides a findExtendedObject() method that searches by INTERNAL ID. This linkage via the internal ID * associates a domain object to an ExtendedObject, allowing us to "decorate" it with custom attributes */ ExtendedObject extObject = findExtendedObject(extObjectType, user.id.value) if (extObject == null) { extObject = new ExtendedObject() extObject.setExtendedObjectType(extObjectType) extObject.setInternalObjectId(user.id.value) extObject.addProperty(createExtendedProperty(isExternalUserPropertyType, isExternalUser.toString())) extObject.addProperty(createExtendedProperty(companyIdPropertyType, companyID)) extendedObjectService.createExtendedObject(extObject) } else { addOrUpdateExtendedProperty(extObject, isExternalUserPropertyType, "IS_EXTERNAL_USER", isExternalUser.toString()) addOrUpdateExtendedProperty(extObject, companyIdPropertyType, "COMPANY_ID", companyID) extendedObjectService.updateExtendedObject(extObject) } } /** * Adds or Updates an extended property. * * @param extendedObject the extended object to associate with the property * @param propertyType the type of the property * @param propertyName the name of the property * @param propertyValue the value of the property */ private void addOrUpdateExtendedProperty(ExtendedObject extendedObject, PropertyType propertyType, String propertyName, String propertyValue) { Property extendedProperty = extendedObject.getPropertyByName(propertyName) if (extendedProperty == null) { extendedProperty = createExtendedProperty(propertyType, propertyValue) extendedObject.addProperty(extendedProperty) } else { extendedProperty.setValue(propertyValue) } } /** * Retrieves and returns the extended object with the given type and internal id. * * @param extObjectType the type of the desired external object * @param internalObjectId the internal id of the desired extended object * @return the extended object matching the given details or <code>null</code> in case there's no match */ private ExtendedObject findExtendedObject(ExtendedObjectType extObjectType, Long internalObjectId) { ExtendedObjectSearchCriteria searchCriteria = new ExtendedObjectSearchCriteria() searchCriteria.setExtendedObjectTypeId(extObjectType.getId()) searchCriteria.setInternalObjectId(internalObjectId) List<ExtendedObject> extObjects = extendedObjectService.findExtendedObjects(searchCriteria, -1, 0, "name") if (!extObjects?.isEmpty()) { return extObjects[0] } return null } /** * Gets a property type given its name and the associated extended object type. * If it cannot find the property type it will create it. * * @param extendedObjectType the associated extended object type for the property type * @param propertyTypeName the property type name * @return the property type */ private PropertyType findOrCreatePropertyType(ExtendedObjectType extendedObjectType, String propertyTypeName) { PropertyType propertyType = extendedObjectType.getPropertyTypeByName(propertyTypeName) if (propertyType == null) { propertyType = new PropertyType() propertyType.setDataType(PropertyDataType.String) propertyType.setName(propertyTypeName) propertyType.setExtendedObjectType(extendedObjectType) extendedObjectService.createPropertyType(propertyType) extendedObjectType.addPropertyType(propertyType) } return propertyType }
By using Extended Objects, and associating them with Axeda domain objects via an internal ID, we can decorate/extend/customize those domain objects with use-case-specific attributes.
Stephen,
Thanks for posting this.
In the above example we are adding new properties to user domain objects, will the property be persisted by default?
Like, I am adding new property external/internal to user domain object will that property be persisted for that user? The next time when I login into the system will that property be available for the user?
Also how we are storing this data in Axeda back end? do we have a database for Axeda?
Hi,
We tried executing the above program, but we are getting error and not able to see any useful information in log files.
<error>
<faultcode>
</faultcode>
<faultstring>
No signature of method: com.axeda.drm.services.customobject.groovy.ExtendedObjectType() is applicable for argument types: (null) values: [null]
</faultstring>
</error>
Could you please suggest how to pull useful log information, I tried pulling the log file archive located down the table of custom objects. I am not able to see any useful information related to this.
Whew - first of all, the migration of this question from the Axeda Community to the ThingWorx Community really did a number on the formatting, so let me post reformatted code, in case that's the problem:
private void updateAdditionalFieldsForUser(User user, boolean isExternalUser, String companyID) {
// GET OBJECT TYPE - This example assumes the ExtendedObjectType has already been created
ExtendedObjectType extObjectType = extendedObjectService.findExtendedObjectTypeByClassname("com.axeda.drm.sdk.user.User")
// GET PROPERTY TYPES
PropertyType isExternalUserPropertyType = findOrCreatePropertyType(extObjectType, "IS_EXTERNAL_USER")
PropertyType companyIdPropertyType = findOrCreatePropertyType(extObjectType, "COMPANY_ID")
/* GET THE EXTENDED OBJECT
* Note - the example provides a findExtendedObject() method that searches by INTERNAL ID. This linkage via the internal ID
* associates a domain object to an ExtendedObject, allowing us to "decorate" it with custom attributes */
ExtendedObject extObject = findExtendedObject(extObjectType, user.id.value)
if (extObject == null) {
extObject = new ExtendedObject()
extObject.setExtendedObjectType(extObjectType)
extObject.setInternalObjectId(user.id.value)
extObject.addProperty(createExtendedProperty(isExternalUserPropertyType, isExternalUser.toString()))
extObject.addProperty(createExtendedProperty(companyIdPropertyType, companyID))
extendedObjectService.createExtendedObject(extObject)
} else {
addOrUpdateExtendedProperty(extObject, isExternalUserPropertyType, "IS_EXTERNAL_USER", isExternalUser.toString())
addOrUpdateExtendedProperty(extObject, companyIdPropertyType, "COMPANY_ID", companyID)
extendedObjectService.updateExtendedObject(extObject)
}
}
/** Adds or Updates an extended property.
* @param extendedObject the extended object to associate with the property
* @param propertyType the type of the property
* @param propertyName the name of the property
* @param propertyValue the value of the property
*/
private void addOrUpdateExtendedProperty(ExtendedObject extendedObject, PropertyType propertyType, String propertyName, String propertyValue) {
Property extendedProperty = extendedObject.getPropertyByName(propertyName)
if (extendedProperty == null)
{
extendedProperty = createExtendedProperty(propertyType, propertyValue)
extendedObject.addProperty(extendedProperty)
} else {
extendedProperty.setValue(propertyValue)
}
}
/** Retrieves and returns the extended object with the given type and internal id.
* @param extObjectType the type of the desired external object
* @param internalObjectId the internal id of the desired extended object
* @return the extended object matching the given details or <code>null</code> in case there's no match */
private ExtendedObject findExtendedObject(ExtendedObjectType extObjectType, Long internalObjectId) {
ExtendedObjectSearchCriteria searchCriteria = new ExtendedObjectSearchCriteria()
searchCriteria.setExtendedObjectTypeId(extObjectType.getId())
searchCriteria.setInternalObjectId(internalObjectId)
List<ExtendedObject> extObjects = extendedObjectService.findExtendedObjects(searchCriteria, -1, 0, "name")
if (!extObjects?.isEmpty()) {
return extObjects[0]
}
return null
}
/** Gets a property type given its name and the associated extended object type.
* If it cannot find the property type it will create it.
* @param extendedObjectType the associated extended object type for the property type
* @param propertyTypeName the property type name
* @return the property type */
private PropertyType findOrCreatePropertyType(ExtendedObjectType extendedObjectType, String propertyTypeName) {
PropertyType propertyType = extendedObjectType.getPropertyTypeByName(propertyTypeName)
if (propertyType == null) {
propertyType = new PropertyType()
propertyType.setDataType(PropertyDataType.String)
propertyType.setName(propertyTypeName)
propertyType.setExtendedObjectType(extendedObjectType)
extendedObjectService.createPropertyType(propertyType)
extendedObjectType.addPropertyType(propertyType)
}
return propertyType
}
There are a couple of things about this example you'll want to keep in mind:
To get more useful log messages, make use of logger.debug(), logger.info(), and logger.error(). (Check your logging levels in your admin pages, and make sure the right level is enabled.) For example, you could get some insights from the code above with:
// GET OBJECT TYPE - This example assumes the ExtendedObjectType has already been created
ExtendedObjectType extObjectType = extendedObjectService.findExtendedObjectTypeByClassname("com.axeda.drm.sdk.user.User")
logger.debug extObjectType.toString()
// GET PROPERTY TYPES
PropertyType isExternalUserPropertyType = findOrCreatePropertyType(extObjectType, "IS_EXTERNAL_USER")
logger.debug isExternalUserPropertyType.toString()
PropertyType companyIdPropertyType = findOrCreatePropertyType(extObjectType, "COMPANY_ID")
...
You could also surround calls to external services like extendedObjectService.findExtendedObjectTypeByClassname(...) and sending detailed info about any caught errors to the log.