/** ソケットの再接続 */ private synchronized void reconnectNotificationSocket() { apnsInputMonitoringThread = null; // 既存の接続をクローズ ApnsUtil.close(apnsNotificationSocket); // パケット送信量をリセット packetSize = 0; // Socket取得 apnsNotificationSocket = null; apnsNotificationSocket = ApnsUtil.createAPNSGatewaySocket(isProduction, factory, socksProxy); // APNsからの入力待ちスレッドを開始 try { apnsInputMonitoringThread = new ApnsInputMonitoringThread(apnsNotificationSocket.getInputStream()); apnsInputMonitoringThread.start(); } catch (IOException e) { logger.info("APNs入力ストリーム取得エラー", e); } logger.debug("APNsへのSocket通信を構築または再構築しました。"); }
/** * 製品フラグ、証明書ファイル、証明書パスワード、SOCKSプロキシ、PUSH通信間隔(ミリ秒)、最大パケットサイズを指定してインスタンスを生成します * * @param isProduction 製品フラグ * @param certFileName 証明書ファイル * @param certPassword 証明書パスワード * @param socksProxy SOCKSプロキシ * @param pushIntervalMs PUSH通信間隔(ミリ秒) * @param maxPacket 最大パケットサイズ */ public ApnsNotificationService( boolean isProduction, String certFileName, String certPassword, Proxy socksProxy, int pushIntervalMs, long maxPacket) { this.isProduction = isProduction; this.certFileName = certFileName; this.certPassword = certPassword; this.socksProxy = socksProxy; this.pushIntervalMs = pushIntervalMs; this.maxPacket = maxPacket; this.factory = ApnsUtil.getSSLSocketFactory(this.certFileName, this.certPassword); }
/** * PUSH通知(複数件送信) * * @param apnsNotificationList 送信データリスト * @return 送信結果 */ public synchronized ApnsResult push(List<ApnsNotification> apnsNotificationList) { logger.info("PUSH通知 - 開始"); try { // Socketの生成 reconnectNotificationSocket(); // 通知リスト読み込み位置 int pos = 0; packetSize = 0; while (true) { int i; for (i = pos; i < apnsNotificationList.size(); i++) { pos = i; // 通知情報取り出し ApnsNotification apnsNotification = apnsNotificationList.get(i); // 実行Mapに格納 executeApnsNotificationMapIdentifier.put( apnsNotification.getIdentifier(), apnsNotification); executeIndexMapApnsNotification.put(apnsNotification, i); logger.trace( "deviceToken:{}, payload:{}", apnsNotification.getToken(), apnsNotification.getPayload()); // バイナリデータに変換 byte[] pushData = apnsNotification.getNotificationBytes(); if (pushData == null) { logger.info( "PUSHデータを生成できませんでした。token={}, payload={}", apnsNotification.getToken(), apnsNotification.getPayload()); // エラーにステータス変更 apnsNotification.setPushStatus(PushStatus.ERROR); // 読み飛ばし continue; } // パケット量制限を超える場合は再接続 if (this.maxPacket != 0 && this.packetSize > this.maxPacket) { reconnectNotificationSocket(); } try { // PUSH通知 OutputStream os = apnsNotificationSocket.getOutputStream(); os.write(pushData); os.flush(); // パケット量加算 packetSize += pushData.length; // 実行済にステータス設定 apnsNotification.setPushStatus(PushStatus.DONE); } catch (IOException e) { // OutputStream書き込みエラー logger.debug("APNs通知情報送信エラー。リトライを試行します。", e); pos = processPushError(i, apnsNotificationList); // forループを抜けてリトライ break; } // 待機 ApnsUtil.sleep(pushIntervalMs); // エラー確認 if (apnsInputMonitoringThread.hasError()) { pos = processPushError(i, apnsNotificationList); // forループを抜けてリトライ break; } pos++; } // 終端まで達していない場合は残りを処理 if (pos < apnsNotificationList.size()) { continue; } // 1秒間待機(最終通信後のAPNsからの入力を待つ) ApnsUtil.sleep(1000); // エラー確認 if (apnsInputMonitoringThread.hasError()) { pos = processPushError(i, apnsNotificationList); // リトライ continue; } // 全件処理完了 break; } return createApnsSendResult(apnsNotificationList, true, null); } catch (Exception e) { logger.error("PUSH通知処理中にException発生。", e); return createApnsSendResult(apnsNotificationList, false, e); } finally { ApnsUtil.close(apnsNotificationSocket); logger.info("PUSH通知 - 終了"); } }
/** * PUSH通知(マルチスレッド送信) * * <p>分割単位ごとにマルチスレッドでPUSH通知します。<br> * * @param apnsNotificationList 送信データリスト * @param threadCount スレッド数 * @return 送信結果 */ public synchronized ApnsResult push( List<ApnsNotification> apnsNotificationList, int threadCount) { logger.info("PUSH通知(マルチスレッド送信) - 開始"); // 送信完了を待機して各スレッドの送信結果を取得 ApnsResult apnsResult = new ApnsResult(); try { // スレッド数が1の場合はシングルスレッド送信 if (threadCount == 1) { logger.info("スレッド数が1のため、シングルスレッドで実行します。"); return push(apnsNotificationList); } // Listをスレッド数に応じて分割 List<List<ApnsNotification>> apnsNotificationListList = ApnsUtil.splitList(apnsNotificationList, threadCount); logger.info("スレッド数:{}", apnsNotificationListList.size()); // 非同期処理用ExecutorService生成 ExecutorService service = Executors.newFixedThreadPool(apnsNotificationListList.size()); List<Future<ApnsResult>> futureList = new ArrayList<Future<ApnsResult>>(); // 非同期PUSH送信 for (List<ApnsNotification> apnsNotificationThreadList : apnsNotificationListList) { ApnsNotificationPushCaller caller = new ApnsNotificationPushCaller(apnsNotificationThreadList); Future<ApnsResult> future = service.submit(caller); futureList.add(future); } // シャットダウン宣言 service.shutdown(); apnsResult.setSuccess(true); for (int i = 0; i < futureList.size(); i++) { // 待機&結果取得 ApnsResult r = futureList.get(i).get(); // 1つでも異常終了があれば異常とする if (!r.isSuccess()) { apnsResult.setSuccess(r.isSuccess()); } // 複数スレッドでExceptionがあった場合は最後のものを格納 if (r.getException() != null) { apnsResult.setException(r.getException()); } // 未実行リスト apnsResult.addAllNone(r.getNoneList()); // 実行済リスト apnsResult.addAllDone(r.getDoneList()); // エラーリスト apnsResult.addAllError(r.getErrorList()); } } catch (Exception e) { apnsResult.setException(e); apnsResult.setSuccess(false); } finally { logger.info("PUSH通知(マルチスレッド送信) - 終了"); } return apnsResult; }