/* * 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.executor.impl.mem; import java.lang.reflect.Field; import java.util.Map; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicLong; import org.jbpm.executor.ExecutorServiceFactory; import org.jbpm.executor.impl.event.ExecutorEventSupport; import org.kie.api.executor.ErrorInfo; import org.kie.api.executor.ExecutorStoreService; import org.kie.api.executor.RequestInfo; import org.kie.api.executor.STATUS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class InMemoryExecutorStoreService implements ExecutorStoreService { private static final Logger logger = LoggerFactory.getLogger(InMemoryExecutorStoreService.class); private AtomicLong requestIds = new AtomicLong(); private AtomicLong errorIds = new AtomicLong(); private static ConcurrentNavigableMap<Long, RequestInfo> requests = new ConcurrentSkipListMap<Long, RequestInfo>(); private static ConcurrentNavigableMap<Long, RequestInfo> processedRequests = new ConcurrentSkipListMap<Long, RequestInfo>(); private static ConcurrentNavigableMap<Long, ErrorInfo> errors = new ConcurrentSkipListMap<Long, ErrorInfo>(); private ExecutorEventSupport eventSupport = new ExecutorEventSupport(); public InMemoryExecutorStoreService(boolean active) { } public void setEventSupport(ExecutorEventSupport eventSupport) { this.eventSupport = eventSupport; } @Override public synchronized void persistRequest(RequestInfo request) { setId(request, requestIds.incrementAndGet()); logger.debug("Storing request {}", request); requests.put(request.getId(), request); } @Override public synchronized void updateRequest(RequestInfo request) { if (request.getStatus() == STATUS.CANCELLED || request.getStatus() == STATUS.DONE || request.getStatus() == STATUS.ERROR || request.getStatus() == STATUS.RUNNING) { logger.debug("Updating request by removing it as it was already processed {}", request); requests.remove(request.getId()); if (processedRequests.size() > 100) { processedRequests.pollFirstEntry(); } processedRequests.put(request.getId(), request); // process errors if any if (request.getErrorInfo() != null) { for (ErrorInfo error : request.getErrorInfo()) { if (error.getId() == null) { persistError(error); } } } return; } logger.debug("Regular update of request {}", request); requests.put(request.getId(), request); } @Override public synchronized RequestInfo removeRequest(Long requestId) { RequestInfo request = requests.remove(requestId); if (processedRequests.size() > 100) { processedRequests.pollFirstEntry(); } processedRequests.put(request.getId(), request); request.setStatus(STATUS.CANCELLED); return request; } @Override public synchronized RequestInfo findRequest(Long id) { return requests.get(id); } @Override public synchronized void persistError(ErrorInfo error) { setId(error, errorIds.incrementAndGet()); errors.put(error.getId(), error); } @Override public synchronized void updateError(ErrorInfo error) { errors.put(error.getId(), error); } @Override public synchronized ErrorInfo removeError(Long errorId) { return errors.remove(errorId); } @Override public synchronized ErrorInfo findError(Long id) { return errors.get(id); } @Override public Runnable buildExecutorRunnable() { return ExecutorServiceFactory.buildRunable(eventSupport); } public synchronized RequestInfo getAndLockFirst() { if (requests.isEmpty()) { return null; } Long toProceed = requests.firstKey(); return requests.remove(toProceed); } public synchronized Map<Long, RequestInfo> getRequests() { return requests; } public synchronized Map<Long, ErrorInfo> getErrors() { return errors; } public synchronized Map<Long, RequestInfo> getProcessedRequests() { return processedRequests; } protected void setId(Object object, Long id) { try { Field idField = object.getClass().getDeclaredField("id"); idField.setAccessible(true); idField.set(object, id); } catch (Exception e) { throw new IllegalStateException("Unable to set id for object" + object); } } }