/*
* Copyright 2009, Mahmood Ali.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Mahmood Ali. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.notnoop.apns.internal;
import java.util.concurrent.*;
import com.notnoop.apns.ApnsNotification;
import com.notnoop.exceptions.NetworkIOException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApnsPooledConnection implements ApnsConnection {
private static final Logger logger = LoggerFactory.getLogger(ApnsPooledConnection.class);
private final ApnsConnection prototype;
private final int max;
private final ExecutorService executors;
private final ConcurrentLinkedQueue<ApnsConnection> prototypes;
public ApnsPooledConnection(ApnsConnection prototype, int max) {
this(prototype, max, Executors.newFixedThreadPool(max));
}
public ApnsPooledConnection(ApnsConnection prototype, int max, ExecutorService executors) {
this.prototype = prototype;
this.max = max;
this.executors = executors;
this.prototypes = new ConcurrentLinkedQueue<ApnsConnection>();
}
private final ThreadLocal<ApnsConnection> uniquePrototype =
new ThreadLocal<ApnsConnection>() {
protected ApnsConnection initialValue() {
ApnsConnection newCopy = prototype.copy();
prototypes.add(newCopy);
return newCopy;
}
};
public void sendMessage(final ApnsNotification m) throws NetworkIOException {
Future<Void> future = executors.submit(new Callable<Void>() {
public Void call() throws Exception {
uniquePrototype.get().sendMessage(m);
return null;
}
});
try {
future.get();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
} catch (ExecutionException ee) {
if (ee.getCause() instanceof NetworkIOException) {
throw (NetworkIOException) ee.getCause();
}
}
}
public ApnsConnection copy() {
// TODO: Should copy executor properly.... What should copy do
// really?!
return new ApnsPooledConnection(prototype, max);
}
public void close() {
executors.shutdown();
try {
executors.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.warn("pool termination interrupted", e);
}
for (ApnsConnection conn : prototypes) {
Utilities.close(conn);
}
Utilities.close(prototype);
}
public void testConnection() {
prototype.testConnection();
}
public synchronized void setCacheLength(int cacheLength) {
for (ApnsConnection conn : prototypes) {
conn.setCacheLength(cacheLength);
}
}
@SuppressFBWarnings(value = "UG_SYNC_SET_UNSYNC_GET", justification = "prototypes is a MT-safe container")
public int getCacheLength() {
return prototypes.peek().getCacheLength();
}
}