/** * Copyright 2010 JBoss Inc * * 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.drools.reteoo; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.drools.common.InternalWorkingMemory; import org.drools.common.RuleBasePartitionId; import org.drools.concurrent.ExternalExecutorService; import org.drools.reteoo.PartitionTaskManager.Action; import org.drools.reteoo.PartitionTaskManager.PartitionTask; /** * A manager class for all partition tasks managers. * * The purpose of this class is to keep the reference to all individual partition task managers * and centralise the synchronisation mechanism between the network and the agenda. * * @author etirelli * */ public class PartitionManager { // these are the actual task managers for each partition private Map<RuleBasePartitionId, PartitionTaskManager> partitionManagers; private InternalWorkingMemory workingMemory; // this is the actual thread pool private AtomicReference<ExternalExecutorService> executorService; // this is a queue that holds new tasks whenever the actual task submission is on hold private PriorityBlockingQueue<PartitionTask> queue; // a boolean flag and monitor lock for holding the task queue private AtomicBoolean onHold; public PartitionManager(InternalWorkingMemory workingMemory) { this.workingMemory = workingMemory; this.executorService = new AtomicReference<ExternalExecutorService>(); this.partitionManagers = new ConcurrentHashMap<RuleBasePartitionId, PartitionTaskManager>(); this.queue = new PriorityBlockingQueue<PartitionTask>(); this.onHold = new AtomicBoolean( false ); } /** * Add partition to the list of managed partitions * * @param partitionId */ public void manage(RuleBasePartitionId partitionId) { if ( !this.partitionManagers.containsKey( partitionId ) ) { this.partitionManagers.put( partitionId, new PartitionTaskManager( this, workingMemory ) ); } } public void setPool(final ExternalExecutorService executorService) { // any monitor/lock could be used... using onHold so that it is obvious synchronized ( onHold ) { this.executorService.set( executorService ); while( this.executorService.get() != null && ! queue.isEmpty() ) { PartitionTask task = queue.poll(); this.executorService.get().execute( task ); } } } public void execute(PartitionTask task) { // any monitor/lock could be used... using onHold so that it is obvious synchronized ( onHold ) { if ( (task.getPriority() < Action.PRIORITY_HIGH && onHold.get()) || this.executorService.get() == null ) { this.queue.add( task ); } else { this.executorService.get().execute( task ); } } } public void holdTasks() { // any monitor/lock could be used... using onHold so that it is obvious synchronized ( onHold ) { this.onHold.set( true ); } } public void waitForPendingTasks() { this.executorService.get().waitUntilEmpty(); } public void releaseTasks() { // any monitor/lock could be used... using onHold so that it is obvious synchronized ( onHold ) { ExecutorService service = this.executorService.get(); if ( service != null ) { for ( PartitionTask task : queue ) { service.execute( task ); } } this.onHold.set( false ); } } public void shutdown() { this.setPool( null ); } public PartitionTaskManager getPartitionTaskManager(RuleBasePartitionId partitionId) { return partitionManagers.get( partitionId ); } public boolean isOnHold() { return this.onHold.get(); } }