
com.ibm.util.merge.template.Template 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!
/*
*
c * 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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import com.ibm.util.merge.Cache;
import com.ibm.util.merge.Config;
import com.ibm.util.merge.Merger;
import com.ibm.util.merge.exception.Merge500;
import com.ibm.util.merge.exception.MergeException;
import com.ibm.util.merge.template.Stat;
import com.ibm.util.merge.template.content.Content;
import com.ibm.util.merge.template.content.TagSegment;
import com.ibm.util.merge.template.directive.AbstractDirective;
/**
* Template Content and a list of Directives that drive Merge functionality
*
* Template content consist of text, with any number of Replace Tag or Book-mark segments
* that are identified by the template.wrapper which is a simple "open" and "close" pair
* that surround the tag and book-mark segments.
* Note: Wrapper characters can not appear anywhere in the template
* content except to identify a Tag or Book-mark.
* The template is a state-full object that goes through a four phase life-cycle
*
* - Raw templates are constructed, or parsed from JSON and as such can
* have invalid values for some attributes.
* - Cached templates have been validated and had transient values initialized.
* The cache put/post methods utilize the cachePrepare() method to transform
* a "Raw" template into a Cache Ready template.
* - Mergable templates are a clone of a cached template. Only in this state can a
* template be "merged". The Cache uses the getMergable() method to get a mergable
* clone of the cached template.
* - Merged templates have completed merge processing and can provide merged output.
* Note that calling getMergedOutput for a non-merged template will cause the merge
* to occur.
*
* @author Mike Storey
* @since: v4.0
* @see com.ibm.util.merge.template.content.Content
* @see com.ibm.util.merge.template.content.TagSegment
* @see com.ibm.util.merge.template.content.BookmarkSegment
* @see com.ibm.util.merge.template.directive.AbstractDirective
* @see com.ibm.util.merge.data.DataManager
*/
public class Template {
private final TemplateId id;
private String content = "";
private Wrapper wrapper = new Wrapper();
private int contentType = Template.CONTENT_TEXT;
private int contentDisposition = Template.DISPOSITION_NORMAL;
private int contentEncoding = TagSegment.ENCODE_NONE;
private String contentFileName = "";
private String contentRedirectUrl = "";
private String description = "";
private List directives = new ArrayList();
/*
* Transient values - initialized in cachePrepare, copied in getMergavble
*/
private transient int state = STATE_RAW;
private transient Stat stats = new Stat();
private transient Content mergeContent;
private transient HashMap replaceStack = new HashMap();
private transient Merger context;
private transient Config config;
/**
* Instantiate a void template - provided for testing only
* @throws MergeException on processing errors
*/
public Template() throws MergeException {
this(new TemplateId("void","void","void"));
}
/**
* Instantiate a Template with the given ID
* @param id The Template ID
* @throws MergeException on processing errors
*/
public Template(TemplateId id) throws MergeException {
this.id = id;
this.setContent("");
this.replaceStack = new HashMap();
}
/**
* Instantiate a Template with the given ID
*
* @param group The template group
* @param name The template name
* @param variant The template variant
* @throws MergeException on processing errors
*/
public Template(String group, String name, String variant) throws MergeException {
this(new TemplateId(group,name,variant));
}
/**
* Instantiate a Template with the given ID and Content
*
* @param group The template group
* @param name The template name
* @param variant The template variant
* @param content The template content
* @throws MergeException on processing errors
*/
public Template(String group, String name, String variant, String content) throws MergeException {
this(new TemplateId(group,name,variant));
this.setContent(content);
}
/**
* Instantiate a Template with the given ID, content and wrapper specification
* @param group The template Group
* @param name The template Name
* @param variant The template Variant
* @param content The template content
* @param before The wrapper open string
* @param after The wrapper close string
* @throws MergeException on processing errors
*/
public Template(String group, String name, String variant, String content, String before, String after) throws MergeException {
this(group,name,variant,content);
this.wrapper.front = before;
this.wrapper.back = after;
}
/**
* Validate all ordinal values, populate transient values.
* @param cache The cache we're being added to.
* @throws MergeException on processing errors
*/
public void cachePrepare(Cache cache) throws MergeException {
if (this.state != STATE_RAW) {
throw new Merge500("Can only prepare a RAW template");
}
this.config = cache.getConfig();
this.stats = new Stat();
this.stats.name = this.getId().shorthand();
this.stats.size = this.content.length();
this.mergeContent = new Content(this.wrapper, this.content, this.contentEncoding);
this.replaceStack = new HashMap();
this.context = null;
for (AbstractDirective directive : this.directives) {
directive.cachePrepare(this, config);
}
this.state = STATE_CACHED;
}
/**
* Gets a mergable copy of this template and an empty replace stack
*
* @param context The merge context
* @return the mergable
* @throws MergeException on processing errors
*/
public Template getMergable(Merger context) throws MergeException {
return getMergable(context, new HashMap());
}
/**
* Gets a mergable copy of this template with the replace stack pre-loaded
*
* @param context The Merge Context
* @param replace The repalce stack
* @return The mergable template
* @throws MergeException on processing errors
*/
public Template getMergable(Merger context, HashMap replace) throws MergeException {
if (this.state != STATE_CACHED) {
throw new Merge500("Can only get a mergable template from cached template");
}
Template mergable = new Template(this.id);
mergable.setConfig(config);
mergable.setContext(context);
mergable.setContentDisposition(contentDisposition);
mergable.setContentEncoding(contentEncoding);
mergable.setContentType(contentType);
mergable.setDescription(description);
mergable.setContentFileName(contentFileName);
mergable.setContentRedirectUrl(contentRedirectUrl);
mergable.setContent(this.content);
mergable.setWrapper(this.wrapper);
mergable.mergeContent = this.getMergeContent().getMergable();
mergable.replaceStack.putAll(replace);
for (AbstractDirective directive : this.directives) {
mergable.addDirective(directive.getMergable(context));
}
mergable.state = STATE_MERGABLE;
return mergable;
}
/**
* Gets the merged output, calling the merge if needed
*
* @return the merged output
* @throws MergeException on processing errors
*/
public Content getMergedOutput() throws MergeException {
if (this.state < STATE_MERGABLE) {
throw new Merge500("Template is not in a mergable state");
}
if (this.state == STATE_MERGABLE) {
Long start = System.currentTimeMillis();
for (AbstractDirective directive : this.directives ) {
try {
directive.execute(this.context);
} catch (MergeException e) {
e.setDirective(directive);
e.setTemplate(this);
throw e;
}
}
this.state = STATE_MERGED;
this.context.getCahce().postStats(this.id.shorthand(), System.currentTimeMillis() - start);
}
return this.mergeContent;
}
/**
* Adds the directive.
*
* @param directive the directive
*/
public void addDirective(AbstractDirective directive) {
if (this.state == STATE_RAW) {
directive.setTemplate(this);
directives.add(directive);
}
}
/**
* Adds a from/to pair to the replace stack.
*
* @param from From Value
* @param to To Value
*/
public void addReplace(String from, String to) {
if (this.state == STATE_MERGABLE) {
this.replaceStack.put(from, to);
}
}
/**
* Adds a from/to pair to the replace stack.
* @param values The values to add
*/
public void addReplace(HashMap values) {
if (this.state == STATE_MERGABLE) {
this.replaceStack.putAll(values);
}
}
/**
* Remove the replace value for one or more tags.
*
* @param tags Tags to set to ""
*/
public void blankReplace(HashSet tags) {
if (this.state == STATE_MERGABLE) {
for (String tag : tags) {
this.replaceStack.put(tag, "");
}
}
}
/**
* Clears the content.
*/
public void clearContent() {
if (this.state == STATE_MERGABLE) {
this.mergeContent = new Content();
this.content = "";
}
}
/**
* Set the Content Wrapper strings
* @param wrapper the value
*/
private void setWrapper(Wrapper wrapper) {
if (this.state == STATE_RAW) {
this.wrapper = wrapper;
}
}
/**
* Sets the wrapper.
*
* @param front the Front wrapper
* @param back The back wrapper
*/
public void setWrapper(String front, String back) {
if (this.state == STATE_RAW) {
this.wrapper = new Wrapper();
this.wrapper.front = front;
this.wrapper.back = back;
}
}
private void setConfig(Config config) {
this.config = config;
}
/**
* Sets the content.
*
* @param content the new content
*/
public void setContent(String content) {
if (this.state == STATE_RAW) {
this.content = content;
}
}
/**
* Sets the content type.
*
* @param contentType the new content type
*/
public void setContentType(int contentType) {
if (this.state == STATE_RAW) {
if (CONTENT_TYPES().containsKey(contentType)) {
this.contentType = contentType;
}
}
}
/**
* Sets the content disposition.
*
* @param contentDisposition the new content disposition
*/
public void setContentDisposition(int contentDisposition) {
if (this.state == STATE_RAW) {
if (DISPOSITION_VALUES().containsKey(contentDisposition)) {
this.contentDisposition = contentDisposition;
}
}
}
public void setContentFileName(String contentFileName) {
if (this.state == STATE_RAW) {
this.contentFileName = contentFileName;
}
}
/**
* Sets the content encoding.
*
* @param contentEncoding the new content encoding
*/
public void setContentEncoding(int contentEncoding) {
if (this.state == STATE_RAW) {
if (TagSegment.ENCODE_VALUES().containsValue(contentEncoding)) {
this.contentEncoding = contentEncoding;
}
}
}
/**
* Sets the description.
*
* @param description the new description
*/
public void setDescription(String description) {
if (this.state == STATE_RAW) {
this.description = description;
}
}
/**
* @param contentRedirectUrl The redirect URL
*/
public void setContentRedirectUrl(String contentRedirectUrl) {
if (this.state == STATE_RAW) {
this.contentRedirectUrl = contentRedirectUrl;
}
}
/**
* Set merge context
*
* @param context The merge context
*/
public void setContext(Merger context) {
this.context = context;
}
/**
* Update cached template stats - NOTE: Not Synchronized, subject to inaccuracy
* @param response The response time for a merge action
*/
public void postStats(Long response) {
if (this.state == STATE_CACHED) {
this.stats.post(response);
}
}
///////////////////////////////////////////////////////////
// Simple Getters
///////////////////////////////////////////////////////////
/**
* Gets the Merge Content
*
* @return the content
*/
public Content getMergeContent() {
return this.mergeContent;
}
/**
* Gets the replace stack.
*
* @return the replace stack
*/
public HashMap getReplaceStack() {
return replaceStack;
}
/**
* Gets the id.
*
* @return the id
*/
public TemplateId getId() {
return id;
}
/**
* Gets the description.
*
* @return the description
*/
public String getDescription() {
return description;
}
/**
* Gets the wrapper.
*
* @return the wrapper
*/
public Wrapper getWrapper() {
return wrapper;
}
/**
* Gets the content.
*
* @return the content
*/
public String getContent() {
return this.content;
}
/**
* Gets the content type.
*
* @return the content type
*/
public int getContentType() {
return contentType;
}
/**
* Gets the content disposition.
*
* @return the content disposition
* @throws MergeException on processing errors
*/
public String getContentDisposition() throws MergeException {
if (DISPOSITION_DOWNLOAD == contentDisposition) {
Content fileName = new Content(this.wrapper, this.contentFileName, this.contentEncoding);
fileName.replace(replaceStack, false, config.getNestLimit());
return "attachment;filename=\"" + fileName.getValue() + "\"";
} else {
return "";
}
}
/**
* Gets the content encoding.
*
* @return the content encoding
*/
public int getContentEncoding() {
return contentEncoding;
}
/**
* @return file name for output archive
*/
public String getContentFileName() {
return contentFileName;
}
/**
* @return redirect URL
*/
public String getContentRedirectUrl() {
return contentRedirectUrl;
}
/**
* Gets the directives.
*
* @return the directives
*/
public List getDirectives() {
return directives;
}
/**
* @return Statistics.
*/
public Stat getStats() {
return stats;
}
/**
* @return State.
*/
public int getState() {
return state;
}
///////////////////////////////////////////////////////////
// Static Values
///////////////////////////////////////////////////////////
/**
* @return option values and descriptions for the Tempalte Class
*/
public static final HashMap> getOptions() {
HashMap> options = new HashMap>();
options.put("Content Type", CONTENT_TYPES());
options.put("Content Disposition", DISPOSITION_VALUES());
return options;
}
/*
* Class Constants and getOptions()
*/
public static final int CONTENT_HTML = 1;
public static final int CONTENT_JSON = 2;
public static final int CONTENT_XML = 3;
public static final int CONTENT_TEXT = 4;
public static final HashMap CONTENT_TYPES() {
HashMap values = new HashMap();
values.put(CONTENT_HTML, "html");
values.put(CONTENT_JSON, "json");
values.put(CONTENT_XML, "xml");
values.put(CONTENT_TEXT, "text");
return values;
}
public static final int DISPOSITION_DOWNLOAD = 1;
public static final int DISPOSITION_NORMAL = 2;
public static final int DISPOSITION_ARCHIVE = 3;
public static final HashMap DISPOSITION_VALUES() {
HashMap values = new HashMap();
values.put(DISPOSITION_DOWNLOAD, "download");
values.put(DISPOSITION_ARCHIVE, "download archive");
values.put(DISPOSITION_NORMAL, "normal");
return values;
}
public static final int STATE_RAW = 0;
public static final int STATE_CACHED = 1;
public static final int STATE_MERGABLE = 3;
public static final int STATE_MERGED = 4;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy