package org.manalith.ircbot.plugin.javaapi; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JavaDocSearch implements SearchInterface { private Logger logger = LoggerFactory.getLogger(getClass()); private final String baseUrl; private static final String JAVADOC_ALLCLASS_FRAME_URL = "allclasses-frame.html"; private List<JavaDocObject> docObjects = null; /** * * @param baseUrl * JavaDoc의 기본 URL (예 : http://java.sun.com/j2se/1.5.0/docs/api/) */ public JavaDocSearch(String baseUrl) { this.baseUrl = baseUrl; } private Document getDocument() { try { return Jsoup.connect(baseUrl + JAVADOC_ALLCLASS_FRAME_URL).get(); } catch (IOException e) { logger.error(e.getMessage(), e); } return null; } private List<JavaDocObject> parseDocObjects(Document doc) { List<JavaDocObject> objs = new ArrayList<>(); for (Element element : doc.select("a")) { JavaDocObject o = new JavaDocObject(); // A 태그 안에 클래스 이름이 있을 경우 String nodeValue = element.text(); if (StringUtils.isEmpty(nodeValue)) { // A 태그 안의 I 태그 안에 인터페이스 이름이 있을 경우 o.setName(element.select("i").get(0).text()); o.setType(JavaDocObject.INTERFACE); } else { o.setName(nodeValue); o.setType(JavaDocObject.CLASS); } o.setURL(element.attr("href")); objs.add(o); } return objs; } /** * 검색하여 일치하는 1개의 클래스를 가져 온다. * * @param className * 검색할 클래스의 이름 * @return 클래스 이름 + 클래스 api 링크 */ @Override public String search(String className) { if (docObjects == null) docObjects = parseDocObjects(getDocument()); StringBuilder sb = new StringBuilder(); for (JavaDocObject o : docObjects) { if (o.getName().equalsIgnoreCase(className)) { sb.append("["); sb.append(o.getName()); sb.append("]"); sb.append(" - "); sb.append(baseUrl); sb.append(o.getURL()); break; } } return sb.toString(); } /** * 검색하여 해당 패턴에 해당하는 클래스명을 가진 모든 클래스를 가져온다. * * @param regex * 검색할 클래스의 이름(정규표현식) * @param classes * 검색 결과를 추가할 리스트, null일 경우 새로이 생성하여 리턴한다. * @return 리스트(클래스 이름 + 클래스 api 링크) */ @Override public List<String> searchAll(String regex, List<String> classes) { if (classes == null) classes = new ArrayList<>(); if (docObjects == null) docObjects = parseDocObjects(getDocument()); for (JavaDocObject o : docObjects) { if (o.getName().matches(regex)) { classes.add("[" + o.getName() + "]" + " - " + baseUrl + o.getURL()); } } return classes; } }