package org.ripple.power.server.socket; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedQueue; class XHRTransport implements IOTransport { public static final String TRANSPORT_NAME = "xhr-polling"; private IOConnection connection; private URL url; ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<String>(); PollThread pollThread = null; private boolean connect; private boolean blocked; HttpURLConnection urlConnection; private class PollThread extends Thread { private static final String CHARSET = "UTF-8"; public PollThread() { super(TRANSPORT_NAME); } @Override public void run() { connection.transportConnected(); while (isConnect()) { try { String line; URL url = new URL(XHRTransport.this.url.toString() + "?t=" + System.currentTimeMillis()); urlConnection = (HttpURLConnection) url.openConnection(); SSLContext context = IOConnection.getSslContext(); if (urlConnection instanceof HttpsURLConnection && context != null) { ((HttpsURLConnection) urlConnection) .setSSLSocketFactory(context.getSocketFactory()); } if (!queue.isEmpty()) { urlConnection.setDoOutput(true); OutputStream output = urlConnection.getOutputStream(); if (queue.size() == 1) { line = queue.poll(); output.write(line.getBytes(CHARSET)); } else { Iterator<String> iter = queue.iterator(); while (iter.hasNext()) { String junk = iter.next(); line = IOConnection.FRAME_DELIMITER + junk.length() + IOConnection.FRAME_DELIMITER + junk; output.write(line.getBytes(CHARSET)); iter.remove(); } } output.close(); InputStream input = urlConnection.getInputStream(); byte[] buffer = new byte[1024]; while (input.read(buffer) > 0) { } input.close(); } else { setBlocked(true); InputStream plainInput = urlConnection.getInputStream(); BufferedReader input = new BufferedReader( new InputStreamReader(plainInput, CHARSET)); while ((line = input.readLine()) != null) { if (connection != null) connection.transportData(line); } setBlocked(false); } } catch (IOException e) { if (connection != null && interrupted() == false) { connection.transportError(e); return; } } try { sleep(100); } catch (InterruptedException e) { } } connection.transportDisconnected(); } } public static IOTransport create(URL url, IOConnection connection) { try { URL xhrUrl = new URL(url.toString() + IOConnection.SOCKET_IO_1 + TRANSPORT_NAME + "/" + connection.getSessionId()); return new XHRTransport(xhrUrl, connection); } catch (MalformedURLException e) { throw new RuntimeException( "Malformed Internal url. This should never happen. Please report a bug.", e); } } public XHRTransport(URL url, IOConnection connection) { this.connection = connection; this.url = url; } @Override public void connect() { this.setConnect(true); pollThread = new PollThread(); pollThread.start(); } @Override public void disconnect() { this.setConnect(false); pollThread.interrupt(); } @Override public void send(String text) throws IOException { sendBulk(new String[] { text }); } @Override public boolean canSendBulk() { return true; } @Override public void sendBulk(String[] texts) throws IOException { queue.addAll(Arrays.asList(texts)); if (isBlocked()) { pollThread.interrupt(); urlConnection.disconnect(); } } @Override public void invalidate() { this.connection = null; } private synchronized boolean isConnect() { return connect; } private synchronized void setConnect(boolean connect) { this.connect = connect; } private synchronized boolean isBlocked() { return blocked; } private synchronized void setBlocked(boolean blocked) { this.blocked = blocked; } @Override public String getName() { return TRANSPORT_NAME; } }