diff --git a/src/main/java/jp/sf/fess/action/IndexAction.java b/src/main/java/jp/sf/fess/action/IndexAction.java index 4b1141452..a3e4aa88d 100644 --- a/src/main/java/jp/sf/fess/action/IndexAction.java +++ b/src/main/java/jp/sf/fess/action/IndexAction.java @@ -205,6 +205,8 @@ public class IndexAction { public String username; + public String appendHighlightQueries; + public String getPagingQuery() { if (pagingQuery == null) { final StringBuilder buf = new StringBuilder(); @@ -317,7 +319,7 @@ public class IndexAction { return "error.jsp"; } - final String content = viewHelper.createCacheContent(doc); + final String content = viewHelper.createCacheContent(doc, indexForm.hq); if (content == null) { errorMessage = MessageResourcesUtil.getMessage(RequestUtil .getRequest().getLocale(), "errors.docid_not_found", @@ -1002,6 +1004,16 @@ public class IndexAction { searchLogHelper.addSearchLog(searchLog); } + final String[] highlightQueries = (String[]) request + .getAttribute(Constants.HIGHLIGHT_QUERIES); + if (highlightQueries != null) { + final StringBuilder buf = new StringBuilder(100); + for (final String q : highlightQueries) { + buf.append("&hq=").append(q); + } + appendHighlightQueries = buf.toString(); + } + Beans.copy(documentItems, this) .includes("pageSize", "currentPageNumber", "allRecordCount", "allPageCount", "existNextPage", "existPrevPage", @@ -1182,6 +1194,7 @@ public class IndexAction { username = loginInfo.getUsername(); } } + } protected void buildInitParams() { diff --git a/src/main/java/jp/sf/fess/form/IndexForm.java b/src/main/java/jp/sf/fess/form/IndexForm.java index 902fddf1f..a9edb8599 100644 --- a/src/main/java/jp/sf/fess/form/IndexForm.java +++ b/src/main/java/jp/sf/fess/form/IndexForm.java @@ -65,6 +65,8 @@ public class IndexForm implements Serializable { @Maxbytelength(maxbytelength = 100) public String docId; + public String[] hq; + // xml/json @Maxbytelength(maxbytelength = 20) diff --git a/src/main/java/jp/sf/fess/helper/PathMappingHelper.java b/src/main/java/jp/sf/fess/helper/PathMappingHelper.java index 504491cc9..957fa74a9 100644 --- a/src/main/java/jp/sf/fess/helper/PathMappingHelper.java +++ b/src/main/java/jp/sf/fess/helper/PathMappingHelper.java @@ -30,14 +30,19 @@ import jp.sf.fess.db.exentity.PathMapping; import org.seasar.framework.container.SingletonS2Container; import org.seasar.framework.container.annotation.tiger.InitMethod; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PathMappingHelper implements Serializable { private static final long serialVersionUID = 1L; + private static final Logger logger = LoggerFactory + .getLogger(PathMappingHelper.class); + private final Map> pathMappingMap = new HashMap>(); - private List cachedPathMappingList = null; + private volatile List cachedPathMappingList = null; @InitMethod public void init() { @@ -45,14 +50,19 @@ public class PathMappingHelper implements Serializable { ptList.add(CDef.ProcessType.Displaying); ptList.add(CDef.ProcessType.Both); - final PathMappingCB cb = new PathMappingCB(); + try { + final PathMappingBhv pathMappingBhv = SingletonS2Container + .getComponent(PathMappingBhv.class); + final PathMappingCB cb = new PathMappingCB(); - cb.query().setDeletedBy_IsNull(); - cb.query().addOrderBy_SortOrder_Asc(); - cb.query().setProcessType_InScope_AsProcessType(ptList); + cb.query().setDeletedBy_IsNull(); + cb.query().addOrderBy_SortOrder_Asc(); + cb.query().setProcessType_InScope_AsProcessType(ptList); - cachedPathMappingList = SingletonS2Container.getComponent( - PathMappingBhv.class).selectList(cb); + cachedPathMappingList = pathMappingBhv.selectList(cb); + } catch (final Exception e) { + logger.warn("Failed to load path mappings.", e); + } } public void setPathMappingList(final String sessionId, @@ -86,6 +96,13 @@ public class PathMappingHelper implements Serializable { } public String replaceUrl(final String url) { + if (cachedPathMappingList == null) { + synchronized (this) { + if (cachedPathMappingList == null) { + init(); + } + } + } return replaceUrl(cachedPathMappingList, url); } diff --git a/src/main/java/jp/sf/fess/helper/QueryHelper.java b/src/main/java/jp/sf/fess/helper/QueryHelper.java index 9a39fd34f..ab9a1b022 100644 --- a/src/main/java/jp/sf/fess/helper/QueryHelper.java +++ b/src/main/java/jp/sf/fess/helper/QueryHelper.java @@ -96,6 +96,8 @@ public class QueryHelper implements Serializable { protected Set apiResponseFieldSet; + protected Set highlightFieldSet = new HashSet<>(); + protected String[] responseFields = new String[] { "id", "docId", "score", "boost", "contentLength", "host", "site", "lastModified", "mimetype", "filetype_s", "created", TITLE_FIELD, "digest", "url", @@ -376,7 +378,7 @@ public class QueryHelper implements Serializable { } nonPrefix = true; operator = _AND_; - if (!LABEL_FIELD.equals(field)) { + if (highlightFieldSet.contains(field)) { highLightQueryList.add(targetWord); } if (fieldLogMap != null) { @@ -1187,6 +1189,10 @@ public class QueryHelper implements Serializable { this.supportedSortFields = supportedSortFields; } + public void addHighlightField(final String field) { + highlightFieldSet.add(field); + } + /** * @return the highlightSnippetSize */ diff --git a/src/main/java/jp/sf/fess/helper/ViewHelper.java b/src/main/java/jp/sf/fess/helper/ViewHelper.java index 294e235b8..7982aff9a 100644 --- a/src/main/java/jp/sf/fess/helper/ViewHelper.java +++ b/src/main/java/jp/sf/fess/helper/ViewHelper.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Resource; @@ -374,7 +375,8 @@ public class ViewHelper implements Serializable { return file.isFile(); } - public String createCacheContent(final Map doc) { + public String createCacheContent(final Map doc, + final String[] queries) { final FileTemplateLoader loader = new FileTemplateLoader(new File( ResourceUtil.getViewTemplatePath(StringUtil.EMPTY))); @@ -401,6 +403,20 @@ public class ViewHelper implements Serializable { doc.put("cacheMsg", MessageResourcesUtil.getMessage(locale, "labels.search_cache_msg", url, created)); + doc.put("queries", queries); + + final String cache = (String) doc.get("cache"); + if (cache != null) { + if (queries != null && queries.length > 0) { + doc.put("hlCache", replaceHighlightQueries(cache, queries)); + } else { + doc.put("hlCache", cache); + } + } else { + doc.put("cache", StringUtil.EMPTY); + doc.put("hlCache", StringUtil.EMPTY); + } + try { final Template template = handlebars.compile(cacheTemplateName); final Context hbsContext = Context.newContext(doc); @@ -412,6 +428,42 @@ public class ViewHelper implements Serializable { return null; } + protected String replaceHighlightQueries(final String cache, + final String[] queries) { + final StringBuffer buf = new StringBuffer(cache.length() + 100); + final StringBuffer segBuf = new StringBuffer(1000); + final Pattern p = Pattern.compile("<[^>]+>"); + final Matcher m = p.matcher(cache); + final String[] regexQueries = new String[queries.length]; + final String[] hlQueries = new String[queries.length]; + for (int i = 0; i < queries.length; i++) { + regexQueries[i] = Pattern.quote(queries[i]); + hlQueries[i] = highlightTagPre + queries[i] + highlightTagPost; + } + while (m.find()) { + segBuf.setLength(0); + m.appendReplacement(segBuf, StringUtil.EMPTY); + String segment = segBuf.toString(); + for (int i = 0; i < queries.length; i++) { + segment = Pattern + .compile(regexQueries[i], Pattern.CASE_INSENSITIVE) + .matcher(segment).replaceAll(hlQueries[i]); + } + buf.append(segment); + buf.append(m.group(0)); + } + segBuf.setLength(0); + m.appendTail(segBuf); + String segment = segBuf.toString(); + for (int i = 0; i < queries.length; i++) { + segment = Pattern + .compile(regexQueries[i], Pattern.CASE_INSENSITIVE) + .matcher(segment).replaceAll(hlQueries[i]); + } + buf.append(segment); + return buf.toString(); + } + public boolean isUseSession() { return useSession; } diff --git a/src/main/java/jp/sf/fess/transformer/AbstractFessXpathTransformer.java b/src/main/java/jp/sf/fess/transformer/AbstractFessXpathTransformer.java index 32996d839..62ad16aeb 100644 --- a/src/main/java/jp/sf/fess/transformer/AbstractFessXpathTransformer.java +++ b/src/main/java/jp/sf/fess/transformer/AbstractFessXpathTransformer.java @@ -118,7 +118,9 @@ public abstract class AbstractFessXpathTransformer extends XpathTransformer { protected void putResultDataBody(final Map dataMap, final String key, final Object value) { - if (dataMap.containsKey(key)) { + if ("url".equals(key)) { + dataMap.put(key, value); + } else if (dataMap.containsKey(key)) { if (appendResultData) { final Object oldValue = dataMap.get(key); if (key.endsWith("_m")) { diff --git a/src/main/resources/app.dicon b/src/main/resources/app.dicon index 37518ce53..938a44e4e 100644 --- a/src/main/resources/app.dicon +++ b/src/main/resources/app.dicon @@ -68,6 +68,12 @@ "contentLength", "host", "site", "lastModified", "mimetype", "filetype_s", "created", "title", "digest", "url"} + + "title" + + + "content" + -