package edu.washington.cs.oneswarm.ui.gwt.server.community; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.List; import java.util.logging.Logger; import org.json.JSONArray; import org.json.JSONTokener; import org.json.JSONWriter; import com.google.common.base.Preconditions; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; import edu.washington.cs.oneswarm.f2f.dht.CHTCallback; import edu.washington.cs.oneswarm.ui.gwt.rpc.CommunityRecord; public class CHTGetOp extends CommunityServerOperation { private static Logger logger = Logger.getLogger(CHTGetOp.class.getName()); private final List<CHTCallback> callbacks; private final List<byte[]> keys; public CHTGetOp(CommunityRecord server, List<byte[]> keys, List<CHTCallback> callbacks) { super(server); Preconditions.checkArgument(keys.size() == callbacks.size(), "Mismatch between keys and callbacks sizese."); this.keys = keys; this.callbacks = callbacks; } @Override void doOp() { Preconditions.checkState(mRecord.isAllowAddressResolution(), "Attempting CHTGet on server without perms: " + mRecord.getBaseURL()); Preconditions.checkState(mRecord.getCht_path() != null, "Attempting CHTGet on server without a valid CHT path! " + mRecord.getBaseURL()); String path = mRecord.getBaseURL(); if (path.endsWith("/") == false) { path += "/"; } path += mRecord.getCht_path() + "?get"; try { URL url = new URL(path); HttpURLConnection conn = getConnection(url, "POST"); // JSON array of key, value pairs. ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(baos); JSONWriter writer = new JSONWriter(outputStreamWriter); writer.array(); for (int i = 0; i < keys.size(); i++) { String encodedKey = Base64.encode(keys.get(i)); writer.value(encodedKey); } writer.endArray(); outputStreamWriter.flush(); logger.finest(baos.toString() + "\n"); conn.getOutputStream().write( ("q=" + URLEncoder.encode(baos.toString(), "UTF-8")).getBytes()); logger.finer("CHT get response code: " + conn.getResponseCode() + " / " + conn.getResponseMessage()); // Collect and parse the get responses ByteArrayOutputStream response = new ByteArrayOutputStream(); readLimitedInto(conn, 1024 * 1024, response); JSONTokener toks = new JSONTokener(new InputStreamReader(new ByteArrayInputStream( response.toByteArray()))); JSONArray vals = (JSONArray) toks.nextValue(); Preconditions.checkState(vals.length() == callbacks.size(), "Server returned " + vals.length() + " values, but we have " + callbacks.size() + " CHT get callbacks."); for (int i = 0; i < vals.length(); i++) { CHTCallback callback = callbacks.remove(0); callback.valueReceived(keys.get(i), Base64.decode(vals.getString(i))); } } catch (Exception e) { e.printStackTrace(); logger.warning("Error during CHT get on server: " + mRecord.getBaseURL() + " / " + e.toString()); for (CHTCallback c : callbacks) { c.errorReceived(e); } } } }