Introduction

Generic Placeholders allow to use one placeholder for several purposes. In this documentation, we describe, how to enable and configure Generic Placeholders in a priint:publishing server environment.

This documentation adresses Comet project configurators and Java developers as well. The concept is described by three common use cases in section Examples, implementation of these use cases is explained in section Example Implementation.

If you are not that interested in background information, you can skip the first sections and directly proceed with Examples.

If you already know all about the Generic Placeholder and Function Variable concept, you can directly shift to the reference sections ISON: Definition of Function Variables resp. Java: Declaration of Function Variables.

Requirements

Generic Placeholders are supported from priint:publishing server and priint:comet plug-in Version 4.1. Please use the latest available release; while basic functionality should work with any 4.1 version, the full functionality as described in this documentation requires

Generic Placeholders / Function Variables Overview

Base technology for Generic Placeholders is a priint:comet plug-in feature introduced in version 4.1 named Function Variables. Function Variables allow to parameterize placeholders and thus modify the statements, which are used to load, store or synchronize this placeholder. In other words, one placeholder configuration can be used for several type of data - depending on the actual values, which are set for the variables of a placeholder instance in the document.
Values can be assigned using the new Function variables area in the Placeholder Values panel (see highlighted area in screenshot below).

Technical Background

From the Renderer point of view, Function Variables are just special cscript directives preceding a placeholder statement or script. They start with #pragma var (for each variable definition in a single line), followed by the variable, optionally label and optionally a list of values to show up in the variable DropDown menu.

Example

(The highlighted area shows the Function Variable definition)

#pragma var "templateId//Template" "268477081//Product Label Green" "268477090//Product Label Yellow" "67108961//article.template" #pragma var "resultEntityId//Result Entity Id" "//Default" "colour//Colour" "keyvaluegroup//Keyvalue Group" "print_product_group//Print Product Group" "size//Size"
getlist elements plugin(globalName='DataProviderManager',methodName='get')[<Session.Id>,'MultiframeData',<Model.Id>,<Entity.Id>,<resultEntityId>,<Record.Id>,<Record.GroupId>,'','','','','',<xml.publication>,'','',<xml.documentId>,{'<Variable.templateId>' => <templateId>}, <Java.ResultClass>]:placeholder#268468732#get
There are two variables defined in this example: templateId and resultEntityId.
When processing this placeholder statement, each occurence of <templateId> resp. <resultEntityId> is replaced by the actual value set for this variable in this placeholder instance.

In a cscript, the values of the Function Variables are available as global const char * variables, and can be used like this:

int main() {
  showmessage ("templateId=%s, resultEntityId=%s", templateId, resultEntityId);
  return 0;
}
(just to get the idea, of course this script does not make much sense).

priint:publishing server Integration 

In a priint:publishing server environment, placeholder statements are usually generated from the placeholder configuration.
For Function Variables, we introduced a new tag schema, which allows to expose any parameter of a DataProcessing or DataMapping method in the placeholder processing chain as Function Variable:

<Variable.Identifier>
If the value of a parameter matches this schema, a Function Variable definition is added for this parameter, also the statement is expanded, so that values set for this Function Variable in a particular placeholder instance in the document are propagated back to the method, which defined this Function Variable parameter.
Sounds complicated, but probably will get quite obvious with the following example.

Example:
We add the DataProcessing method formatPrice to a price placeholder. This method takes three parameters

If we set the value of the decimalPlaceCharacter to <Variable.DecimalPlaceCharacter>, this parameter is exposed as a Function Variable and can be set in the document for each particular placeholder.

priint:publishing server Integration II

In priint:publishing server Integration we showed, how to define Function Variables in ISON, but it should be more common to declare Function Variables in the Java code of a DataMapping or DataProcessing method (detailed description in the examples below and in section Java: declaration of Function Variales).
The idea is, that in most cases the Java developer should know, if a parameter of the method is suitable for being exposed as a Function Variable or not. Also, he should know about value ranges or value lists applicable for a parameter, so usually the best place to declare Function Variables would be in the Java code.

Declaring Function Variables in the Java Code also allows to define or calculate value lists for the DropDowns in the Placeholder Values panel, show user readable labels instead of parameter names etc.

Naming Conventions 

According to the naming conventions of ParameterTags (see PubServerSDK documentation for the ParameterTags class), the Identifier part of the tag Examples:

The name of the identifier of the parameter used in the document (and in statements) is derived from the identifier part of the tag: it is simply the first character in lowercase, the rest of the identifier unchanged.
This is to meet cscript conventions for variable names, also in the renderer tags with lowercase first character are more common.

Examples:

Usually, you do not have to bother this, unless you refer to Function Variables values in cscript.

Examples 

The following examples use standard DataMapping and DataProcessing methods delivered with priint:publishing server.
We assume, that an entity model and Comet project already exist, also some example data would be nice. In that regard, the output on your system probably will differ from the result shown in the examples.
The configuration of all other resources (DataProvider, placeholder, templates, Java methods) is described in the section Example implementation, so at least it should be possible to achieve equivalent results in your environment.

Generic KeyValue 

We use this generic placeholder to retrieve any type of KeyValue data associated to a bucket.
See Generic KeyValue implementation for details.

The placeholder defines two Function Variables:

Because the list of available keys is dynamic (i.e. depending on the document context resp. bucket linked to the placeholder), we cannot predefine or use a Java method to provide a list of values for this variable (except for the default value Any key), but have to enter an appropriate key manually instead.

Usage of Generic KeyValue placeholder

In a text frame, we create a text placeholder of type "Generic KeyValue" (configuration of this placeholder see Generic KeyValue implementation).
In the Place Holder Values panel, we can see the list of Function Variables, which can be configured for this placeholder (the text cursor must be somewhere in the range of this placeholder or parts of this placeholder must be selected). By clicking the lock item at the top of the list, values can be edited - either by selecting an entry of the DropDown menu in the Value column or by typing a value in the Custom value column (when clicking in the cell, a text input field should appear).
To save the new values, click the lock button again while pressing down the ALT-key.

Load result with key=compatibility and designator=Value with unit

We set key to "compatibility" and designator to "Value with unit", save and link this placeholder with a product:

Load result with key=complete_length and designator=Value without unit

We set key to "complete_length" and designator to "Value without unit", save and reload this placeholder:

Generic Attribute 

This placeholder allows us to load all types of text entities using the same placeholder configuration. While other examples require definition of Function Variables as parameters for certain DataMapping or DataProcessing methods, this example works out of the box: the variable definition is generated automatically, if the Result Entity Id field in the placeholder configuration is left (or set to) empty.
See Generic Attribute Implementation for details.

The placeholder defines one function variable:

Usage of Generic attribute placeholder

In a text frame, we create a text placeholder of type "Generic attribute" (configuration of this placeholder see Generic Attribute Implementation).
In the Place Holder Values panel, we can see the list of Function Variables, which can be configured for this placeholder (the text cursor must be somewhere in the range of this placeholder or parts of this placeholder must be selected). By clicking the lock item at the top of the list, values can be edited - either by selecting an entry of the DropDown menu in the Value column or by typing a value in the Custom value column (when clicking in the cell, a text input field should appear).
To save the new values, click the lock button again while pressing down the ALT-key.

Load result with resultEntityId=product_application

We set resultEntityId to "product_application", save and link this placeholder with a product:

Load result with resultEntityId=product_description

We set resultEntityId to "product_description", save and reload this placeholder:

Template Selector 

In this example, we use a Multiframe placeholder to build sub elements. We add a DataProcessing method to the placeholder configuration, which allows to choose the templates for sub elements via a function variable. This DataProcessing method is included in the standard delivery, see Template Selector Implementation for details.

The placeholder defines two function variable:

Usage of Template Selector

We create a frame and tag it as a Multiframe placeholder (configuration of this Multiframe placeholder see Template Selector Implementation).
In the Place Holder Values panel, we can see the list of Function Variables, which can be configured for this placeholder (the frame must be selected). By clicking the lock item at the top of the list, values can be edited - either by selecting an entry of the DropDown menu in the Value column or by typing a value in the Custom value column (when clicking in the cell, a text input field should appear).

Load result with template=Product Label Green

We set template to Product Label Green, link the frame with a product and execute Repeating elements > Create sub elements of selected products of the Product Pool panel menu while the frame is selected.
Note: we leave resultEntityId empty, thus we can use this frame for any entity type. The DataProvider of the example configuration just loads all direct child buckets of a given bucket.

Load result with template=Product Label Yellow

We change template to Product Label Yellow, clear the sub elements created before and run Repeating elements > Create sub elements of selected products of the Product Pool panel menu again:

Example Implementation 

Generic KeyValue Implementation 

Implementation of this placeholder consist of three parts:

  1. DataMapping method, which declares the key and designator Function Variables
  2. DataProvider for KeyValues using this DataMapping method
  3. Placeholder, which uses this DataProvider

Generic KeyValue for Project Configurators

Follow these configuration steps:

  1. In the ISON DataProvider Explorer, create a new DataProvider:
  2. Use Label="Generic KeyValue", Identifier="genericveyvalue" and Entity class="Bucket":
  3. In the DataProvider editor, click the "Choose" button to choose a DataQuery method. Select "getEntityKeyValuesOfBucket" from the EntityManager plug-in:
  4. Change to the DataMapping tab and click the "Choose" button to choose a DataMapping method. Select "firstKeyValueByKeyToString" from the DataMappingToString plug-in:
  5. Save and checkin the DataProvider
  6. In the ISON CometExplorer, create a new Placeholder:
  7. Set Name="Generic KeyValue" and Type=TEXT (also choose an appropriate description and category):
  8. In the Placeholder editor, click the "Choose" button next to the DataProvider field and select the "Generic KeyValue" DataProvider we just created:

    As you like, you can also set the Result Entity Id, if you want to load KeyValues of a certain entity only.
  9. Save and checkin the placeholder.
There is no more configuration required on the ISON side. Once you relogin from InDesign (or click the "Search" button in the InDesign Placeholder panel while pressing down the ALT key), you should find Generic KeyValue in the list of placeholders:

If this is the case, you can use the newly created Generic KeyValue placeholder out of the box as shown in the Generic KeyValue example.

Why isn't there any more configuration required?
This is, because the Java developer did all the job and added appropriate annotations to the Parameter declarations in the Java class. If this is the case, Function Variables are automatically defined for the DataProvider resp. Placeholder once you use this method in your configuration.
If this is not the case, you can still define Function Variables for certain parameters, though there are some limitations regarding value lists and variable naming. See ISON: Configuration of Generic Placeholders for details.

Generic KeyValue for Java Developers

Though the DataMapping method we use here is part of the standard delivery (and therefore no extra Java implementation is required for this example), the relevant code fragments are explained in the following.

Note:
The example is taken from the DataMapping plug-in, which is part of the standard delivery. For demonstration purposes, the code has been slightly simplified.

Requirements

Remarks

  1. We use a special Tag annotation for Function Variables, the general format is <Variable.Identifier>. If a parameter is set to a value matching this pattern, the CometBridge will generate a Function Variable definition for this parameter (no matter, if this is declared in the Java parameter annotation as shown below or just configured in ISON).
    By setting the defaultValue attribute to <Variable.Key>, the default value when embedding this method in a DataProvider or Placeholder configuration will be <Variable.Key> also, so on the ISON side no further configuration is necessary.
  2. the optional attribute value allows definition of value lists for this parameter. The first entry in the value list (Custom) will always be present, this allows to enter custom values for a particular placeholder in the InDesign document (so as the Java developer you should be aware, that there is no guarantee that one of the values provided in the value list will be passed to the method call).
    Value lists can originate from several sources:
    • Value.Type.INLINE: values are defined inline in the method parameter annotation (as shown in the example below).
    • Value.Type.PLUGIN: values are provided from a Java mthod call (as shown in the third example)
    • Value.Type.CONFIG: values are defined in a configuration file in the Jackrabbit repository (this feature is not yet implemented)
  3. In this case, values are defined INLINE, so we expect a list of or just one (or none, if only the Custom entry should be shown) @ValueItems, each one described by an identifier - this is the value passed to the Java method call, if this entry is selected - and a label - this is the value shown in the popup in the placeholder configuration. Both should (but do not have to) be unique.

import com.priint.pubserver.plugin.annotation.Value;
import com.priint.pubserver.plugin.annotation.ValueItem;

@PubServerPlugin
public class DataMappingToString extends PluginControlDefault { /** * Returns designated field(s) of first KeyValue with given key in input list * * @param keyValues List of KeyValues to be converted * @param key filter KeyValues by this, '{*}' for 'Any key' * @param designator String 'ValueWithoutUnit', 'ValueWithUnit', etc. * @return String list with one or no element * @throws PubServerException */ @PubServerMethod( type = PluginMethod.MethodType.DATA_MAPPING, label ="firstKeyValueByKeyToString", description = "Returns designated field(s) of first KeyValue" + " with given key in input list") public List<String> firstKeyValueByKeyToString( @PubServerMethodParameter( name = "keyValues", defaultValue="<Entity.ResultList>", description="result of query") List<KeyValue> keyValues, @PubServerMethodParameter( name = "key", defaultValue="<Variable.Key>", // Remark (1) description="filter KeyValues by this", value=@Value( // Remark (2) type=Value.Type.INLINE, label="Key", values={ // Remark (3) @ValueItem(identifier="{*}",label="Any Key") } )) String key, @PubServerMethodParameter( name = "designator", defaultValue="<Variable.Designator>", description="Designator for the output format", value=@Value( type=Value.Type.INLINE, label="Designator", values={ @ValueItem(identifier="ValueWithoutUnit", label="Value without unit"), @ValueItem(identifier="ValueWithUnit", label="Value with unit"), @ValueItem(identifier="Label", label="Label"), @ValueItem(identifier="Unit", label="Unit"), @ValueItem(identifier="Symbol", label="Symbol"), @ValueItem(identifier="ParentIdentifier", label="Parent identifier"), @ValueItem(identifier="LabelValueWithUnit", label="Label, value with unit") } )) String designator) throws PubServerException { List<String> resultlist = new ArrayList<String>(); String result = ""; if (keyValues == null || keyValues.isEmpty()) { return resultlist; } for (KeyValue kv : keyValues) { if ( (key != null && key.equals(DataMappingToString.MATCH_ALL)) || (kv.getKey() != null && kv.getKey().equals(key))) { result = getDesignatedFieldFromKeyValue (kv, designator); } } resultlist.add(result); return resultlist; }

Generic Attribute Implementation 

Implementation of this placeholder works out of the box for any placeholder.

Generic Attribute for Project Configurators

There isn't much to regard for project configurators when configuring a "Generic attribute" placeholder. All you have to do, is leave the Result Entity Id field empty, see screenshot below.


If the Result Entity Id is empty, variable definitions are added automatically, when generating statements resp. processing scripts for this placeholder. In this case, the Result Entity Id can be set in the Placeholder Values panel as shown in example Generic Attribute.
The DropDown contains all entities, which match the result type of the DataProvider query method set for this placeholder, i.e.: if the query returns KeyValues, the DropDown list contains all KeyValue entities.

Generic Attribute for Java Developers

There is nothing to do for the Java developer for this example. Function Variable support for the Result Entity Id is a "built-in" feature and there is no other proposed solution to access the resultEntityId attribute of a placeholder in any other way than the auto-generated variable definitions, if unset.

However, this is a good example for context sensitive ValueList provider methods, so it is worth to take a look at the getEntities implementation, which provides the list of entities applicable for this placeholder.

Example: placeholder sensitive ValueList provider method

Note:
Again, this is a real life example, which - for demonstration purpose - has been slightly simplified. Particularly, all failure check has been removed from the code below (and there are lots of possible failures ... starting with incomplete placeholder configurations etc.).

Remarks

  1. we need to access some of the priint:publishing server resources and therefore first get the appropriate managers.
    The code may look somewhat complicated at a first glance, but this is in the nature of things, when dealing with placeholders.
  2. certain properties are predefined in the parameters Map, see Value List from Method for details.

package com.priint.pubserver.comet.bridge.value;

import com.priint.pubserver.comet.config.CometConfigurationLocal;
import com.priint.pubserver.comet.entity.CometProject;
import com.priint.pubserver.comet.entity.placeholder.CometPlaceholder;
import com.priint.pubserver.comet.util.ConfigUtils;
import com.priint.pubserver.comet.util.PathUtils;
import com.priint.pubserver.entity.Entity;
import com.priint.pubserver.entity.EntityModel;
import com.priint.pubserver.exception.PubServerException;
import com.priint.pubserver.plugin.PluginControlDefault;
import com.priint.pubserver.plugin.PluginMethod;
import com.priint.pubserver.plugin.PluginUtils;
import com.priint.pubserver.plugin.ValueItem;
import com.priint.pubserver.plugin.annotation.PubServerMethod;
import com.priint.pubserver.plugin.annotation.PubServerMethodParameter;
import com.priint.pubserver.plugin.annotation.PubServerPlugin;
import com.priint.pubserver.plugin.interfaces.DataProviderManagerLocal;
import com.priint.pubserver.plugin.interfaces.EntityManagerLocal;
import com.priint.pubserver.util.Constants;
import com.priint.pubserver.util.ValueUtils;

@Stateless(mappedName=ValueDefinitions.MAPPED_NAME)
@PubServerPlugin
public class ValueDefinitions extends PluginControlDefault {

  private static final Logger LOGGER = LoggerFactory.getLogger(ValueDefinitions.class);

  @PubServerMethod(type=PluginMethod.MethodType.VALUE_LIST)
  public List<ValueItem> getPlaceholderEntities(
    @PubServerMethodParameter(name="parameters") Map<String,Object> parameters) 
        throws PubServerException {
    List<ValueItem> result = new ArrayList<ValueItem>();

    // Remark (1)
    String sessionId = PluginControlDefault.getSessionId();
    EntityManagerLocal entityManager = 
                         PluginUtils.getPlugin(Constants.MANAGER_ENTITY, sessionId,
                                               EntityManagerLocal.class);
    DataProviderManagerLocal dataproviderManager =
                         PluginUtils.getPlugin(Constants.MANAGER_DATAPROVIDER, sessionId,
                                               DataProviderManagerLocal.class);
    CometConfigurationLocal cometConfiguration =
                         PluginUtils.getPlugin(CometConfigurationLocal.MAPPED_NAME, sessionId, 
                                               CometConfigurationLocal.class);

    // 1st step: get the placeholder we are processing this ValueList for
    // Remark (2)
    Integer placeholderId = (Integer)parameters.get(CometConfigurationLocal.ENV_PLACEHOLDER_PROPERTY);

    String relativePath = PathUtils.getProjectRelativeContainerPath(placeholderId, 
                                                                    CometPlaceholder.class);
    String absolutePath = cometConfiguration.getAbsolutePath(relativePath);

    CometPlaceholder placeholder = ConfigUtils.getEmbeddedEntity(
                                    cometConfiguration.getItem(absolutePath, CometPlaceholder.class), 
                                    CometPlaceholder.class); 

    // 2nd step: get the result type from the DataProvider set for this placeholder
    String dataproviderId = placeholder.getDataProvider().getIdentifier();
    Class<?> returnType = 
                    dataproviderManager.getDataProviderGetterQueryReturnTypeArgument(dataproviderId);

    // 3d step: get EntityModel from the CometProject we are connected with
    CometProject project    = cometConfiguration.getSessionProject();
    String entityModelName  = project.getEntityModel();
    EntityModel entityModel = entityManager.getEntityModel(entityModelName);

    // 4th step: add all matching entities to the result list ...
    for (Entity entity : entityModel.getEntities().values()) {
      if (entity.getEntityDataClass().equals(returnType)) {
        result.add(new ValueItem(entity.getIdentifier(), entity.getLabel()));
      }
    }

    // ... sort and return
    ValueUtils.sortAscending(result);
    return result;
  }
}
    

Template Selector Implementation 

This placeholders requires

Template Selector for Project Configurators

The Template selector implementation is very similar to the Generic KeyValue Implementation shown above. Therefore, we omit screenshots and just do with a simple step-by-step description:

  1. In the ISON DataProvider Explorer, create a new DataProvider
  2. Use Label="Child Buckets As Elements", Identifier="childbucketsaselements" and Entity class="Bucket".
  3. In the DataProvider editor, click the "Choose" button to choose a DataQuery method. Select "getEntityChildBuckets" from the EntityManager plug-in.
  4. Change to the DataMapping tab and click the "Choose" button to choose a DataMapping method. Select "bucketsToElements" from the DataMappingToElement plug-in.
  5. Save and checkin the DataProvider
  6. In the ISON CometExplorer, create a new Placeholder.
  7. Set Name="Child Buckets" and Type=MULTIFRAMES (also choose an appropriate description and category):
  8. In the Placeholder editor, click the "Choose" button next to the DataProvider field and select the "Child Buckets As Elements" DataProvider we just created. As you like, you can also set the Result Entity Id, if you want to load buckets of a certain entity only.
  9. Change to the DataProcessing Load tab, right-click in the function list and select "Add" to add a DataProcessing method.
  10. In the dialog, select the "setTemplate" method from the CometElementFunctions plug-in and click "Ok".
  11. Save and checkin the placeholder.

There is no more configuration required on the ISON side. Once you relogin from InDesign (or click the "Search" button in the InDesign Placeholder panel while pressing down the ALT key), you should find Child Buckets in the list of placeholders.
Before you can use this placeholder, you should also create appropriate templates for the sub elements in InDesign. After creating these templates, you have to reload the Placeholder panel again (click "Search" button while pressing down the ALT key); after that you can use this placeholder like shown in Template Selector example above.

Template Selector for Java Developers

The Java implementation of the Template selector example consists of two parts:

  1. DataProcessing method with appropriate parameter annotations
  2. ValueList method, which provides the list of templates
(both methods are part of the standard delivery, but nevertheless described below).

DataProcessing method setTemplate

Remarks:

  1. by convention, the result list of previous methods in the processing chain is the first parameter.
  2. optional name attribute, this has no further effect on the Function Variable behaviour.
  3. this value will be used as default when adding the method to a configuration (DataProvider or Placeholder). If the parameter should be exposed as a Function Variable, the default value must start with the <Variable. prefix. The identifier of the Function Variable is derived from this value, see PubServerMethodParameter Annotation for details.
  4. source for the value list is a plug-in method. In this case, the attributes pluginMappedName and methodName must also be provided.
package com.priint.pubserver.comet.bridge.dataprocessing;

import java.util.List;
import javax.ejb.Stateless;
import com.priint.pubserver.comet.bridge.entitydata.Element;
import com.priint.pubserver.comet.bridge.value.CometValueDefinitionsLocal;
import com.priint.pubserver.parameterparser.ParameterTags;
import com.priint.pubserver.plugin.PluginControlDefault;
import com.priint.pubserver.plugin.PluginMethod;
import com.priint.pubserver.plugin.annotation.PubServerMethod;
import com.priint.pubserver.plugin.annotation.PubServerMethodParameter;
import com.priint.pubserver.plugin.annotation.PubServerPlugin;
import com.priint.pubserver.plugin.annotation.Value;
import com.priint.pubserver.tracing.Tracer;
import com.priint.pubserver.tracing.TracerFactory;

@Stateless
@PubServerPlugin
public class CometElementFunctions extends PluginControlDefault {

  private static final Tracer TRACER = TracerFactory.getTracer(CometElementFunctions.class);

  @PubServerMethod(
      type = PluginMethod.MethodType.DATA_PROCESSING, 
      description="Applies a template Id to a list of elements.")
  public List<Element> setTemplate(
      @PubServerMethodParameter(
          name="inputList", 
          defaultValue=ParameterTags.Tag.ENTITY_RESULTLIST, 
          description="List of elements") List<Element> inputList,        // Remark (1)
      @PubServerMethodParameter(
          name="templateId",                                              // Remark (2)
          defaultValue="<Variable.TemplateId>",                           // Remark (3)
          description="Id of the template",
          value=@Value(
            type=Value.Type.PLUGIN,                                       // Remark (4)
            label="Template",
            pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
            methodName=CometValueDefinitionsLocal.getTemplates
              )) int templateId) {
    TRACER.info(this.getClass().getSimpleName(), "", 
                     "inputList={}, templateId={}", inputList, templateId);
    for (Element e : inputList) {
      e.setTemplateId(templateId);
    }
    return inputList;
  }
}
    

ValueList provider method getTemplates

Remarks:

  1. type for ValueList provider methods must be PluginMethod.MethodType.VALUE_LIST
  2. by convention, the signature of a ValueList provider method must be
    public List<ValueItem> methodName(Map<String,Object> parameters)
    The method is allowed to throw any PubServerException (which will be handled when processing this method).

package com.priint.pubserver.comet.bridge.value;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;

import com.priint.pubserver.comet3.entity.PageItem;
import com.priint.pubserver.exception.PubServerException;
import com.priint.pubserver.plugin.PluginControlDefault;
import com.priint.pubserver.plugin.PluginMethod;
import com.priint.pubserver.plugin.ValueItem;
import com.priint.pubserver.plugin.annotation.PubServerMethod;
import com.priint.pubserver.plugin.annotation.PubServerMethodParameter;
import com.priint.pubserver.plugin.annotation.PubServerPlugin;
import com.priint.pubserver.util.ValueUtils;

@Stateless
@PubServerPlugin
public class CometValueDefinitions extends PluginControlDefault {

  @PubServerMethod(type=PluginMethod.MethodType.VALUE_LIST)                        // Remark (1)
  public List<ValueItem> getTemplates(
      @PubServerMethodParameter(name="parameters") Map<String,Object> parameters)  // Remark (2)
      throws PubServerException {
    List<ValueItem> result = new ArrayList<ValueItem>();
    Map<String,PageItem> pageitems = this.getPageItemHash();
    
    for (PageItem it : pageitems.values()) {
      result.add(new ValueItem(it.getId() + "", it.getName()));
    }
    ValueUtils.sortAscending(result);
    return result;
  }

}

ISON: Definition of Function Variables 

Most of it has already been said in priint:publishing server Integration.

Summary:

The most common way to use Function Variables will probably be, to just add DataMapping or DataProcessing methods to the DataProvider resp. placeholder, which already declare Function Variables in the Java code of these methods.
In this case, you can leave the configuration unchanged and everything works like supposed by the Java developer.

There are three situations, when a Comet project configurator might want to manually change Function Variable support:

Java: Declaration of Function Variables 

In this section, we describe the Java resources required for Function Variable support.
As already mentioned, Function Variables can be declared for any parameter of a DataMapping or DataProcessing method. Whenever this method is included in a DataProvider or placeholder configuration, the Function Variable will be available out of the box.

DataMapping and DataProcessing method implies the following requirements:

@PubServerMethodParameter Annotation 

package com.priint.pubserver.plugin.annotation;
public @interface PubServerMethodParameter

The @PubServerMethodParameter annotation is the general annotation for any parameter of any @PubServerMethod and documented in the PubServerSDK. Some of the attributes are relevant for Function Variable declaration and therefore described here:

@Value Annotation 

package com.priint.pubserver.plugin.annotation;
public @interface Value

The @Value annotation allows declaration of Function Variable labels and value lists for this Function Variable.


The relevant attributes are described here:

Empty Value List / no Drop Down

No values (except for the "Custom" entry, which will always be present) should be shown in the DropDown for a Function Variable.
This can be achieved very simple:

Value List Inline 

We use this value type, if we have a fixed set of values (however, if these values are used for several Function Variables, it can still make sense to define a method, which returns this list).

To use fixed / inline lists of values

@PubServerMethodParameter(
  name = "designator",
  defaultValue="<Variable.Designator>",
  description="Designator for the output format",
  value=@Value(
    type=Value.Type.INLINE,
    label="Designator",
    values={
      @ValueItem(identifier="ValueWithoutUnit", label="Value without unit"),
      @ValueItem(identifier="ValueWithUnit", label="Value with unit"),
      @ValueItem(identifier="Label", label="Label"),
      @ValueItem(identifier="Unit", label="Unit"),
      @ValueItem(identifier="Symbol", label="Symbol"),
      @ValueItem(identifier="ParentIdentifier", label="Parent identifier"),
      @ValueItem(identifier="LabelValueWithUnit", label="Label, value with unit")
      }
    )) String designator)

Value List from Method 

Values are provided by a ValueList provider method. This method must match the following signature:

public List<ValueItem> methodName(Map<String, Object> parameters)
Also, the method must be annotated as @PubServerMethod with PluginMethod.MethodType.VALUE_LIST.

Note:
The return type of ValueList methods must be
  List<com.priint.pubserver.plugin.ValueItem>
rather than
  List<com.priint.pubserver.plugin.annotation.ValueItem>

Example: fully annotated ValueList provider method:

@PubServerMethod(type=PluginMethod.MethodType.VALUE_LIST)
public List<ValueItem> getTemplates(
  @PubServerMethodParameter(name="parameters") Map<String,Object> parameters);

The method is allowed to throw a PubServerException. Other exceptions should be handled in the method itself.

Relevant @Value attributes

The following parameters are provided by the priint:publishing server when calling this method:

More parameters can be provided using the methodParameters attribute, see example below.
@PubServerMethodParameter(
  name="templateId",
  defaultValue="<Variable.TemplateId>",
  description="Id of the template",
  value=@Value(
    type=Value.Type.PLUGIN,
    label="Template",
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME, // it is a good idea to define constants
    methodName=CometValueDefinitionsLocal.getTemplates,      // for plug-in and method names...
    methodParameters={
      @ValueMethodParameter(key="templateDomain",value="all"),
      @ValueMethodParameter(key="pageType",value="anyPage"),
    }
      )) int templateId)

Value List from Configuration File 

In future versions, it will also be possible to load value lists from certain configuration files. At the time of this writing, this is not yet implemented.

Standard Methods supporting Function Variables

There are a couple of methods in the standard delivery, which already support Function Variables. Also a (small) set of ValueList provider methods is included.

Methods and Resources for Value Lists 

Methods defined in com.priint.pubserver.datamapping.DataMappingValueDefinitionsLocal (PubServerSDK):

getKeys(Map<String, Object>)
Gets keys. Actually, this will just return the MATCH_ALL entry, because (as explained in the example above), keys are "dynamic" and, at the time, cannot be retrieved from EntityManager.

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=DataMappingValueDefinitionsLocal.MAPPED_NAME,
    methodName=DataMappingValueDefinitionsLocal.getKeys
    // ...

getKeyValueDesignators(Map<String, Object>)
Gets the standard set of key designators.

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=DataMappingValueDefinitionsLocal.MAPPED_NAME,
    methodName=DataMappingValueDefinitionsLocal.getKeyValueDesignators
    // ...

getMediaFormats(Map<String, Object>)
Gets available media formats.

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=DataMappingValueDefinitionsLocal.MAPPED_NAME,
    methodName=DataMappingValueDefinitionsLocal.getMediaFormats
    // ...

getMediaTypes(Map<String, Object>)
Gets available media types

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=DataMappingValueDefinitionsLocal.MAPPED_NAME,
    methodName=DataMappingValueDefinitionsLocal.getMediaTypes
    // ...

getPriceDesignators(Map<String, Object>)
Gets the standard set of price designators

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=DataMappingValueDefinitionsLocal.MAPPED_NAME,
    methodName=DataMappingValueDefinitionsLocal.getPriceDesignators
    // ...

Methods defined in com.priint.pubserver.comet.bridge.value.CometValueDefinitionsLocal (CometBridgeSDK).
All of these methods require a connection to a Comet project.

getTemplates(Map<String, Object>)
Gets all templates of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getTemplates
    // ...

getBucketEntities(Map<String, Object>)
Gets all Bucket entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getBucketEntities
    // ...

getCordEntities(Map<String, Object>)
Gets all Cord entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getCordEntities
    // ...

getEntities(Map<String, Object>)
Gets all entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getEntities
    // ...

getKeyValueEntities(Map<String, Object>)
Gets all KeyValue entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getKeyValueEntities
    // ...

getMediaAssetEntities(Map<String, Object>)
Gets all MediaAsset entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getMediaAssetEntities
    // ...

getPlanningEntities(Map<String, Object>)
Gets all Planning entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getPlanningEntities
    // ...

getPriceEntities(Map<String, Object>)
Gets all Price entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getPriceEntities
    // ...

getTableDataEntities(Map<String, Object>)
Gets all TableData entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getTableDataEntities
    // ...

getTextEntities(Map<String, Object>)
Gets all Text entities of the entity model of the current Comet project

// ...
value=@Value(
    type=Value.Type.PLUGIN,
    pluginMappedName=CometValueDefinitionsLocal.MAPPED_NAME,
    methodName=CometValueDefinitionsLocal.getTextEntities
    // ...

DataMapping Methods

For further information about the parameter meanings, refer to the SDK documentation

Methods defined in com.priint.pubserver.plugins.datamapping.DataMappingToString

textListToString

textListToStrings

firstKeyValueToString

firstKeyValueByKeyToString

mapKeyValuesToString

mapKeyValuesByKeyToString

valuesByKeyToStrings

mediaAssetListToFileUrl

firstMediaAssetToFileUrl

lastMediaAssetToFileUrl

mediaAssetListToFilePath

firstMediaAssetToFilePath

lastMediaAssetToFilePath

priceListToString

DataProcessing Methods

Methods defined in com.priint.pubserver.plugins.dataprocessing.StringFunctions

setPrefix

replace

replaceRegEx

truncate

leftPad

rightPad

match

inverseMatch

substring

join

split

Methods defined in com.priint.pubserver.comet.bridge.CometElementFunctions

setTemplate