All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ocpsoft.rewrite.config.Subset Maven / Gradle / Ivy

There is a newer version: 10.0.2.Final
Show newest version
/*
 * Copyright 2013 Lincoln Baxter, III
 * 
 * Licensed 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.ocpsoft.rewrite.config;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import org.ocpsoft.common.util.Assert;
import org.ocpsoft.logging.Logger;
import org.ocpsoft.rewrite.bind.Binding;
import org.ocpsoft.rewrite.bind.Evaluation;
import org.ocpsoft.rewrite.context.ContextBase;
import org.ocpsoft.rewrite.context.EvaluationContext;
import org.ocpsoft.rewrite.context.RewriteState;
import org.ocpsoft.rewrite.event.Rewrite;
import org.ocpsoft.rewrite.param.ConfigurableParameter;
import org.ocpsoft.rewrite.param.Constraint;
import org.ocpsoft.rewrite.param.DefaultParameter;
import org.ocpsoft.rewrite.param.DefaultParameterStore;
import org.ocpsoft.rewrite.param.Parameter;
import org.ocpsoft.rewrite.param.ParameterStore;
import org.ocpsoft.rewrite.param.ParameterValueStore;
import org.ocpsoft.rewrite.param.Parameterized;
import org.ocpsoft.rewrite.param.Transposition;
import org.ocpsoft.rewrite.util.ParameterUtils;
import org.ocpsoft.rewrite.util.Visitor;

/**
 * An {@link Operation} that allows for conditional evaluation of nested {@link Rule} sets.
 * 
 * @author Lincoln Baxter, III
 */
public class Subset extends DefaultOperationBuilder implements CompositeOperation, Parameterized
{
   private static Logger log = Logger.getLogger(Subset.class);
   private final Configuration config;

   private Subset(Configuration config)
   {
      Assert.notNull(config, "Configuration must not be null.");
      this.config = config;
   }

   public static Subset evaluate(Configuration config)
   {
      return new Subset(config);
   }

   /*
    * Executors
    */
   @Override
   public void perform(Rewrite rewrite, EvaluationContext context)
   {

      /*
       * Highly optimized loop - for performance reasons. Think before you change this!
       */
      Rewrite event = (Rewrite) rewrite;
      List cacheable = new ArrayList();
      List rules = config.getRules();

      final EvaluationContextImpl subContext = new EvaluationContextImpl();
      for (int i = 0; i < rules.size(); i++)
      {
         Rule rule = rules.get(i);

         subContext.clear();
         subContext.put(ParameterStore.class, context.get(ParameterStore.class));
         ParameterValueStore values = (ParameterValueStore) context.get(ParameterValueStore.class);
         subContext.put(ParameterValueStore.class, values);
         subContext.setState(RewriteState.EVALUATING);

         if (rule.evaluate(event, subContext))
         {
            if (handleBindings(event, subContext, values))
            {
               subContext.setState(RewriteState.PERFORMING);
               log.debug("Rule [" + rule + "] matched and will be performed.");
               cacheable.add(rule);
               List preOperations = subContext.getPreOperations();
               for (int k = 0; k < preOperations.size(); k++) {
                  preOperations.get(k).perform(event, subContext);
               }

               if (event.getFlow().isHandled())
               {
                  break;
               }

               rule.perform(event, subContext);

               if (event.getFlow().isHandled())
               {
                  break;
               }

               List postOperations = subContext.getPostOperations();
               for (int k = 0; k < postOperations.size(); k++) {
                  postOperations.get(k).perform(event, subContext);
               }

               if (event.getFlow().isHandled())
               {
                  break;
               }
            }
         }
      }
   }

   private boolean handleBindings(final Rewrite event, final EvaluationContextImpl context,
            ParameterValueStore values)
   {
      boolean result = true;
      ParameterStore store = (ParameterStore) context.get(ParameterStore.class);

      for (Entry> entry : store) {
         Parameter parameter = entry.getValue();
         String value = values.retrieve(parameter);

         if (!ParameterUtils.enqueueSubmission(event, context, parameter, value))
         {
            result = false;
            break;
         }
      }
      return result;
   }

   /*
    * Getters
    */

   @Override
   public List getOperations()
   {
      return Collections.emptyList();
   }

   class EvaluationContextImpl extends ContextBase implements EvaluationContext
   {
      private final List preOperations = new ArrayList();
      private final List postOperations = new ArrayList();
      private RewriteState state;

      public EvaluationContextImpl()
      {
         put(ParameterStore.class, new DefaultParameterStore());
      }

      @Override
      public void addPreOperation(final Operation operation)
      {
         this.preOperations.add(operation);
      }

      @Override
      public void addPostOperation(final Operation operation)
      {
         this.preOperations.add(operation);
      }

      /**
       * Get an immutable view of the added pre-{@link Operation} instances.
       */
      public List getPreOperations()
      {
         return Collections.unmodifiableList(preOperations);
      }

      /**
       * Get an immutable view of the added post-{@link Operation} instances.
       */
      public List getPostOperations()
      {
         return Collections.unmodifiableList(postOperations);
      }

      @Override
      public String toString()
      {
         return "EvaluationContextImpl [preOperations=" + preOperations + ", postOperations=" + postOperations + "]";
      }

      /**
       * Clears the state of this context so that it may be reused, saving instantiation cost during rule iteration.
       */
      public void clear()
      {
         this.postOperations.clear();
         this.postOperations.clear();
      }

      @Override
      public RewriteState getState()
      {
         return state;
      }

      public void setState(RewriteState state)
      {
         this.state = state;
      }
   }

   @Override
   public Set getRequiredParameterNames()
   {
      return Collections.emptySet();
   }

   @Override
   public void setParameterStore(final ParameterStore parent)
   {
      for (final Rule rule : config.getRules()) {
         if (rule instanceof RuleBuilder) {
            ParameterizedCallback callback = new ParameterizedCallback() {
               @Override
               public void call(Parameterized parameterized)
               {
                  Set names = parameterized.getRequiredParameterNames();
                  if (rule instanceof RuleBuilder)
                  {
                     ParameterStore store = ((RuleBuilder) rule).getParameterStore();

                     for (Entry> entry : parent) {
                        String name = entry.getKey();
                        Parameter parentParam = entry.getValue();

                        if (!store.contains(name)) {
                           store.get(name, parentParam);
                        }
                        else
                        {
                           Parameter parameter = store.get(name);
                           for (Binding binding : parameter.getBindings()) {
                              if (!parentParam.getBindings().contains(binding))
                                 throwRedefinitionError(rule, name);
                           }

                           for (Constraint constraint : parameter.getConstraints()) {
                              if (!parentParam.getConstraints().contains(constraint))
                                 throwRedefinitionError(rule, name);
                           }

                           for (Transposition transposition : parameter.getTranspositions()) {
                              if (!parentParam.getTranspositions().contains(transposition))
                                 throwRedefinitionError(rule, name);
                           }

                           if (parentParam.getConverter() != null
                                    && !parentParam.getConverter().equals(parameter.getConverter()))
                              throwRedefinitionError(rule, name);

                           if (parentParam.getValidator() != null
                                    && !parentParam.getValidator().equals(parameter.getValidator()))
                              throwRedefinitionError(rule, name);
                        }
                     }

                     for (String name : names) {
                        Parameter parameter = store.get(name, new DefaultParameter(name));
                        if (parameter instanceof ConfigurableParameter)
                           ((ConfigurableParameter) parameter).bindsTo(Evaluation.property(name));
                     }
                     parameterized.setParameterStore(store);
                  }

               }

               private void throwRedefinitionError(Rule rule, String name)
               {
                  throw new IllegalStateException("Subset cannot re-configure parameter [" + name
                           + "] that was configured in parent Configuration. Re-definition was attempted at ["
                           + rule + "] ");
               }
            };

            Visitor conditionVisitor = new ParameterizedConditionVisitor(callback);
            new ConditionVisit(rule).accept(conditionVisitor);

            Visitor operationVisitor = new ParameterizedOperationVisitor(callback);
            new OperationVisit(rule).accept(operationVisitor);
         }
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy