/** * Copyright 2013-2015 Seagate Technology LLC. * * This Source Code Form is subject to the terms of the Mozilla * Public License, v. 2.0. If a copy of the MPL was not * distributed with this file, You can obtain one at * https://mozilla.org/MP:/2.0/. * * This program is distributed in the hope that it will be useful, * but is provided AS-IS, WITHOUT ANY WARRANTY; including without * the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or * FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public * License for more details. * * See www.openkinetic.org for more project information */ package com.seagate.kinetic.simulator.internal; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import com.seagate.kinetic.common.lib.KineticMessage; import com.seagate.kinetic.simulator.io.provider.spi.MessageService; import com.seagate.kinetic.simulator.io.provider.tcp.IoHandler; /** * * Server network I/O message handler. * <p> * * @author James Hughes * @author chiaming Yang * */ public class MessageHandler implements Runnable { // my logger private final static Logger logger = Logger.getLogger(MessageHandler.class .getName()); // my message queue private final LinkedBlockingQueue<KineticMessage> lbqueue = new LinkedBlockingQueue<KineticMessage>(); // io handler private IoHandler ioHandler = null; // master server private MessageService messageService = null; // flag running flag private volatile boolean isRunning = false; // close flag private volatile boolean isClosed = false; // reference to current running flag private Thread currentThread = null; /** * Constructor. * * @param ioHandler * the iohandler associated with this message handler. */ public MessageHandler(IoHandler ioHandler) { this.ioHandler = ioHandler; this.messageService = ioHandler.getIoService().getMessageService(); } /** * process request message from IoHandler. * * @param message * request message. * * @throws InterruptedException * if interrupted. */ public void processRequest(KineticMessage message) throws InterruptedException { // put to queue this.lbqueue.put(message); // check if there is a thread running. if not, submit to thread pool // for execution. checkRunning(); } @Override public void run() { try { while (isRunning()) { // save the current thread reference this.currentThread = Thread.currentThread(); // poll message from queue KineticMessage msg = this.lbqueue.poll(6, TimeUnit.SECONDS); if (msg != null) { // process message doProcessMessage(msg); } else { // break out of loop this.isRunning = false; } } } catch (InterruptedException ie) { // interrupted when closed ; } catch (Exception e) { logger.log(Level.WARNING, e.getMessage(), e); } finally { // set running to false isRunning = false; // thread returning to pool this.currentThread = null; } } /** * process request message. * * @param request * request message from IoHandler. */ private void doProcessMessage(KineticMessage request) { // delegate to server instance to process KineticMessage response = this.messageService.processRequest(request); // delegate to IoHandler to send the response message this.ioHandler.sendResponse(response); } /** * Check if there is a thread running and processing the queue. If not, * submit myself to the executor service. */ private void checkRunning() { if (this.isRunning == false) { synchronized (this) { if (this.isRunning == false) { if (this.isClosed) { return; } // set flag to true this.isRunning = true; // execute by the thread pool this.ioHandler.getIoService().getPool().execute(this); logger.fine("started message handler thread ..." + this.ioHandler.getIoService().getName()); } } } } /** * check if there is a thread running. * * @return true if the thread is polling the message. */ private boolean isRunning() { return (isRunning && (!isClosed)); } /** * Close the message handler. */ public void close() { // set closed flag this.isClosed = true; // wake up lbqueue if (this.currentThread != null) { this.currentThread.interrupt(); } } }