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