Author: mreutegg
Date: Fri Dec 21 04:50:28 2007
New Revision: 606180
URL: http://svn.apache.org/viewvc?rev=606180&view=rev
Log:
JCR-1278: Add configuration path to SynonymProvider
Added:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PropertiesSynonymProvider.java
(with props)
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SynonymProviderTest.java
(with props)
jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/synonyms.properties
(with props)
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SynonymProvider.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java
jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/workspace.xml
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PropertiesSynonymProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PropertiesSynonymProvider.java?rev=606180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PropertiesSynonymProvider.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PropertiesSynonymProvider.java
Fri Dec 21 04:50:28 2007
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.core.query.lucene;
+
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.fs.FileSystemException;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Iterator;
+
+/**
+ * Implements a synonym provider based on a properties file. Each line in the
+ * properties file is treated as a synonym definition. Example:
+ * <pre>
+ * A=B
+ * B=C
+ * </pre>
+ * This synonym provider will return B as a synonym for A and vice versa. The
+ * same applies to B and C. However A is not considered a synonym for C, nor
+ * C a synonym for A.
+ */
+public class PropertiesSynonymProvider implements SynonymProvider {
+
+ /**
+ * The logger instance for this class.
+ */
+ private static final Logger log = LoggerFactory.getLogger(PropertiesSynonymProvider.class);
+
+ /**
+ * An empty string array. Returned when no synonym is found.
+ */
+ private static final String[] EMPTY_ARRAY = new String[0];
+
+ /**
+ * Check at most every 10 seconds for configuration updates.
+ */
+ private static final long CHECK_INTERVAL = 10 * 1000;
+
+ /**
+ * The file system resource that contains the configuration.
+ */
+ private FileSystemResource config;
+
+ /**
+ * Timestamp when the configuration was checked last.
+ */
+ private long lastCheck;
+
+ /**
+ * Timestamp when the configuration was last modified.
+ */
+ private long configLastModified;
+
+ /**
+ * Contains the synonym mapping. Map<String, String[]>
+ */
+ private Map synonyms = new HashMap();
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized void initialize(FileSystemResource fsr)
+ throws IOException {
+ if (fsr == null) {
+ throw new IOException("PropertiesSynonymProvider requires a path configuration");
+ }
+ try {
+ config = fsr;
+ synonyms = getSynonyms(config);
+ configLastModified = config.lastModified();
+ lastCheck = System.currentTimeMillis();
+ } catch (FileSystemException e) {
+ IOException ex = new IOException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getSynonyms(String term) {
+ checkConfigUpdated();
+ term = term.toLowerCase();
+ String[] syns;
+ synchronized (this) {
+ syns = (String[]) synonyms.get(term);
+ }
+ if (syns == null) {
+ syns = EMPTY_ARRAY;
+ }
+ return syns;
+ }
+
+ //---------------------------------< internal >-----------------------------
+
+ /**
+ * Checks if the synonym properties file has been updated and this provider
+ * should reload the synonyms. This method performs the actual check at most
+ * every {@link #CHECK_INTERVAL}. If reloading fails an error is logged and
+ * this provider will retry after {@link #CHECK_INTERVAL}.
+ */
+ private synchronized void checkConfigUpdated() {
+ if (lastCheck + CHECK_INTERVAL > System.currentTimeMillis()) {
+ return;
+ }
+ // check last modified
+ try {
+ if (configLastModified != config.lastModified()) {
+ synonyms = getSynonyms(config);
+ configLastModified = config.lastModified();
+ log.info("Reloaded synonyms from {}", config.getPath());
+ }
+ } catch (Exception e) {
+ log.error("Exception while reading synonyms", e);
+ }
+ // update lastCheck timestamp, even if error occured (retry later)
+ lastCheck = System.currentTimeMillis();
+ }
+
+ /**
+ * Reads the synonym properties file and returns the contents as a synonym
+ * Map.
+ *
+ * @param config the synonym properties file.
+ * @return a Map containing the synonyms.
+ * @throws IOException if an error occurs while reading from the file system
+ * resource.
+ */
+ private static Map getSynonyms(FileSystemResource config) throws IOException {
+ try {
+ Map synonyms = new HashMap();
+ Properties props = new Properties();
+ props.load(config.getInputStream());
+ for (Iterator it = props.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry e = (Map.Entry) it.next();
+ String key = (String) e.getKey();
+ String value = (String) e.getValue();
+ addSynonym(key, value, synonyms);
+ addSynonym(value, key, synonyms);
+ }
+ return synonyms;
+ } catch (FileSystemException e) {
+ IOException ex = new IOException();
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ /**
+ * Adds a synonym definition to the map.
+ *
+ * @param term the term
+ * @param synonym synonym for <code>term</code>.
+ * @param synonyms the Map containing the synonyms.
+ */
+ private static void addSynonym(String term, String synonym, Map synonyms) {
+ term = term.toLowerCase();
+ String[] syns = (String[]) synonyms.get(term);
+ if (syns == null) {
+ syns = new String[]{synonym};
+ } else {
+ String[] tmp = new String[syns.length + 1];
+ System.arraycopy(syns, 0, tmp, 0, syns.length);
+ tmp[syns.length] = synonym;
+ syns = tmp;
+ }
+ synonyms.put(term, syns);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/PropertiesSynonymProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=606180&r1=606179&r2=606180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
Fri Dec 21 04:50:28 2007
@@ -20,6 +20,10 @@
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.NodeIdIterator;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.fs.FileSystemException;
+import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
import org.apache.jackrabbit.core.query.AbstractQueryHandler;
import org.apache.jackrabbit.core.query.DefaultQueryNodeFactory;
import org.apache.jackrabbit.core.query.ExecutableQuery;
@@ -326,6 +330,17 @@
private SynonymProvider synProvider;
/**
+ * The configuration path for the synonym provider.
+ */
+ private String synonymProviderConfigPath;
+
+ /**
+ * The FileSystem for the synonym if the query handler context does not
+ * provide one.
+ */
+ private FileSystem synonymProviderConfigFs;
+
+ /**
* Indicates the index format version which is relevant to a <b>query</b>.
This
* value may be different from what {@link MultiIndex#getIndexFormatVersion()}
* returns because queries may be executed on two physical indexes with
@@ -598,6 +613,13 @@
* to this handler.
*/
public void close() {
+ if (synonymProviderConfigFs != null) {
+ try {
+ synonymProviderConfigFs.close();
+ } catch (FileSystemException e) {
+ log.warn("Exception while closing FileSystem", e);
+ }
+ }
// shutdown extractor
if (extractor instanceof PooledTextExtractor) {
((PooledTextExtractor) extractor).shutdown();
@@ -897,6 +919,7 @@
if (synonymProviderClass != null) {
try {
sp = (SynonymProvider) synonymProviderClass.newInstance();
+ sp.initialize(createSynonymProviderConfigResource());
} catch (Exception e) {
log.warn("Exception initializing synonym provider: " +
synonymProviderClass, e);
@@ -906,6 +929,52 @@
}
/**
+ * Creates a file system resource to the synonym provider configuration.
+ *
+ * @return a file system resource or <code>null</code> if no path was
+ * configured.
+ * @throws FileSystemException if an exception occurs accessing the file
+ * system.
+ */
+ protected FileSystemResource createSynonymProviderConfigResource()
+ throws FileSystemException {
+ if (synonymProviderConfigPath != null) {
+ FileSystemResource fsr;
+ // simple sanity check
+ if (synonymProviderConfigPath.endsWith(FileSystem.SEPARATOR)) {
+ throw new FileSystemException(
+ "Invalid synonymProviderConfigPath: " +
+ synonymProviderConfigPath);
+ }
+ FileSystem fs = getContext().getFileSystem();
+ if (fs == null) {
+ fs = new LocalFileSystem();
+ int lastSeparator = synonymProviderConfigPath.lastIndexOf(
+ FileSystem.SEPARATOR_CHAR);
+ if (lastSeparator != -1) {
+ File root = new File(path,
+ synonymProviderConfigPath.substring(0, lastSeparator));
+ ((LocalFileSystem) fs).setRoot(root);
+ fs.init();
+ fsr = new FileSystemResource(fs,
+ synonymProviderConfigPath.substring(lastSeparator + 1));
+ } else {
+ ((LocalFileSystem) fs).setPath(path);
+ fs.init();
+ fsr = new FileSystemResource(fs, synonymProviderConfigPath);
+ }
+ synonymProviderConfigFs = fs;
+ } else {
+ fsr = new FileSystemResource(fs, synonymProviderConfigPath);
+ }
+ return fsr;
+ } else {
+ // path not configured
+ return null;
+ }
+ }
+
+ /**
* Creates a spell checker for this query handler.
*
* @return the spell checker or <code>null</code> if none is configured or
@@ -1683,6 +1752,23 @@
*/
public boolean getEnableConsistencyCheck() {
return consistencyCheckEnabled;
+ }
+
+ /**
+ * Sets the configuration path for the synonym provider.
+ *
+ * @param path the configuration path for the synonym provider.
+ */
+ public void setSynonymProviderConfigPath(String path) {
+ synonymProviderConfigPath = path;
+ }
+
+ /**
+ * @return the configuration path for the synonym provider. If none is set
+ * this method returns <code>null</code>.
+ */
+ public String getSynonymProviderConfigPath() {
+ return synonymProviderConfigPath;
}
//----------------------------< internal >----------------------------------
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SynonymProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SynonymProvider.java?rev=606180&r1=606179&r2=606180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SynonymProvider.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SynonymProvider.java
Fri Dec 21 04:50:28 2007
@@ -16,11 +16,28 @@
*/
package org.apache.jackrabbit.core.query.lucene;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+
+import java.io.IOException;
+
/**
* <code>SynonymProvider</code> defines an interface for a component that
* returns synonyms for a given term.
*/
public interface SynonymProvider {
+
+ /**
+ * Initializes the synonym provider and passes the file system resource to
+ * the synonym provider configuration defined by the configuration value of
+ * the <code>synonymProviderConfigPath</code> parameter. The resource may
be
+ * <code>null</code> if the configuration parameter is not set.
+ *
+ * @param fsr the file system resource to the synonym provider
+ * configuration.
+ * @throws IOException if an error occurs while initializing the synonym
+ * provider.
+ */
+ public void initialize(FileSystemResource fsr) throws IOException;
/**
* Returns an array of terms that are considered synonyms for the given
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SynonymProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SynonymProviderTest.java?rev=606180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SynonymProviderTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SynonymProviderTest.java
Fri Dec 21 04:50:28 2007
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.jackrabbit.core.query;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+
+/**
+ * <code>SynonymProviderTest</code> contains test cases for the
+ * <code>PropertiesSynonymProvider</code> class.
+ * This test assumes that the following synonyms are defined:
+ * <ul>
+ * <li>quick <-> fast</li>
+ * <li>sluggish <-> lazy</li>
+ * <li>ASF <-> Apache Software Foundation</li>
+ * </ul>
+ */
+public class SynonymProviderTest extends AbstractQueryTest {
+
+ public void testSynonyms() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName1);
+ n.setProperty(propertyName1, "The quick brown fox jumps over the lazy dog.");
+ testRootNode.save();
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~fast')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~Fast')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~quick')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~sluggish')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~sluGGish')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~lazy')]", new Node[]{n});
+ // check term which is not in the synonym provider
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~brown')]", new Node[]{n});
+ }
+
+ public void testPhrase() throws RepositoryException {
+ Node n = testRootNode.addNode(nodeName1);
+ n.setProperty(propertyName1, "Licensed to the Apache Software Foundation ...");
+ testRootNode.save();
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~ASF')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~asf')]", new Node[]{n});
+ executeXPathQuery(testPath + "//*[jcr:contains(., 'asf')]", new Node[]{});
+ }
+
+ public void disabled_testReload() throws RepositoryException, InterruptedException {
+ for (int i = 0; i < 60; i++) {
+ Thread.sleep(1 * 1000);
+ executeXPathQuery(testPath + "//*[jcr:contains(., '~asf')]", new Node[]{});
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/SynonymProviderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java?rev=606180&r1=606179&r2=606180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/TestAll.java
Fri Dec 21 04:50:28 2007
@@ -50,6 +50,7 @@
suite.addTestSuite(QueryResultTest.class);
suite.addTestSuite(FnNameQueryTest.class);
suite.addTestSuite(PathQueryNodeTest.class);
+ suite.addTestSuite(SynonymProviderTest.class);
// exclude long running tests per default
//suite.addTestSuite(MassiveRangeTest.class);
Added: jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/synonyms.properties
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/synonyms.properties?rev=606180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/synonyms.properties
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/synonyms.properties
Fri Dec 21 04:50:28 2007
@@ -0,0 +1,4 @@
+# this is a synonym definition file for PropertiesSynonymProvider
+ASF=Apache Software Foundation
+quick=fast
+sluggish=lazy
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/synonyms.properties
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/workspace.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/workspace.xml?rev=606180&r1=606179&r2=606180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/workspace.xml
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/workspace.xml
Fri Dec 21 04:50:28 2007
@@ -36,6 +36,8 @@
-->
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
<param name="path" value="${wsp.home}/index" />
+ <param name="synonymProviderClass" value="org.apache.jackrabbit.core.query.lucene.PropertiesSynonymProvider"/>
+ <param name="synonymProviderConfigPath" value="../synonyms.properties"/>
</SearchIndex>
</Workspace>
|