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.jee;
29
30 import java.util.Collection;
31
32 import javax.ejb.EJBTransactionRolledbackException;
33
34 import org.imixs.workflow.ItemCollection;
35 import org.imixs.workflow.Plugin;
36 import org.imixs.workflow.WorkflowContext;
37 import org.imixs.workflow.exceptions.AccessDeniedException;
38 import org.imixs.workflow.exceptions.PluginException;
39 import org.imixs.workflow.exceptions.ProcessingErrorException;
40 import org.imixs.workflow.jee.ejb.EntityService;
41 import org.imixs.workflow.jee.ejb.WorkflowService;
42
43 /**
44 * This plugin handles the creation and management of versions from an existing
45 * workitem. inside the Imix JEE Workflow. The creation or modificatin of a
46 * version is defined by the workflowmodel. The plugin can generate new versions
47 * (e.g. creating a version of a master version) and also converting a existing
48 * version into a master version.
49 * <p>
50 * The Plugin depends on the org.imixs.workflow.jee.ejb.WorkflowManager. So the
51 * Plugin can not be used in other implementations.
52 * <p>
53 * The creation and management of a new version is defined by the workflow model
54 * (See Imixs Modeler) There are currently two modes supported (provided by the
55 * activity property 'keyVersion')
56 * <p>
57 * mode=1 indicates that the plugin should create a new version of the current
58 * workitem. The two workitems are identically except the attributes $unqiueid
59 * and $workitemidRef. The attribute workitemidRef points to the $uniqueid form
60 * the source workitem. So the availability of this property indicates that the
61 * workitem is a version of source workitem with this $uniqueid. The source
62 * workitem has typically no $workitemidRef attribute. The Source Workitem is
63 * also named Master Version. After the new version is created the plugin
64 * processes the version with the activity provided by the model
65 * (numVersionActivityID) if provided by the model.
66 * <p>
67 * 2=indicates that the plugin should convert a existing version into a Master
68 * Version. This means that the $workitemIDRef will be nulled. An existing
69 * Master Version will be processed by the activity provided by the model
70 * (numVersionActivityID). Also the $workitemidRef will be set to the current
71 * $workitemID.
72 * <p>
73 * If an error occured during the workflow process this plugin will throw a new
74 * ejbexception in the close() method to cancel the current transaction. So no
75 * changes will be saved by the ejb container
76 *
77 * @see org.imixs.workflow.jee.ejb.WorkflowManager
78 * @author Ralph Soika
79 * @version 1.0
80 */
81
82 public class VersionPlugin extends AbstractPlugin {
83
84 private EntityService entityService = null;
85 private WorkflowService workflowService = null;
86 private String versionMode = "";
87 private int versionActivityID = -1;
88 private ItemCollection version = null;
89
90 /**
91 * the init method throws an exception if the plugin is not run in a
92 * instance of org.imixs.workflow.jee.ejb.WorkflowManager. This is necessary
93 * as the plugin needs an instance of the EntityService.
94 */
95 public void init(WorkflowContext actx) throws PluginException {
96 super.init(actx);
97
98 // check for an instance of WorkflowService
99 if (actx instanceof WorkflowService) {
100 // yes we are running in a WorkflowService EJB
101 workflowService = (WorkflowService) actx;
102 // get latest model version....
103 entityService = workflowService.getEntityService();
104 }
105
106 if (workflowService == null)
107 throw new PluginException(
108 "VersionPlugin unable to access WorkflowSerive");
109
110 }
111
112 public EntityService getEntityService() {
113 return entityService;
114 }
115
116 public WorkflowService getWorkflowService() {
117 return workflowService;
118 }
119
120 public ItemCollection getVersion() {
121 return version;
122 }
123
124 public void setVersion(ItemCollection version) {
125 this.version = version;
126 }
127
128 /**
129 * creates an version depending to the version mode and the version activity
130 * ID provided by the workflow model.
131 *
132 * @throws InvalidItemValueException
133 *
134 */
135 public int run(ItemCollection adocumentContext,
136 ItemCollection adocumentActivity) throws PluginException {
137
138 // determine mode and ActivityID to manage version
139 versionMode = adocumentActivity.getItemValueString("keyVersion");
140 versionActivityID = adocumentActivity
141 .getItemValueInteger("numVersionActivityID");
142 try {
143 // lookup ejbs ?
144 if ("1".equals(versionMode) || "2".equals(versionMode)) {
145
146 // handle different version modes
147 // 1 = create a new Version from current workitem
148 if ("1".equals(versionMode)) {
149
150 // copy workitem
151
152 version = createVersion(adocumentContext);
153
154 if (this.ctx.getLogLevel() > 0)
155 System.out
156 .println("[VersionPlugin] new version created");
157 // check if workitem should be processed
158 if (versionActivityID > 0) {
159 version.replaceItemValue("$ActivityID",
160 versionActivityID);
161 version = workflowService.processWorkItem(version);
162 } else {
163 // no processing - simply save workitem
164 version = entityService.save(version);
165 }
166 return Plugin.PLUGIN_OK;
167
168 }
169
170 // convert to Master Version
171 if ("2".equals(adocumentActivity
172 .getItemValueString("keyVersion"))) {
173
174 /*
175 * this code iterates over all existing workitems with the
176 * same $workitemid and fixes lost parent workitemRefIDs.
177 */
178 String sworkitemID = adocumentContext
179 .getItemValueString("$WorkItemID");
180
181 // get current master version
182 String query = " SELECT workitem FROM Entity AS workitem "
183 + " JOIN workitem.textItems AS t1"
184 + " WHERE t1.itemName = '$workitemid'"
185 + " AND t1.itemValue ='" + sworkitemID + "'";
186
187 Collection<ItemCollection> col = entityService
188 .findAllEntities(query, 0, -1);
189 // now search master version...
190 for (ItemCollection aVersion : col) {
191 String sWorkitemRef = aVersion
192 .getItemValueString("$workitemIDRef");
193 if ("".equals(sWorkitemRef)) {
194 // Master version found!
195 // convert now this workitem into a Version from the
196 // current workitem
197 String id = adocumentContext
198 .getItemValueString("$uniqueID");
199 aVersion.replaceItemValue("$WorkItemIDRef", id);
200 // process version?
201 // check if worktiem should be processed
202 if (versionActivityID > 0) {
203 aVersion.replaceItemValue("$ActivityID",
204 versionActivityID);
205 aVersion = workflowService
206 .processWorkItem(aVersion);
207 } else {
208 // no processing - simply save workitem
209 aVersion = entityService.save(aVersion);
210 }
211 version = aVersion;
212 }
213 }
214 // now remove workitemIDRef from current version
215 adocumentContext.removeItem("$WorkItemIDRef");
216 }
217 }
218
219 } catch (AccessDeniedException e) {
220 throw new PluginException(e.getMessage(), e);
221 } catch (ProcessingErrorException e) {
222 throw new PluginException(e.getMessage(), e);
223 }
224 return Plugin.PLUGIN_OK;
225 }
226
227 public void close(int status) throws PluginException {
228 // if an error has occurred during processing take back new created
229 // versions
230 if (status == Plugin.PLUGIN_ERROR) {
231 // throw a ejb exception to cancel a running transaction
232 // this will avoid changes back into the database
233 throw new EJBTransactionRolledbackException();
234 }
235 }
236
237 /**
238 * This method creates a new instance of a exiting workitem. The method did
239 * not save the workitem!. The method can be subclassed to modify the new
240 * created version.
241 *
242 * The new property $WorkitemIDRef will be added which points to the
243 * $uniqueID of the sourceWorkitem.
244 *
245 * @param sourceItemCollection
246 * the ItemCollection which should be versioned
247 * @return new version of the source ItemCollection
248 *
249 * @throws PluginException
250 * @throws Exception
251 */
252 public ItemCollection createVersion(ItemCollection sourceItemCollection)
253 throws PluginException {
254 ItemCollection itemColNewVersion = new ItemCollection();
255
256 itemColNewVersion.replaceAllItems(sourceItemCollection.getAllItems());
257
258 String id = sourceItemCollection.getItemValueString("$uniqueid");
259 if ("".equals(id))
260 throw new PluginException(
261 "Error - unable to create a version from a new workitem!");
262 // remove $Uniqueid to force the generation of a new Entity Instance.
263 itemColNewVersion.getAllItems().remove("$uniqueid");
264
265 // update $WorkItemIDRef to current worktiemID
266 itemColNewVersion.replaceItemValue("$WorkItemIDRef", id);
267
268 return itemColNewVersion;
269
270 }
271
272 }