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.jee.ejb;
29  
30  import java.util.Collection;
31  import java.util.List;
32  import java.util.StringTokenizer;
33  import java.util.logging.Logger;
34  
35  import javax.annotation.PostConstruct;
36  import javax.annotation.Resource;
37  import javax.annotation.security.DeclareRoles;
38  import javax.annotation.security.RolesAllowed;
39  import javax.ejb.EJB;
40  import javax.ejb.LocalBean;
41  import javax.ejb.SessionContext;
42  import javax.ejb.Stateless;
43  
44  import org.imixs.workflow.ExtendedModel;
45  import org.imixs.workflow.ExtendedWorkflowContext;
46  import org.imixs.workflow.ItemCollection;
47  import org.imixs.workflow.Model;
48  import org.imixs.workflow.WorkflowKernel;
49  import org.imixs.workflow.exceptions.AccessDeniedException;
50  import org.imixs.workflow.exceptions.ProcessingErrorException;
51  import org.imixs.workflow.jee.jpa.EntityIndex;
52  
53  /**
54   * The WorkflowService is the JEE Implementation for the Imixs Workflow Core
55   * API. This interface acts as a service facade and supports basic methods to
56   * create, process and access workitems. The Interface extends the core api
57   * interface org.imixs.workflow.WorkflowManager with getter methods to fetch
58   * collections of workitems.
59   * 
60   * @author rsoika
61   * 
62   */
63  
64  @DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS",
65  		"org.imixs.ACCESSLEVEL.READERACCESS",
66  		"org.imixs.ACCESSLEVEL.AUTHORACCESS",
67  		"org.imixs.ACCESSLEVEL.EDITORACCESS",
68  		"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
69  @RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS",
70  		"org.imixs.ACCESSLEVEL.READERACCESS",
71  		"org.imixs.ACCESSLEVEL.AUTHORACCESS",
72  		"org.imixs.ACCESSLEVEL.EDITORACCESS",
73  		"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
74  @Stateless
75  @LocalBean
76  public class WorkflowService implements ExtendedWorkflowContext {
77  
78  	public static final int SORT_ORDER_CREATED_DESC = 0;
79  	public static final int SORT_ORDER_CREATED_ASC = 1;
80  	public static final int SORT_ORDER_MODIFIED_DESC = 2;
81  	public static final int SORT_ORDER_MODIFIED_ASC = 3;
82  
83  	private int logLevel = WorkflowKernel.LOG_LEVEL_SEVERE;
84  
85  	@EJB
86  	EntityService entityService;
87  
88  	@EJB
89  	ModelService modelService;
90  
91  	@Resource
92  	SessionContext ctx;
93  
94  	private static Logger logger = Logger.getLogger("org.imixs.workflow");
95  
96  	/**
97  	 * create default index properties
98  	 * 
99  	 * @throws AccessDeniedException
100 	 */
101 	@SuppressWarnings("unused")
102 	@PostConstruct
103 	private void initIndexProperties() throws AccessDeniedException {
104 		entityService.addIndex("namCreator", EntityIndex.TYP_TEXT);
105 		entityService.addIndex("txtWorkflowGroup", EntityIndex.TYP_TEXT);
106 		entityService.addIndex("$ProcessID", EntityIndex.TYP_INT);
107 		entityService.addIndex("$workitemid", EntityIndex.TYP_TEXT);
108 		entityService.addIndex("$uniqueidref", EntityIndex.TYP_TEXT);
109 		entityService.addIndex("txtname", EntityIndex.TYP_TEXT);
110 		entityService.addIndex("namowner", EntityIndex.TYP_TEXT);
111 	}
112 
113 	/**
114 	 * This method loads a Workitem with the corresponding uniqueid
115 	 */
116 	public ItemCollection getWorkItem(String uniqueid) {
117 		return entityService.load(uniqueid);
118 	}
119 
120 	/**
121 	 * Returns a collection of workitems belonging to a specified name. The name
122 	 * is a username or role contained in the $WriteAccess attribute of the
123 	 * workitem.
124 	 * 
125 	 * 
126 	 * The method returns only workitems the call has sufficient read access
127 	 * for.
128 	 * 
129 	 * @param name
130 	 *            = username or role contained in $writeAccess - if null current
131 	 *            username will be used
132 	 * @param startpos
133 	 *            = optional start position
134 	 * @param count
135 	 *            = optional count - default = -1
136 	 * @param type
137 	 *            = defines the type property of the workitems to be returnd.
138 	 *            can be null
139 	 * @param sortorder
140 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
141 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
142 	 *            SORT_ORDER_MODIFIED_ASC = 3)
143 	 * @return List of workitems
144 	 * 
145 	 */
146 	public Collection<ItemCollection> getWorkList(String name) {
147 		return getWorkList(name, 0, -1, null, 0);
148 	}
149 
150 	public Collection<ItemCollection> getWorkList(String name, int startpos,
151 			int count, String type, int sortorder) {
152 
153 		if (name == null || "".equals(name))
154 			name = ctx.getCallerPrincipal().getName();
155 
156 		String sQuery = null;
157 		sQuery = "SELECT";
158 		sQuery += " wi FROM Entity as wi " + " JOIN wi.writeAccessList as wa"
159 				+ " JOIN wi.textItems as s " + "WHERE ";
160 
161 		if (type != null && !"".equals(type))
162 			sQuery += " wi.type='" + type + "' AND ";
163 
164 		sQuery += " wa.value = '" + name + "'"
165 				+ " AND s.itemName = '$workitemid' ORDER BY wi.created desc";
166 		return entityService.findAllEntities(sQuery, startpos, count);
167 	}
168 
169 	/**
170 	 * Returns a collection of workitems created by a specified user
171 	 * (namCreator). The behaivor is simmilar to the method getWorkList.
172 	 * 
173 	 * 
174 	 * @param name
175 	 *            = username for property namCreator - if null current username
176 	 *            will be used
177 	 * @param startpos
178 	 *            = optional start position
179 	 * @param count
180 	 *            = optional count - default = -1
181 	 * @param type
182 	 *            = defines the type property of the workitems to be returnd.
183 	 *            can be null
184 	 * @param sortorder
185 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
186 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
187 	 *            SORT_ORDER_MODIFIED_ASC = 3)
188 	 * @return List of workitems
189 	 * 
190 	 */
191 	public Collection<ItemCollection> getWorkListByCreator(String name,
192 			int startpos, int count, String type, int sortorder) {
193 
194 		if (name == null || "".equals(name))
195 			name = ctx.getCallerPrincipal().getName();
196 
197 		String sQuery = null;
198 		sQuery = "SELECT";
199 		sQuery += " wi FROM Entity as wi"
200 				+ " JOIN wi.textItems as t JOIN wi.textItems as s " + "WHERE ";
201 		if (type != null && !"".equals(type))
202 			sQuery += " wi.type='" + type + "' AND ";
203 
204 		sQuery += " t.itemName = 'namcreator' and t.itemValue = '" + name + "'"
205 				+ " AND s.itemName = '$workitemid' "
206 				+ createSortOrderClause(sortorder);
207 
208 		return entityService.findAllEntities(sQuery, startpos, count);
209 	}
210 
211 	/**
212 	 * Returns a collection of workitems containing a namOwner property
213 	 * belonging to a specified username. The namOwner property is typical
214 	 * controled by the OwnerPlugin
215 	 * 
216 	 * @param name
217 	 *            = username for property namOwner - if null current username
218 	 *            will be used
219 	 * @param startpos
220 	 *            = optional start position
221 	 * @param count
222 	 *            = optional count - default = -1
223 	 * @param type
224 	 *            = defines the type property of the workitems to be returnd.
225 	 *            can be null
226 	 * @param sortorder
227 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
228 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
229 	 *            SORT_ORDER_MODIFIED_ASC = 3)
230 	 * @return List of workitems
231 	 * 
232 	 */
233 	public Collection<ItemCollection> getWorkListByOwner(String name,
234 			int startpos, int count, String type, int sortorder) {
235 
236 		if (name == null || "".equals(name))
237 			name = ctx.getCallerPrincipal().getName();
238 
239 		String sQuery = null;
240 		sQuery = "SELECT";
241 		sQuery += " wi FROM Entity as wi"
242 				+ " JOIN wi.textItems as t JOIN wi.textItems as s " + "WHERE ";
243 		if (type != null && !"".equals(type))
244 			sQuery += " wi.type='" + type + "' AND ";
245 
246 		sQuery += " t.itemName = 'namowner' and t.itemValue = '" + name + "'"
247 				+ " AND s.itemName = '$workitemid' "
248 				+ createSortOrderClause(sortorder);
249 
250 		return entityService.findAllEntities(sQuery, startpos, count);
251 	}
252 
253 	/**
254 	 * Returns a collection of workitems where the current user has a
255 	 * writeAccess. This means the either the username or one of the userroles
256 	 * is contained in the $writeaccess property
257 	 * 
258 	 * 
259 	 * @param startpos
260 	 *            = optional start position
261 	 * @param count
262 	 *            = optional count - default = -1
263 	 * @param type
264 	 *            = defines the type property of the workitems to be returnd.
265 	 *            can be null
266 	 * @param sortorder
267 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
268 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
269 	 *            SORT_ORDER_MODIFIED_ASC = 3)
270 	 * @return List of workitems
271 	 * 
272 	 */
273 	public Collection<ItemCollection> getWorkListByWriteAccess(int startpos,
274 			int count, String type, int sortorder) {
275 		StringBuffer nameListBuffer = new StringBuffer();
276 
277 		String name = ctx.getCallerPrincipal().getName();
278 
279 		// construct nameList. Begin with empty string '' and username
280 		nameListBuffer.append("'" + name + "'");
281 		// now construct role list
282 
283 		String accessRoles = entityService.getAccessRoles();
284 
285 		String roleList = "org.imixs.ACCESSLEVEL.READERACCESS,org.imixs.ACCESSLEVEL.AUTHORACCESS,org.imixs.ACCESSLEVEL.EDITORACCESS,"
286 				+ accessRoles;
287 		// add each role the user is in to the name list
288 		StringTokenizer roleListTokens = new StringTokenizer(roleList, ",");
289 		while (roleListTokens.hasMoreTokens()) {
290 			String testRole = roleListTokens.nextToken().trim();
291 			if (!"".equals(testRole) && ctx.isCallerInRole(testRole))
292 				nameListBuffer.append(",'" + testRole + "'");
293 		}
294 
295 		String sQuery = "SELECT wi FROM Entity as wi "
296 				+ " JOIN wi.writeAccessList wa " + " WHERE ";
297 		if (type != null && !"".equals(type))
298 			sQuery += " wi.type='" + type + "' ";
299 
300 		sQuery += " AND wa.value IN (" + nameListBuffer.toString() + ")"
301 				+ createSortOrderClause(sortorder);
302 
303 		return entityService.findAllEntities(sQuery, startpos, count);
304 	}
305 
306 	public Collection<ItemCollection> getWorkListByGroup(String name,
307 			int startpos, int count, String type, int sortorder) {
308 
309 		String sQuery = null;
310 		sQuery = "SELECT";
311 		sQuery += " wi FROM Entity as wi " + " JOIN wi.textItems as t "
312 				+ " JOIN wi.textItems as s " + "WHERE ";
313 
314 		if (type != null && !"".equals(type))
315 			sQuery += " wi.type='" + type + "' AND ";
316 
317 		sQuery += " t.itemName = 'txtworkflowgroup' and t.itemValue = '" + name
318 				+ "'" + " AND s.itemName = '$workitemid' "
319 				+ createSortOrderClause(sortorder);
320 		return entityService.findAllEntities(sQuery, startpos, count);
321 	}
322 
323 	/**
324 	 * Returns a collection of workitems belonging to a specified $processID
325 	 * defined by the workflow model. The behaivor is simmilar to the method
326 	 * getWorkList.
327 	 * 
328 	 * @param aID
329 	 *            = $ProcessID for the workitems to be returned.
330 	 * @param startpos
331 	 *            = optional start position
332 	 * @param count
333 	 *            = optional count - default = -1
334 	 * @param type
335 	 *            = defines the type property of the workitems to be returnd.
336 	 *            can be null
337 	 * @param sortorder
338 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
339 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
340 	 *            SORT_ORDER_MODIFIED_ASC = 3)
341 	 * @return List of workitems
342 	 * 
343 	 */
344 	public Collection<ItemCollection> getWorkListByProcessID(int aid,
345 			int startpos, int count, String type, int sortorder) {
346 
347 		String sQuery = null;
348 		sQuery = "SELECT";
349 		sQuery += " wi FROM Entity as wi "
350 				+ " JOIN wi.integerItems as t JOIN wi.textItems as s "
351 				+ "WHERE ";
352 
353 		if (type != null && !"".equals(type))
354 			sQuery += " wi.type='" + type + "' AND ";
355 
356 		sQuery += " t.itemName = '$processid' and t.itemValue = '" + aid + "'"
357 				+ " AND s.itemName = '$workitemid' "
358 				+ createSortOrderClause(sortorder);
359 
360 		return entityService.findAllEntities(sQuery, startpos, count);
361 	}
362 
363 	/**
364 	 * Returns a collection of workitems belonging to a specified workitem
365 	 * identified by the attribute $UniqueIDRef.
366 	 * 
367 	 * The behaivor of this Mehtod is simmilar to the method getWorkList.
368 	 * 
369 	 * @param aref
370 	 *            A unique reference to another workitem inside a database *
371 	 * @param startpos
372 	 *            = optional start position
373 	 * @param count
374 	 *            = optional count - default = -1
375 	 * @param type
376 	 *            = defines the type property of the workitems to be returnd.
377 	 *            can be null
378 	 * @param sortorder
379 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
380 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
381 	 *            SORT_ORDER_MODIFIED_ASC = 3)
382 	 * @return List of workitems
383 	 */
384 	public Collection<ItemCollection> getWorkListByRef(String aref) {
385 		return getWorkListByRef(aref, 0, -1, null, 0);
386 	}
387 
388 	/**
389 	 * Returns a collection of workitems belonging to a specified workitem
390 	 * identified by the attribute $UniqueIDRef.
391 	 * 
392 	 * The behaivor of this Mehtod is simmilar to the method getWorkList.
393 	 * 
394 	 * @param aref
395 	 *            A unique reference to another workitem inside a database *
396 	 * @param startpos
397 	 *            = optional start position
398 	 * @param count
399 	 *            = optional count - default = -1
400 	 * @param type
401 	 *            = defines the type property of the workitems to be returnd.
402 	 *            can be null
403 	 * @param sortorder
404 	 *            = defines sortorder (SORT_ORDER_CREATED_DESC = 0
405 	 *            SORT_ORDER_CREATED_ASC = 1 SORT_ORDER_MODIFIED_DESC = 2
406 	 *            SORT_ORDER_MODIFIED_ASC = 3)
407 	 * @return List of workitems
408 	 */
409 	public Collection<ItemCollection> getWorkListByRef(String aref,
410 			int startpos, int count, String type, int sortorder) {
411 
412 		String sQuery = null;
413 		sQuery = "SELECT";
414 		sQuery += " wi FROM Entity as wi "
415 				+ " JOIN wi.textItems as t JOIN wi.textItems as s " + "WHERE ";
416 		if (type != null && !"".equals(type))
417 			sQuery += " wi.type='" + type + "' AND ";
418 
419 		sQuery += " t.itemName = '$uniqueidref' and t.itemValue = '" + aref
420 				+ "'" + " and s.itemName = '$workitemid' "
421 				+ createSortOrderClause(sortorder);
422 
423 		return entityService.findAllEntities(sQuery, startpos, count);
424 	}
425 
426 	/**
427 	 * generates a sort order clause depending on a sororder id
428 	 * 
429 	 * @param asortorder
430 	 * @return
431 	 */
432 	private String createSortOrderClause(int asortorder) {
433 		switch (asortorder) {
434 
435 		case WorkflowService.SORT_ORDER_CREATED_ASC: {
436 			return " ORDER BY wi.created asc";
437 		}
438 		case WorkflowService.SORT_ORDER_MODIFIED_ASC: {
439 			return " ORDER BY wi.modified asc";
440 		}
441 		case WorkflowService.SORT_ORDER_MODIFIED_DESC: {
442 			return " ORDER BY wi.modified desc";
443 		}
444 		default:
445 			return " ORDER BY wi.created desc";
446 		}
447 
448 	}
449 
450 	/**
451 	 * processes a workItem. The workitem have to provide the properties
452 	 * '$modelversion', '$processid' and '$activityid'
453 	 * 
454 	 * The method try to load the current instance of the given workitem and
455 	 * compares the property $processID. If it is not equal the method throws an
456 	 * ProcessingErrorException.
457 	 * 
458 	 * @param workitem
459 	 *            - the workItem to be processed
460 	 * @return updated version of the processed workItem
461 	 * @throws InvalidItemValueException
462 	 *             if $modelVersion did not exists or the workItem has an
463 	 *             invalid status
464 	 * @throws AccessDeniedException
465 	 *             if call has no write access for the given workItem
466 	 * @throws ProcessingErrorException
467 	 *             if processing by a plugin fails
468 	 */
469 	public ItemCollection processWorkItem(ItemCollection workitem)
470 			throws AccessDeniedException, ProcessingErrorException {
471 
472 		if (workitem == null)
473 			throw new ProcessingErrorException(
474 					"WorkflowService: error - workitem is null");
475 
476 		// load current instance of this workitem
477 		ItemCollection currentInstance = this.getWorkItem(workitem
478 				.getItemValueString(EntityService.UNIQUEID));
479 		// test if $ProcessID matches current instance
480 		if (currentInstance != null
481 				&& currentInstance.getItemValueInteger("$ProcessID") != workitem
482 						.getItemValueInteger("$ProcessID"))
483 			throw new ProcessingErrorException(
484 					"WorkflowService: error - $ProcesssID ("
485 							+ workitem.getItemValueInteger("$ProcessID")
486 							+ ") did not match expected $ProcesssID ("
487 							+ currentInstance.getItemValueInteger("$ProcessID")
488 							+ ")");
489 
490 		/*
491 		 * Fetch the current Profile Entity for this version. The method will
492 		 * automatically default to the next Version number if the provided
493 		 * version is no longer provided by the ModelManager
494 		 */
495 		String modelversion = workitem.getItemValueString("$modelversion");
496 		ItemCollection profile = findModelProfile(modelversion);
497 
498 		WorkflowKernel workflowkernel = new WorkflowKernel(this);
499 
500 		// register plugins defined in the environment.profile ....
501 		List<String> vPlugins = profile.getItemValue("txtPlugins");
502 		for (int i = 0; i < vPlugins.size(); i++) {
503 			String sPlugin = vPlugins.get(i);
504 			workflowkernel.registerPlugin(sPlugin);
505 		}
506 
507 		// determine Debuglevel....
508 		String sDebug = profile.getItemValueString("keyDebugLevel");
509 		try {
510 			int idebug = Integer.parseInt(sDebug);
511 			logLevel = idebug;
512 		} catch (NumberFormatException e) {
513 			logLevel = WorkflowKernel.LOG_LEVEL_FINE;
514 		}
515 
516 		// test if expected modelVersion matches the profile modelVersion
517 		if (!modelversion.equals(profile.getItemValueString("$ModelVersion"))) {
518 			logger.info("WorkflowService: modelversion '"
519 					+ modelversion
520 					+ "' no longer provided. Continue processing with modelversion '"
521 					+ profile.getItemValueString("$ModelVersion") + "'");
522 			// update Model Version for the WorkItem - this is the version
523 			// the
524 			// workitem will be processed now
525 			modelversion = profile.getItemValueString("$ModelVersion");
526 			workitem.replaceItemValue("$modelversion", modelversion);
527 		}
528 
529 		// identify Caller and update CurrentEditor
530 		String name;
531 		name = ctx.getCallerPrincipal().getName();
532 
533 		// add namCreator if new workitem
534 		if ("".equals(workitem.getItemValueString("namCreator")))
535 			workitem.replaceItemValue("namCreator", name);
536 
537 		// update curreneditor
538 		workitem.replaceItemValue("namlasteditor",
539 				workitem.getItemValueString("namcurrenteditor"));
540 		workitem.replaceItemValue("namcurrenteditor", name);
541 
542 		// now process the workitem
543 		workflowkernel.process(workitem);
544 
545 		if (this.getLogLevel() == WorkflowKernel.LOG_LEVEL_FINE)
546 			logger.info("[WorkflowManager] workitem processed sucessfull");
547 
548 		return entityService.save(workitem);
549 
550 	}
551 
552 	public void removeWorkItem(ItemCollection aworkitem)
553 			throws AccessDeniedException {
554 		entityService.remove(aworkitem);
555 	}
556 
557 	/***************************************************************************
558 	 * Workflow Context
559 	 */
560 	public int getLogLevel() {
561 		return logLevel;
562 	}
563 
564 	/**
565 	 * This Method returns the modelManager Instance. The current ModelVersion
566 	 * is automatically updated during the Method updateProfileEntity which is
567 	 * called from the processWorktiem method.
568 	 * 
569 	 */
570 	public Model getModel() {
571 		return modelService;
572 	}
573 
574 	public ExtendedModel getExtendedModel() {
575 		return modelService;
576 	}
577 
578 	public Object getSessionContext() {
579 		return ctx;
580 	}
581 
582 	/**
583 	 * This method lookups the WorkflowEnvironmentEntity "environment.profile"
584 	 * for a given $modelVersion. The profile entity is used to determine the
585 	 * current Plugin definition, FieldMappings and logging information
586 	 * 
587 	 * If no WorkflowEnvironmentEntity to the provided ModelVersion is found,
588 	 * the method fetches automatically the next ModelVersion (in alphabetical
589 	 * order) provided by the ModelManager. The Version can be different from
590 	 * the provided version if no corresponding model was found. So the caller
591 	 * of this method should verfiy the model version of the returned
592 	 * WorkflowEnvironmentEntity.
593 	 * 
594 	 * 
595 	 * @param modelversion
596 	 *            - model version to find the profile
597 	 * @return WorkflowEnvironmentEntity
598 	 * @throws ProcessingErrorException
599 	 */
600 	private ItemCollection findModelProfile(String modelversion)
601 			throws ProcessingErrorException {
602 		ItemCollection profile = null;
603 
604 		// if no modelversion is provided default to newest version
605 		if (modelversion == null || "".equals(modelversion)) {
606 			modelversion = modelService.getLatestVersion();
607 		}
608 
609 		// try to get a Profile matching the provided version.....
610 		// we lookup for '..>=modelversion' to fetch automatically the next
611 		// model version if the expected model version is not available
612 		Collection<ItemCollection> col;
613 		String sQuery = null;
614 		sQuery = "SELECT";
615 		sQuery += " environment FROM Entity AS environment"
616 				+ " JOIN environment.textItems as n "
617 				+ " JOIN environment.textItems as v "
618 				+ " WHERE environment.type = 'WorkflowEnvironmentEntity'"
619 				+ " AND n.itemName = 'txtname' AND n.itemValue = 'environment.profile'"
620 				+ " AND v.itemName = '$modelversion' AND v.itemValue >= '"
621 				+ modelversion + "' ORDER BY v.itemValue";
622 		col = entityService.findAllEntities(sQuery, 0, 1);
623 		// if no model for that ModelVersion is found - throw a exception
624 
625 		if (col.size() == 0) {
626 			logger.severe("WorkflowService: fatal error - no valid model version '"
627 					+ modelversion + "' found! Verify WorkflowModels.");
628 			throw new ProcessingErrorException(
629 					"WorkflowService: fatal error - no valid model version '"
630 							+ modelversion + "' found! Verify WorkflowModels.");
631 		}
632 
633 		profile = col.iterator().next();
634 
635 		return profile;
636 	}
637 
638 	/**
639 	 * This method returns an instance of the Imixs JEE EntityService used by
640 	 * the WorkflowManager Implementation. The method can be used to access the
641 	 * EntityService during a Plugin call.
642 	 * 
643 	 * @return EntityService
644 	 * @throws Exception
645 	 */
646 	public EntityService getEntityService() {
647 		return entityService;
648 	}
649 
650 	/**
651 	 * This method returns an instance of the Imixs JEE ModelService used by the
652 	 * WorkflowManager Implementation. The method can be used to access the
653 	 * ModelService during a Plugin call.
654 	 * 
655 	 * @return EntityService
656 	 * @throws Exception
657 	 */
658 	public ModelService getModelService() {
659 		return modelService;
660 	}
661 
662 	/**
663 	 * Obtain the java.security.Principal that identifies the caller and returns
664 	 * the name of this principal.
665 	 * 
666 	 * @return the user name
667 	 */
668 	public String getUserName() {
669 		return ctx.getCallerPrincipal().getName();
670 
671 	}
672 
673 	/**
674 	 * Test if the caller has a given security role.
675 	 * 
676 	 * @param rolename
677 	 * @return true if user is in role
678 	 */
679 	public boolean isUserInRole(String rolename) {
680 		try {
681 			return ctx.isCallerInRole(rolename);
682 		} catch (Exception e) {
683 			// avoid a exception for a role request which is not defined
684 			return false;
685 		}
686 	}
687 
688 	/**
689 	 * This method returns a list of user names, roles and application groups
690 	 * the caller belongs to.
691 	 * 
692 	 * @return
693 	 */
694 	public List<String> getUserNameList() {
695 		return entityService.getUserNameList();
696 	}
697 }