001    /*
002      Copyright (C) 2001-2002 Renaud Pawlak <renaud@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
017    
018    package org.objectweb.jac.aspects.tracing;
019    
020    import java.util.*;
021    import org.aopalliance.intercept.ConstructorInvocation;
022    import org.aopalliance.intercept.MethodInvocation;
023    import org.objectweb.jac.core.*;
024    import org.objectweb.jac.core.rtti.ClassItem;
025    import org.objectweb.jac.core.rtti.ClassRepository;
026    
027    /**
028     * This counter must wrap the methods of which calls have to be
029     * counted. It extends the simple counting wrapper to provide 2
030     * optimization methods when client methods call several times the
031     * method wrapped by <code>incr</code>. In these cases, the counter is
032     * direcly incremented by the number of times the <code>incr</code>
033     * method has to be called.
034     *
035     * <p>In order to avoid redundancy, <code>incr</code> must not be
036     * called if <code>incrWithArg</code> or <code>incrWithField</code>
037     * have already been called. To perform this contextual test, use the
038     * before and after running wrapper methods of the aspect
039     * component. */
040    
041    public class OptimizedCountingWrapper extends SimpleCountingWrapper {
042    
043       /** The field on which the optimization can be done. */
044       String field = null;
045    
046       /** The argument on which the optimization can be done. */
047       int arg = 0;
048       
049       /**
050        * Create the counter and parametrize it regarding the base program
051        * shape.
052        *
053        * @param c the used counter
054        * @param field the field that is used to optimize the counting */
055    
056       public OptimizedCountingWrapper(AspectComponent ac, Counter c, String field) {
057          super(ac,c);
058          this.field = field;
059       }
060    
061       /**
062        * Create the counter and parametrize it regarding the base program
063        * shape.
064        *
065        * @param c the used counter 
066        * @param arg the argument number that used to optimize the
067        * counting */
068    
069       public OptimizedCountingWrapper(AspectComponent ac, Counter c, int arg) {
070          super(ac,c);
071          this.arg = arg;
072       }
073    
074       /**
075        * This wrapping method increments the counter with the field when
076        * the wrapped method is called. It is an optimization for the incr
077        * method.
078        *
079        * @return the return value of the wrapped method
080        * @see SimpleCountingWrapper#incr(Interaction) */
081    
082       public Object incrWithField(Interaction interaction) {
083          attrdef( "tracing.globalIncr", "" );
084          Object ret = proceed(interaction);
085          ClassItem cl=ClassRepository.get().getClass(interaction.wrappee);
086          Object fval = cl.getField(field).get(interaction.wrappee);
087          if (fval == null) {
088             System.out.println( "<<< Counting aspect says: the field to count (" + 
089                                 field + ") is null or does not exist... >>>" );
090             return ret;
091          }
092          if (fval.getClass().isArray()) {
093             counter.incr(((Object[])fval).length);
094          } else if ( fval instanceof Collection ) {
095             counter.incr(((Collection)fval).size());
096          } else {
097             /** this type is not supported... */
098             System.out.println( "<<< Counting aspect says: the field to count (" + 
099                                 field + ") is not of a supported type... >>>" );
100             return ret;
101          }
102          printCounter();
103          return ret;
104       }
105    
106       /**
107        * This wrapping method increments the counter with the argument
108        * value when the wrapped method is called. It is an optimization
109        * for the <code>incr</code> method.
110        *
111        * @return the return value of the wrapped method
112        * @see SimpleCountingWrapper#incr(Interaction) */
113    
114       public Object incrWithArg(Interaction interaction) {
115          attrdef( "tracing.globalIncr", "" );
116          Object ret = proceed(interaction);
117          counter.incr( ((Integer)interaction.args[arg]).intValue() );
118          printCounter();
119          return ret;
120       }
121    
122        public Object invoke(MethodInvocation invocation) throws Throwable {
123            if (field==null)
124                return incrWithArg((Interaction)invocation);
125            else
126                return incrWithField((Interaction)invocation);
127        }
128    
129        public Object construct(ConstructorInvocation invocation) throws Throwable {
130            if (field==null)
131                return incrWithArg((Interaction)invocation);
132            else
133                return incrWithField((Interaction)invocation);
134        }  
135    
136    }