Package org.infinispan.objectfilter

Source Code of org.infinispan.objectfilter.BaseMatcher

package org.infinispan.objectfilter;

import org.hibernate.hql.QueryParser;
import org.infinispan.objectfilter.impl.FilterRegistry;
import org.infinispan.objectfilter.impl.FilterSubscriptionImpl;
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.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
*/
public 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>>();

   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) {
      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();
      }
   }

   public Matcher getSingleFilterMatcher(FilterSubscription filterSubscription, final FilterCallback filterCallback) {
      final FilterSubscriptionImpl filterSubscriptionImpl = (FilterSubscriptionImpl) filterSubscription;
      final Set<String> types = Collections.singleton(filterSubscriptionImpl.getEntityTypeName());
      final PredicateIndex<AttributeId> predicateIndex = new PredicateIndex<AttributeId>();

      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 context = ctx.getFilterContext(filterSubscriptionImpl);
                  predicateNode.handleChildValue(predicateNode, isMatching, context);
               }
            };
            predicateIndex.addSubscriptionForPredicate(predicateNode, predicateCallback);
         }
      }

      return new Matcher() {
         @Override
         public void match(Object instance) {
            MatcherEvalContext<AttributeId> ctx = startContext(instance, types);
            if (ctx != null) {
               ctx.process(predicateIndex.getRoot());

               // TODO [anistor] the instance here can be a byte[] or stream if the payload is protobuf encoded
               filterCallback.onFilterResult(ctx.getInstance(), null, ctx.getFilterContext(filterSubscriptionImpl).getResult());   //todo projection
            }
         }
      };
   }

   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);
   }

   public FilterSubscription registerFilter(String jpaQuery, final FilterCallback callback) {
      FilterParsingResult<TypeMetadata> parsingResult = queryParser.parseQuery(jpaQuery, createFilterProcessingChain(null)); //todo [anistor] query params not yet supported
      BooleanExpr normalizedFilter = booleanFilterNormalizer.normalize(parsingResult.getQuery());

      write.lock();
      try {
         FilterRegistry filterRegistry = filtersByType.get(parsingResult.getTargetEntityName());
         if (filterRegistry == null) {
            filterRegistry = createFilterRegistryForType(parsingResult.getTargetEntityMetadata());
            filtersByType.put(parsingResult.getTargetEntityName(), filterRegistry);
         }

         return filterRegistry.addFilter(normalizedFilter, parsingResult.getProjections(), callback);
      } finally {
         write.unlock();
      }
   }

   public void unregisterFilter(FilterSubscription filterSubscription) {
      FilterSubscriptionImpl filterSubscriptionImpl = (FilterSubscriptionImpl) filterSubscription;
      write.lock();
      try {
         FilterRegistry 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 instances has any registered filters. This method is called
    * while holding the write lock.
    *
    * @param instance
    * @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.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.