001
014
015 package com.liferay.portal.kernel.workflow;
016
017 import aQute.bnd.annotation.ProviderType;
018
019 import com.liferay.portal.kernel.exception.PortalException;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
023 import com.liferay.portal.kernel.util.GetterUtil;
024 import com.liferay.portal.kernel.util.ListUtil;
025 import com.liferay.portal.kernel.util.LocaleUtil;
026 import com.liferay.portal.model.WorkflowDefinitionLink;
027 import com.liferay.portal.model.WorkflowInstanceLink;
028 import com.liferay.portal.service.ServiceContext;
029 import com.liferay.portal.service.WorkflowInstanceLinkLocalServiceUtil;
030 import com.liferay.registry.Registry;
031 import com.liferay.registry.RegistryUtil;
032 import com.liferay.registry.ServiceReference;
033 import com.liferay.registry.ServiceRegistration;
034 import com.liferay.registry.ServiceTracker;
035 import com.liferay.registry.ServiceTrackerCustomizer;
036 import com.liferay.registry.collections.ServiceRegistrationMap;
037
038 import java.io.Serializable;
039
040 import java.util.Collections;
041 import java.util.HashMap;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.TreeMap;
045 import java.util.concurrent.Callable;
046 import java.util.concurrent.ConcurrentSkipListMap;
047
048
052 @ProviderType
053 public class WorkflowHandlerRegistryUtil {
054
055 public static List<WorkflowHandler<?>> getScopeableWorkflowHandlers() {
056 return _instance._getScopeableWorkflowHandlers();
057 }
058
059 public static <T> WorkflowHandler<T> getWorkflowHandler(String className) {
060 return (WorkflowHandler<T>)_instance._getWorkflowHandler(className);
061 }
062
063 public static List<WorkflowHandler<?>> getWorkflowHandlers() {
064 return _instance._getWorkflowHandlers();
065 }
066
067 public static void register(List<WorkflowHandler<?>> workflowHandlers) {
068 for (WorkflowHandler<?> workflowHandler : workflowHandlers) {
069 register(workflowHandler);
070 }
071 }
072
073 public static void register(WorkflowHandler<?> workflowHandler) {
074 _instance._register(workflowHandler);
075 }
076
077 public static <T> void startWorkflowInstance(
078 long companyId, long groupId, long userId, String className,
079 long classPK, T model, ServiceContext serviceContext)
080 throws PortalException {
081
082 Map<String, Serializable> workflowContext =
083 (Map<String, Serializable>)serviceContext.removeAttribute(
084 "workflowContext");
085
086 if (workflowContext == null) {
087 workflowContext = Collections.emptyMap();
088 }
089
090 startWorkflowInstance(
091 companyId, groupId, userId, className, classPK, model,
092 serviceContext, workflowContext);
093 }
094
095 public static <T> T startWorkflowInstance(
096 final long companyId, final long groupId, final long userId,
097 String className, final long classPK, final T model,
098 ServiceContext serviceContext,
099 Map<String, Serializable> workflowContext)
100 throws PortalException {
101
102 if (serviceContext.getWorkflowAction() !=
103 WorkflowConstants.ACTION_PUBLISH) {
104
105 return model;
106 }
107
108 final WorkflowHandler<T> workflowHandler = getWorkflowHandler(
109 className);
110
111 if (workflowHandler == null) {
112 if (WorkflowThreadLocal.isEnabled()) {
113 throw new WorkflowException(
114 "No workflow handler found for " + className);
115 }
116
117 return model;
118 }
119
120 boolean hasWorkflowInstanceInProgress =
121 _instance._hasWorkflowInstanceInProgress(
122 companyId, groupId, className, classPK);
123
124 if (hasWorkflowInstanceInProgress) {
125 if (_log.isWarnEnabled()) {
126 _log.warn(
127 "Workflow already started for class " + className +
128 " with primary key " + classPK + " in group " +
129 groupId);
130 }
131
132 return model;
133 }
134
135 WorkflowDefinitionLink workflowDefinitionLink = null;
136
137 if (WorkflowThreadLocal.isEnabled() &&
138 WorkflowEngineManagerUtil.isDeployed()) {
139
140 workflowDefinitionLink = workflowHandler.getWorkflowDefinitionLink(
141 companyId, groupId, classPK);
142 }
143
144 int status = WorkflowConstants.STATUS_PENDING;
145
146 if (workflowDefinitionLink == null) {
147 status = WorkflowConstants.STATUS_APPROVED;
148 }
149
150 workflowContext = new HashMap<>(workflowContext);
151
152 workflowContext.put(
153 WorkflowConstants.CONTEXT_COMPANY_ID, String.valueOf(companyId));
154 workflowContext.put(
155 WorkflowConstants.CONTEXT_GROUP_ID, String.valueOf(groupId));
156 workflowContext.put(
157 WorkflowConstants.CONTEXT_USER_ID, String.valueOf(userId));
158 workflowContext.put(
159 WorkflowConstants.CONTEXT_ENTRY_CLASS_NAME, className);
160 workflowContext.put(
161 WorkflowConstants.CONTEXT_ENTRY_CLASS_PK, String.valueOf(classPK));
162 workflowContext.put(
163 WorkflowConstants.CONTEXT_ENTRY_TYPE,
164 workflowHandler.getType(LocaleUtil.getDefault()));
165 workflowContext.put(
166 WorkflowConstants.CONTEXT_SERVICE_CONTEXT, serviceContext);
167 workflowContext.put(
168 WorkflowConstants.CONTEXT_TASK_COMMENTS,
169 GetterUtil.getString(serviceContext.getAttribute("comments")));
170
171 T updatedModel = workflowHandler.updateStatus(status, workflowContext);
172
173 if (workflowDefinitionLink != null) {
174 final Map<String, Serializable> tempWorkflowContext =
175 workflowContext;
176
177 TransactionCommitCallbackRegistryUtil.registerCallback(
178 new Callable<Void>() {
179
180 @Override
181 public Void call() throws Exception {
182 workflowHandler.startWorkflowInstance(
183 companyId, groupId, userId, classPK, model,
184 tempWorkflowContext);
185
186 return null;
187 }
188
189 });
190 }
191
192 return updatedModel;
193 }
194
195 public static <T> void startWorkflowInstance(
196 long companyId, long userId, String className, long classPK,
197 T model, ServiceContext serviceContext)
198 throws PortalException {
199
200 Map<String, Serializable> workflowContext =
201 (Map<String, Serializable>)serviceContext.removeAttribute(
202 "workflowContext");
203
204 if (workflowContext == null) {
205 workflowContext = Collections.emptyMap();
206 }
207
208 startWorkflowInstance(
209 companyId, WorkflowConstants.DEFAULT_GROUP_ID, userId, className,
210 classPK, model, serviceContext, workflowContext);
211 }
212
213 public static <T> void startWorkflowInstance(
214 long companyId, long userId, String className, long classPK,
215 T model, ServiceContext serviceContext,
216 Map<String, Serializable> workflowContext)
217 throws PortalException {
218
219 startWorkflowInstance(
220 companyId, WorkflowConstants.DEFAULT_GROUP_ID, userId, className,
221 classPK, model, serviceContext, workflowContext);
222 }
223
224 public static void unregister(List<WorkflowHandler<?>> workflowHandlers) {
225 for (WorkflowHandler<?> workflowHandler : workflowHandlers) {
226 unregister(workflowHandler);
227 }
228 }
229
230 public static void unregister(WorkflowHandler<?> workflowHandler) {
231 _instance._unregister(workflowHandler);
232 }
233
234 public static <T> T updateStatus(
235 int status, Map<String, Serializable> workflowContext)
236 throws PortalException {
237
238 String className = (String)workflowContext.get(
239 WorkflowConstants.CONTEXT_ENTRY_CLASS_NAME);
240
241 WorkflowHandler<T> workflowHandler = getWorkflowHandler(className);
242
243 if (workflowHandler != null) {
244 return workflowHandler.updateStatus(status, workflowContext);
245 }
246
247 return null;
248 }
249
250 private WorkflowHandlerRegistryUtil() {
251 Registry registry = RegistryUtil.getRegistry();
252
253 _serviceTracker = registry.trackServices(
254 (Class<WorkflowHandler<?>>)(Class<?>)WorkflowHandler.class,
255 new WorkflowHandlerServiceTrackerCustomizer());
256
257 _serviceTracker.open();
258 }
259
260 private List<WorkflowHandler<?>> _getScopeableWorkflowHandlers() {
261 return ListUtil.fromMapValues(_scopeableWorkflowHandlerMap);
262 }
263
264 private WorkflowHandler<?> _getWorkflowHandler(String className) {
265 return _workflowHandlerMap.get(className);
266 }
267
268 private List<WorkflowHandler<?>> _getWorkflowHandlers() {
269 return ListUtil.fromMapValues(_workflowHandlerMap);
270 }
271
272 private boolean _hasWorkflowInstanceInProgress(
273 long companyId, long groupId, String className, long classPK)
274 throws PortalException {
275
276 WorkflowInstanceLink workflowInstanceLink =
277 WorkflowInstanceLinkLocalServiceUtil.fetchWorkflowInstanceLink(
278 companyId, groupId, className, classPK);
279
280 if (workflowInstanceLink == null) {
281 return false;
282 }
283
284 WorkflowInstance workflowInstance =
285 WorkflowInstanceManagerUtil.getWorkflowInstance(
286 companyId, workflowInstanceLink.getWorkflowInstanceId());
287
288 if (!workflowInstance.isComplete()) {
289 return true;
290 }
291
292 return false;
293 }
294
295 private void _register(WorkflowHandler<?> workflowHandler) {
296 Registry registry = RegistryUtil.getRegistry();
297
298 ServiceRegistration<WorkflowHandler<?>> serviceRegistration =
299 registry.registerService(
300 (Class<WorkflowHandler<?>>)(Class<?>)WorkflowHandler.class,
301 workflowHandler);
302
303 _serviceRegistrations.put(workflowHandler, serviceRegistration);
304 }
305
306 private void _unregister(WorkflowHandler<?> workflowHandler) {
307 ServiceRegistration<WorkflowHandler<?>> serviceRegistration =
308 _serviceRegistrations.remove(workflowHandler);
309
310 if (serviceRegistration != null) {
311 serviceRegistration.unregister();
312 }
313 }
314
315 private static final Log _log = LogFactoryUtil.getLog(
316 WorkflowHandlerRegistryUtil.class);
317
318 private static final WorkflowHandlerRegistryUtil _instance =
319 new WorkflowHandlerRegistryUtil();
320
321 private final Map<String, WorkflowHandler<?>> _scopeableWorkflowHandlerMap =
322 new ConcurrentSkipListMap<>();
323 private final ServiceRegistrationMap<WorkflowHandler<?>>
324 _serviceRegistrations = new ServiceRegistrationMap<>();
325 private final ServiceTracker<WorkflowHandler<?>, WorkflowHandler<?>>
326 _serviceTracker;
327 private final Map<String, WorkflowHandler<?>> _workflowHandlerMap =
328 new TreeMap<>();
329
330 private class WorkflowHandlerServiceTrackerCustomizer
331 implements
332 ServiceTrackerCustomizer <WorkflowHandler<?>, WorkflowHandler<?>> {
333
334 @Override
335 public WorkflowHandler<?> addingService(
336 ServiceReference<WorkflowHandler<?>> serviceReference) {
337
338 Registry registry = RegistryUtil.getRegistry();
339
340 WorkflowHandler<?> workflowHandler = registry.getService(
341 serviceReference);
342
343 _workflowHandlerMap.put(
344 workflowHandler.getClassName(), workflowHandler);
345
346 if (workflowHandler.isScopeable()) {
347 _scopeableWorkflowHandlerMap.put(
348 workflowHandler.getClassName(), workflowHandler);
349 }
350
351 return workflowHandler;
352 }
353
354 @Override
355 public void modifiedService(
356 ServiceReference<WorkflowHandler<?>> serviceReference,
357 WorkflowHandler<?> workflowHandler) {
358 }
359
360 @Override
361 public void removedService(
362 ServiceReference<WorkflowHandler<?>> serviceReference,
363 WorkflowHandler<?> workflowHandler) {
364
365 Registry registry = RegistryUtil.getRegistry();
366
367 registry.ungetService(serviceReference);
368
369 _workflowHandlerMap.remove(workflowHandler.getClassName());
370
371 if (workflowHandler.isScopeable()) {
372 _scopeableWorkflowHandlerMap.remove(
373 workflowHandler.getClassName());
374 }
375 }
376
377 }
378
379 }