com.ibm.util.merge.template.directive.Insert Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of idmu Show documentation
Show all versions of idmu Show documentation
IBM Data Merge Utility - a template based transformation and enrichment engine
The newest version!
/*
*
* Copyright 2015-2017 IBM
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.ibm.util.merge.template.directive;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.TreeMap;
import com.ibm.util.merge.Config;
import com.ibm.util.merge.Merger;
import com.ibm.util.merge.data.DataElement;
import com.ibm.util.merge.data.DataList;
import com.ibm.util.merge.data.DataObject;
import com.ibm.util.merge.data.DataPrimitive;
import com.ibm.util.merge.exception.Merge500;
import com.ibm.util.merge.exception.MergeException;
import com.ibm.util.merge.template.Template;
import com.ibm.util.merge.template.content.BookmarkSegment;
/**
* Insert Sub-Templates at Bookmarks based on data in the Data Store. Sub-Templates
* are inserted based on data from the Data Manager. A sub-template is inserted
* for each member of a list, or each attribute of an object, or a
* single template for a primitive. See the Object Properties for more details.
*
* @author Mike Storey
* @since: v4.0
* @see com.ibm.util.merge.template.content.Content
* @see com.ibm.util.merge.template.content.BookmarkSegment
* @see com.ibm.util.merge.data.DataManager
*/
public class Insert extends AbstractDataDirective {
private HashSet notFirst;
private HashSet notLast;
private HashSet onlyFirst;
private HashSet onlyLast;
private String bookmarkPattern;
private int ifOperator;
private String ifValue;
/**
* Instantiate an Insert Directive with default values
*/
public Insert() {
this("", "-", Insert.MISSING_IGNORE,
Insert.PRIMITIVE_IGNORE,
Insert.OBJECT_IGNORE,
Insert.LIST_IGNORE,
new HashSet(),
new HashSet(),
new HashSet(),
new HashSet(),
".*",
Insert.INSERT_IF_STRING_EQUALS,
""
);
}
/**
* Instantiate a Insert Directive with the provided values
* @param source The Data Source
* @param delimeter The Source path delimiter
* @param missing The If Missing option
* @param primitive The if Primitive option
* @param object The if Object option
* @param list The if List option
* @param notFirst The Not First tags
* @param notLast The Not Last tags
* @param onlyFirst The only first tags
* @param onlyLast The only last tags
* @param pattern the bookmark pattern to match
* @param ifOperator The if primitive comparison operator option
* @param ifValue The if primitive comparison value
*/
public Insert(String source, String delimeter, int missing, int primitive, int object, int list,
HashSet notFirst, HashSet notLast, HashSet onlyFirst, HashSet onlyLast,
String pattern, int ifOperator, String ifValue) {
super(source, delimeter, missing, primitive, object, list);
this.setType(AbstractDirective.TYPE_INSERT);
this.notFirst = new HashSet(); this.notFirst.addAll(notFirst);
this.notLast = new HashSet(); this.notLast.addAll(notLast);
this.onlyFirst = new HashSet();this.onlyFirst.addAll(onlyFirst);
this.onlyLast = new HashSet(); this.onlyLast.addAll(onlyLast);
this.bookmarkPattern = pattern;
this.ifOperator = ifOperator;
this.ifValue = ifValue;
}
@Override
public void cachePrepare(Template template, Config config) throws MergeException {
super.cachePrepare(template, config);
// Validate enums
if (!Insert.MISSING_OPTIONS().containsKey(this.getIfSourceMissing())) {
throw new Merge500("Invalide Source Missing Option:" + Integer.toString(this.getIfSourceMissing()));
}
if (!Insert.PRIMITIVE_OPTIONS().containsKey(this.getIfPrimitive())) {
throw new Merge500("Invalide If Primitive Option:" + Integer.toString(this.getIfPrimitive()));
}
if (!Insert.LIST_OPTIONS().containsKey(this.getIfList())) {
throw new Merge500("Invalide If List Option:" + Integer.toString(this.getIfList()));
}
if (!Insert.OBJECT_OPTIONS().containsKey(this.getIfObject())) {
throw new Merge500("Invalide If Object Option:" + Integer.toString(this.getIfObject()));
}
if (!Insert.INSERT_IF_OPERATORS().containsKey(this.getIfOperator())) {
throw new Merge500("Invalide Insert If Operator:" + Integer.toString(this.getIfOperator()));
}
}
@Override
public Insert getMergable(Merger context) throws MergeException {
Insert mergable = new Insert();
this.makeMergable(mergable, context);
mergable.setType(TYPE_INSERT);
mergable.setBookmarkPattern(bookmarkPattern);
mergable.setDataSource(this.getDataSource());
mergable.setSourceContent(this.getSourceContent().getMergable());
mergable.setNotFirst(notFirst);
mergable.setNotLast(notLast);
mergable.setOnlyFirst(onlyFirst);
mergable.setOnlyLast(onlyLast);
mergable.setIfSourceMissing(this.getIfSourceMissing());
mergable.setIfList(this.getIfList());
mergable.setIfObject(this.getIfObject());
mergable.setIfPrimitive(this.getIfPrimitive());
mergable.setIfOperator(this.ifOperator);
mergable.setIfValue(this.ifValue);
return mergable;
}
@Override
public void execute(Merger context) throws MergeException {
this.getSourceContent().replace(this.getTemplate().getReplaceStack(), true, this.getConfig().getNestLimit());
String source = this.getSourceContent().getValue();
if (!context.getMergeData().contians(source, this.getDataDelimeter())) {
switch (this.getIfSourceMissing()) {
case MISSING_THROW :
throw new Merge500("Source Data Missing for " + source + " in " + this.getTemplate().getDescription() + " at " + this.getName());
case MISSING_IGNORE :
return;
case MISSING_INSERT:
this.insertAtBookmarks(context, null, true, true);
return;
}
}
DataElement data = context.getMergeData().get(source, this.getDataDelimeter());
DataList list;
if (data.isPrimitive()) {
switch (this.getIfPrimitive()) {
case PRIMITIVE_THROW :
throw new Merge500("Primitive Data found for " + source + " in " + this.getTemplate().getDescription() + " at " + this.getName());
case PRIMITIVE_IGNORE :
return;
case PRIMITIVE_INSERT :
this.insertFromPrimitive(context, (DataPrimitive) data);
return;
case PRIMITIVE_INSERT_IF :
Double dbl = new Double(0);
Double cmp = new Double(0);
String value = data.getAsPrimitive();
try {
cmp = Double.valueOf(this.ifValue);
dbl = Double.valueOf(value);
} catch (Throwable e) {
// ok
}
switch (this.getIfOperator()) {
case INSERT_IF_STRING_EQUALS :
if (value.equals(this.ifValue)) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_STRING_EMPTY:
if (value.isEmpty()) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_STRING_NOT_EMPTY :
if (!value.isEmpty()) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_STRING_GT :
if (this.ifValue.compareTo(value) > 0) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_STRING_LT :
if (this.ifValue.compareTo(value) < 0) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_VALUE_EQUALS :
if (dbl.equals(cmp)) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_VALUE_GT :
if (dbl.compareTo(cmp) < 0) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
case INSERT_IF_VALUE_LT :
if (dbl.compareTo(cmp) > 0) {
this.insertFromPrimitive(context, (DataPrimitive) data);
}
return;
}
this.insertFromPrimitive(context, (DataPrimitive) data);
return;
}
} else if (data.isObject()) {
switch (this.getIfObject()) {
case OBJECT_THROW :
throw new Merge500("Object Data found for " + source + " in " + this.getTemplate().getDescription() + " at " + this.getName());
case OBJECT_IGNORE :
return;
case OBJECT_INSERT_OBJECT :
this.insertFromObject(context, data.getAsObject());
break;
case OBJECT_INSERT_LIST :
this.insertAtBookmarks(context, data, true, true);
break;
}
} else if (data.isList()) {
switch (this.getIfList()) {
case LIST_THROW :
throw new Merge500("List Data found for " + source + " in " + this.getTemplate().getDescription() + " at " + this.getName());
case LIST_IGNORE :
return;
case LIST_INSERT_FIRST :
list = new DataList();
if (data.getAsList().size() > 0) {
list.add(data.getAsList().get(0));
}
data = list;
case LIST_INSERT_LAST :
list = new DataList();
if (data.getAsList().size() > 0) {
list.add(data.getAsList().get(data.getAsList().size()-1));
}
data = list;
case LIST_INSERT :
this.insertFromList(context, data.getAsList());
break;
}
}
}
/**
* Insert a sub-template for each attribute in a DataObject
* @param context
* @throws MergeException
*/
private void insertFromObject(Merger context, DataObject dataObject) throws MergeException {
int loopcount; int size;
loopcount = 1; size = dataObject.entrySet().size();
TreeMap ordered = new TreeMap(dataObject);
for (Entry member: ordered.entrySet()) {
DataObject row = new DataObject();
row.put("attribute",new DataPrimitive(member.getKey()));
row.put("value", member.getValue());
this.insertAtBookmarks(context, row, (loopcount==1), (loopcount==size));
loopcount++;
}
}
/**
* Insert a sub-template for each member of a DataList
* @param context
* @throws MergeException
*/
private void insertFromList(Merger context, DataList dataList) throws MergeException {
int loopcount; int size;
loopcount = 1; size = dataList.size();
for (DataElement value : dataList) {
this.insertAtBookmarks(context, value, (loopcount==1), (loopcount==size));
loopcount++;
}
}
/**
* Insert a sub-template based on a primitive value
* @param context
* @throws MergeException
*/
private void insertFromPrimitive(Merger context, DataPrimitive from) throws MergeException {
String dataString = from.getAsPrimitive();
// conditional insert?
this.insertAtBookmarks(context, new DataPrimitive(dataString), true, true);
}
/**
* Perform sub-template insert at the specified bookmarks.
* @param context The Merge Context
* @param value The new data context for the merge
* @param isFirst First member indicator
* @param isLast Last member indicator
* @throws MergeException on processing errors
*/
public void insertAtBookmarks(Merger context, DataElement value, boolean isFirst, boolean isLast) throws MergeException {
if (context.getStackSize() > this.getConfig().getInsertLimit()) {
throw new Merge500("template insert recursion safety, merge stack size exceded");
}
for (BookmarkSegment bookmark : this.getTemplate().getMergeContent().getBookmarks()) {
if (bookmark.getBookmarkName().matches(this.bookmarkPattern)) {
Template subTemplate = context.getMergable(
bookmark.getTemplateShorthand(value),
bookmark.getDefaultShorthand(),
this.getTemplate().getReplaceStack());
context.pushTemplate(subTemplate.getId().shorthand(), value);
subTemplate.blankReplace((isFirst ? this.notFirst : this.onlyFirst));
subTemplate.blankReplace((isLast ? this.notLast : this.onlyLast));
bookmark.insert(subTemplate.getMergedOutput());
int size = context.getStackSize();
context.popTemplate();
if (!(context.getStackSize() < size)) throw new Merge500("pop didn't work");
}
}
}
/*
* Simple Getters / Setters / Enumerator Constants below here
*/
/**
* @return bookmark name match pattern
*/
public String getBookmarkPattern() {
return bookmarkPattern;
}
/**
* @return Tags to be blank on the first insert
*/
public HashSet getNotFirst() {
return notFirst;
}
/**
* @return list of tags to be blank on the last insert
*/
public HashSet getNotLast() {
return notLast;
}
/**
* @return list of tags to be blank on all but first insert
*/
public HashSet getOnlyFirst() {
return onlyFirst;
}
/**
* @return list of tags to be blank on all but last insert
*/
public HashSet getOnlyLast() {
return onlyLast;
}
public int getIfOperator() {
return ifOperator;
}
public String getIfValue() {
return ifValue;
}
/**
* @param bookmarkPattern The bookmark pattern
*/
public void setBookmarkPattern(String bookmarkPattern) {
this.bookmarkPattern = bookmarkPattern;
}
/**
* @param notFirst Not First tag list
*/
public void setNotFirst(HashSet notFirst) {
this.notFirst.clear();
this.notFirst.addAll(notFirst);
}
/**
* @param notLast Not Last tag list
*/
public void setNotLast(HashSet notLast) {
this.notLast.clear();
this.notLast.addAll(notLast);
}
/**
* @param onlyFirst Only First tag list
*/
public void setOnlyFirst(HashSet onlyFirst) {
this.onlyFirst.clear();
this.onlyFirst.addAll(onlyFirst);
}
/**
* @param onlyLast Tag List
*/
public void setOnlyLast(HashSet onlyLast) {
this.onlyLast.clear();
this.onlyLast.addAll(onlyLast);
}
public void setIfOperator(int ifOperator) {
this.ifOperator = ifOperator;
}
public void setIfValue(String ifValue) {
this.ifValue = ifValue;
}
@Override
public void setIfSourceMissing(int value) {
if (Insert.MISSING_OPTIONS().keySet().contains(new Integer(value))) {
super.setIfSourceMissing(value);
}
}
@Override
public void setIfPrimitive(int value) {
if (Insert.PRIMITIVE_OPTIONS().keySet().contains(new Integer(value))) {
super.setIfPrimitive(value);
}
}
@Override
public void setIfObject(int value) {
if (Insert.OBJECT_OPTIONS().keySet().contains(new Integer(value))) {
super.setIfObject(value);
}
}
@Override
public void setIfList(int value) {
if (Insert.LIST_OPTIONS().keySet().contains(new Integer(value))) {
super.setIfList(value);
}
}
/*
* Static Constants and Options below here
*/
/**
* Value for get/setIfMissing - If the data manager doesn't have the Source provided throw an exception and fail the merge
*/
public static final int MISSING_THROW = 1;
/**
* Value for get/setIfMissing - If the data manager doesn't have the Source provided ignore this directive and continue with the Merge
*/
public static final int MISSING_IGNORE = 2;
/**
* Value for get/setIfMissing - If the data manager doesn't have the Source provided perform a single insert with a null context
*/
public static final int MISSING_INSERT = 3;
/**
* @return Hashmap of supported values for get/setIfMissing
*/
public static final HashMap MISSING_OPTIONS() {
HashMap options = new HashMap();
options.put(MISSING_THROW, "throw");
options.put(MISSING_IGNORE, "ignore");
options.put(MISSING_INSERT, "insert");
return options;
}
/**
* Value used in get/setIfPrimitive value: If the data element identified by Source is a Primitive throw an exception and stop the merge
*/
public static final int PRIMITIVE_THROW = 1;
/**
* Value used in get/setIfPrimitive value: If the data element identified by Source is a Primitive ignore the directive and continue the merge
*/
public static final int PRIMITIVE_IGNORE = 2;
/**
* Value used in get/setIfPrimitive value: If the data element identified by Source is a Primitive perform a single insert with the Primitive context
*/
public static final int PRIMITIVE_INSERT = 3;
/**
* Value used in get/setIfPrimitive value: If the data element identified by Source is a Primitive conditionally insert one sub-template based on IfOperator and Value
*/
public static final int PRIMITIVE_INSERT_IF = 4;
/**
* @return The options for get/setIfPrimitive
*/
public static final HashMap PRIMITIVE_OPTIONS() {
HashMap options = new HashMap();
options.put(PRIMITIVE_THROW, "throw");
options.put(PRIMITIVE_IGNORE, "ignore");
options.put(PRIMITIVE_INSERT, "insert");
options.put(PRIMITIVE_INSERT_IF, "insert if");
return options;
}
/**
* Value used in ifPrimitive-insertIfOperator value: If the value provided is String.equals() the primitive value perform 1 insert
*/
public static final int INSERT_IF_STRING_EQUALS = 1;
/**
* Value used in ifPrimitive-insertIfOperator value: If the primitive is an empty string perform 1 insert
*/
public static final int INSERT_IF_STRING_EMPTY = 2;
/**
* Value used in ifPrimitive-insertIfOperator value: If the primitive is not an empty string perform 1 insert
*/
public static final int INSERT_IF_STRING_NOT_EMPTY = 3;
/**
* Value used in ifPrimitive-insertIfOperator value: If the primitive is greater than the value provided perform 1 insert
*/
public static final int INSERT_IF_STRING_GT = 4;
/**
* Value used in ifPrimitive-insertIfOperator value: If the primitive is less than the value provided perform 1 insert
*/
public static final int INSERT_IF_STRING_LT = 5;
/**
* Value used in ifPrimitive-insertIfOperator value: If the value of the primitive equals the value of the string provided perform 1 insert
*/
public static final int INSERT_IF_VALUE_EQUALS = 6;
/**
* Value used in ifPrimitive-insertIfOperator value: If the value of the primitive is greater than the value of the string provided perform 1 insert
*/
public static final int INSERT_IF_VALUE_GT = 7;
/**
* Value used in ifPrimitive-insertIfOperator value: If the value of the primitive is less than the value of the string provided perform 1 insert
*/
public static final int INSERT_IF_VALUE_LT = 8;
/**
* @return The options for get/setIfOperator
*/
public static final HashMap INSERT_IF_OPERATORS() {
HashMap options = new HashMap();
options.put(INSERT_IF_STRING_EQUALS, "string equals");
options.put(INSERT_IF_STRING_EMPTY, "string is empty");
options.put(INSERT_IF_STRING_NOT_EMPTY, "string not empty");
options.put(INSERT_IF_STRING_GT, "string >");
options.put(INSERT_IF_STRING_LT, "string <");
options.put(INSERT_IF_VALUE_EQUALS, "value =");
options.put(INSERT_IF_VALUE_GT, "value >");
options.put(INSERT_IF_VALUE_LT, "value <");
return options;
}
/**
* Value used in get/setIfObject value: If the data element identified by Source is an Object throw an exception and stop the merge
*/
public static final int OBJECT_THROW = 1;
/**
* Value used in get/setIfObject value: If the data element identified by Source is an Object ignore this directive and continue the merge
*/
public static final int OBJECT_IGNORE = 2;
/**
* Value used in get/setIfObject value: If the data element identified by Source is an Object perform an insert for each attribute of the object
*/
public static final int OBJECT_INSERT_OBJECT = 3;
/**
* Value used in get/setIfObject value: If the data element identified by Source is an Object perform an insert as List for a single object
*/
public static final int OBJECT_INSERT_LIST = 4;
/**
* @return The options for get/setIfOjbect
*/
public static final HashMap OBJECT_OPTIONS() {
HashMap options = new HashMap();
options.put(OBJECT_THROW, "throw");
options.put(OBJECT_IGNORE, "ignore");
options.put(OBJECT_INSERT_OBJECT, "insertObject");
options.put(OBJECT_INSERT_LIST, "insertList");
return options;
}
/**
* Value used in get/setIfList value: If the data element identified by Source is an List throw an exception and stop the merge
*/
public static final int LIST_THROW = 1;
/**
* Value used in get/setIfList value: If the data element identified by Source is an List ignore this directive and continue the merge
*/
public static final int LIST_IGNORE = 2;
/**
* Value used in get/setIfList value: If the data element identified by Source is an List insert subtemplates for each member of the list
*/
public static final int LIST_INSERT = 3;
/**
* Value used in get/setIfList value: If the data element identified by Source is an List insert one subtemplate for the first member of the list
*/
public static final int LIST_INSERT_FIRST = 4;
/**
* Value used in get/setIfList value: If the data element identified by Source is an List insert one subtemplate for the last member of the list
*/
public static final int LIST_INSERT_LAST = 5;
/**
* @return The options for get/setIfList
*/
public static final HashMap LIST_OPTIONS() {
HashMap options = new HashMap();
options.put(LIST_THROW, "throw");
options.put(LIST_IGNORE, "ignore");
options.put(LIST_INSERT, "insert");
options.put(LIST_INSERT_FIRST, "insert first member");
options.put(LIST_INSERT_LAST, "insert last member");
return options;
}
public static final HashMap> getOptions() {
HashMap> options = new HashMap>();
options.put("Source Missing", MISSING_OPTIONS());
options.put("If Primitive", PRIMITIVE_OPTIONS());
options.put("If Object", OBJECT_OPTIONS());
options.put("If List", LIST_OPTIONS());
options.put("Insert If operators", INSERT_IF_OPERATORS());
return options;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy