/**
* Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis
*
* The present code is developed in the scope of the joint LINAGORA -
* Université Joseph Fourier - Floralis research program and is designated
* as a "Result" pursuant to the terms and conditions of the LINAGORA
* - Université Joseph Fourier - Floralis research program. Each copyright
* holder of Results enumerated here above fully & independently holds complete
* ownership of the complete Intellectual Property rights applicable to the whole
* of said Results, and may freely exploit it in any manner which does not infringe
* the moral rights of the other copyright holders.
*
* 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 net.roboconf.messaging.api;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import net.roboconf.messaging.api.business.IClient;
import net.roboconf.messaging.api.extensions.IMessagingClient;
import net.roboconf.messaging.api.jmx.RoboconfMessageQueue;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
/**
* A message processor is in charge of (guess what) processing messages.
* <p>
* The DM is supposed to have only one message processor running.<br>
* Same thing for an agent. When the DM or an agent stops, the processor thread should be stopped.
* </p>
* <p>
* This class is a thread that will process messages. The method {@link #stopProcessor()} will stop
* processing messages after the current message is processed, or right after the next one is received.
* For an immediate stop, use the {@link #interrupt()} method.
* </p>
*
* @param <T> a sub-class of {@link IMessagingClient}
* @author Vincent Zurczak - Linagora
*/
public abstract class AbstractMessageProcessor<T extends IClient> extends Thread {
private final RoboconfMessageQueue messageQueue = new RoboconfMessageQueue();
private final AtomicBoolean running = new AtomicBoolean( false );
protected T messagingClient;
/**
* Constructor.
* @param threadName the thread name
*/
public AbstractMessageProcessor( String threadName ) {
super( threadName );
}
/**
* Stores a message so that it can be processed later.
* @param message a message to store
*/
public final void storeMessage( Message message ) {
this.messageQueue.add( message );
}
/**
* @return the messageQueue
*/
public RoboconfMessageQueue getMessageQueue() {
return this.messageQueue;
}
/**
* This method must be invoked before {@link #start()}.
* <p>
* It is not recommended to change the messaging client once the thread has started.
* It is better to use a {@link ReconfigurableClient} to handle messaging reconfiguration.
* </p>
* @param messagingClient the messaging client to set
*/
public void setMessagingClient( T messagingClient ) {
this.messagingClient = messagingClient;
}
/*
* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public final void run() {
this.running.set( true );
while( this.running.get()) {
try {
Message message = this.messageQueue.take();
if( this.running.get())
processMessage( message );
} catch( InterruptedException e ) {
break;
}
}
Logger.getLogger( getClass().getName()).fine( "Roboconf's message processing thread is stopping." );
this.running.set( false );
}
/**
* @return the running
*/
public boolean isRunning() {
return this.running.get();
}
/**
* Stops the processor.
*/
public void stopProcessor() {
this.running.set( false );
}
/**
* Processes a message.
* @param message the message to process
*/
protected abstract void processMessage( Message message );
}