package org.limewire.promotion; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpException; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.limewire.promotion.impressions.UserQueryEvent; import org.limewire.promotion.impressions.UserQueryEventData; import org.limewire.util.StringUtils; /** * Instances of this class make <code>POST</code> requests to the URL given * for containers, and also add the data given in the {@link UserQueryEvent}. * <p> * The {@link PromotionBinder} that is passed in is created by the injected * {@link PromotionBinderFactory}. */ public abstract class AbstractPromotionBinderRequestor implements PromotionBinderRequestor { private final PromotionBinderFactory binderFactory; public AbstractPromotionBinderRequestor(PromotionBinderFactory binderFactory) { this.binderFactory = binderFactory; } /** * The main entry point. This will create a <code>POST</code> request to * <code>url</code> and include the proper information we want to store. */ public final PromotionBinder request(String url, long id, Set<? extends UserQueryEvent> queries) { // // This request takes the following parameters // - id: bucket ID for the bucket that will be returned // - for i=1..n // query_<i>: query for the ith UserQueryEvent // data_<i>: data for the ith UserQueryEvent // List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2*queries.size() + 1); nameValuePairs.add(new BasicNameValuePair("id", String.valueOf(id))); int i = 0; for (UserQueryEvent e : queries) { // // The query and data // UserQueryEventData data = new UserQueryEventData(e); String dataStr = StringUtils.getASCIIString(new Base64().encode(data.getData())); nameValuePairs.add(new BasicNameValuePair("query_" + i, data.getQuery())); nameValuePairs.add(new BasicNameValuePair("data_" + i, dataStr)); i++; } HttpPost tmp = null; String alteredUrl = alterUrl(url); tmp = new HttpPost(alteredUrl); final HttpPost request = tmp; try { request.setEntity(new UrlEncodedFormEntity(nameValuePairs)); } catch (UnsupportedEncodingException e) { error(e); return null; } HttpParams params = new BasicHttpParams(); request.addHeader("User-Agent", getUserAgent()); try { return binderFactory.newBinder(makeRequest(request, params)); } catch (HttpException e) { error(e); } catch (IOException e) { error(e); } return null; } /** * Called when an {@link Exception} occurs. * * @param e the {@link Exception} that occurred. */ protected abstract void error(Exception e); /** * Returns the <code>User-Agent</code> to send along with the * <code>POST</code> request. * * @return the <code>User-Agent</code> to send along with the * <code>POST</code> request. */ protected abstract String getUserAgent(); /** * Subclasses should alter the final URL in this method, such as adding * version information, etc. */ protected abstract String alterUrl(String url); /** * Called once the {@link PostMethod} <code>request</code> is constructed. * The purpose of the callback is so we can pass a {@link PromotionBindder} * created from the {@link PromotionBinderFactory} from the passed in bytes * we receive from the request. * * @param request <code>POST</code> to send to a server * @throws HttpException thrown when a protocol error occurs * @throws IOException thrown when a protocol I/O occurs * * @return a stream for the HTTP request */ protected abstract InputStream makeRequest(HttpPost request, HttpParams params) throws HttpException, IOException; public static String encode(String string) { try { return URLEncoder.encode(string, "8859_1"); } catch(UnsupportedEncodingException uee) { return string; } } }