Java tutorial
/* HttpEventManager.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.message.http.event; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.logging.Logger; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultHttpClient; import org.deviceconnect.message.DConnectMessage; import org.deviceconnect.message.event.AbstractEventManager; import org.deviceconnect.utils.URIBuilder; import org.java_websocket.client.WebSocketClient; import org.java_websocket.handshake.ServerHandshake; import org.json.JSONException; import org.json.JSONObject; /** * ?. * ???WebSocket????? * * * @author NTT DOCOMO, INC. */ public final class HttpEventManager extends AbstractEventManager { /** * WebSocket. */ private static final int NORMAL_CLOSE_CODE = 1000; /** * ?. */ private static final int RETRY_TIMES = 5; /** * ??. * ?????????????? * ex. 1 {@value} ?2 {@value} * 2 */ private static final long RETRY_WAIT = 30 * 1000; /** * ?EventManager?. */ public static final HttpEventManager INSTANCE = new HttpEventManager(); /** * WebSocket. */ private EventWebSocketClient mWSClient; /** * ??. */ private CloseHandler mCloseHandler; /** * . */ private Logger mLogger = Logger.getLogger("org.deviceconnect.sdk"); /** * . */ private Object mLock; /** * WebSocket. * * @author NTT DOCOMO, INC. * */ private enum Status { /** * ?. */ WAITING_OPEN, /** * ???. */ OPEN, /** * ???. */ CLOSE, /** * . */ RETRYING, } /** * WebSocket. */ private Status mStatus; /** * ???private. */ private HttpEventManager() { mLock = new Object(); mStatus = Status.CLOSE; } /** * ????. <br/> * ????????????????<br/> * ???????????{@link #disconnect()}??????? * ??????????????????????? * * @param host ?? * @param port ?? * @param isSSL ??SSL??????? * @param sessionKey * @param handler ?????????? * @return ?????true?????false? */ public synchronized boolean connect(final String host, final int port, final boolean isSSL, final String sessionKey, final CloseHandler handler) { if (host == null) { throw new IllegalArgumentException("host must not be null."); } else if (port < 0) { throw new IllegalArgumentException("port must be larger than 0."); } else if (sessionKey == null) { throw new IllegalArgumentException("sessionKey must not be null."); } if (mStatus == Status.OPEN || mStatus == Status.RETRYING) { if (!sessionKey.equals(getSessionKey())) { setSessionKey(sessionKey); if (mStatus == Status.OPEN) { mWSClient.sendSessionKey(sessionKey); } } return true; } URIBuilder builder = new URIBuilder(); if (isSSL) { builder.setScheme("wss"); } else { builder.setScheme("ws"); } builder.setHost(host).setPort(port).setPath("/" + DConnectMessage.EXTRA_WEBSOCKET); URI webSocketUri; try { webSocketUri = builder.build(); } catch (URISyntaxException e) { throw new IllegalArgumentException("Can not create uri. Do check the parameters."); } setSessionKey(sessionKey); mStatus = Status.WAITING_OPEN; mWSClient = new EventWebSocketClient(webSocketUri); mWSClient.connect(); waitConnect(); if (mWSClient.isOpen()) { mCloseHandler = handler; return true; } setSessionKey(null); return false; } @Override public synchronized void disconnect() { if (mWSClient != null && mWSClient.isOpen()) { mWSClient.close(); mWSClient = null; mStatus = Status.CLOSE; } } /** * ??. */ private synchronized void retry() { mStatus = Status.RETRYING; new Thread(new RetryProcess()).start(); } /** * WebSocket??. */ private void waitConnect() { synchronized (mLock) { try { mLock.wait(); } catch (InterruptedException e) { mWSClient.close(); } } } @Override protected HttpResponse execute(final HttpUriRequest request) throws IOException { DefaultHttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(request); HttpResponse retRes = copyResponse(response); client.getConnectionManager().shutdown(); return retRes; } /** * Event??WebSocket?. * * @author NTT DOCOMO, INC. * */ private class EventWebSocketClient extends WebSocketClient { /** * WebSocket??. * * @param serverURI ??URI */ public EventWebSocketClient(final URI serverURI) { super(serverURI); } @Override public void onOpen(final ServerHandshake handshakedata) { mStatus = Status.OPEN; sendSessionKey(getSessionKey()); synchronized (mLock) { mLock.notifyAll(); } } @Override public void onMessage(final String message) { try { sendEvent(new JSONObject(message)); } catch (JSONException e) { mLogger.warning("EventWebSocketClient#onMessage Invalid message. : " + e.getMessage()); } } @Override public void onClose(final int code, final String reason, final boolean remote) { synchronized (HttpEventManager.this) { if (mStatus == Status.WAITING_OPEN || mStatus == Status.RETRYING) { synchronized (mLock) { mLock.notifyAll(); } } else if (mStatus == Status.OPEN) { if (code != NORMAL_CLOSE_CODE) { // ?????? retry(); return; } else if (mCloseHandler != null) { mCloseHandler.onClosed(); } } if (mStatus != Status.RETRYING) { mStatus = Status.CLOSE; } } } @Override public synchronized void onError(final Exception ex) { mLogger.warning("EventWebSocketClient#onError : " + ex); } /** * ??. * * @param sessionKey */ public void sendSessionKey(final String sessionKey) { send("{\"" + DConnectMessage.EXTRA_SESSION_KEY + "\":\"" + sessionKey + "\"}"); } } /** * ??. * * @author NTT DOCOMO, INC. * */ private class RetryProcess implements Runnable { @Override public void run() { mLogger.fine("RetryProcess#run. Retrying..."); for (int i = 0; i < RETRY_TIMES; i++) { long wait = RETRY_WAIT * (i + 1); if (retry(wait)) { mLogger.fine("RetryProcess#run. Successed to retry."); return; } } disconnect(); if (mCloseHandler != null) { mLogger.fine("RetryProcess#run. Failed to retry."); mCloseHandler.onClosed(); } } /** * ??. * * @param wait ?????????????????????? * @return ????true???false? */ private boolean retry(final long wait) { try { Thread.sleep(wait); } catch (InterruptedException e) { mLogger.warning("RetryProcess#retry Interrupted. : " + e.getMessage()); } mWSClient = new EventWebSocketClient(mWSClient.getURI()); mWSClient.connect(); waitConnect(); if (mWSClient.isOpen()) { return true; } return false; } } }