/*
* Copyright (2005-2012) Schibsted ASA
* This file is part of Possom.
*
* Possom is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Possom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Possom. If not, see <http://www.gnu.org/licenses/>.
*/
package no.sesat.search.mode.command;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import no.sesat.search.mode.config.OverturePpcCommandConfig;
import no.sesat.search.query.token.EvaluationException;
import no.sesat.search.query.token.TokenPredicate;
import no.sesat.search.query.token.TokenPredicateUtility;
import no.sesat.search.result.BasicResultList;
import no.sesat.search.result.BasicResultItem;
import no.sesat.search.result.OvertureSearchResult;
import no.sesat.search.result.ResultItem;
import no.sesat.search.result.ResultList;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This command gets the overture ads to display. It also does some analysis of
* the query to decide if it is a query that yields a high click frequency for
* the ads. This is done by evaluating the predicate "exact_ppctoplist".
*
* @version $Id$
*/
public class OverturePPCSearchCommand extends AbstractYahooSearchCommand {
private static final String OVERTURE_PPC_ELEMENT = "Listing";
private static final Logger LOG = Logger.getLogger(OverturePPCSearchCommand.class);
private boolean top = false;
/**
* Create new overture command.
*
* @param cxt the context
*/
public OverturePPCSearchCommand(final Context cxt) {
super(cxt);
setXmlRestful(
new AbstractXmlRestful(cxt) {
@Override
public String createRequestURL() {
final OverturePpcCommandConfig ppcConfig
= (OverturePpcCommandConfig) cxt.getSearchConfiguration();
final StringBuilder url = new StringBuilder(ppcConfig.getUrl());
try {
url.append("&Partner=" + OverturePPCSearchCommand.this.getPartnerId());
if (null != ppcConfig.getType() && ppcConfig.getType().length() > 0) {
url.append("&type=" + ppcConfig.getType());
}
final String serveUrl = "http://"
+ cxt.getDataModel().getSite().getSite().getName()
+ "/search/";
url.append("&Keywords=");
url.append(URLEncoder.encode(
OverturePPCSearchCommand.this.getTransformedQuery().replace(' ', '+'),
ppcConfig.getEncoding()));
url.append("&maxCount=");
url.append(OverturePPCSearchCommand.this.getResultsToReturn());
url.append("&serveUrl=");
url.append(URLEncoder.encode(serveUrl.toString(), "UTF-8"));
url.append("&" + OverturePPCSearchCommand.this.getAffilDataParameter());
} catch (UnsupportedEncodingException e) {
throw new SearchCommandException(e);
}
return url.toString();
}
});
}
/**
* Execute the command.
*
* @return the search result
*/
@Override
public ResultList<ResultItem> execute() {
// Need to rerun the token evaluation stuff on the transformed query
// The transformed query does not contain site: and nyhetskilde: which
// could have prevented exact matching in the previous evaluation.
final ReconstructedQuery rq = createQuery(getTransformedQuery());
final TokenPredicate predicate = TokenPredicateUtility.getTokenPredicate("PPCTOPLIST").exactPeer();
try {
top = rq.getEngine()
.evaluateQuery(predicate, rq.getQuery());
} catch (EvaluationException ex) {
LOG.error("failed to check predicate" + predicate +" with evaluateQuery " + rq.getQuery());
}
try {
final Document doc = getXmlRestful().getXmlResult();
LOG.debug(doc.toString());
final OvertureSearchResult<ResultItem> searchResult = new OvertureSearchResult<ResultItem>(top);
searchResult.setHitCount(0);
if (doc != null) {
final Element elem = doc.getDocumentElement();
final NodeList list = elem.getElementsByTagName(OVERTURE_PPC_ELEMENT);
for (int i = 0; i < list.getLength(); ++i) {
final Element listing = (Element) list.item(i);
final BasicResultItem item = createItem(listing);
searchResult.addResult(item);
}
final NodeList resultSetList = elem.getElementsByTagName("ResultSet");
if(resultSetList.getLength()>0){
searchResult.setHitCount(Integer.parseInt(
((Element)resultSetList.item(0)).getAttribute("numResults")));
}
}
return (ResultList<ResultItem>) searchResult;
} catch (SocketTimeoutException ste) {
LOG.error(getSearchConfiguration().getId() + " --> " + ste.getMessage());
return new BasicResultList<ResultItem>();
} catch (IOException e) {
throw new SearchCommandException(e);
} catch (SAXException e) {
throw new SearchCommandException(e);
}
}
@Override
protected BasicResultItem createItem(final Element ppcListing) {
final BasicResultItem item = new BasicResultItem();
final NodeList click = ppcListing.getElementsByTagName("ClickUrl");
item.addField("title", ppcListing.getAttribute("title"));
item.addField("description", ppcListing.getAttribute("description"));
item.addField("siteHost", ppcListing.getAttribute("siteHost"));
if (click.getLength() > 0) {
item.addField("clickURL", click.item(0).getFirstChild().getNodeValue());
}
return item;
}
@Override
protected String getAffilDataParameter() {
return super.getAffilDataParameter();
}
@Override
protected int getResultsToReturn() {
return super.getResultsToReturn();
}
}