/* * Copyright 2015 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. * * 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.persistence; import java.util.ArrayList; import java.util.List; import org.drools.persistence.infinispan.InfinispanPersistenceContext; import org.infinispan.Cache; import org.jbpm.persistence.api.PersistentCorrelationKey; import org.jbpm.persistence.api.PersistentProcessInstance; import org.jbpm.persistence.api.ProcessPersistenceContext; import org.jbpm.persistence.correlation.CorrelationKeyInfo; import org.jbpm.persistence.processinstance.ProcessEntityHolder; import org.jbpm.persistence.processinstance.ProcessInstanceInfo; import org.kie.internal.process.CorrelationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class InfinispanProcessPersistenceContext extends InfinispanPersistenceContext implements ProcessPersistenceContext { private static Logger logger = LoggerFactory.getLogger(InfinispanProcessPersistenceContext.class); private static long PROCESSINSTANCEINFO_KEY = 1; private static long CORRELATIONKEYINFO_KEY = 1; private static final Object keyObject = new Object(); public InfinispanProcessPersistenceContext(Cache<String, Object> cache ) { super( cache ); } public PersistentProcessInstance persist(PersistentProcessInstance processInstance) { ProcessInstanceInfo processInstanceInfo = (ProcessInstanceInfo) processInstance; String id = generateProcessInstanceInfoId(processInstanceInfo); getCache().put( id, new ProcessEntityHolder(id, processInstanceInfo) ); return processInstanceInfo; } public ProcessInstanceInfo findProcessInstanceInfo(Long processInstanceId) { String key = inferProcessInstanceInfoId(processInstanceId); ProcessEntityHolder holder = (ProcessEntityHolder) getCache().get( key ); if (holder == null) { return null; } return holder.getProcessInstanceInfo(); } public void remove(PersistentProcessInstance processInstance) { ProcessInstanceInfo processInstanceInfo = (ProcessInstanceInfo) processInstance; getCache().remove( generateProcessInstanceInfoId(processInstanceInfo) ); getCache().evict( generateProcessInstanceInfoId(processInstanceInfo) ); List<CorrelationKeyInfo> correlations = getCorrelationKeysByProcessInstanceId(processInstanceInfo.getId()); if (correlations != null) { for (CorrelationKeyInfo key : correlations) { getCache().remove(generateCorrelationKeyInfoId(key)); } } } private String generateCorrelationKeyInfoId(CorrelationKeyInfo info) { if (info != null && info.getId() <= 0) { synchronized (keyObject) { while (getCache().containsKey("correlationInfo" + CORRELATIONKEYINFO_KEY)) { CORRELATIONKEYINFO_KEY++; } } try { java.lang.reflect.Field idField = CorrelationKeyInfo.class.getDeclaredField("id"); idField.setAccessible(true); idField.set(info, CORRELATIONKEYINFO_KEY); } catch (Exception e) { if( e instanceof RuntimeException ) { throw (RuntimeException) e; } else { throw new RuntimeException( "Unable to set id field of " + CorrelationKeyInfo.class.getSimpleName() + " instance.", e ); } } } return "correlationInfo" + info.getId(); } private String generateProcessInstanceInfoId(ProcessInstanceInfo info) { if (info != null && (info.getId() == null || info.getId() <= 0)) { synchronized (keyObject) { while (getCache().containsKey(inferProcessInstanceInfoId(PROCESSINSTANCEINFO_KEY))) { PROCESSINSTANCEINFO_KEY++; } } info.setId(PROCESSINSTANCEINFO_KEY); } return inferProcessInstanceInfoId(info.getId()); } private String inferProcessInstanceInfoId(Long processInstanceId) { return "processInstanceInfo" + processInstanceId; } private List<CorrelationKeyInfo> getCorrelationKeysByProcessInstanceId(Long pId) { Cache<String, Object> cache = getCache(); List<CorrelationKeyInfo> retval = new ArrayList<CorrelationKeyInfo>(); for (String key : cache.keySet()) { if (key.startsWith("correlationInfo")) { ProcessEntityHolder holder = (ProcessEntityHolder) cache.get(key); if (pId.equals(holder.getProcessInstanceId())) { retval.add(holder.getCorrelationKeyInfo()); } } } return retval; } public List<Long> getProcessInstancesWaitingForEvent(String type) { Cache<String, Object> cache = getCache(); List<Long> retval = new ArrayList<Long>(); for (String key : cache.keySet()) { if (key.startsWith("processInstanceInfo")) { ProcessEntityHolder holder = (ProcessEntityHolder) cache.get(key); if (holder != null && holder.getProcessInstanceEventTypes() != null) { if (holder.getProcessInstanceEventTypes().contains(type)) { retval.add(holder.getProcessInstanceId()); } } } } return retval; } public CorrelationKeyInfo persist(PersistentCorrelationKey correlationKey) { CorrelationKeyInfo correlationKeyInfo = (CorrelationKeyInfo) correlationKey; Long processInstanceId = getProcessInstanceByCorrelationKey(correlationKeyInfo); if (processInstanceId != null) { throw new RuntimeException(correlationKeyInfo + " already exists"); } String id = generateCorrelationKeyInfoId(correlationKeyInfo); getCache().put( id, new ProcessEntityHolder(id, correlationKeyInfo) ); return correlationKeyInfo; } public Long getProcessInstanceByCorrelationKey(CorrelationKey correlationKey) { String propertiesString = ProcessEntityHolder.generateString(correlationKey.getProperties()); Cache<String, Object> cache = getCache(); List<Long> retval = new ArrayList<Long>(); for (String key : cache.keySet()) { if (key.startsWith("correlationInfo")) { ProcessEntityHolder holder = (ProcessEntityHolder) cache.get(key); if (holder.getCorrelationKeyId() == correlationKey.getProperties().size()) { if (holder.getCorrelationKeyProperties().contains(propertiesString)) { retval.add(holder.getProcessInstanceId()); } } } } return (retval.size() == 1) ? retval.iterator().next() : null; } }