View Javadoc

1   /*******************************************************************************
2    *  Imixs Workflow 
3    *  Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,  
4    *  http://www.imixs.com
5    *  
6    *  This program is free software; you can redistribute it and/or 
7    *  modify it under the terms of the GNU General Public License 
8    *  as published by the Free Software Foundation; either version 2 
9    *  of the License, or (at your option) any later version.
10   *  
11   *  This program is distributed in the hope that it will be useful, 
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
14   *  General Public License for more details.
15   *  
16   *  You can receive a copy of the GNU General Public
17   *  License at http://www.gnu.org/licenses/gpl.html
18   *  
19   *  Project: 
20   *  	http://www.imixs.org
21   *  	http://java.net/projects/imixs-workflow
22   *  
23   *  Contributors:  
24   *  	Imixs Software Solutions GmbH - initial API and implementation
25   *  	Ralph Soika - Software Developer
26   *******************************************************************************/
27  
28  package org.imixs.workflow.plugins;
29  
30  import java.text.DateFormat;
31  import java.text.SimpleDateFormat;
32  import java.util.Calendar;
33  import java.util.Collection;
34  import java.util.Date;
35  import java.util.List;
36  import java.util.Vector;
37  
38  import org.imixs.workflow.ItemCollection;
39  import org.imixs.workflow.Plugin;
40  import org.imixs.workflow.WorkflowContext;
41  import org.imixs.workflow.exceptions.PluginException;
42  
43  /**
44   * This abstract class implements different helper methods used by subclasses
45   * 
46   * @author Ralph Soika
47   * @version 1.1
48   * @see org.imixs.workflow.WorkflowManager
49   * 
50   */
51  
52  public abstract class AbstractPlugin implements Plugin {
53  
54  	public WorkflowContext ctx;
55  
56  	public void init(WorkflowContext actx) throws PluginException {
57  		ctx = actx;
58  	}
59  
60  	/**
61  	 * this method parses a string for xml tag <itemvalue>. Those tags will be
62  	 * replaced with the corresponding item value.
63  	 * 
64  	 * <code>
65  	 *   
66  	 *   hello <itemvalue>namCreator</itemvalue>
67  	 *   
68  	 *   
69  	 * </code>
70  	 * 
71  	 * Item values can also be formated. e.g. for date/time values
72  	 * 
73  	 * <code>
74  	 *  
75  	 *  Last access Time= <itemvalue format="mm:ss">$created</itemvalue>
76  	 * 
77  	 * </code>
78  	 * 
79  	 * If the itemValue is a multiValue object the single values can be
80  	 * spearated by a separator
81  	 * 
82  	 * <code>
83  	 *  
84  	 *  Phone List: <itemvalue separator="<br />">txtPhones</itemvalue>
85  	 * 
86  	 * </code>
87  	 * 
88  	 * 
89  	 * 
90  	 */
91  	public String replaceDynamicValues(String aString,
92  			ItemCollection documentContext) {
93  		int iTagStartPos;
94  		int iTagEndPos;
95  
96  		int iContentStartPos;
97  		int iContentEndPos;
98  
99  		int iFormatStartPos;
100 		int iFormatEndPos;
101 
102 		int iSeparatorStartPos;
103 		int iSeparatorEndPos;
104 
105 		String sFormat = "";
106 		String sSeparator = " ";
107 		String sItemValue;
108 
109 		if (aString == null)
110 			return "";
111 
112 		// test if a <value> tag exists...
113 		while ((iTagStartPos = aString.toLowerCase().indexOf("<itemvalue")) != -1) {
114 
115 			iTagEndPos = aString.toLowerCase().indexOf("</itemvalue>",
116 					iTagStartPos);
117 
118 			// if no end tag found return string unchanged...
119 			if (iTagEndPos == -1)
120 				return aString;
121 
122 			// reset pos vars
123 			iContentStartPos = 0;
124 			iContentEndPos = 0;
125 			iFormatStartPos = 0;
126 			iFormatEndPos = 0;
127 			iSeparatorStartPos = 0;
128 			iSeparatorEndPos = 0;
129 			sFormat = "";
130 			sSeparator = " ";
131 			sItemValue = "";
132 
133 			// so we now search the beginning of the tag content
134 			iContentEndPos = iTagEndPos;
135 			// start pos is the last > before the iContentEndPos
136 			String sTestString = aString.substring(0, iContentEndPos);
137 			iContentStartPos = sTestString.lastIndexOf('>') + 1;
138 
139 			// if no end tag found return string unchanged...
140 			if (iContentStartPos >= iContentEndPos)
141 				return aString;
142 
143 			iTagEndPos = iTagEndPos + "</itemvalue>".length();
144 
145 			// now we have the start and end position of a tag and also the
146 			// start and end pos of the value
147 
148 			// next we check if the start tag contains a 'format' attribute
149 			iFormatStartPos = aString.toLowerCase().indexOf("format=",
150 					iTagStartPos);
151 			// extract format string if available
152 			if (iFormatStartPos > -1 && iFormatStartPos < iContentStartPos) {
153 				iFormatStartPos = aString.indexOf("\"", iFormatStartPos) + 1;
154 				iFormatEndPos = aString.indexOf("\"", iFormatStartPos + 1);
155 				sFormat = aString.substring(iFormatStartPos, iFormatEndPos);
156 			}
157 
158 			// next we check if the start tag contains a 'separator'
159 			// attribute
160 			iSeparatorStartPos = aString.toLowerCase().indexOf("separator=",
161 					iTagStartPos);
162 			// extract format string if available
163 			if (iSeparatorStartPos > -1
164 					&& iSeparatorStartPos < iContentStartPos) {
165 				iSeparatorStartPos = aString.indexOf("\"", iSeparatorStartPos) + 1;
166 				iSeparatorEndPos = aString
167 						.indexOf("\"", iSeparatorStartPos + 1);
168 				sSeparator = aString.substring(iSeparatorStartPos,
169 						iSeparatorEndPos);
170 			}
171 
172 			// extract Item Value
173 			sItemValue = aString.substring(iContentStartPos, iContentEndPos);
174 
175 			// format field value
176 			List vValue = documentContext.getItemValue(sItemValue);
177 
178 			String sResult = formatItemValues(vValue, sSeparator, sFormat);
179 
180 			// now replace the tag with the result string
181 			aString = aString.substring(0, iTagStartPos) + sResult
182 					+ aString.substring(iTagEndPos);
183 		}
184 
185 		return aString;
186 
187 	}
188 
189 	/**
190 	 * this method formats a string object depending of an attribute type.
191 	 * MultiValues will be separated by the provided separator
192 	 */
193 	public String formatItemValues(Collection aItem, String aSeparator,
194 			String sFormat) {
195 
196 		StringBuffer sBuffer = new StringBuffer();
197 
198 		if (aItem == null)
199 			return "";
200 
201 		for (Object aSingleValue : aItem) {
202 			String aValue = formatObjectValue(aSingleValue, sFormat);
203 			sBuffer.append(aValue);
204 			// append delimiter
205 			sBuffer.append(aSeparator);
206 		}
207 
208 		String sString = sBuffer.toString();
209 
210 		// cut last separator
211 		if (sString.endsWith(aSeparator)) {
212 			sString = sString.substring(0, sString.lastIndexOf(aSeparator));
213 		}
214 
215 		return sString;
216 
217 	}
218 
219 	/**
220 	 * This helper method test the type of an object provided by a
221 	 * itemcollection and formats the object into a string value.
222 	 * 
223 	 * Only Date Objects will be formated into a modified representation. other
224 	 * objects will be returned using the toString() method.
225 	 * 
226 	 * if an optional format is provided this will be used to format date
227 	 * objects.
228 	 * 
229 	 * @param o
230 	 * @return
231 	 */
232 	private String formatObjectValue(Object o, String format) {
233 
234 		Date dateValue = null;
235 
236 		// now test the objct type to date
237 		if (o instanceof Date) {
238 			dateValue = (Date) o;
239 		}
240 
241 		if (o instanceof Calendar) {
242 			Calendar cal = (Calendar) o;
243 			dateValue = cal.getTime();
244 		}
245 
246 		// format date string?
247 		if (dateValue != null) {
248 			String singleValue = "";
249 			if (format != null && !"".equals(format)) {
250 				// format date with provided formater
251 				SimpleDateFormat formatter = new SimpleDateFormat(format);
252 				singleValue = formatter.format(dateValue);
253 			} else
254 				// use standard formate short/short
255 				singleValue = DateFormat.getDateTimeInstance(DateFormat.SHORT,
256 						DateFormat.SHORT).format(dateValue);
257 
258 			return singleValue;
259 		}
260 
261 		return o.toString();
262 	}
263 
264 	/**
265 	 * This method merges the values from p_VectorSource into vectorDest and
266 	 * removes duplicates
267 	 * 
268 	 * @param p_VectorDestination
269 	 * @param p_VectorSource
270 	 */
271 	public void mergeVectors(List p_VectorDestination, List p_VectorSource) {
272 		if ((p_VectorSource != null) && (p_VectorSource.size() > 0)) {
273 			for (Object o : p_VectorSource) {
274 				if (p_VectorDestination.indexOf(o) == -1)
275 					p_VectorDestination.add(o);
276 			}
277 		}
278 	}
279 
280 	/**
281 	 * this method merges the values of p_VectorFieldList into
282 	 * p_VectorDestination and test for duplicates
283 	 * 
284 	 * @param p_VectorDestination
285 	 * @param p_VectorFieldList
286 	 */
287 	public void mergeMappedFieldValues(ItemCollection documentContext,
288 			List p_VectorDestination, List<String> p_VectorFieldList) {
289 		if (p_VectorDestination == null || p_VectorFieldList == null)
290 			return;
291 
292 		if (p_VectorFieldList.size() > 0) {
293 			// iterate over fieldlist
294 			for (String sFeldName : p_VectorFieldList) {
295 				List vValues = documentContext.getItemValue(sFeldName);
296 				// now append the values into p_VectorDestination
297 				if ((vValues != null) && (vValues.size() > 0)) {
298 					for (Object o : vValues) {
299 						// append only if not used
300 						if (p_VectorDestination.indexOf(o) == -1)
301 							p_VectorDestination.add(o);
302 					}
303 				}
304 			}
305 		}
306 
307 	}
308 
309 	/**
310 	 * this method removes duplicate and null values from a vector object The
311 	 * method is called by the run method after build new read and write access
312 	 * elements.
313 	 * 
314 	 * @param p_Vector
315 	 */
316 	public List uniqueList(List p_Vector) {
317 		int iVectorSize = p_Vector.size();
318 		Vector cleanedVector = new Vector();
319 
320 		for (int i = 0; i < iVectorSize; i++) {
321 			Object o = p_Vector.get(i);
322 			if (o == null || cleanedVector.indexOf(o) > -1
323 					|| "".equals(o.toString()))
324 				continue;
325 
326 			// add unique object
327 			cleanedVector.add(o);
328 		}
329 		p_Vector = cleanedVector;
330 		// do not work with empty vectors....
331 		if (p_Vector.size() == 0)
332 			p_Vector.add("");
333 
334 		return p_Vector;
335 	}
336 }