Browse Source

fix #128, remove mobile jsp and minor fixes.

Shinsuke Sugaya 11 years ago
parent
commit
ef4e3b4fe7

+ 14 - 1
src/main/java/jp/sf/fess/action/IndexAction.java

@@ -205,6 +205,8 @@ public class IndexAction {
 
 
     public String username;
     public String username;
 
 
+    public String appendHighlightQueries;
+
     public String getPagingQuery() {
     public String getPagingQuery() {
         if (pagingQuery == null) {
         if (pagingQuery == null) {
             final StringBuilder buf = new StringBuilder();
             final StringBuilder buf = new StringBuilder();
@@ -317,7 +319,7 @@ public class IndexAction {
             return "error.jsp";
             return "error.jsp";
         }
         }
 
 
-        final String content = viewHelper.createCacheContent(doc);
+        final String content = viewHelper.createCacheContent(doc, indexForm.hq);
         if (content == null) {
         if (content == null) {
             errorMessage = MessageResourcesUtil.getMessage(RequestUtil
             errorMessage = MessageResourcesUtil.getMessage(RequestUtil
                     .getRequest().getLocale(), "errors.docid_not_found",
                     .getRequest().getLocale(), "errors.docid_not_found",
@@ -1002,6 +1004,16 @@ public class IndexAction {
             searchLogHelper.addSearchLog(searchLog);
             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)
         Beans.copy(documentItems, this)
                 .includes("pageSize", "currentPageNumber", "allRecordCount",
                 .includes("pageSize", "currentPageNumber", "allRecordCount",
                         "allPageCount", "existNextPage", "existPrevPage",
                         "allPageCount", "existNextPage", "existPrevPage",
@@ -1182,6 +1194,7 @@ public class IndexAction {
                 username = loginInfo.getUsername();
                 username = loginInfo.getUsername();
             }
             }
         }
         }
+
     }
     }
 
 
     protected void buildInitParams() {
     protected void buildInitParams() {

+ 2 - 0
src/main/java/jp/sf/fess/form/IndexForm.java

@@ -65,6 +65,8 @@ public class IndexForm implements Serializable {
     @Maxbytelength(maxbytelength = 100)
     @Maxbytelength(maxbytelength = 100)
     public String docId;
     public String docId;
 
 
+    public String[] hq;
+
     // xml/json
     // xml/json
 
 
     @Maxbytelength(maxbytelength = 20)
     @Maxbytelength(maxbytelength = 20)

+ 24 - 7
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.SingletonS2Container;
 import org.seasar.framework.container.annotation.tiger.InitMethod;
 import org.seasar.framework.container.annotation.tiger.InitMethod;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 
 public class PathMappingHelper implements Serializable {
 public class PathMappingHelper implements Serializable {
 
 
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
+    private static final Logger logger = LoggerFactory
+            .getLogger(PathMappingHelper.class);
+
     private final Map<String, List<PathMapping>> pathMappingMap = new HashMap<String, List<PathMapping>>();
     private final Map<String, List<PathMapping>> pathMappingMap = new HashMap<String, List<PathMapping>>();
 
 
-    private List<PathMapping> cachedPathMappingList = null;
+    private volatile List<PathMapping> cachedPathMappingList = null;
 
 
     @InitMethod
     @InitMethod
     public void init() {
     public void init() {
@@ -45,14 +50,19 @@ public class PathMappingHelper implements Serializable {
         ptList.add(CDef.ProcessType.Displaying);
         ptList.add(CDef.ProcessType.Displaying);
         ptList.add(CDef.ProcessType.Both);
         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,
     public void setPathMappingList(final String sessionId,
@@ -86,6 +96,13 @@ public class PathMappingHelper implements Serializable {
     }
     }
 
 
     public String replaceUrl(final String url) {
     public String replaceUrl(final String url) {
+        if (cachedPathMappingList == null) {
+            synchronized (this) {
+                if (cachedPathMappingList == null) {
+                    init();
+                }
+            }
+        }
         return replaceUrl(cachedPathMappingList, url);
         return replaceUrl(cachedPathMappingList, url);
     }
     }
 
 

+ 7 - 1
src/main/java/jp/sf/fess/helper/QueryHelper.java

@@ -96,6 +96,8 @@ public class QueryHelper implements Serializable {
 
 
     protected Set<String> apiResponseFieldSet;
     protected Set<String> apiResponseFieldSet;
 
 
+    protected Set<String> highlightFieldSet = new HashSet<>();
+
     protected String[] responseFields = new String[] { "id", "docId", "score",
     protected String[] responseFields = new String[] { "id", "docId", "score",
             "boost", "contentLength", "host", "site", "lastModified",
             "boost", "contentLength", "host", "site", "lastModified",
             "mimetype", "filetype_s", "created", TITLE_FIELD, "digest", "url",
             "mimetype", "filetype_s", "created", TITLE_FIELD, "digest", "url",
@@ -376,7 +378,7 @@ public class QueryHelper implements Serializable {
                     }
                     }
                     nonPrefix = true;
                     nonPrefix = true;
                     operator = _AND_;
                     operator = _AND_;
-                    if (!LABEL_FIELD.equals(field)) {
+                    if (highlightFieldSet.contains(field)) {
                         highLightQueryList.add(targetWord);
                         highLightQueryList.add(targetWord);
                     }
                     }
                     if (fieldLogMap != null) {
                     if (fieldLogMap != null) {
@@ -1187,6 +1189,10 @@ public class QueryHelper implements Serializable {
         this.supportedSortFields = supportedSortFields;
         this.supportedSortFields = supportedSortFields;
     }
     }
 
 
+    public void addHighlightField(final String field) {
+        highlightFieldSet.add(field);
+    }
+
     /**
     /**
      * @return the highlightSnippetSize
      * @return the highlightSnippetSize
      */
      */

+ 53 - 1
src/main/java/jp/sf/fess/helper/ViewHelper.java

@@ -28,6 +28,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
@@ -374,7 +375,8 @@ public class ViewHelper implements Serializable {
         return file.isFile();
         return file.isFile();
     }
     }
 
 
-    public String createCacheContent(final Map<String, Object> doc) {
+    public String createCacheContent(final Map<String, Object> doc,
+            final String[] queries) {
 
 
         final FileTemplateLoader loader = new FileTemplateLoader(new File(
         final FileTemplateLoader loader = new FileTemplateLoader(new File(
                 ResourceUtil.getViewTemplatePath(StringUtil.EMPTY)));
                 ResourceUtil.getViewTemplatePath(StringUtil.EMPTY)));
@@ -401,6 +403,20 @@ public class ViewHelper implements Serializable {
         doc.put("cacheMsg", MessageResourcesUtil.getMessage(locale,
         doc.put("cacheMsg", MessageResourcesUtil.getMessage(locale,
                 "labels.search_cache_msg", url, created));
                 "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 {
         try {
             final Template template = handlebars.compile(cacheTemplateName);
             final Template template = handlebars.compile(cacheTemplateName);
             final Context hbsContext = Context.newContext(doc);
             final Context hbsContext = Context.newContext(doc);
@@ -412,6 +428,42 @@ public class ViewHelper implements Serializable {
         return null;
         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() {
     public boolean isUseSession() {
         return useSession;
         return useSession;
     }
     }

+ 3 - 1
src/main/java/jp/sf/fess/transformer/AbstractFessXpathTransformer.java

@@ -118,7 +118,9 @@ public abstract class AbstractFessXpathTransformer extends XpathTransformer {
 
 
     protected void putResultDataBody(final Map<String, Object> dataMap,
     protected void putResultDataBody(final Map<String, Object> dataMap,
             final String key, final Object value) {
             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) {
             if (appendResultData) {
                 final Object oldValue = dataMap.get(key);
                 final Object oldValue = dataMap.get(key);
                 if (key.endsWith("_m")) {
                 if (key.endsWith("_m")) {

+ 6 - 0
src/main/resources/app.dicon

@@ -68,6 +68,12 @@
             "contentLength", "host", "site", "lastModified", "mimetype", "filetype_s",
             "contentLength", "host", "site", "lastModified", "mimetype", "filetype_s",
             "created", "title", "digest", "url"}</arg>
             "created", "title", "digest", "url"}</arg>
 		</initMethod>
 		</initMethod>
+		<initMethod name="addHighlightField">
+			<arg>"title"</arg>
+		</initMethod>
+		<initMethod name="addHighlightField">
+			<arg>"content"</arg>
+		</initMethod>
 		<!-- 
 		<!-- 
 		<property name="additionalGeoQuery">"location_i_i:1"</property>
 		<property name="additionalGeoQuery">"location_i_i:1"</property>
 		<property name="responseFields">new String[]{ "id", "docId", "score",
 		<property name="responseFields">new String[]{ "id", "docId", "score",

+ 0 - 4
src/main/resources/fess.dicon

@@ -72,10 +72,6 @@ new String[] {
 "-XX:G1ReservePercent=10",
 "-XX:G1ReservePercent=10",
  -->
  -->
 </property>
 </property>
-<!--
-"-XX:+OptimizeStringConcat",
-"-XX:+UseCompressedStrings",
--->
 <!-- remote debug
 <!-- remote debug
 "-Xdebug",
 "-Xdebug",
 "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=127.0.0.1:8000",
 "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=127.0.0.1:8000",

+ 1 - 1
src/main/webapp/WEB-INF/view/cache.hbs

@@ -4,4 +4,4 @@
 <div style="border:1px solid #999;margin:5px -1px;padding:0;">
 <div style="border:1px solid #999;margin:5px -1px;padding:0;">
 <div style="color:#000;background:#ddd;border:1px solid #666;margin:10px 15px;padding:5px;text-align:left;">{{cacheMsg}}</div>
 <div style="color:#000;background:#ddd;border:1px solid #666;margin:10px 15px;padding:5px;text-align:left;">{{cacheMsg}}</div>
 </div>
 </div>
-{{{cache}}}
+{{{hlCache}}}

+ 0 - 9
src/main/webapp/WEB-INF/view/mobile/index.jsp

@@ -1,9 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-<html>
-<head>
-<jsp:include page="indexHtmlHead.jsp"/>
-</head>
-<body>
-<jsp:include page="indexMain.jsp"/>
-</body>
-</html>

+ 0 - 4
src/main/webapp/WEB-INF/view/mobile/indexHtmlHead.jsp

@@ -1,4 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-<meta http-equiv="Content-Type" content="text/html; charset=<m:charset/>" />
-<meta content="no-cache" http-equiv="Cache-Control"/>
-<title><bean:message key="labels.mobile_search_title"/></title>

+ 0 - 14
src/main/webapp/WEB-INF/view/mobile/indexMain.jsp

@@ -1,14 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-    <div>
-      <div style="text-align: center;">
-        <m:img src="logo-top.gif" magniWidth="0.8" style="vertical-align: middle;" />
-        <br/>
-        <s:form>
-          <div>
-          	<html:text property="query" title="Search" size="20" maxlength="1000" />
-            <br/>
-            <input type="submit" value="<bean:message key="labels.top.search"/>" name="search" />
-          </div>
-        </s:form>
-      </div>
-    </div>

+ 0 - 18
src/main/webapp/WEB-INF/view/mobile/search.jsp

@@ -1,18 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-<html>
-<head>
-<jsp:include page="searchHtmlHead.jsp"/>
-</head>
-<body>
-<jsp:include page="searchHeader.jsp"/>
-<c:choose>
-<c:when test="${f:h(allRecordCount) != 0}">
-<jsp:include page="searchResults.jsp"/>
-</c:when>
-<c:otherwise>
-<jsp:include page="searchNoResult.jsp"/>
-</c:otherwise>
-</c:choose>
-<jsp:include page="searchFooter.jsp"/>
-</body>
-</html>

+ 0 - 5
src/main/webapp/WEB-INF/view/mobile/searchFooter.jsp

@@ -1,5 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-<hr style="border-style: solid; border-color: #ffffff;"/>
-<div style="font-size: x-small; text-align: center;">
-  <bean:message key="labels.footer.copyright"/>
-</div>

+ 0 - 13
src/main/webapp/WEB-INF/view/mobile/searchHeader.jsp

@@ -1,13 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-<div id="header">
-  <div>
-    <s:form>
-      <div>
-<m:img src="logo-top.gif" magniWidth="0.3" />
-<br/>
-<html:text property="query" title="Search" size="16" maxlength="1000" />
-<input type="submit" value="<bean:message key="labels.search"/>" name="search"/>
-      </div>
-    </s:form>
-  </div>
-</div>

+ 0 - 4
src/main/webapp/WEB-INF/view/mobile/searchHtmlHead.jsp

@@ -1,4 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-<meta http-equiv="Content-Type" content="text/html; charset=<m:charset/>" />
-<meta content="no-cache" http-equiv="Cache-Control"/>
-<title>${f:h(query)} - <bean:message key="labels.search_title"/></title>

+ 0 - 4
src/main/webapp/WEB-INF/view/mobile/searchNoResult.jsp

@@ -1,4 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-              <div id="result">
-                <bean:message key="labels.did_not_match" arg0="${f:h(query)}"/>
-              </div>

+ 0 - 55
src/main/webapp/WEB-INF/view/mobile/searchResults.jsp

@@ -1,55 +0,0 @@
-<%@page pageEncoding="UTF-8" %>
-              <div id="result">
-                <div>
-                  <c:forEach var="doc" varStatus="s" items="${documentItems}">
-                    <div>
-                      <a href="${doc.urlLink}"><span>${f:h(doc.contentTitle)}</span></a>
-                      <span id="snip">
-                        <br/>
-                        <span style="color: #666666;">
-                          ${doc.contentDescription}
-                        </span>
-                      </span>
-                      <span style="color: #008000;">
-                        <br/>
-                        ${f:h(doc.site)}
-                      </span>
-                      <br/>
-                    </div>
-                    <br/>
-                  </c:forEach>
-                </div>
-              </div>
-
-              <div id="subfooter"  style="text-align: center;">
-                <p>
-                  <c:if test="${existPrevPage}">
-                    <span>
-                      <s:link href="prev?query=${f:u(query)}&pn=${f:u(currentPageNumber)}&num=${f:u(pageSize)}">
-                        <bean:message key="labels.prev_page"/>
-                      </s:link>
-                    </span>
-                  </c:if>
-                  <c:forEach var="pageNumber" varStatus="s" items="${pageNumberList}">
-                    <c:if test="${pageNumber == currentPageNumber}">
-                      <span>
-                        ${pageNumber}
-                      </span>
-                    </c:if>
-                    <c:if test="${pageNumber != currentPageNumber}">
-                      <span>
-                        <s:link href="move?query=${f:u(query)}&pn=${f:u(pageNumber)}&num=${f:u(pageSize)}">
-                          ${f:h(pageNumber)}
-                        </s:link>
-                      </span>
-                    </c:if>
-                  </c:forEach>
-                  <c:if test="${existNextPage}">
-                    <span>
-                      <s:link href="next?query=${f:u(query)}&pn=${f:u(currentPageNumber)}&num=${f:u(pageSize)}">
-                        <bean:message key="labels.next_page"/>
-                      </s:link>
-                    </span>
-                  </c:if>
-                </p>
-              </div>

+ 1 - 1
src/main/webapp/WEB-INF/view/searchResults.jsp

@@ -36,7 +36,7 @@
 						<div class="site ellipsis">
 						<div class="site ellipsis">
 							<cite>${f:h(doc.site)}</cite>
 							<cite>${f:h(doc.site)}</cite>
 							<c:if test="${doc.hasCache_s_s=='true'}">
 							<c:if test="${doc.hasCache_s_s=='true'}">
-								<a href="cache?docId=${doc.docId}" class="cache"><bean:message
+								<a href="cache?docId=${doc.docId}${appendHighlightQueries}" class="cache"><bean:message
 										key="labels.search_result_cache" /></a>
 										key="labels.search_result_cache" /></a>
 							</c:if>
 							</c:if>
 						</div>
 						</div>

+ 1 - 0
src/main/webapp/css/style.css

@@ -57,6 +57,7 @@ h3 {
 
 
 #result .body a.cache {
 #result .body a.cache {
 	color: #093;
 	color: #093;
+    margin-left: 10px;
 }
 }
 
 
 #result .favorited {
 #result .favorited {

+ 88 - 0
src/test/java/jp/sf/fess/helper/ViewHelperTest.java

@@ -0,0 +1,88 @@
+/*
+ * Copyright 2009-2014 the CodeLibs Project and the Others.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+package jp.sf.fess.helper;
+
+import org.seasar.extension.unit.S2TestCase;
+
+public class ViewHelperTest extends S2TestCase {
+    public ViewHelper viewHelper;
+
+    @Override
+    protected String getRootDicon() throws Throwable {
+        return "jp/sf/fess/helper/view.dicon";
+    }
+
+    public void test_replaceHighlightQueries() {
+        String text;
+        String[] queries;
+
+        text = "<a>123<b>456<c>";
+        queries = new String[] { "123", "456" };
+        assertEquals("<a><em>123</em><b><em>456</em><c>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "<123><456>";
+        queries = new String[] { "123", "456" };
+        assertEquals("<123><456>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "123<aaa 123>456<bbb 456>123";
+        queries = new String[] { "123", "456" };
+        assertEquals("<em>123</em><aaa 123><em>456</em><bbb 456><em>123</em>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "abc";
+        queries = new String[] { "123" };
+        assertEquals("abc", viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "123";
+        queries = new String[] { "123" };
+        assertEquals("<em>123</em>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "abc123efg";
+        queries = new String[] { "123" };
+        assertEquals("abc<em>123</em>efg",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "123";
+        queries = new String[] { "123", "456" };
+        assertEquals("<em>123</em>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "123456";
+        queries = new String[] { "123", "456" };
+        assertEquals("<em>123</em><em>456</em>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "a123b456c";
+        queries = new String[] { "123", "456" };
+        assertEquals("a<em>123</em>b<em>456</em>c",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "abc";
+        queries = new String[] { "abc" };
+        assertEquals("<em>abc</em>",
+                viewHelper.replaceHighlightQueries(text, queries));
+
+        text = "1ABC2";
+        queries = new String[] { "abc" };
+        assertEquals("1<em>abc</em>2",
+                viewHelper.replaceHighlightQueries(text, queries));
+    }
+
+}

+ 18 - 0
src/test/resources/jp/sf/fess/helper/view.dicon

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
+	"http://www.seasar.org/dtd/components24.dtd">
+<components>
+	<component name="viewHelper" class="jp.sf.fess.helper.ViewHelper">
+	</component>
+	<component name="pathMappingHelper" class="jp.sf.fess.helper.PathMappingHelper">
+	</component>
+	<component name="userAgentHelper" class="jp.sf.fess.helper.UserAgentHelper">
+	</component>
+	<component name="crawlerProperties" class="org.codelibs.core.util.DynamicProperties">
+		<arg>
+			@org.seasar.framework.util.ResourceUtil@getBuildDir(@jp.sf.fess.FessClass@class).getCanonicalPath()
+			+ "/conf/crawler.properties"
+		</arg>
+	</component>
+
+</components>