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 aBoolean
OR resolved value isfalse
, 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 aliasresourceFromFieldPattern
getDimensions
which will call the transformation referenced by the aliasresourceToDimension
with asinput
the result of the transformation referenced by the presetgetBinary
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 pixelscom.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 <= 0xdpi :
java.lang.Integer
pixels density on X axiscom.noheto.image.interfaces.IDimension.getXDpi
ydpi :
java.lang.Integer
pixels density on Y axiscom.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
orjava.lang.String
ornull
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 plugininput : none
output :
com.noheto.remote.interfaces.IResourceDimensionExtended
obtained 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 resourcecom.noheto.image.interfaces.IImaging.getHashImageAverage
phdiff :
java.lang.Long
the hash of perceptual difference resourcecom.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.createIfNotExists
(default to:true
) do we must create the instance if the instance is not found ?withoutSecurity
(default tofalse
) 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 tofalse
) 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
orjava.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
init :
java.lang.String
(a regular expression) or anorg.json.JSONObject
that can define :regexp :
java.lang.String
a regular expressionoutputNullIfNoMatch :
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 ajava.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
oujava.lang.Double
oujava.lang.Integer
tolerance (ex: 2 for 2% tolerance)input : a transformation returning a
java.lang.Double
a ratio width / heightoutput
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.String
a separatorinput :
java.util.Collection
The 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 nameinput : a transformation returning a
com.noheto.remote.interfaces.IResourceDimensionExtended
(cf resourceFromFieldPattern)output :
com.noheto.remote.interfaces.IResourceExtended
resource 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.String
key of the report property to returnSINCE 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 totrue
) should we extract the translations? only taken into account by: caption and tagstranslation
(default tonull
) used only for a caption or tag attribute: allows ifwithTranslations
is set tofalse
to force a language to be extracted. The fallback is set on the "untranslated" value which is EnglishwithoutTranslationFallback
(default tofalse
) Used only on attribute caption ou tags : allow to no apply the fallback to english ( →withTranslation
is set tofalse
andtranslation
to nullnull
), we returnnull
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 mediatags :
java.util.List<String>
The text values of the tags.celebrities :
java.util.List<String>
Celebrity nameslandmarks :
java.util.List<String>
Notable place namesdominantColorForeground :
java.lang.String
the dominant foreground colordominantColorBackground :
java.lang.String
the dominant background coloravgAge :
java.lang.Integer
average age of the faces discoverednbFaces :
java.lang.Integer
the number of faces discoveredfaces :
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 heightnamedFaces : 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.Integer
the 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 ofcom.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 (cfjava.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 nameinput : 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 elseoutput: result of if / else if / else
Prior to SINCE 11.28default final else (if n is even) value was null
. Starting from 11.28, default else value is the field current value (= no changes)
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
This transformer will return the first format matching available formats, using ratio (± threshold) or minRatio -threshold and maxRatio+threshold.
You can provide as many formats definitions as you want for this transformer.
Following definitions will always always be added to your configuration (thus evaluated after yours): [{key: "5:4", ratio: 5/4}, {key: "4:3", ratio: 4/3}, {key: "3:2", ratio: 3/2}, {key: "16:10", ratio: 16/10}, {key: "16:9", ratio: 16/9}, {key: "1.85:1", ratio: 1.85}, {key: "2.39:1", minRatio: 2.39, maxRatio: 2.40}, {key: "others"}]
If you want to completely override default behaviour, you have to define your own formats (with either ratio or minRatio maxRatio and provide the last entry without neither ratio nor minRatio maxRatio. A key can be omitted if you want to retrieve null.
SINCE 11.27 staticVal
class :
com.wedia.packaged.dam.triggers.datatransformers.impl.StaticPropertyTransformer
init :
java.lang.String
The String representation of the value you want to retrieve.input : none
output : the init String
If target field is of type date (new) or datetime, the init value “now” will return a new Date()
SINCE 11.27 greaterThan
class :
com.wedia.packaged.dam.triggers.datatransformers.impl.GreaterThan
init :
java.lang.String
orjava.lang.Number
The number to compare input withinput :
java.lang.Integer
int value to compareoutput :
true
if input is strictly greater than init
SINCE 11.27 countCommon
class :
com.wedia.packaged.dam.triggers.datatransformers.impl.CountCommonValues
init :
null
(default) orjava.lang.String
or JSON array ofjava.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 isnull
!input
if input is aBoolean
!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 aBoolean
,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
orJSONObject
; 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
andsurfer
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.
boolean applyAndSaveDenorms(IPlugin damUtilsPlugin, IObjectWritable instance, CTSurfer surfer, Map<String, Boolean> groups, List<String> fields) throws Throwable
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 pluginsIObjectWritable instance
The instance for which we want to apply the transformationsCTSurfer surfer
The surfer performing the operationMap<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 includedList<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 :
import java.util.*; import com.noheto.plugins.IPlugin; import com.noheto.plugins.PluginFactory; import wsnoheto.engine.IObjectWritable; import wsnoheto.engine.CTSurfer; IPlugin damUtilsPlugin = PluginFactory.getPlugin("PACKAGED_DAM_Utils"); boolean changed = ((Boolean)damUtilsPlugin.invoke( "com.wedia.packaged.dam.DamUtilsHelper", "applyAndSaveDenorms", new Object[] { damUtilsPlugin, // The PACKAGED_DAM_Utils plugins instance, // The instance for which we want to apply the transformations surfer, // the surfer groups, // la Map of the groups (can be null) fields // the properties list (can be null) } ));
The first parameter is the PACKAGED_DAM_Utils plugin itself, and especially not your plugin in where you are calling PACKAGED_DAM_Utils.
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 folderThe plugin must be active to be taken into account
Be careful, it is mandatory that you always write your groovy file names and the folders in which they are located in lower case. This is because the application restore mechanism forces file names in lower case.
Here is a sample code of a groovy file :
import com.wedia.packaged.dam.triggers.datatransformers.AbstractDataTransformer; import com.wedia.packaged.dam.triggers.datatransformers.IDataTransformer; import com.wedia.packaged.dam.triggers.datatransformers.context.IDataTransformContext; class MyTransformer extends AbstractDataTransformer { @Override public IDataTransformer transform(IDataTransformContext context) throws Throwable { // read the init Object init = this.getInit(); // if the init is a string : String initString = this.getInitString(); // the the result of previous transformations Object input = this.getInput(context); // apply the transformations we want Object transformationResult = doSomethingSmart(init, input); // Return their results this.setOutput(transformationResult); // return this return this; } }
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)
{ "aliases": { "myTransform": ["damutils/transfo/mytransformer.groovy", "samplePlugin"], ... } }
If this file is in the SAN : (<SAN>/scripts/damutils/transfo/mytransformer.groovy
)
{ "aliases": { "myTransform": "damutils/transfo/mytransformer.groovy", ... } }
If you update your groovy code, you have to update the PACKAGED_DAM_Utils plugin so that your modifications are updated.
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
:
"asyncCallback": [ { "objectSelector":"#damobject", "plugin": "PACKAGED_DAM_Utils", "callbackClass": "com.wedia.packaged.dam.NotifyUserAsyncCallback", "callbackMethod": "notifyUser", "active": true, "runOnEmptyChanges": true } ]
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
void yourMethodName( CTSurfer surfer, IObjectReadOnly instance, Collection<String> changedproperties ) throws Throwable { System.out.println("Instance " + instance.getObjectType() + "/" + instance.getId() + " has been denormalized by damutils after user " + surfer.getName() + " updates. Damutils has changed properties: " + changedproperties.stream().collect(Collectors.joining(", ")) ); }