Metadata and AI extraction with DAM_Utils

General concepts of Metadata extraction and AI setup.

When inserting a new asset, Wedia can extract and populate metadata from the asset itself, or a AI analysis of the asset.

This process is handled by the PACKAGED_DAM_Utils. In its configuration file, you can setup automatic rules that will feed you metadata with information coming from the asset.

Some top level parameters are needed to setup which data objects should be part of the processing, the property that does actually holds the asset binary, and the extraction / transformation rules.

This plugin also performs other tasks such as :

  • activating the creative review on DAM Assets

  • restricting in the file view which variation are displayed…

Plugin Parameters

  • dam_objects_selector (String) : This is a selector for data structures that should be processed. Typical setup include either the objectname (damimport,transfer,massimportitem), or a tag prefixed by a # to select the data structures (“#damobject”) .

  • dam_resource_field_selector (String) : Selector for the property that stores the binary file : ‘binary’

  • async_denorm_thread_pool_size (int): since 2021.4 Maximum number of threads for asynchronous operations

  • dam_denormalization_config (JSON) : A long JSON that will describes the extraction and transformations that will be applied to an asset.

  • enable_async_transforms (Boolean) : Activates the Async transformations

  • dam_denormalization_force_update (Boolean) : Will activate the transformations at each save of the asset.

This property, when set to true, will overwrite metadata of an existing asset with IPTC, EXIF information, this is frequent issue in development setup.

 

Other options :

  • dam_enable_creareview_objects_selector (String) : In some cases, you would like to activate the “Comment” feature coming from the Creative Review for DAM assets. This is the data structure selector if you want to activate this feature. The dam_resource_field_selector will be used to find the binary property.

     

  • dam_fileview_config (JSON) : Most often, you do not want all variations visible in the FileView : this JSON property allows for selecting which variation you want to display for each role.

  • dam_denorm_buttons (JSON) : If you need to show a button to manually trigger the metadata extraction, this JSON will setup for which asset and which role it will show up in the toolbar.

  • dam_denorm_buttons_bypass_security (Boolean) : This allows to bypass security rules to display the “Extract Metadata” button.

Setting Up metadata Extraction.

Understanding selectors.

Selectors can reference data structures or properties based on their names or tags.

A selector can be a comma separated list.

A selector can be setup with a data structure name, a property, or a tag attached to the data structure or the field, with a # prefix :

Sample :

A structure selector such as #damobject,damimport will select all the objects named damimport, or all objects with a tag damobject attached.

How metadata extract works.

The plugin relies on extensions points AbstractObjetcTriggerBusinessServices that the Engine API offers to trigger the automatic metadata extraction based on the plugin configuration.

Creating :

When a object instance which structure name matches with dam_objects_selector, the following process is triggered :

  • On the hook onBeforeInsert_beforeValidate the synchronized transforms are performed. This means that the updated properties are available for the next hooks. If you implement other triggers on these objects, do use a hook that starts after onBeforeInsert_beforeValidate. If you need to use the hook onBeforeInsert_beforeValidate, with, in your process, the result of the extractions of the plugin, then setup the priority order of the plugins in the plugin interface.

  • On the hook onAfterInsert_after, the async transforms are started, in a separate process. The data instance is unlocked immediately. When the async process is over, the data instance is updated without triggering any hook.

Updating :

When a object instance which structure name matches with dam_objects_selector, and the property name setup in dam_resource_field_selector, or the option dam_denormalization_force_update is set to true.

  • On the hook onBeforeUpdate_beforeValidate the synchronized transforms are performed. This means that the updated properties are available for the next hooks. If you implement other triggers on these objects, do use a hook that starts after onBeforeInsert_beforeValidate. If you need to use the hook onBeforeUpdate_beforeValidate, with, in your process, the result of the extractions of the plugin, then setup the priority order of the plugins in the plugin interface.

  • On the hook onAfterUpdate_after, the async transforms are started, in a separate process. The data instance is unlocked immediately. When the async process is over, the data instance is updated without triggering any hook.

Setting up the transformations

The value to be applied to each property of an instance is defined by executing a chain of transformations. Each transformation receives a context object allowing to get the current user, the modified object, the previous object (in case of update).

Transformations can also obtain the result of the execution of nested transformations. This architecture allows to realize very simple classes of transformations and to adapt to different requests by chaining the transformations.

The JSON configuration object

The configuration of the transformation rules is done by defining a JSON object. The plugin uses the following properties:

aliases

An object allowing to define aliases to transformation classes.

Aliases are here for convenience: rather than repetitively writing the full class name, it is easier to just use the class alias.

For each entry in this object, the key is the name of the alias. The value can be:

  • A string : the fully qualified class name : “the.complete.name.of.the.transformation.class"

  • Since 11.25 An array of 1 or 2 string : [“the.complete.name.of.the.transformation.class“, “ThePluginNameThatHoldsTheTransformationClass“]. If the plugin name is omitted, the class will be loaded from the current plugin.

  • Since 11.25 An Object with the following properties:

    • class a String : the fully qualified class name : “the.complete.name.of.the.transformation.class"

    • plugin a String : the plugin name that holds the class.

presets

An array that defines common transformation chains.
The choice of an array definition may seem impractical, but this structure guarantees an orderly definition of presets. It is thus possible to reference another preset in a preset as long as the referenced preset has been defined before in the array.

Each entry in the array is a JSON object describing a preset.

  • key (required) : the name to give to the preset

  • class or classAlias : respectively the full name of the class or the name of the class alias to be used (one of the two is mandatory. class has priority)

  • init (optional) a JSON element (free) to initialize the transform

  • input (optional) a JSON object or a JSON array to define the transformation(s) that will be used as input.

transformations

A JSON array describing the transformations to be carried out. Each entry in the array contains an object with 2 properties :

  • objectSelector : a String allowing to define a selector of the objects which must apply the transformations

  • propertiesTransforms an array to define transformations on properties. Each entry of the array is an object containing 2 properties :

    • fieldSelector: a String allowing to define a selector of the property on which the transformations must be applied.

    • transformers the array of transformations to be applied. Each entry in this array is an object describing either a preset or a transformation

      • A transformation is defined with following properties:

        • class or classAlias, the full name of the class or the alias name of the class to be used (one of the two is mandatory. class has priority)

        • init (optional) a JSON element (free) to initialize the transform

        • input (optional) a JSON object or a JSON array to define the transformation(s) that will be used as input.

      • A preset is defined with following properties:

        • preset, the name of the preset.

  • Since 11.26 workflowTrigger (optional) a string or an array of string giving the ordered list of workflow actions that can be ran after the transformations. Only first valid action will be ran.

  • Since 11.27 preventGuard (optional) a preset or transformation resolving to a boolean. Allows to condition the execution of propertiesTransforms and/or workflowTrigger to the result of the execution of this guard
    If guard is not defined OR guard does not resolve to a BooleanOR resolved value is false, propertiesTransforms will be ran, workflowTrigger will be executed
    If guard resolves totrue OR guard execution throws an Exception, none of propertiesTransforms will be ran, workflowTrigger will not be executed.

asyncTransformations

identical to transformations. The transformations described in this section are performed asynchronously.

manualTransformations Since 11.25

identical to transformations. The transformations described in this input are performed only by a manual call.

Example

{ "aliases": { "resourceFromFieldPattern": "com.wedia.packaged.dam.triggers.datatransformers.impl.PropertyToResourceTransformer", "resourceToDimension": "com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToDimensionTransformer", "dimensionProperty": "com.wedia.packaged.dam.triggers.datatransformers.impl.DimensionToPropertyTransformer", "resourceProperty": "com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToPropertyTransformer" }, "presets": [ { "key": "getBinary", "classAlias": "resourceFromFieldPattern" }, { "key": "getDimensions", "classAlias": "resourceToDimension", "input": { "preset": "getBinary" } } ], "transformations": [ { "objectSelector": "#damobject,damimport", "propertiesTransforms": [ { "fieldSelector": "filesize", "transformers": [ { "classAlias": "resourceProperty", "init": "filesize", "input": { "preset": "getBinary" } } ] } ] } ], "asyncTransformations": [ { "objectSelector": "#damobject,damimport", "propertiesTransforms": [ { "fieldSelector": "width", "transformers": [ { "classAlias": "dimensionProperty", "init": "pxwidth", "input": { "preset": "getDimensions" } } ] }, { "fieldSelector": "height", "transformers": [ { "classAlias": "dimensionProperty", "init": "pxheight", "input": { "preset": "getDimensions" } } ] } ] } ] }

In the example above,

  • we declare 4 aliases, so we can write our presets or transformations by referencing the aliases rather than the full names of the classes. Thus, the alias resourceFromFieldPattern references the class "com.wedia.packaged.dam.triggers.datatransformers.impl.PropertyToResourceTransformer".

  • 2 presets are declared:

  • getBinary which will call the transformation referenced by the alias resourceFromFieldPattern

  • getDimensions which will call the transformation referenced by the alias resourceToDimension with as input the result of the transformation referenced by the preset getBinary

  • A synchronous transformation is declared

  • We declare 2 asynchronous transformations

Out of the box Transformations

This is the standard list of the Transformations offered by the plugin :

  • booleanToActivated

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.BooleanToActivatedTransformer

    • init : none

    • input : a transformation returning java.lang.Boolean

    • output : java.lang.String Value for a property of type child and nature activated (true → "1", false → "2"). If the input is not a Boolean, we parse in Boolean (if input is "true" then the output will be 1). If the input is null, null is returned (and can be processed by the caller).

  • blurHash

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.BlurhashTransformer

    • init : org.json.JSONObject (optional) may contain :

      • baseVariations : String or array of strings ; the base variations used to compute the hash. By default: ["photo", "poster", "thumbnailtiny"]

      • components: Integer or array of Integer, the number of components to be included in the hash. If an array is provided, the first one represents the number of components on the X axis, the second one on the Y axis. Default: 4

    • output : java.lang.String the asset blurhash

  • dimensionProperty

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.DimensionToPropertyTransformer

    • init : java.lang.String (required)

    • input : a transformation returning a com.noheto.image.interfaces.IDimension object (cf resourceToDimension)

    • output : According to the past init :

      • pxwidth : java.lang.Long the width in pixels com.noheto.image.interfaces.IDimension.getPixelWidth

      • pxheight : java.lang.Long the height en pixelcom.noheto.image.interfaces.IDimension.getPixelHeight

      • duration : java.lang.Double the duration in secondscom.noheto.image.interfaces.IDimension.getDurationVideo

      • colorspace : java.lang.String The color spacecom.noheto.image.interfaces.IDimension.getColorspace

      • ratio : java.lang.Double the image ratio or -1 if width or height <= 0

      • xdpi : java.lang.Integer pixels density on X axiscom.noheto.image.interfaces.IDimension.getXDpi

      • ydpi : java.lang.Integerpixels density on Y axis com.noheto.image.interfaces.IDimension.getYDpi

  • dimensionTag

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.DimensionToTagValueTransformer

    • init : java.lang.String (required), the name of the tag to return (ex: “exif:artist”)

    • input : a transformation returning a com.noheto.image.interfaces.IDimension object (cf resourceToDimension)

    • output : java.lang.String the value of the tag passed in init. Returns null if the value of the tag is empty or null.

  • dimensionMultiTag

    • class: com.wedia.packaged.dam.triggers.datatransformers.impl.DimensionToMultiTagValue

    • init: java.lang.String (required), the name of the tag to return (ex: “iptc:2:25”)

    • input: a transformation returning a com.noheto.image.interfaces.IDimension object (cf resourceToDimension)

    • output : java.util.List<java.lang.String> containing the value of the tag as well as those of tags with the same prefix (ex: “iptc:2:25_1”, “iptc:2:25_2”, …)

  • duplicatesFinder

    • class: com.wedia.packaged.dam.triggers.datatransformers.impl.DuplicatesFinderTransformer

    • init: org.json.JSONObject or java.lang.String or null

      • if a JSONObject, valid properties are:

        • objects: java.lang.String a selector on structures to check (default: #damobject)

        • properties: java.lang.String a coma separated list of properties to check (default: phdiff)

        • Since 11.28 properties can be defined as a

          • JSONObject. Each key is treated as a fieldSelector. Value is a boolean defining if a proximity search should be done on this field

          • JSONArray, each value can be

            • a String

            • a JSONObject (as above)

          • default value Since 11.28 is: {"phavg,phdiff": true, "sha": false}

      • if a String, the value will define properties to check

    • input: none

    • output: A JSONArray containing found duplicates. Each item in the array is a JSON object containing:

      • $resource: String, name of the structure having a duplicate of current instance

      • id: Long, id of instance in the structure

  • parseExifDate

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.ExifToDateTransformer

    • init : java.lang.String name of the tag to read (don't forget the prefix "exif:")

    • input : a transformation returning a com.noheto.image.interfaces.IDimension object (cf resourceToDimension)

    • output : java.util.Date if the parse did not fail. Otherwise, the input is returned.

  • parseBoolean

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.StringToBooleanTransformer

    • init : none

    • input : a transformation returning a java.lang.String

    • output : the result of a Boolean.parseBoolean on the String passed in parameter. Returns the input if the input is not a String

  • resourceFromFieldPattern

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.PropertyToResourceTransformer

    • init : java.lang.String if null or empty, we use the value of the dam_resource_field_selector parameter of the plugin

    • input : none

    • output : com.noheto.remote.interfaces.IResourceDimensionExtendedobtained using the first field which is validated by the selector in init and which is a file or image type

  • resourceToDimension

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToDimensionTransformer

    • init : none

    • input : a transformation returning a com.noheto.remote.interfaces.IResourceDimensionExtended(cf resourceFromFieldPattern)

    • output : com.noheto.image.interfaces.IDimension the IDimension object obtained from the input resource

  • resourceProperty

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToPropertyTransformer

    • init : java.lang.String (required)

    • input : a transformation returning a com.noheto.remote.interfaces.IResourceDimensionExtended (cf resourceFromFieldPattern)

    • output : According to the input init :

      • filesize : java.lang.Long the size of the resource in bytescom.noheto.remote.interfaces.IResourceDimensionExtended.getSize

      • contenttype : java.lang.String the content-type of the resourcecom.noheto.remote.interfaces.IResourceDimensionExtended.getContentType

      • pagecount : java.lang.Integer the number of pages in the resourcecom.noheto.image.interfaces.IImaging.getNumberOfPages

      • imagehash : java.lang.String the hash of the imagecom.noheto.image.interfaces.IImaging.getHashImage

      • sha256 : java.lang.String the sha256 of the resource (beware this processing is expensive)

      • phavg : java.lang.Long the average perceptual hash of the resource com.noheto.image.interfaces.IImaging.getHashImageAverage

      • phdiff : java.lang.Long the hash of perceptual difference resource com.noheto.image.interfaces.IImaging.getHashImageDifference

  • asChild

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.StringToChild

    • init :

      • java.lang.String the property that will host the value to create in a Wedia structure (by default "name")

      • Since 11.25, it is possible to pass a JSON object which will be extended with the following values:

        • lookupProperty (default to: “name”) the name of the property that will host the value to create in a Wedia structure.

        • createIfNotExist (default to: true) do we must create the instance if the instance is not found ?

        • withoutSecurity (default to false) must override the security at the creation of the target instance (we use the surfer who is at the origin of the denormalization)

        • withoutTriggers (default to false) should we ignore the triggers ?

    • input : A transformation returning java.lang.String ou unejava.util.Collection<java.lang.String>
      Since 11.25 also accepts :

      • com.wedia.packaged.utils.i18n.ITranslated

      • com.wedia.packaged.utils.i18n.ITranslatable

      • java.util.Collection<com.wedia.packaged.utils.i18n.ITranslated>

      • java.util.Collection<com.wedia.packaged.utils.i18n.ITranslatable>
        which allow to create target instances in different locales (i18n fields management)

    • output : wsnoheto.engine.IObjectReadOnly or java.util.List<wsnoheto.engine.IObjectReadOnly>For each value of the input, search in the nature of the transformed property the instance whose property passed in init has this value. If not found, create the instance (with the current user).

  • resourcePath

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.SelectorToPath

    • init : init : java.lang.String (optional Since 11.25) if null or empty, the value of the dam_resource_field_selector parameter of the plugin is used.

    • input : none

    • output : java.lang.String representing the server path to the resource

  • regexExtract

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.RegExpPatternMatcher

      • .matches() is used in the java service, so it is important that the entire input must match the regular expression.

      • The regular expression should be a capturing one with “( )”, and as said before, it should be made for the entire input (by using .*).

        • Example : Regex to match the first 7 characters of your input : "^(.{7}).*"

    • init : java.lang.String (a regular expression) or an org.json.JSONObjectthat can define :

      • regexp : java.lang.String a regular expression

      • outputNullIfNoMatch : boolean (default false)

      • outputFirstNotEmptyGroup : boolean (default false)

    • input : a transformation returning java.lang.String

    • output : Checks the regular expression on the input. Depending on the options :

      • If the regular expression does not matches, returns null if outputNullIfNoMatch is true, returns the input otherwise

      • If the regular expression match

        • returns the value of the first group capturing non null and non empty if outputFirstNotEmptyGroup (group 0 excluded)

        • returns the value of index group 1 otherwise

 

  • relFinder

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.KeyToChildTransformer

    • init : java.lang.String the property that must be used to search for instances in the Wedia structure (by default "name")

    • input : A transformation returning a java.lang.String or a java.util.Collection<java.lang.String>

    • output : java.lang.String looks for the corresponding instances in the relationship. Does not create the missing instances.

  • ifEmpty

    • classe : com.wedia.packaged.dam.triggers.datatransformers.impl.DenormIfEmpty

    • init : none

    • input : A transformation

    • output : if the current value of the property is not empty, returns the current value of the property. Otherwise, returns the result of the input

  • append

    • classe : com.wedia.packaged.dam.triggers.datatransformers.impl.AppendIfNotEmpty

    • init : none

    • input : java.util.Collection

    • output : appends to a multiple child the elements coming from the input (keeps the previous values)

  • ratioToOrientation

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.RatioToOrientationTransformer

    • init : java.lang.String ou java.lang.Double ou java.lang.Integer tolerance (ex: 2 for 2% tolerance)

    • input : a transformation returning a java.lang.Double a ratio width / height

    • output java.lang.String :

      • vertical" if ratio < (1-tolerance)

      • "horizontal" if ratio > (1+tolerance)

      • "square" otherwise

  • geoCoords

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.GeographicalsCoordinates

    • init : java.lang.String”latitude” or ”longitude”

    • input : a transformation returning com.noheto.image.interfaces.IDimension (cf resourceToDimension)

    • output : java.lang.Double a latitude representation that can be stored in Wedia

  • join

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.JoinValuesTransformer

    • init : java.lang.Stringa separator

    • input : java.util.CollectionThe elements to be joined, separated by the separator transmitted in init.

    • output : java.lang.String the resulting string

  • resourceToPreset

    • classe : com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToPresetTransformer

    • init : java.lang.String a preset name

    • input : a transformation returning a com.noheto.remote.interfaces.IResourceDimensionExtended (cf resourceFromFieldPattern)

    • output : com.noheto.remote.interfaces.IResourceExtendedresource corresponding to the given init.

  • toAiReport

    • classe : com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToAiReport

    • init : none

    • input : A transformation returning a com.noheto.remote.interfaces.IResourceExtended

    • output : An instance of com.wedia.packaged.model.ai.AiReport

This transform relies on the AI variation that is returned by the WXM_DAMDY plugin :

This variation is a JSON object containing all the results of the AI queries activated for this object and on this server.

  • aiAttributeFromReport

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.AiAttributeFromReport

    • init :

      • java.lang.Stringkey of the report property to return

      • Since 11.25 it is possible to pass a JSON object. If you continue to pass a String, it will be used to build a JSON object by filling only the attribute key.

        • attribute((key of the property of the report to return))

        • withTranslations(default to true) should we extract the translations? only taken into account by: caption and tags

        • translation(default to null) used only for a caption or tag attribute: allows if withTranslations is set to false to force a language to be extracted. The fallback is set on the "untranslated" value which is English

        • withoutTranslationFallback (default to false) Used only on attribute caption ou tags : allow to no apply the fallback to english ( → withTranslation is set to false and translation to null null), we return null is translation is not found.

    • input : a transformation returning an instance of de com.wedia.packaged.model.ai.AiReport

    • output : according to the init :

      • caption : java.lang.String A description of the media

      • tags : java.util.List<String> The text values of the tags.

      • celebrities : java.util.List<String> Celebrity names

      • landmarks : java.util.List<String> Notable place names

      • dominantColorForeground : java.lang.String the dominant foreground color

      • dominantColorBackground : java.lang.String the dominant background color

      • avgAge : java.lang.Integeraverage age of the faces discovered

      • nbFaces : java.lang.Integer the number of faces discovered

      • faces : java.lang.String a JSON stream describing faces (array containing faces ; a face is an object containing the age (Number), gender (String) and faceRectangle (rectangle) properties ; a rectangle is an object containing the top, left, width and height properties of the Number)

      • relativeFaces : same as faces but the rectangles are expressed in % of width and height

      • namedFaces : same as relativeFaces but with the name of the celebrity

  • countZipEntries

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.ResourceToZipFileEntriesCount

    • init: none

    • input : a transformation returning a com.noheto.remote.interfaces.IResourceDimensionExtended (cf resourceFromFieldPattern)

    • output : java.lang.Integerthe number of entries (which are not folders) found in the resource if it is an archive (application/zip, application/x-7z-compressed, application/x-htmlzip, application/x-rar-compressed). -1 in case of error; 0 if the input is not an instance of com.noheto.remote.interfaces.IResourceDimensionExtended or the resource does not point to an existing file)

  • firstNonNull

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.FirstNonNullValueTransformer

    • init : none

    • input : an array of transformations

    • output : the output of the first transformation that is not null.

 

  • parseDate

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.DateTransformer

    • init : java.lang.String the date format (cf java.text.SimpleDateFormat)

    • input : A transformation returning a java.lang.String

    • output : java.util.Date the parded date or null

  • rootTree

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.TreeRootTransformer

    • init : java.lang.String a property name

    • input : none

    • output : java.lang.String the id of the root element of the tree (pointed by the property defined by init)

  • Since 11.25 ifElse

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.IfElseTransformer

    • init: none

    • input: Array of transforms. Must be at least 2 items
      Given an array of n items,
      if n is even, all items in an even position are considered as conditions to perform transformation of index + 1.
      If n is odd, last item is the output value treated as final else

    • output: result of if / else if / else

  • Since 11.26 videoAspectRatio

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.RatioToVideoAspectRatioTransformer

    • init (optional) : JSON Object containing following properties:

      • threshold: (optional) Number, threshold for comparing ratio - default: 0.01

      • formats: Array of formats. Each format is an object with following properties:

        • key: The value that will be returned when the ratio is matching

        • ratio: The matching width / height ratio for this format (± threshold)

        • minRatio: Only if ratio is not defined the minimum value for this ratio (threshold will be subtracted)

        • maxRatio: Only if ratio is not defined the maximum value for this ratio (threshold will be added)

    • input : a java.lang.Double ratio (as what dimensionProperty with ratio init would return)

    • output : the key of the matching ratio

  • Since 11.27 staticVal

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.StaticPropertyTransformer

    • init : java.lang.StringThe String representation of the value you want to retrieve.

    • input : none

    • output : the init String

  • Since 11.27 greaterThan

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.GreaterThan

    • init : java.lang.String or java.lang.Number The number to compare input with

    • input : java.lang.Integer int value to compare

    • output : true if input is strictly greater than init

  • Since 11.27 countCommon

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.CountCommonValues

    • init : null (default) or java.lang.Stringor JSON array of java.lang.String

    • input : String output transform or Array of String output transforms

    • output : number of common values between input and init (case sensitive)

  • Since 11.28 negate

    • class : com.wedia.packaged.dam.triggers.datatransformers.impl.NegationTransformer

    • init: none

    • input : any

    • output :

      • null if input is null

      • !input if input is a Boolean

      • !Boolean.parseBoolean(input.toString()) else

  • Since 11.30 every

    • class: com.wedia.packaged.dam.triggers.datatransformers.impl.EveryTransformer

    • init: none

    • input: Collection of transforms or single transform

    • output: if a Collection of transforms is given as input, will set output to true if none of given inputs returns an output of null, something different than a Boolean, false. If input is a single transform, returns the output of the single transform.

  • Since 11.30 isAllowed

    • class: com.wedia.packaged.dam.triggers.datatransformers.impl.IsAllowedBySecurity

    • init: null or JSONObject; object can contain following keys:

      • domain: Security domain name (default: objectdata)

      • action: Security action (default: update)

      • params: Object containing String values that are added before calling the security rule.
        objectname, object and surfer are automatically added by the transformer

    • input: none

    • output: true if surfer is allowed to perform action described in init, false otherwise

Trigger metadata extraction manually

Since 11.25, it is possible to trigger the extraction of metadata by calling an API service.

It is possible to define by configuration additional buttons to be displayed on the detail sheet of an instance to trigger the extraction of metadata.

Presentation of API services

See server documentation :

https://<your-server>/api/packaged/dam-utils/?export=swagger

Button configuration

The configuration of the buttons to be displayed is done by defining the parameter dam_denorm_buttons

This JSON parameter contains an object that can set 2 properties:

  • default allows to set the default configuration

  • roles allows you to specify an object, each key of which is the ID of a role and the configuration value for this role.

A configuration is an object whose keys are selectors to structures. The value associated to each selector is an array where each entry is a button descriptor.

A button descriptor is an object whose keys are bundle keys and the value is the description of a button.

A description of a button is an object that can contain the following keys :

  • cssClass (String) css classes to be applied on the button

  • includedGroups (String or array of strings) list of transformation groups to be applied

  • excludedGroups (String or array of strings) list of transformation groups to be excluded

  • fields (String or array of strings) list limiting the properties to be updated. If this list is empty or null, all the properties are processed.

Example

{ "default": {}, "roles": { "4": { "#damobject": [ { "packaged_btn_resubmit": {} } ] } } }

Trigger the process from code

It is possible to trigger a denormalization from java code, in another plugin for example.

2 methods are provided to allow to trigger all or part of the transformations:

boolean applyDenorms(IPlugin damUtilsPlugin, IObjectWritable instance, CTSurfer surfer, Map<String, Boolean> groups, List<String> fields) throws Throwable

This method applies the transformations on the instance but does not make a database save. The instance can be modified at the end of the call. Returns true if changes have been made, false if not.

 

This method applies the transformations on the instance and performs a save to the database. Returns true if changes have been made, false if not.

Parameter documentation

  • IPlugin damUtilsPlugin The PACKAGED_DAM_Utils plugins

  • IObjectWritable instance The instance for which we want to apply the transformations

  • CTSurfer surfer The surfer performing the operation

  • Map<String, Boolean> groups allows to define the groups to include or exclude. The entries of the Map that have the value true will be the groups to include. Those with value false will be the groups to exclude. If the value is null, then all groups are included

  • List<String> fields The properties you want to modify. If null or empty, all fields are taken.Exemple

Here is an example of a call with saving at the end of processing :

Extension

Since 11.25, it is possible to create your own classes performing transformations.

These new transformations can be isolated in a separate plugin or in the SAN of your application to facilitate updates without the risk of losing your own transformations.

The procedure to follow is as follows:

To create a transformation in the SAN :

  • Create a groovy file from SAN/scripts

To create a transformation in a plugin :

  • Create a groovy file from the scripts folder in the plugin folder

  • The plugin must be active to be taken into account

Here is a sample code of a groovy file :

You can then register your class in the plugin PACKAGED_DAM_Utils: (in the following example we consider that the plugin in which the class is located is samplePlugin and that the file is located in scripts/damutils/transfo/mytransformer.groovy of the plugin)

If this file is in the SAN : (<SAN>/scripts/damutils/transfo/mytransformer.groovy)

Callbacks Since 11.28

In some situations, you need to get know when properties have been updated by DAM_Utils. During synchronous transforms (configured in transforms section), you just need to hook after DAM_Utils entry point (see How metadata extraction works).

You cannot be notified after asynchronous operations as the save performed during asynchronous operations is done without triggers. Instead, you need to register callbacks:

Within the dam_denormalization_config you can add a section asyncCallback:

asyncCallbacks is an array of objects containing following properties:

  • objectSelector - String (required): Selector defining objects for which you need to be callbacked.

  • plugin - String (required): Name of the plugin holding your callback code

  • callbackClass - String (required): Name of the class holding your callback code

  • callbackMethod - String (required): Name of the method holding your callback code

  • active - Boolean (default: true): Is this callback active?

  • runOnEmptyChanges - Boolean (default: false): Should this callback be called even if no changes were done on the object?

Whereas the callback method name can be defined freely, it must comply with the following signature:

void methodName(wsnoheto.engine.CTSurfer surfer, wsnoheto.engine.IObjectReadOnly instance, java.util.Collection<String> changedProperties) throws Throwable