Coverage Report - org.boretti.drools.integration.drools5.implementation.DroolsProxy
 
Classes in this File Line Coverage Branch Coverage Complexity
DroolsProxy
94 %
99/105
88 %
78/88
7.444
DroolsProxy$1
N/A
N/A
7.444
DroolsProxy$ProductFactResult
77 %
7/9
N/A
7.444
 
 1  
 /*
 2  
     Drools5 Integration Helper
 3  
     Copyright (C) 2009  Mathieu Boretti mathieu.boretti@gmail.com
 4  
 
 5  
     This program is free software: you can redistribute it and/or modify
 6  
     it under the terms of the GNU General Public License as published by
 7  
     the Free Software Foundation, either version 3 of the License, or
 8  
     (at your option) any later version.
 9  
 
 10  
     This program is distributed in the hope that it will be useful,
 11  
     but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  
     GNU General Public License for more details.
 14  
 
 15  
     You should have received a copy of the GNU General Public License
 16  
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17  
 
 18  
  */
 19  
 package org.boretti.drools.integration.drools5.implementation;
 20  
 
 21  
 import java.lang.annotation.Annotation;
 22  
 import java.lang.reflect.InvocationHandler;
 23  
 import java.lang.reflect.Method;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Collection;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 import java.util.concurrent.ExecutorService;
 30  
 import java.util.concurrent.Executors;
 31  
 import java.util.concurrent.Future;
 32  
 
 33  
 import org.apache.log4j.Logger;
 34  
 import org.boretti.drools.integration.drools5.DroolsInterface;
 35  
 import org.boretti.drools.integration.drools5.DroolsParameterHandling;
 36  
 import org.boretti.drools.integration.drools5.DroolsSessionType;
 37  
 import org.boretti.drools.integration.drools5.annotations.DroolsMethod;
 38  
 import org.boretti.drools.integration.drools5.annotations.DroolsParameter;
 39  
 import org.boretti.drools.integration.drools5.annotations.DroolsVariable;
 40  
 import org.boretti.drools.integration.drools5.exceptions.IncompatibleAnnotationDroolsError;
 41  
 
 42  
 
 43  
 /**
 44  
  * @author mbo
 45  
  * 
 46  
  */
 47  
 class DroolsProxy<T> implements InvocationHandler {
 48  
         
 49  110
         private final Logger logger = Logger.getLogger(this.getClass());
 50  
         
 51  288
         private static class ProductFactResult {
 52  144
                 private List<Object> fact= new ArrayList<Object>();
 53  144
                 private Class<?> returnType=null;
 54  
                 
 55  
                 /**
 56  
                  * @return the fact
 57  
                  */
 58  
                 public List<Object> getFact() {
 59  236
                         return fact;
 60  
                 }
 61  
                 /**
 62  
                  * @param fact the fact to set
 63  
                  */
 64  
                 public void setFact(List<Object> fact) {
 65  0
                         this.fact = fact;
 66  0
                 }
 67  
                 /**
 68  
                  * @return the returnType
 69  
                  */
 70  
                 public Class<?> getReturnType() {
 71  154
                         return returnType;
 72  
                 }
 73  
                 /**
 74  
                  * @param returnType the returnType to set
 75  
                  */
 76  
                 public void setReturnType(Class<?> returnType) {
 77  6
                         this.returnType = returnType;
 78  6
                 }
 79  
         }
 80  
                         
 81  
         private ProductFactResult produceFact(Method m,Object[] args) {
 82  144
                 ProductFactResult pfr = new ProductFactResult();
 83  144
                 if (args==null) return pfr;
 84  84
                 if (args.length==0) return pfr;
 85  84
                 Annotation[][] ass = m.getParameterAnnotations();
 86  178
                 for(int i=0;i<args.length;i++) {
 87  94
                         Annotation[] as = ass[i];
 88  94
                         DroolsParameterHandling handling = DroolsParameterHandling.NONE;
 89  94
                         for(Annotation a:as) {
 90  20
                                 if (a.annotationType().equals(DroolsParameter.class)) {
 91  20
                                         handling = ((DroolsParameter)a).handling();
 92  20
                                         break;
 93  
                                 }
 94  
                         }
 95  94
                         if (handling==null) handling = DroolsParameterHandling.NONE;
 96  94
                         if (DroolsParameterHandling.NONE.equals(handling)) {
 97  74
                                 pfr.getFact().add(args[i]);
 98  20
                         } else if (DroolsParameterHandling.IGNORED.equals(handling)) {
 99  18
                         } else if (DroolsParameterHandling.GENERICDEFINITION.equals(handling)) {
 100  6
                                 if (args[i] instanceof Class) pfr.setReturnType((Class<?>)args[i]);
 101  
                                 else {
 102  0
                                         String msg = "GenericDefinition can only be used on Class parameter";
 103  0
                                         logger.error(msg);
 104  0
                                         throw new IncompatibleAnnotationDroolsError(msg);
 105  
                                 }
 106  12
                         } else if (DroolsParameterHandling.TOFLAT1.equals(handling)) {
 107  8
                                 if (args[i] instanceof Object[]) for(Object o:(Object[])args[i]) pfr.getFact().add(o);
 108  4
                                 else if (args[i] instanceof Collection) for(Object o:(Collection<?>)args[i]) pfr.getFact().add(o);
 109  2
                                 else pfr.getFact().add(args[i]);
 110  4
                         } else if (DroolsParameterHandling.TOFLATALL.equals(handling)) {
 111  4
                                 addFlat(pfr.getFact(),args[i]);
 112  
                         } 
 113  
                 }
 114  84
                 return pfr;
 115  
         }
 116  
         
 117  
         private void addFlat(List<Object> fact,Object args) {
 118  20
                 if (args instanceof Object[]) for(Object o:(Object[])args) addFlat(fact,o);
 119  14
                 else if (args instanceof Collection) for(Object o:(Collection<?>)args) addFlat(fact,o);
 120  10
                 else fact.add(args);
 121  20
         }
 122  
 
 123  
         /*
 124  
          * (non-Javadoc)
 125  
          * 
 126  
          * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
 127  
          *      java.lang.reflect.Method, java.lang.Object[])
 128  
          */
 129  
         @Override
 130  
         public Object invoke(final Object proxy, final Method method, final Object[] args)
 131  
                         throws Throwable {
 132  174
                 if (method.getDeclaringClass().equals(clazz)) {
 133  172
                         DroolsMethod annotation = null;
 134  172
                         DroolsVariable variable = null;
 135  
                         try {
 136  172
                                 annotation = method.getAnnotation(DroolsMethod.class);
 137  172
                         } catch (NullPointerException ex) {}
 138  
                         try {
 139  172
                                 variable = method.getAnnotation(DroolsVariable.class);
 140  172
                         } catch (NullPointerException ex) {}
 141  172
                         if (annotation!=null && variable!=null) {
 142  2
                                 String msg ="Method is annotated with both @DroolsMethod and @DroolsVariable.";
 143  2
                                 logger.error(msg);
 144  2
                                 throw new IncompatibleAnnotationDroolsError(msg);
 145  
                         }
 146  170
                         if (variable!=null) {
 147  26
                                 String methodName = method.getName();
 148  26
                                 if (!methodName.startsWith("set")) {
 149  2
                                         String msg ="Method is annotated with @DroolsVariable and name is not set<something>.";
 150  2
                                         logger.error(msg);
 151  2
                                         throw new IncompatibleAnnotationDroolsError(msg);
 152  
                                 }
 153  24
                                 if (method.getParameterTypes().length!=1) {
 154  2
                                         String msg ="Method is annotated with @DroolsVariable and name is set<something>, but number of parameter is not 1.";
 155  2
                                         logger.error(msg);
 156  2
                                         throw new IncompatibleAnnotationDroolsError(msg);
 157  
                                 }
 158  22
                                 if (!method.getReturnType().equals(Void.TYPE)) {
 159  2
                                         String msg ="Method is annotated with @DroolsVariable and name is set<something> and number of parameter is 1, but return type is not void.";
 160  2
                                         logger.error(msg);
 161  2
                                         throw new IncompatibleAnnotationDroolsError(msg);
 162  
                                 }
 163  20
                                 String fieldName = methodName.substring(3,4).toLowerCase()+methodName.substring(4);
 164  20
                                 Object data = args[0];
 165  20
                                 Map<String,DroolsVariableImplementation> fields = inter.getFields();
 166  20
                                 if (data==null) {
 167  4
                                         if (logger.isDebugEnabled()) logger.debug("Received parameter is null. Retracting field for next call");
 168  4
                                         if (fields.containsKey(fieldName)) fields.remove(fieldName);
 169  
                                 } else {
 170  16
                                         fields.put(fieldName, new DroolsVariableImplementation(variable.global(), data));
 171  
                                 }
 172  20
                                 return null;
 173  
                         } else {
 174  144
                                 Class<?> c = method.getReturnType();
 175  144
                                 DroolsSessionType session = DroolsSessionType.NONE;
 176  144
                                 if (annotation!=null && annotation.session()!=null) session = annotation.session();        
 177  144
                                 ProductFactResult facts = produceFact(method,args);
 178  144
                                 List<Object> fact = facts.getFact();
 179  144
                                 if (c.equals(Future.class)) {
 180  4
                                         if (facts.getReturnType()!=null) c=facts.getReturnType();
 181  4
                                         DroolsFutureTask<T> dft = new DroolsFutureTask<T>(this, proxy,(facts.getReturnType()!=null)?c:null, method, session, args,fact);
 182  4
                                         executors.execute(dft);
 183  4
                                         return dft;
 184  
                                 }
 185  140
                                 if (facts.getReturnType()!=null) c=facts.getReturnType();
 186  140
                                 return invokeInternal(proxy,method,c,session,args,fact);
 187  
                         }
 188  2
                 } else if (method.getDeclaringClass().equals(DroolsInterface.class)) {
 189  2
                         return method.invoke(inter, args);
 190  
                 }
 191  0
                 String msg = "Unable to handle the received parameter";
 192  0
                 logger.error(msg);
 193  0
                 throw new IllegalArgumentException(msg);
 194  
         }
 195  
         
 196  
         public Object invokeInternal(Object proxy, Method method, Class<?> returnType,DroolsSessionType session, Object[] args,List<Object> fact)
 197  
         throws Throwable {
 198  144
                 Iterator<?> result=null;
 199  144
                 if (DroolsSessionType.NONE.equals(session)) {
 200  80
                         result = inter.runStatelessSession(fact);
 201  64
                 } else if (DroolsSessionType.NEW.equals(session)) {
 202  16
                         if (inter.getCurrentSession()!=null) {
 203  2
                                 inter.getCurrentSession().halt();
 204  2
                                 inter.setCurrentSession(null);
 205  
                         }
 206  16
                         result=inter.runStatefulSession(fact, false);
 207  48
                 } else if (DroolsSessionType.END.equals(session)) {
 208  10
                         result=inter.runStatefulSession(fact, true);
 209  8
                         inter.getCurrentSession().halt();
 210  8
                         inter.setCurrentSession(null);
 211  38
                 } else if (DroolsSessionType.JOIN.equals(session)) {
 212  16
                         if (inter.getCurrentSession()==null) result = inter.runStatelessSession(fact);
 213  10
                         else result = inter.runStatefulSession(fact, true);
 214  22
                 } else if (DroolsSessionType.REQUIRE.equals(session)) {
 215  22
                         result = inter.runStatefulSession(fact, true);
 216  
                 }
 217  138
                 return inter.getResult(returnType, result);
 218  
         }
 219  
         
 220  
         private Class<T> clazz;
 221  
         
 222  
         private DroolsInterfaceImplementation<T> inter;
 223  
                 
 224  110
         public DroolsProxy(Class<T> clazz,DroolsInterfaceImplementation<T> inter) {
 225  110
                 this.clazz=clazz;
 226  110
                 this.inter=inter;
 227  110
         }
 228  
         
 229  2
         private static final ExecutorService executors = Executors.newCachedThreadPool();
 230  
 
 231  
 
 232  
 }