/*
* Copyright 2014 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.services.cdi.producer;
import java.util.HashSet;
import java.util.List;
import javax.enterprise.inject.AmbiguousResolutionException;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import org.jbpm.runtime.manager.impl.deploy.DeploymentDescriptorManager;
import org.jbpm.runtime.manager.impl.jpa.EntityManagerFactoryManager;
import org.jbpm.services.task.HumanTaskConfigurator;
import org.jbpm.services.task.HumanTaskServiceFactory;
import org.jbpm.services.task.audit.JPATaskLifeCycleEventListener;
import org.jbpm.services.task.impl.command.CommandBasedTaskService;
import org.jbpm.services.task.lifecycle.listeners.BAMTaskEventListener;
import org.kie.api.task.TaskLifeCycleEventListener;
import org.kie.api.task.UserGroupCallback;
import org.kie.internal.runtime.conf.AuditMode;
import org.kie.internal.runtime.conf.DeploymentDescriptor;
import org.kie.internal.task.api.InternalTaskService;
import org.kie.internal.task.api.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* CDI producer for <code>TaskService</code> instances. By default it runs in new mode,
* meaning new <code>TaskService</code> instance for every injection point.
* This behavior can be altered by setting <code>org.jbpm.cdi.taskservice.mode</code> system
* property to one of the values.
* <ul>
* <li>none - disables producer to not return TaskService instances</li>
* <li>singleton - produces only one instance of TaskService that will be shared</li>
* <li>new - produces new instance for every injection point</li>
* </ul>
* This bean accept following injections:
* <ul>
* <li>UserGroupCallback</li>
* <li>UserInfo</li>
* <li>TaskLifeCycleEventListener</li>
* </ul>
* all of these are optional injections and if not available defaults will be used. Underneath it uses
* <code>HumanTaskConfigurator</code> for <code>TaskService</code> instances creations.
* @see HumanTaskConfigurator
*/
public class HumanTaskServiceProducer {
private static final Logger logger = LoggerFactory.getLogger( HumanTaskServiceProducer.class );
final String mode = System.getProperty( "org.jbpm.cdi.taskservice.mode", "new" );
@Inject
private Instance<UserGroupCallback> userGroupCallback;
@Inject
private Instance<UserInfo> userInfo;
@Inject
@Any
private Instance<TaskLifeCycleEventListener> taskListeners;
@Inject
@Any
private Instance<List<TaskLifeCycleEventListener>> listOfListeners;
@Inject
@PersistenceUnit(unitName = "org.jbpm.domain")
private EntityManagerFactory emf;
// internal member to ensure only single instance of task service is produced
private InternalTaskService taskService;
@Produces
public CommandBasedTaskService produceTaskService() {
if ( mode.equalsIgnoreCase( "none" ) ) {
return null;
}
if ( taskService == null ) {
HumanTaskConfigurator configurator = createHumanTaskConfigurator();
if ( mode.equalsIgnoreCase( "singleton" ) ) {
this.taskService = (CommandBasedTaskService) configurator.getTaskService();
} else {
return (CommandBasedTaskService) configurator.getTaskService();
}
}
return (CommandBasedTaskService) taskService;
}
protected HumanTaskConfigurator createHumanTaskConfigurator() {
HumanTaskConfigurator configurator = HumanTaskServiceFactory.newTaskServiceConfigurator();
configureHumanTaskConfigurator(configurator);
return configurator;
}
protected void configureHumanTaskConfigurator(HumanTaskConfigurator configurator) {
configurator
.entityManagerFactory( emf )
.userGroupCallback( safeGet( userGroupCallback ) )
.userInfo( safeGet( userInfo ) );
DeploymentDescriptorManager manager = new DeploymentDescriptorManager("org.jbpm.domain");
DeploymentDescriptor descriptor = manager.getDefaultDescriptor();
// in case there is descriptor with enabled audit register then by default
if (!descriptor.getAuditMode().equals(AuditMode.NONE)) {
JPATaskLifeCycleEventListener listener = new JPATaskLifeCycleEventListener(false);
BAMTaskEventListener bamListener = new BAMTaskEventListener(false);
// if the audit persistence unit is different than default for the engine perform proper init
if (!"org.jbpm.domain".equals(descriptor.getAuditPersistenceUnit())) {
EntityManagerFactory emf = EntityManagerFactoryManager.get().getOrCreate(descriptor.getAuditPersistenceUnit());
listener = new JPATaskLifeCycleEventListener(emf);
bamListener = new BAMTaskEventListener(emf);
}
configurator.listener( listener );
configurator.listener( bamListener );
}
// next proceed with registration of further listeners as cdi injections
try {
for ( TaskLifeCycleEventListener listener : taskListeners ) {
configurator.listener( listener );
logger.debug( "Registering listener {}", listener );
}
} catch ( Exception e ) {
logger.debug( "Cannot add listeners to task service due to {}", e.getMessage() );
}
}
protected <T> T safeGet( Instance<T> instance ) {
try {
T object = instance.get();
logger.debug( "About to set object {} on task service", object );
return object;
} catch ( AmbiguousResolutionException e ) {
// special handling in case cdi discovered multiple injections
// that are actually same instances - e.g. weld on tomcat
HashSet<T> available = new HashSet<T>();
for ( T object : instance ) {
available.add( object );
}
if ( available.size() == 1 ) {
return available.iterator().next();
} else {
throw e;
}
} catch ( Throwable e ) {
logger.debug( "Cannot get value of of instance {} due to {}", instance, e.getMessage() );
}
return null;
}
}