Package org.infinispan.objectfilter.impl

Source Code of org.infinispan.objectfilter.impl.BaseMatcher

package org.infinispan.objectfilter.impl;

import org.hibernate.hql.QueryParser;
import org.infinispan.objectfilter.FilterCallback;
import org.infinispan.objectfilter.FilterSubscription;
import org.infinispan.objectfilter.Matcher;
import org.infinispan.objectfilter.ObjectFilter;
import org.infinispan.objectfilter.SortField;
import org.infinispan.objectfilter.impl.hql.FilterParsingResult;
import org.infinispan.objectfilter.impl.hql.FilterProcessingChain;
import org.infinispan.objectfilter.impl.predicateindex.FilterEvalContext;
import org.infinispan.objectfilter.impl.predicateindex.MatcherEvalContext;
import org.infinispan.objectfilter.impl.predicateindex.Predicate;
import org.infinispan.objectfilter.impl.predicateindex.PredicateIndex;
import org.infinispan.objectfilter.impl.predicateindex.be.BENode;
import org.infinispan.objectfilter.impl.predicateindex.be.PredicateNode;
import org.infinispan.objectfilter.impl.syntax.BooleanExpr;
import org.infinispan.objectfilter.impl.syntax.BooleanFilterNormalizer;
import org.infinispan.objectfilter.query.FilterQuery;
import org.infinispan.objectfilter.query.FilterQueryFactory;
import org.infinispan.query.dsl.Query;
import org.infinispan.query.dsl.QueryFactory;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* @author anistor@redhat.com
* @since 7.0
*/
abstract class BaseMatcher<TypeMetadata, AttributeId extends Comparable<AttributeId>> implements Matcher {

   private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

   private final Lock read = readWriteLock.readLock();

   private final Lock write = readWriteLock.writeLock();

   private final QueryParser queryParser = new QueryParser();

   private final BooleanFilterNormalizer booleanFilterNormalizer = new BooleanFilterNormalizer();

   private final Map<String, FilterRegistry<AttributeId>> filtersByType = new HashMap<String, FilterRegistry<AttributeId>>();

   @Override
   public QueryFactory<Query> getQueryFactory() {
      return new FilterQueryFactory();
   }

   /**
    * Executes the registered filters and notifies each one of them whether it was satisfied or not by the given
    * instance.
    *
    * @param instance the instance to match filters against
    */
   @Override
   public void match(Object instance) {
      if (instance == null) {
         throw new IllegalArgumentException("argument cannot be null");
      }

      read.lock();
      try {
         MatcherEvalContext<AttributeId> ctx = startContext(instance, filtersByType.keySet());
         if (ctx != null) {
            FilterRegistry<AttributeId> filterRegistry = filtersByType.get(ctx.getEntityTypeName());
            filterRegistry.match(ctx);
         }
      } finally {
         read.unlock();
      }
   }

   @Override
   public ObjectFilter getObjectFilter(Query query) {
      if (!(query instanceof FilterQuery)) {
         throw new IllegalArgumentException("The Query object must be created by a QueryFactory returned by this Matcher");
      }
      FilterQuery filterQuery = (FilterQuery) query;
      return getObjectFilter(filterQuery.getJpqlString());
   }

   @Override
   public ObjectFilter getObjectFilter(String jpaQuery) {
      FilterParsingResult<TypeMetadata> parsingResult = parse(jpaQuery);
      BooleanExpr normalizedFilter = booleanFilterNormalizer.normalize(parsingResult.getQuery());

      //todo [anistor] we need an efficient single-filter registry ...
      FilterRegistry filterRegistry = createFilterRegistryForType(parsingResult.getTargetEntityMetadata());
      FilterSubscriptionImpl filterSubscriptionImpl = filterRegistry.addFilter(normalizedFilter, parsingResult.getProjections(), parsingResult.getSortFields(), new FilterCallback() {
         @Override
         public void onFilterResult(Object instance, Object[] projection, Comparable[] sortProjection) {
            // do nothing
         }
      });

      return getObjectFilter(filterSubscriptionImpl);
   }

   @Override
   public ObjectFilter getObjectFilter(FilterSubscription filterSubscription) {
      final FilterSubscriptionImpl<AttributeId> filterSubscriptionImpl = (FilterSubscriptionImpl<AttributeId>) filterSubscription;
      final Set<String> knownTypes = Collections.singleton(filterSubscriptionImpl.getEntityTypeName());
      final PredicateIndex<AttributeId> predicateIndex = new PredicateIndex<AttributeId>(filterSubscriptionImpl.getMetadataAdapter());

      filterSubscriptionImpl.registerProjection(predicateIndex);

      for (BENode node : filterSubscriptionImpl.getBETree().getNodes()) {
         if (node instanceof PredicateNode) {
            final PredicateNode<AttributeId> predicateNode = (PredicateNode<AttributeId>) node;
            Predicate.Callback predicateCallback = new Predicate.Callback() {
               @Override
               public void handleValue(MatcherEvalContext<?> ctx, boolean isMatching) {
                  FilterEvalContext filterEvalContext = ctx.getFilterEvalContext(filterSubscriptionImpl);
                  predicateNode.handleChildValue(null, isMatching, filterEvalContext);
               }
            };
            predicateIndex.addSubscriptionForPredicate(predicateNode, predicateCallback);
         }
      }

      return new ObjectFilter() {

         @Override
         public String getEntityTypeName() {
            return filterSubscriptionImpl.getEntityTypeName();
         }

         @Override
         public String[] getProjection() {
            return filterSubscriptionImpl.getProjection();
         }

         @Override
         public SortField[] getSortFields() {
            return filterSubscriptionImpl.getSortFields();
         }

         @Override
         public Comparator<Comparable[]> getComparator() {
            return filterSubscriptionImpl.getComparator();
         }

         @Override
         public FilterResult filter(Object instance) {
            if (instance == null) {
               throw new IllegalArgumentException("argument cannot be null");
            }

            MatcherEvalContext<AttributeId> matcherEvalContext = startContext(instance, knownTypes);
            if (matcherEvalContext != null) {
               FilterEvalContext filterEvalContext = matcherEvalContext.getFilterEvalContext(filterSubscriptionImpl);
               matcherEvalContext.process(predicateIndex.getRoot());

               if (filterEvalContext.getMatchResult()) {
                  return new FilterResultImpl(instance, filterEvalContext.getProjection(), filterEvalContext.getSortProjection());
               }
            }

            return null;
         }
      };
   }

   @Override
   public FilterSubscription registerFilter(Query query, FilterCallback callback) {
      if (!(query instanceof FilterQuery)) {
         throw new IllegalArgumentException("The Query object must be created by a QueryFactory returned by this Matcher");
      }
      FilterQuery filterQuery = (FilterQuery) query;
      return registerFilter(filterQuery.getJpqlString(), callback);
   }

   @Override
   public FilterSubscription registerFilter(String jpaQuery, FilterCallback callback) {
      FilterParsingResult<TypeMetadata> parsingResult = parse(jpaQuery);
      BooleanExpr normalizedFilter = booleanFilterNormalizer.normalize(parsingResult.getQuery());

      write.lock();
      try {
         FilterRegistry<AttributeId> filterRegistry = filtersByType.get(parsingResult.getTargetEntityName());
         if (filterRegistry == null) {
            filterRegistry = createFilterRegistryForType(parsingResult.getTargetEntityMetadata());
            filtersByType.put(parsingResult.getTargetEntityName(), filterRegistry);
         }
         return filterRegistry.addFilter(normalizedFilter, parsingResult.getProjections(), parsingResult.getSortFields(), callback);
      } finally {
         write.unlock();
      }
   }

   private FilterParsingResult<TypeMetadata> parse(String jpaQuery) {
      //todo [anistor] query params not yet fully supported by HQL parser. to be added later.
      return queryParser.parseQuery(jpaQuery, createFilterProcessingChain(null));
   }

   @Override
   public void unregisterFilter(FilterSubscription filterSubscription) {
      FilterSubscriptionImpl filterSubscriptionImpl = (FilterSubscriptionImpl) filterSubscription;
      write.lock();
      try {
         FilterRegistry<AttributeId> filterRegistry = filtersByType.get(filterSubscriptionImpl.getEntityTypeName());
         if (filterRegistry != null) {
            filterRegistry.removeFilter(filterSubscription);
         } else {
            throw new IllegalStateException("Reached illegal state");
         }
         if (filterRegistry.isEmpty()) {
            filtersByType.remove(filterRegistry.getTypeName());
         }
      } finally {
         write.unlock();
      }
   }

   /**
    * Creates a new MatcherEvalContext only if the given instance has filters registered. This method is called while
    * holding the write lock.
    *
    * @param instance   the instance to filter; never null
    * @param knownTypes
    * @return the context or null if no filter was registered for the instance
    */
   protected abstract MatcherEvalContext<AttributeId> startContext(Object instance, Set<String> knownTypes);

   protected abstract FilterProcessingChain<?> createFilterProcessingChain(Map<String, Object> namedParameters);

   protected abstract FilterRegistry<AttributeId> createFilterRegistryForType(TypeMetadata typeMetadata);
}
TOP

Related Classes of org.infinispan.objectfilter.impl.BaseMatcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.