/* 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/>. * AbstractOperationClause.java * * Created on 7 January 2006, 16:05 * */ package no.sesat.search.query.parser; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Set; import no.sesat.commons.ref.ReferenceMap; import no.sesat.search.query.Clause; import no.sesat.search.query.UnaryClause; import no.sesat.search.query.token.TokenEvaluationEngine; import no.sesat.search.query.token.TokenPredicate; import org.apache.log4j.Logger; /** * Basic implementation of the OperationClause interface. * Implements ontop of AbstractClause. * <b>Objects of this class are immutable</b> * * * @version $Id$ */ public abstract class AbstractUnaryClause extends AbstractClause implements UnaryClause { private static final Logger LOG = Logger.getLogger(AbstractLeafClause.class); /** * Works off the assumption that OperationClause constructor's have the exact parameter list: * final String term, * final Clause left, * final Clause right, * final Set<Predicate> knownPredicates, * final Set<Predicate> possiblePredicates * * Where this is true subclasses are free to use this helper method. * * @param left the left child clause for OperationClause the clause we are about to create (or find) will have. * @param right the right child clause the clause we are about to create (or find) will have. * @param clauseClass the exact subclass of AbstracLeafClause that we are about to create (or find already in use). * @param term the term the clause we are about to create (or find) will have. * @param engine the factory handing out evaluators against TokenPredicates. * Also holds state information about the current term/clause we are finding predicates against. * @param weakCache the map containing the key to WeakReference (of the Clause) mappings. * @return Either a clause already in use that matches this term and field, or a newly created cluase for this term and field. */ public static <T extends AbstractUnaryClause> T createClause( final Class<T> clauseClass, final String term, final Clause left, final Clause right, final TokenEvaluationEngine engine, final ReferenceMap<String,T> weakCache) { final String key = term; // important that the key argument is unique to this object. // 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. T clause = findClauseInUse(key, 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); try { // find the constructor... final Constructor<T> constructor = clauseClass.getDeclaredConstructor( String.class, Clause.class, Clause.class, Set.class, Set.class ); // use the constructor... clause = constructor.newInstance( term, left, right, engine.getState().getKnownPredicates(), engine.getState().getPossiblePredicates() ); } catch (SecurityException ex) { LOG.error(ERR_FAILED_FINDING_OR_USING_CONSTRUCTOR + clauseClass.getName(), ex); } catch (NoSuchMethodException ex) { LOG.error(ERR_FAILED_FINDING_OR_USING_CONSTRUCTOR + clauseClass.getName(), ex); } catch (IllegalArgumentException ex) { LOG.error(ERR_FAILED_FINDING_OR_USING_CONSTRUCTOR + clauseClass.getName(), ex); } catch (InstantiationException ex) { LOG.error(ERR_FAILED_FINDING_OR_USING_CONSTRUCTOR + clauseClass.getName(), ex); } catch (InvocationTargetException ex) { LOG.error(ERR_FAILED_FINDING_OR_USING_CONSTRUCTOR + clauseClass.getName(), ex); } catch (IllegalAccessException ex) { LOG.error(ERR_FAILED_FINDING_OR_USING_CONSTRUCTOR + clauseClass.getName(), ex); } if( healthy ){ return addClauseInUse(key, clause, weakCache); } } return clause; } /** * Create clause with the given term, known and possible predicates. * @param term the term (query string) for this clause. * @param first * @param knownPredicates the set of known predicates for this clause. * @param possiblePredicates the set of possible predicates for this clause. */ protected AbstractUnaryClause( final String term, final Clause first, final Set<TokenPredicate> knownPredicates, final Set<TokenPredicate> possiblePredicates) { super(term, knownPredicates, possiblePredicates); firstClause = first; } /** * The first clause of a binary clause, or the only clause of a UnaryClause. */ protected final Clause firstClause; /** * Get the firstClause. * * @return the firstClause. */ public Clause getFirstClause() { return firstClause; } @Override public String toString() { return getClass().getSimpleName() + '[' + getFirstClause() + ']'; } }