com.dbay.apns4j.impl.ApnsServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.dbay.apns4j.impl.ApnsServiceImpl.java

Source

/*
 * Copyright 2013 DiscoveryBay 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 com.dbay.apns4j.impl;

import static com.dbay.apns4j.model.ApnsConstants.ALGORITHM;
import static com.dbay.apns4j.model.ApnsConstants.KEYSTORE_TYPE;
import static com.dbay.apns4j.model.ApnsConstants.PROTOCOL;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.net.SocketFactory;
import javax.security.cert.CertificateExpiredException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dbay.apns4j.ErrorProcessHandler;
import com.dbay.apns4j.IApnsConnection;
import com.dbay.apns4j.IApnsFeedbackConnection;
import com.dbay.apns4j.IApnsService;
import com.dbay.apns4j.model.ApnsConfig;
import com.dbay.apns4j.model.Feedback;
import com.dbay.apns4j.model.Payload;
import com.dbay.apns4j.model.PushNotification;
import com.dbay.apns4j.tools.ApnsTools;

/**
 * The service should be created twice at most. One for the development env, and
 * the other for the production env
 * 
 * @author RamosLi
 * 
 */
public class ApnsServiceImpl implements IApnsService {

    private static Log logger = LogFactory.getLog(ApnsServiceImpl.class);
    private ExecutorService service = null;
    private ApnsConnectionPool connPool = null;
    private IApnsFeedbackConnection feedbackConn = null;
    private String name;
    private int queueSize = 10240;

    private ApnsServiceImpl(ApnsConfig config, ErrorProcessHandler errorProcessHandler)
            throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException,
            CertificateException, CertificateExpiredException, IOException {
        this.name = config.getName();
        int poolSize = config.getPoolSize();
        // this.service = Executors.newFixedThreadPool(poolSize);
        this.service = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(queueSize));

        SocketFactory factory = ApnsTools.createSocketFactory(config.getKeyStore(), config.getPassword(),
                KEYSTORE_TYPE, ALGORITHM, PROTOCOL);
        this.connPool = ApnsConnectionPool.newConnPool(config, factory, errorProcessHandler);
        this.feedbackConn = new ApnsFeedbackConnectionImpl(config, factory);
    }

    @Override
    public void sendNotification(final String token, final Payload payload) {
        service.execute(new Runnable() {
            @Override
            public void run() {
                IApnsConnection conn = null;
                try {
                    conn = getConnection();
                    conn.sendNotification(token, payload);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                } finally {
                    if (conn != null) {
                        connPool.returnConn(conn);
                    }
                }
            }
        });
    }

    @Override
    public void sendNotification(final PushNotification notification) {
        service.execute(new Runnable() {
            @Override
            public void run() {
                IApnsConnection conn = null;
                try {
                    conn = getConnection();
                    conn.sendNotification(notification);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                } finally {
                    if (conn != null) {
                        connPool.returnConn(conn);
                    }
                }
            }
        });
    }

    private IApnsConnection getConnection() {
        IApnsConnection conn = connPool.borrowConn();
        if (conn == null) {
            throw new RuntimeException("Can't get apns connection");
        }
        return conn;
    }

    private static void checkConfig(ApnsConfig config) {
        if (config == null || config.getKeyStore() == null || config.getPassword() == null
                || "".equals(config.getPassword().trim())) {
            throw new IllegalArgumentException("KeyStore and password can't be null");
        }
        if (config.getPoolSize() <= 0 || config.getRetries() <= 0 || config.getCacheLength() <= 0) {
            throw new IllegalArgumentException("poolSize,retry, cacheLength must be positive");
        }
    }

    private final static Map<String, IApnsService> serviceCacheMap = new HashMap<String, IApnsService>();

    public final static IApnsService getCachedService(String name) {
        return serviceCacheMap.get(name);
    }

    public final static IApnsService createInstance(ApnsConfig config, ErrorProcessHandler errorProcessHandler)
            throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException,
            CertificateException, CertificateExpiredException, IOException {
        checkConfig(config);
        String name = config.getName();
        IApnsService service = getCachedService(name);
        if (service == null) {
            synchronized (name.intern()) {
                service = getCachedService(name);
                if (service == null) {
                    service = new ApnsServiceImpl(config, errorProcessHandler);
                    serviceCacheMap.put(name, service);
                }
            }
        }
        return service;
    }

    @Override
    public void shutdown() {
        service.shutdown();
        try {
            service.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            logger.warn("Shutdown ApnsService interrupted", e);
        }
        connPool.close();
    }

    @Override
    public List<Feedback> getFeedbacks() {
        return feedbackConn.getFeedbacks();
    }
}