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.jaxrs.plugins;
29  
30  import java.io.ByteArrayOutputStream;
31  import java.io.FileOutputStream;
32  import java.io.StringWriter;
33  import java.util.Collection;
34  import java.util.StringTokenizer;
35  import java.util.Vector;
36  import java.util.logging.Logger;
37  
38  import javax.naming.Context;
39  import javax.naming.InitialContext;
40  import javax.naming.NamingException;
41  import javax.xml.bind.JAXBContext;
42  import javax.xml.bind.Marshaller;
43  
44  import org.imixs.workflow.ItemCollection;
45  import org.imixs.workflow.Plugin;
46  import org.imixs.workflow.WorkflowContext;
47  import org.imixs.workflow.jee.ejb.EntityService;
48  import org.imixs.workflow.jee.ejb.ReportService;
49  import org.imixs.workflow.xml.EntityCollection;
50  import org.imixs.workflow.xml.XMLItemCollectionAdapter;
51  
52  /**
53   * This plugin handles the creation of a Imixs Reoprt. The coresponding
54   * activityEntity provide the following properties:
55   * <p>
56   * <ul>
57   * <li>
58   * txtReportName=Name of the Report to be processed
59   * <li>
60   * txtReportFilePath= filename or filepath the result will be saved
61   * <li>
62   * txtReportTarget = where the result is saved (0=workitem, 1=blobWorkitem, 2=
63   * disk)
64   * 
65   * 
66   * 
67   * 
68   * 
69   * @author Ralph Soika
70   * @version 1.0
71   */
72  
73  public class ReportPlugin extends org.imixs.workflow.plugins.AbstractPlugin {
74  
75  	private EntityService entityServiceEJB = null;
76  	private ReportService reportServiceEJB = null;
77  	//private Collection<ItemCollection> col = null;
78  	private String reportName = null;
79  	private String reportFilePath = null;
80  	private String reportTarget = null;
81  	private String sEQL;
82  	private String sXSL;
83  	private String sContentType;
84  	private String sEncoding;
85  	private ItemCollection blobWorkitem = null;
86  
87  	private static Logger logger = Logger.getLogger("org.imixs.workflow");
88  
89  	public void init(WorkflowContext actx) throws Exception {
90  		super.init(actx);
91  	}
92  
93  	public EntityService getEntityService() throws Exception {
94  		if (entityServiceEJB == null)
95  			lookupEJBs();
96  
97  		return entityServiceEJB;
98  	}
99  
100 	public ReportService getReportService() throws Exception {
101 		if (reportServiceEJB == null)
102 			lookupEJBs();
103 
104 		return reportServiceEJB;
105 	}
106 
107 	/**
108 	 * creates report defined by the txtReportName.
109 	 * <p>
110 	 * The method runs the EQL Statement defined in the corepsonding Imixs
111 	 * Report to compute the collection of entities to be processed by a
112 	 * template.
113 	 * <p>
114 	 * As the current Workitem can not be identically included by the resultset
115 	 * of the EQL Statement (because the documentContext is yet not saved) the
116 	 * method tests if the resultset includes the current workitem. In this case
117 	 * the 'old' result will be replaced with the new currently processed
118 	 * workitem.
119 	 * 
120 	 * 
121 	 */
122 	public int run(ItemCollection adocumentContext,
123 			ItemCollection adocumentActivity) throws Exception {
124 		try {
125 
126 			reportName = adocumentActivity.getItemValueString("txtReportName");
127 			reportFilePath = adocumentActivity
128 					.getItemValueString("txtReportFilePath");
129 			if ("".equals(reportFilePath))
130 				reportFilePath = reportName;
131 
132 			// replace dynamic field values
133 			reportFilePath = this.replaceDynamicValues(reportFilePath,
134 					adocumentContext);
135 
136 			reportTarget = adocumentActivity
137 					.getItemValueString("txtReportTarget");
138 
139 			if ("".equals(reportName))
140 				return PLUGIN_OK;
141 
142 			// autocomplete file extention if missing
143 			if (!reportName.endsWith(".ixr"))
144 				reportName = reportName + ".ixr";
145 
146 			ItemCollection itemCol = getReportService().getReport(reportName);
147 
148 			// get Query and output format
149 			sEQL = itemCol.getItemValueString("txtquery");
150 
151 			// compute dynamical params
152 			String sParamString = adocumentActivity
153 					.getItemValueString("txtReportParams");
154 			// replace field values...
155 			sParamString = this.replaceDynamicValues(sParamString,
156 					adocumentContext);
157 
158 			// compute jpql statement
159 			sEQL = computeEQLParams(sEQL, sParamString);
160 			logger.info("ReportPlugin JPQL=" + sEQL);
161 			sXSL = itemCol.getItemValueString("txtXSL").trim();
162 			// if no XSL is provided return
163 			if ("".equals(sXSL))
164 				return PLUGIN_OK;
165 
166 			sContentType = itemCol.getItemValueString("txtcontenttype");
167 			if ("".equals(sContentType))
168 				sContentType = "text/html";
169 
170 			sEncoding = itemCol.getItemValueString("txtencoding");
171 			// no encoding defined so take a default encoding
172 			// (UTF-8)
173 			if ("".equals(sEncoding))
174 				sEncoding = "UTF-8";
175 
176 			// query result ....
177 			Collection<ItemCollection> col = getEntityService().findAllEntities(sEQL, 0, -1);
178 			// now add the current Workitem into the collection if an older
179 			// version is
180 			// included in the result
181 			String sUnqiueID = adocumentContext.getItemValueString("$uniqueID");
182 			if (!"".equals(sUnqiueID)) {
183 				Collection<ItemCollection> colNew=new Vector<ItemCollection>();
184 				for (ItemCollection aitemCol : col) {
185 					if (sUnqiueID.equals(aitemCol
186 							.getItemValueString("$uniqueid"))) {
187 						
188 						
189 						ItemCollection itemTemp = new ItemCollection(
190 								adocumentContext.getAllItems());
191 						itemTemp.replaceItemValue("$temp", "true");
192 						colNew.add(itemTemp);
193 						logger.info(" ReportPlugin - relaced deprecated workitem from collection" );
194 					} else
195 						colNew.add(aitemCol);
196 				}
197 				col=colNew;
198 			} else {
199 				// seems that we are currently processing a new workitem - so
200 				// include it into the resultset
201 				ItemCollection itemTemp = new ItemCollection(
202 						adocumentContext.getAllItems());
203 				itemTemp.replaceItemValue("$temp", "true");
204 				col.add(itemTemp);
205 				logger.info(" ReportPlugin - add current workitem into collection" );
206 				
207 			}
208 
209 			// Transform XML per XSL and generate output
210 			EntityCollection xmlCol = XMLItemCollectionAdapter
211 					.putCollection(col);
212 
213 			StringWriter xmlWriter = new StringWriter();
214 
215 			JAXBContext context = JAXBContext
216 					.newInstance(EntityCollection.class);
217 
218 			Marshaller m = context.createMarshaller();
219 			m.setProperty("jaxb.encoding", sEncoding);
220 			m.marshal(xmlCol, xmlWriter);
221 
222 			// test if FOP Tranformation
223 			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
224 
225 			try {
226 				if ("application/pdf".equals(sContentType.toLowerCase()))
227 					org.imixs.workflow.jaxrs.ReportRestService
228 							.fopTranformation(xmlWriter.toString(), sXSL,
229 									sEncoding, outputStream);
230 				else
231 					org.imixs.workflow.jaxrs.ReportRestService
232 							.xslTranformation(xmlWriter.toString(), sXSL,
233 									sEncoding, outputStream);
234 			} finally {
235 				outputStream.close();
236 			}
237 
238 			// write to workitem
239 			if ("0".equals(reportTarget)) {
240 				
241 				adocumentContext.addFile(outputStream.toByteArray(),
242 						reportFilePath, sContentType);
243 			}
244 			// write to blob
245 			if ("1".equals(reportTarget)) {
246 				load(adocumentContext);
247 				
248 				blobWorkitem.addFile(outputStream.toByteArray(),
249 						reportFilePath, sContentType);
250 				save(adocumentContext);
251 			}
252 			// write to filesystem
253 			if ("2".equals(reportTarget)) {
254 				FileOutputStream fos = null;
255 				try {
256 					fos = new FileOutputStream(reportFilePath);
257 					fos.write(outputStream.toByteArray());
258 					fos.flush();
259 				} finally {
260 					if (fos != null) {
261 						fos.close();
262 					}
263 				}
264 			}
265 
266 			return Plugin.PLUGIN_OK;
267 		} catch (Exception e) {
268 			e.printStackTrace();
269 		}
270 
271 		return Plugin.PLUGIN_ERROR;
272 	}
273 
274 	public void close(int status) throws Exception {
275 
276 	}
277 
278 	/**
279 	 * This method loads the EJBs EntityService und WorkflowService which need
280 	 * to be available throgh a declaration in teh dployment descriptor
281 	 * ejb-jar.xml.
282 	 * <p>
283 	 * <code>
284 	 * 
285 			<ejb-ref>
286 			    <ejb-ref-name>ejb/WorkflowServiceBean</ejb-ref-name>
287 			    <ejb-ref-type>Session</ejb-ref-type>
288 			    <remote>org.imixs.workflow.jee.ejb.WorkflowService</remote>
289 			</ejb-ref>
290 			<ejb-ref>
291 			    <ejb-ref-name>ejb/EntityServiceBean</ejb-ref-name>
292 			    <ejb-ref-type>Session</ejb-ref-type>
293 			    <remote>org.imixs.workflow.jee.ejb.EntityService</remote>
294 			</ejb-ref>
295 
296 	 * 
297 	 * </code>
298 	 * 
299 	 * @return
300 	 * @throws NamingException
301 	 */
302 	private void lookupEJBs() throws Exception {
303 
304 		if (entityServiceEJB == null || reportServiceEJB == null) {
305 			String jndiName = null;
306 			// "java:comp/env/ejb/EntityService";
307 			InitialContext ictx = new InitialContext();
308 			Context ctx = (Context) ictx.lookup("java:comp/env");
309 			jndiName = "ejb/EntityServiceBean";
310 			entityServiceEJB = (org.imixs.workflow.jee.ejb.EntityService) ctx
311 					.lookup(jndiName);
312 
313 			jndiName = "ejb/ReportServiceBean";
314 			reportServiceEJB = (ReportService) ctx.lookup(jndiName);
315 
316 		}
317 
318 		if (entityServiceEJB == null)
319 			throw new Exception(
320 					"Error - unable to load EJB ejb/EntityServiceBean....");
321 
322 		if (reportServiceEJB == null)
323 			throw new Exception(
324 					"Error - unable to load EJB ejb/ReportServiceBean....");
325 
326 	}
327 
328 	/**
329 	 * This method parses the query Params of a Request URL and adds params to a
330 	 * given EQL Query.
331 	 * 
332 	 * The Query params are provided in the attribute txtReportParams from the
333 	 * Activity Entity in the following format<br>
334 	 * 
335 	 * <code>
336 	      param1=xxx&param2=xxx&param3=xxx
337 	 * </code>
338 	 * 
339 	 * @param uriInfo
340 	 * @return
341 	 */
342 	private String computeEQLParams(String aQuery, String sParamString) {
343 
344 		// cut prafix ? or & if available
345 		if (sParamString.startsWith("?") || sParamString.startsWith("&"))
346 			sParamString = sParamString.substring(1);
347 
348 		// split params
349 		StringTokenizer tokenizer = new StringTokenizer(sParamString, "&");
350 
351 		while (tokenizer.hasMoreTokens()) {
352 
353 			String aToken = tokenizer.nextToken();
354 			// if no '=' contained - continue...
355 			if (aToken.indexOf('=') == -1)
356 				continue;
357 
358 			String sKeyName = aToken.substring(0, aToken.indexOf('='));
359 			String sParamValue = aToken.substring(aToken.indexOf('=') + 1);
360 			// test if key is contained in query
361 			if (aQuery.indexOf("?" + sKeyName) > -1)
362 				aQuery = aQuery.replace("?" + sKeyName, sParamValue);
363 
364 		}
365 		return aQuery;
366 	}
367 
368 	/**
369 	 * Loads the BlobWorkitem of a given parent Workitem. The BlobWorkitem is
370 	 * identified by the $unqiueidRef. If no BlobWorkitem still exists the
371 	 * method creates a new empty BlobWorkitem which can be saved later.
372 	 * 
373 	 * @param itemCol
374 	 *            - parent workitem where the BlobWorkitem will be attached to
375 	 * @throws Exception
376 	 */
377 	private void load(ItemCollection itemCol) throws Exception {
378 
379 		String sUniqueID = itemCol.getItemValueString("$uniqueid");
380 
381 		// search entity...
382 		String sQuery = " SELECT lobitem FROM Entity as lobitem"
383 				+ " join lobitem.textItems as t1"
384 				+ " join lobitem.textItems as t2"
385 				+ " WHERE t1.itemName = 'type'"
386 				+ " AND t1.itemValue = 'workitemlob'"
387 				+ " AND t2.itemName = '$uniqueidref'" + " AND t2.itemValue = '"
388 				+ sUniqueID + "'";
389 
390 		Collection<ItemCollection> itemcol = getEntityService()
391 				.findAllEntities(sQuery, 0, 1);
392 		if (itemcol != null && itemcol.size() > 0) {
393 
394 			blobWorkitem = itemcol.iterator().next();
395 		} else {
396 			blobWorkitem = new ItemCollection();
397 			blobWorkitem.replaceItemValue("$uniqueidRef", sUniqueID);
398 			blobWorkitem.replaceItemValue("type", "workitemlob");
399 		}
400 
401 	}
402 
403 	/**
404 	 * This method saves the current BlobWorkitem. Therefore the method copies
405 	 * the read- and write access list from the given parent workitem into the
406 	 * BlobWorkitem before save.
407 	 * 
408 	 * So this method should be called after a WorkflowProcessing step to update
409 	 * the read- and write access identically to the parentWorkitem
410 	 * 
411 	 * @throws Exception
412 	 */
413 	private void save(ItemCollection parentWorkitem) throws Exception {
414 
415 		if (blobWorkitem != null && parentWorkitem != null) {
416 
417 			// Update Read and write access list from parent workitem
418 			Vector vAccess = parentWorkitem.getItemValue("$ReadAccess");
419 			blobWorkitem.replaceItemValue("$ReadAccess", vAccess);
420 
421 			vAccess = parentWorkitem.getItemValue("$WriteAccess");
422 			blobWorkitem.replaceItemValue("$WriteAccess", vAccess);
423 
424 			blobWorkitem.replaceItemValue("$uniqueidRef",
425 					parentWorkitem.getItemValueString("$uniqueID"));
426 			blobWorkitem.replaceItemValue("type", "workitemlob");
427 			// Update BlobWorkitem
428 			blobWorkitem = getEntityService().save(blobWorkitem);
429 
430 		}
431 	}
432 
433 }