/*
* 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.exoplatform.services.jcr.impl.core.query.lucene;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
/**
* 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
{
/**
* 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 InputStream config;
/**
* Timestamp when the configuration was checked last.
*/
private long lastCheck;
/**
* Contains the synonym mapping. Map<String, String[]>
*/
private Map<String, String[]> synonyms = new HashMap<String, String[]>();
/**
* {@inheritDoc}
*/
public synchronized void initialize(InputStream fsr) throws IOException
{
if (fsr == null)
{
throw new IOException("PropertiesSynonymProvider requires a path configuration");
}
try
{
config = fsr;
synonyms = getSynonyms(config);
lastCheck = System.currentTimeMillis();
}
catch (IOException e)
{
throw e;
}
}
/**
* {@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<String, String[]> getSynonyms(InputStream config) throws IOException
{
try
{
Map<String, String[]> synonyms = new HashMap<String, String[]>();
Properties props = new Properties();
props.load(config);
Iterator<Map.Entry<Object, Object>> it = props.entrySet().iterator();
while (it.hasNext())
{
Map.Entry<Object, Object> e = it.next();
String key = (String)e.getKey();
String value = (String)e.getValue();
addSynonym(key, value, synonyms);
addSynonym(value, key, synonyms);
}
return synonyms;
}
catch (Exception e)
{
throw Util.createIOException(e);
}
}
/**
* 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<String, String[]> synonyms)
{
term = term.toLowerCase();
String[] syns = 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);
}
}