I made an implementation of the Bridge Pattern to handle ever-changing in crawler APIs that I'm using in my APP.
public interface CrawlerApi {
// common constants to serveral implementations.
String CHARSET = "ISO8859_1";
int TIMEOUT = 20000;
/**
* Visit an url and return contents in String format.
*
* @param url
* @return
*/
String visit (String url);
/**
* Parse an Html code into an Navigable object that is provided by the API.
*
* @param htmlCode
* @param documentType
* @param <T>
* @return
*/
<T> T getDocument (String htmlCode, Class <T> documentType);
}
public class HtmlUnitCrawlerApi implements CrawlerApi {
private WebClient webClient;
public HtmlUnitCrawlerApi() {
this.webClient = createWebClient();
}
@Override
public String visit(String url) {
Page p = null;
try {
p = webClient.getPage(url);
return p.getWebResponse().getContentAsString(CHARSET);
} catch (IOException e) {
return "";
}
}
@Override
public <T> T getDocument(String htmlCode, Class<T> documentType) {
throw new IllegalArgumentException("not implemented");
}
private WebClient createWebClient() {
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_38);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setCssEnabled(false);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
webClient.waitForBackgroundJavaScript(TIMEOUT);
return webClient;
}
}
public class JsoupCrawlerApi implements CrawlerApi {
public static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36";
@Override
public String visit(String url) {
return connect.apply(url).html();
}
//I made this static because of the peculiarity of api that is static and because I have to
//set some config parameters.
private static Function<String, Document> connect = url -> {
try {
return Jsoup.connect(url).timeout(TIMEOUT).userAgent(USER_AGENT).postDataCharset(CHARSET).get();
} catch (IOException e) {
return new Document("");
}
};
private static Function<String, Document> parse = html -> {
Document doc = Jsoup.parse(html);
doc.charset(Charset.forName(CHARSET));
return doc;
};
@Override
public <T> T getDocument(String htmlCode, Class<T> type) {
return (T) parse.apply(htmlCode);
}
}
Usage:
public class ApiClientExample {
private CrawlerApi crawlerApi;
public ApiClientExample(CrawlerApi crawlerApi) {
this.crawlerApi = crawlerApi;
}
public void visit (String url){
crawlerApi.visit(url);
}
}
Concerns:
Is this code clean enough?
Is there anything that can be improved?
RefinedAbstraction
classes. Why not just Strategy pattern? \$\endgroup\$