/*
* Copyright (2005-2012) Schibsted ASA
* This file is part of Possom.
*
* Possom is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Possom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Possom. If not, see <http://www.gnu.org/licenses/>.
*/
package no.sesat.search.query.parser;
import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import no.sesat.commons.ref.ReferenceMap;
import no.sesat.search.query.Clause;
import no.sesat.search.query.LeafClause;
import no.sesat.search.query.XorClause;
import no.sesat.search.query.token.EvaluationState;
import no.sesat.search.query.token.TokenEvaluationEngine;
import no.sesat.search.query.token.TokenPredicate;
import no.sesat.search.site.Site;
/**
* The XorClauseImpl represents a joining clause between two terms in the query.
* For example: "term1 OR term2".
* <b>Objects of this class are immutable</b>
*
*
* @version $Id: OrClauseImpl.java 2344 2006-02-20 20:07:12Z mickw $
*/
public final class XorClauseImpl extends OrClauseImpl implements XorClause {
private static final int WEAK_CACHE_INITIAL_CAPACITY = 2000;
private static final float WEAK_CACHE_LOAD_FACTOR = 0.5f;
private static final int WEAK_CACHE_CONCURRENCY_LEVEL = 16;
/** Values are WeakReference object to AbstractClause.
* Unsynchronized are there are no 'changing values', just existance or not of the AbstractClause in the system.
*/
private static final Map<Site,ReferenceMap<String,XorClauseImpl>> WEAK_CACHE
= new ConcurrentHashMap<Site,ReferenceMap<String,XorClauseImpl>>();
/* A WordClause specific collection of TokenPredicates that *could* apply to this Clause type. */
private static final Collection<TokenPredicate> PREDICATES_APPLICABLE;
private final Hint hint;
static {
PREDICATES_APPLICABLE = Collections.unmodifiableCollection(new ArrayList());
}
/**
* Creator method for XorClauseImpl objects. By avoiding the constructors,
* and assuming all XorClauseImpl objects are immutable, we can keep track
* (via a weak reference map) of instances already in use in this JVM and reuse
* them.
* The methods also allow a chunk of creation logic for the XorClauseImpl to be moved
* out of the QueryParserImpl.jj file to here.
*
*
* @param first the left child clause of the operation clause we are about to create (or find).
* @param second the right child clause of the operation clause we are about to create (or find).
* @param hint
* @param engine the factory handing out evaluators against TokenPredicates.
* Also holds state information about the current term/clause we are finding predicates against.
* @return returns a XorClauseImpl matching the term, left and right child clauses.
* May be either newly created or reused.
*/
public static XorClauseImpl createXorClause(
final Clause first,
final Clause second,
final Hint hint,
final TokenEvaluationEngine engine) {
// construct the proper "schibstedsøk" formatted term for this operation.
// XXX eventually it would be nice not to have to expose the internal string representation of this object.
final String term =
(first instanceof LeafClause && ((LeafClause) first).getField() != null
? ((LeafClause) first).getField() + ':'
: "")
+ first.getTerm()
+ " "
+ (second instanceof LeafClause && ((LeafClause) second).getField() != null
? ((LeafClause) second).getField() + ':'
: "")
+ second.getTerm();
try{
// create predicate sets
engine.setState(new EvaluationState(term, new HashSet<TokenPredicate>(), new HashSet<TokenPredicate>()));
// the weakCache to use.
ReferenceMap<String,XorClauseImpl> weakCache = WEAK_CACHE.get(engine.getSite());
if( weakCache == null ){
weakCache = new ReferenceMap<String,XorClauseImpl>(
DFAULT_REFERENCE_MAP_TYPE,
new ConcurrentHashMap<String,Reference<XorClauseImpl>>(
WEAK_CACHE_INITIAL_CAPACITY,
WEAK_CACHE_LOAD_FACTOR,
WEAK_CACHE_CONCURRENCY_LEVEL));
WEAK_CACHE.put(engine.getSite(), weakCache);
}
// we can't use the helper method because of the extra Hint argument to the XorClauseImpl constructor
// check weak reference cache of immutable wordClauses here.
// no need to synchronise, no big lost if duplicate identical objects are created and added over each other
// into the cache, compared to the performance lost of trying to synchronise this.
XorClauseImpl clause = findClauseInUse(term, weakCache);
if (clause == null) {
// Doesn't exist in weak-reference cache. let's find the predicates and create the WordClause.
// find the applicale predicates now
final boolean healthy = findPredicates(engine);
// create it...
clause = new XorClauseImpl(
term,
first,
second,
hint,
engine.getState().getKnownPredicates(),
engine.getState().getPossiblePredicates()
);
if( healthy ){
return addClauseInUse(term, clause, weakCache);
}
}
return clause;
}finally{
engine.setState(null);
}
}
public XorClause.Hint getHint() {
return hint;
}
/**
* Create the XorClauseImpl with the given term, left and right child clauses, and known and possible predicate sets.
*
* @param term the term for this OrClauseImpl.
* @param knownPredicates set of known predicates.
* @param possiblePredicates set of possible predicates.
* @param first the left child clause.
* @param second the right child clause.
*/
protected XorClauseImpl(
final String term,
final Clause first,
final Clause second,
final Hint hint,
final Set<TokenPredicate> knownPredicates,
final Set<TokenPredicate> possiblePredicates) {
super(term, first, second, knownPredicates, possiblePredicates);
this.hint = hint;
}
}