package com.robonobo.wang.client;
import static com.robonobo.common.util.TextUtil.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import com.google.protobuf.AbstractMessage;
import com.google.protobuf.GeneratedMessage;
import com.robonobo.common.exceptions.SeekInnerCalmException;
import com.robonobo.common.http.PreemptiveHttpClient;
import com.robonobo.wang.WangServerException;
import com.robonobo.wang.proto.WangProtocol.BalanceMsg;
import com.robonobo.wang.proto.WangProtocol.BlindedCoinListMsg;
import com.robonobo.wang.proto.WangProtocol.CoinListMsg;
import com.robonobo.wang.proto.WangProtocol.CoinRequestListMsg;
import com.robonobo.wang.proto.WangProtocol.DenominationListMsg;
import com.robonobo.wang.proto.WangProtocol.DepositStatusMsg;
public class BankFacade {
static final Pattern URL_PATTERN = Pattern.compile("^http://([\\w\\.]+?):?(\\d*)/.*$");
private String baseUrl;
private PreemptiveHttpClient client;
Log log = LogFactory.getLog(getClass());
private String bankHost;
private int bankPort;
public BankFacade(String baseUrl, String userEmail, String password, PreemptiveHttpClient client) {
this.baseUrl = baseUrl;
this.client = client;
if (!baseUrl.endsWith("/"))
baseUrl += "/";
Matcher m = URL_PATTERN.matcher(baseUrl);
if (!m.matches())
throw new SeekInnerCalmException("bank url " + baseUrl + "does not match expected pattern");
bankHost = m.group(1);
String portStr = m.group(2);
// Note that the httpclient preemptive auth breaks if we set this to 80, instead we have to use -1 :-P :-P :-P
if (isEmpty(portStr))
bankPort = -1;
else
bankPort = Integer.parseInt(portStr);
log.debug("Setting up bank http auth scope on " + bankHost + ":" + bankPort);
AuthScope bankAuthScope = new AuthScope(bankHost, bankPort);
client.getCredentialsProvider().setCredentials(bankAuthScope, new UsernamePasswordCredentials(userEmail, password));
}
public DenominationListMsg getDenominations() throws WangServerException {
DenominationListMsg.Builder bldr = DenominationListMsg.newBuilder();
makeRequest(null, bldr, baseUrl + "getDenominations");
return bldr.build();
}
public double getBalance() throws WangServerException {
BalanceMsg.Builder bldr = BalanceMsg.newBuilder();
makeRequest(null, bldr, baseUrl + "getBalance");
return bldr.getAmount();
}
public BlindedCoinListMsg getCoins(CoinRequestListMsg requestList) throws WangServerException {
BlindedCoinListMsg.Builder bldr = BlindedCoinListMsg.newBuilder();
makeRequest(requestList, bldr, baseUrl + "getCoins");
return bldr.build();
}
public DepositStatusMsg depositCoins(CoinListMsg coinList) throws WangServerException {
DepositStatusMsg.Builder bldr = DepositStatusMsg.newBuilder();
makeRequest(coinList, bldr, baseUrl + "depositCoins");
return bldr.build();
}
@SuppressWarnings("unchecked")
protected void makeRequest(GeneratedMessage toSend, AbstractMessage.Builder builder, String url) throws WangServerException {
try {
HttpRequestBase request;
if (toSend == null)
request = new HttpGet(url);
else {
HttpPut put = new HttpPut(url);
put.setEntity(new ByteArrayEntity(toSend.toByteArray()));
request = put;
}
HttpEntity body = null;
try {
// We use a new context each time as basichttpcontext is not thread safe
HttpContext context = new BasicHttpContext();
HttpResponse resp = client.execute(request, context);
body = resp.getEntity();
int statusCode = resp.getStatusLine().getStatusCode();
if (statusCode != 200)
throw new IOException("Server replied with status: " + statusCode);
InputStream is = body.getContent();
try {
builder.mergeFrom(is);
} finally {
is.close();
}
} finally {
if (body != null)
EntityUtils.consume(body);
}
} catch (IOException e) {
throw new WangServerException(e);
}
}
}