package com.workshare.msnos.core.protocols.ip.http; import java.io.IOException; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.workshare.msnos.core.Agent; import com.workshare.msnos.core.Cloud; import com.workshare.msnos.core.Gateway; import com.workshare.msnos.core.Iden; import com.workshare.msnos.core.Identifiable; import com.workshare.msnos.core.Message; import com.workshare.msnos.core.Message.Status; import com.workshare.msnos.core.MsnosException; import com.workshare.msnos.core.Receipt; import com.workshare.msnos.core.protocols.ip.Endpoint; import com.workshare.msnos.core.protocols.ip.Endpoints; import com.workshare.msnos.core.protocols.ip.HttpEndpoint; import com.workshare.msnos.core.receipts.SingleReceipt; import com.workshare.msnos.core.serializers.WireJsonSerializer; public class HttpGateway implements Gateway { private static Logger log = LoggerFactory.getLogger(HttpGateway.class); private final Map<Iden, HttpEndpoint> endpoints; private final HttpClient client; private final WireJsonSerializer serializer; public HttpGateway(HttpClient client) { this.client = client; this.endpoints = new ConcurrentHashMap<Iden, HttpEndpoint>(); this.serializer = new WireJsonSerializer(); } @Override public String name() { return "HTTP"; } @Override public void addListener(Cloud cloud, Listener listener) { } @Override public Receipt send(Cloud cloud, Message message, Identifiable to) throws IOException { Iden destination = (to != null ? to.getIden() : message.getTo()); HttpEndpoint endpoint = endpoints.get(destination); if (endpoint == null) return new SingleReceipt(this, Status.FAILED, message); else return sendTo(message, endpoint); } private Receipt sendTo(Message message, HttpEndpoint endpoint) { try { HttpPost request = new HttpPost(endpoint.getUrl()); request.setEntity(new StringEntity(serializer.toText(message))); HttpResponse res = client.execute(request); consume(res); return new SingleReceipt(this, Status.DELIVERED, message); } catch (IOException ex) { if (log.isDebugEnabled()) log.debug("Unexpected exception sending message "+message+" to url "+endpoint.getUrl(), ex); else log.warn("Unexpected exception sending message "+message+" to url "+endpoint.getUrl()); return new SingleReceipt(this, Status.FAILED, message); } } @Override public void close() throws IOException { } @Override public Endpoints endpoints() { return new Endpoints() { @Override public Set<Endpoint> all() { return new HashSet<Endpoint>(endpoints.values()); } @Override public Endpoint install(Endpoint endpoint) throws MsnosException { HttpEndpoint httpEndpoint = ensureHttp(endpoint); endpoints.put(httpEndpoint.getTarget(), httpEndpoint); log.debug("Installed endpoint {}, all: {}",endpoint, endpoints); return endpoint; } @Override public Endpoint remove(Endpoint endpoint) throws MsnosException { endpoints.remove(ensureHttp(endpoint).getTarget()); log.debug("Removed endpoint {}, all: {}",endpoint, endpoints); return endpoint; } private HttpEndpoint ensureHttp(Endpoint endpoint) throws MsnosException { if (!(endpoint instanceof HttpEndpoint)) throw new MsnosException("The HTTP gateway accepts only HTTP endpoints", MsnosException.Code.UNRECOVERABLE_FAILURE); HttpEndpoint ep = (HttpEndpoint) endpoint; if (ep.getTarget().equals(Iden.NULL)) throw new MsnosException("The HTTP gateway accepts only targeted endpoints", MsnosException.Code.UNRECOVERABLE_FAILURE); return ep; } @Override public Set<? extends Endpoint> of(Agent agent) { HashSet<Endpoint> result = new HashSet<Endpoint>(endpoints.size()); for(HttpEndpoint endpoint : endpoints.values()) { if (agent.getIden().equals(endpoint.getTarget())) result.add(endpoint); } return result; } @Override public Set<? extends Endpoint> publics() { HashSet<Endpoint> result = new HashSet<Endpoint>(endpoints.size()); for(HttpEndpoint endpoint : endpoints.values()) { if (endpoint.getTarget() == Iden.NULL) result.add(endpoint); } return result; }}; } private void consume(HttpResponse res) { EntityUtils.consumeQuietly(res.getEntity()); } }