package tv.dyndns.kishibe.qmaclone.server.websocket; import java.io.Closeable; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.WriteCallback; import com.google.common.base.Preconditions; import tv.dyndns.kishibe.qmaclone.server.ThreadPool; public abstract class MessageSender<T> implements Closeable { private static final Logger logger = Logger.getLogger(MessageSender.class.getName()); private final Set<Session> sessions = new CopyOnWriteArraySet<>(); private final ThreadPool threadPool; private final ScheduledFuture<?> futurePing; protected MessageSender(ThreadPool threadPool) { this.threadPool = Preconditions.checkNotNull(threadPool); // 25秒間隔でpingを送る futurePing = threadPool.scheduleAtFixedRate(runnablePing, 25L, 25L, TimeUnit.SECONDS); } private final Runnable runnablePing = new Runnable() { @Override public void run() { send(""); } }; public void send(T data) { String json = encode(data); send(json); } private void send(String json) { for (Session session : sessions) { try { WriteCallback writeCallback = new WriteCallback() { @Override public void writeSuccess() { // Do nothing. } @Override public void writeFailed(Throwable x) { logger.log(Level.WARNING, "WebSocketでのデータの送信に失敗しました。接続を閉じます。 remoteAddress=" + session.getRemoteAddress().toString(), x); try { session.close(); } catch (Exception e) { } bye(session); } }; session.getRemote().sendString(json, writeCallback); } catch (Exception e) { logger.log(Level.WARNING, "WebSocketでのデータの送信に失敗しました。接続を閉じます。 remoteAddress=" + session.getRemoteAddress().toString(), e); try { session.close(); } catch (Exception e2) { } bye(session); } } } @Override public void close() { futurePing.cancel(false); for (Session session : sessions) { session.close(); } sessions.clear(); } public void join(Session session) { sessions.add(session); } public void bye(Session session) { sessions.remove(session); } /** * T型のオブジェクトを文字列に変換する * * @param data * 変換元のオブジェクト * @return T型のオブジェクトの文字列表現 */ protected abstract String encode(T data); }