/
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 } }