/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.smscserver.message.impl; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.smscserver.DeliveryManager; import org.apache.smscserver.DeliveryManagerConfig; import org.apache.smscserver.SmscServerContext; import org.apache.smscserver.smsclet.SmscIoSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <strong>Internal class, do not use directly.</strong> * <p> * Manager manage the delivery of short messages to clients * * @author hceylan */ public class DefaultDeliveryManager implements DeliveryManager { private class Worker implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { try { MessagePoller poller = DefaultDeliveryManager.this.sessionQueue.poll(); if (poller == null) { Thread.sleep(100); continue; } DefaultDeliveryManager.this.getDeliveryExecuter().submit(poller); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); break; } } } } private static final Logger LOG = LoggerFactory.getLogger(DefaultDeliveryManager.class); private static final int DEFAULT_KEEPALIVE_TIME = 30000; private final SmscServerContext serverContext; private boolean started; private boolean suspended; private int managerThreads; private int minThreads; private int maxThreads; private ExecutorService managerExecuter; private ThreadPoolExecutor deliveryExecuter; private final SynchronousQueue<Runnable> workQueue; private IOSessionQueue sessionQueue; private long[] deliveryPeriods; private int deliveryPollTime; public DefaultDeliveryManager(SmscServerContext serverContext) { this.serverContext = serverContext; this.workQueue = new SynchronousQueue<Runnable>(true); } /** * {@inheritDoc} * */ public void closeBoundSession(SmscIoSession ioSession) { this.sessionQueue.remove(ioSession); } private void createManagerThreadPoolExecutor() { if (this.managerExecuter == null) { DeliveryManagerConfig config = this.serverContext.getDeliveryManagerConfig(); this.managerThreads = config.getManagerThreads(); this.minThreads = config.getMinThreads(); this.maxThreads = config.getMaxThreads(); if (this.managerThreads < 1) { this.managerThreads = Runtime.getRuntime().availableProcessors(); } if (this.minThreads < 1) { this.minThreads = Runtime.getRuntime().availableProcessors(); this.maxThreads = Runtime.getRuntime().availableProcessors(); } if (this.minThreads < 1) { this.minThreads = this.maxThreads / 4; } if (this.maxThreads > this.minThreads) { this.maxThreads = this.minThreads; } DefaultDeliveryManager.LOG.info("Intializing thread pool executor for Delivery Manager", this.minThreads, this.maxThreads); this.sessionQueue = new IOSessionQueue(); this.startManager(); } } /** * {@inheritDoc} * */ public synchronized void destroy() { if (this.started) { this.managerExecuter.shutdownNow(); this.managerExecuter = null; } } /** * @return the threadPool */ public ThreadPoolExecutor getDeliveryExecuter() { if (!this.started || this.suspended) { return null; } if (this.deliveryExecuter == null) { this.deliveryExecuter = new ThreadPoolExecutor(this.minThreads, this.maxThreads, DefaultDeliveryManager.DEFAULT_KEEPALIVE_TIME, TimeUnit.MILLISECONDS, this.workQueue); } return this.deliveryExecuter; } /** * {@inheritDoc} * */ public long[] getDeliveryPeriods() { return this.deliveryPeriods; } /** * Returns the server context. * * @return the serverContext */ public SmscServerContext getServerContext() { return this.serverContext; } /** * {@inheritDoc} * */ public void newBoundSession(SmscIoSession ioSession) { this.sessionQueue.add(new MessagePoller(this, ioSession)); } /** * Adds the message poller back to the queue. * * @param messagePoller * the message poller to add back to the queue */ public void reschedule(MessagePoller messagePoller) { messagePoller.setNextCheckTime(System.currentTimeMillis() + (this.deliveryPollTime)); this.sessionQueue.add(messagePoller); } /** * {@inheritDoc} * */ public synchronized void resume() { if (!this.started) { throw new IllegalStateException("Delivery Manager has not been started"); } if (this.suspended) { this.startManager(); this.suspended = false; } } /** * Starts the delivery manager. * * @throws IllegalStateException * if the manager has already been started */ public synchronized void start() { if (this.started) { throw new IllegalStateException("Delivery Manager already started"); } this.serverContext.getDeliveryManagerConfig(); this.createManagerThreadPoolExecutor(); DeliveryManagerConfig config = this.serverContext.getDeliveryManagerConfig(); this.deliveryPeriods = config.getDeliveryPeriods(); this.deliveryPollTime = config.getDeliveryPollTime(); if (this.deliveryPollTime == 0) { this.deliveryPollTime = 15000; } this.started = true; } private void startManager() { ThreadFactory threadFactory = new ThreadFactory() { private int i = 0; public Thread newThread(Runnable r) { return new Thread(r, "Delivery-Manager-" + this.i++); } }; this.managerExecuter = Executors.newCachedThreadPool(threadFactory); for (int i = 0; i < this.managerThreads; i++) { this.managerExecuter.submit(new Worker()); } } /** * {@inheritDoc} * */ public synchronized void suspend() { if (!this.started) { throw new IllegalStateException("Delivery Manager has not been started"); } if (!this.suspended) { this.deliveryExecuter.shutdownNow(); this.deliveryExecuter = null; this.managerExecuter.shutdownNow(); this.managerExecuter = null; this.suspended = true; } } }