/
Assets automations
Assets automations
Geocoding
You can use our geocoding service to automatically update your Assets. To do so, save the code below into a Groovy script file and make required changes following the instructions in the comments.
Afterwards, add a new Assets automation rule. You can find more information about creating automation rules in the official Assets documentation. You should use "Execute Groovy script" as the "THEN" action of your rule and give it an absolute path to the script file you have created.
Finally, you need to whitelist the script file. Go to Jira administration > Manage apps > Assets allowlist and click the Edit Settings button. On the next screen, add the absolute path to your script to the list of whitelisted items.
import com.atlassian.jira.component.ComponentAccessor
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade
import com.riadalabs.jira.plugins.insight.services.model.ObjectAttributeBean
import com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory
import groovy.transform.Field
@Field
def objectFacade
def objectTypeAttributeFacade
def objectAttributeBeanFactory
// Helper methods
static def getComponent(String name) {
return ComponentAccessor.getOSGiComponentInstanceOfType(
ComponentAccessor.getPluginAccessor().getClassLoader().findClass(name)
)
}
def readAttributeValue(object, attributeId) {
def objectAttributeBean = objectFacade.loadObjectAttributeBean(object.id, attributeId)
if (objectAttributeBean != null) {
def valueBeans = objectAttributeBean.objectAttributeValueBeans as List<ObjectAttributeBean>
return valueBeans && valueBeans.size() ? valueBeans[0].value : ""
} else {
return ""
}
}
objectFacade = getComponent("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade") as ObjectFacade
objectTypeAttributeFacade = getComponent("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade") as ObjectTypeAttributeFacade
objectAttributeBeanFactory = getComponent("com.riadalabs.jira.plugins.insight.services.model.factory.ObjectAttributeBeanFactory") as ObjectAttributeBeanFactory
/*
Data available to the Groovy script by the Insight automation engine:
object: com.riadalabs.Jira.plugins.insight.services.model.ObjectBean
currentUser: com.atlassian.Jira.user.ApplicationUser
log: org.apache.commons.logging.Log
objectUpdateList: List<com.riadalabs.jira.plugins.insight.services.model.ObjectUpdateBean>
For more details see:
https://confluence.atlassian.com/servicemanagementserver/configuring-automation-rules-1044784502.html
The geocoding operation only needs to be performed if the address has been changed.
Let's assume you store address information in four attributes (Street, House number, City and Country) and these
attributes have IDs 12, 13, 14 and 15 (in the same order).
`objectUpdateList` is empty for Object create event. For Object update event it contains names of updated
attributes. This script determines whether the object is being created or if any of the specified attributes
are being changed.
If the condition is fulfilled, then you have to read values of these attributes.
In this case, the function `readAttributeValue` is used (see above) which accepts the ID of given attribute.
You can find these IDs on the Insight object type configuration page.
You can choose one of several methods to run the geocoding service:
Structured query:
List<Location> geocode(String street, String city, String country)
Plain text query (e.g. if you store complete address in one attribute):
List<Location> query(String query)
After receiving the result from the geocoding service, you need to store it. In this example script we use
two attributes called Longitude and Latitude, whose IDs are 5 and 6. Why do we use two attributes to store the
values? Currently, this is the only way the Insight dataset can read geographic coordinates.
Finally, you need to implement your business logic in case the address is not found, i.e. no coordinates have been found
for given address parameters. You may want to:
- delete longitude and latitude,
- create a comment,
- send a notification,
- etc.
You can find five to-do comments in the sample code. For the script to work properly, you must change the values listed
there (e.g. set IDs or attribute names) to those that match your Insight configuration.
*/
// TODO 1: replace the names of attributes where you store the address information
def addressAttributes = ["Street", "House Number", "City", "Country"]
def changedAttributes = objectUpdateList.collect {bean -> bean.attributeName}
if (changedAttributes.isEmpty() || !addressAttributes.disjoint(changedAttributes)) {
def geocodingService = getComponent("sk.eea.geodata.geocoding.GeocodingService")
// TODO 2: replace these IDs with IDs that correspond to your Insight configuration
def street = readAttributeValue(object, 12)
def houseNumber = readAttributeValue(object, 13)
def city = readAttributeValue(object, 14)
def country = readAttributeValue(object, 15)
log.info("The address is: " + street + " / " + houseNumber + " / " + city + " / " + country)
// TODO 3: use the appropriate method (geocode or query, see above)
def geocodingResult = geocodingService.geocode(houseNumber + " " + street, city, country)
if (!geocodingResult.isEmpty()) {
def result = geocodingResult.get(0)
log.info(result.toString())
// TODO 4: store latitude and longitude in Object attributes, use IDs that correspond to your Insight configuration
def latitudeObjectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttribute(5).createMutable()
def longitudeObjectTypeAttributeBean = objectTypeAttributeFacade.loadObjectTypeAttribute(6).createMutable()
def newLatitudeObjectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(object, latitudeObjectTypeAttributeBean, String.valueOf(result.coordinates.latitude))
def newLongitudeObjectAttributeBean = objectAttributeBeanFactory.createObjectAttributeBeanForObject(object, longitudeObjectTypeAttributeBean, String.valueOf(result.coordinates.longitude))
def longitudeObjectAttributeBean = objectFacade.loadObjectAttributeBean(object.id, longitudeObjectTypeAttributeBean.id)
def latitudeObjectAttributeBean = objectFacade.loadObjectAttributeBean(object.id, latitudeObjectTypeAttributeBean.id)
if (longitudeObjectAttributeBean != null) {
newLongitudeObjectAttributeBean.setId(longitudeObjectAttributeBean.id)
}
if (latitudeObjectAttributeBean != null) {
newLatitudeObjectAttributeBean.setId(latitudeObjectAttributeBean.id)
}
// store attributes
try {
objectFacade.storeObjectAttributeBean(newLatitudeObjectAttributeBean)
objectFacade.storeObjectAttributeBean(newLongitudeObjectAttributeBean)
} catch (Exception e) {
log.warn("Could not update object attribute due to validation exception: " + e.getMessage())
}
} else {
// TODO 5: implement your business logic in case the address is not found
}
}
, multiple selections available,