001    /*
002      Copyright (C) 2004 Laurent Martelli <laurent@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.timestamp;
019    
020    import java.util.Iterator;
021    import org.aopalliance.intercept.ConstructorInvocation;
022    import org.aopalliance.intercept.MethodInvocation;
023    import org.apache.log4j.Logger;
024    import org.objectweb.*;
025    import org.objectweb.jac.core.AspectComponent;
026    import org.objectweb.jac.core.Interaction;
027    import org.objectweb.jac.core.NameRepository;
028    import org.objectweb.jac.core.rtti.ClassItem;
029    import org.objectweb.jac.core.rtti.ClassRepository;
030    import org.objectweb.jac.core.rtti.CollectionItem;
031    import org.objectweb.jac.core.rtti.FieldItem;
032    import org.objectweb.jac.core.rtti.RttiAC;
033    import org.objectweb.jac.util.ExtBoolean;
034    
035    public class TimestampAC extends AspectComponent implements TimestampConf {
036        static final Logger logger = Logger.getLogger("timestamp");
037        
038        public static final String FOLLOW = "TimestampAC.FOLLOW";
039    
040        public void declareTimestampedClasses(String classExpr, 
041                                              String wrappeeExpr,
042                                              String repositoryName) 
043        {
044            pointcut("ALL",classExpr,"MODIFIERS",
045                     new Wrapper(this,repositoryName),null);
046        }
047    
048        public void followLink(FieldItem link, boolean follow) {
049            logger.info("Setting follow on "+link);
050            link.setAttribute(FOLLOW,ExtBoolean.valueOf(follow));
051        }
052    
053        public static class Wrapper extends org.objectweb.jac.core.Wrapper {
054            public Wrapper(AspectComponent ac, String stampsName) {
055                super(ac);
056                this.stampsName = stampsName;
057            }
058    
059            String stampsName;
060            Timestamps stamps; 
061    
062            void setStamps() {
063                stamps = (Timestamps)NameRepository.get().getObject(stampsName);
064            }
065    
066            public Object invoke(MethodInvocation invocation) throws Throwable {
067                Object res = invocation.proceed();
068                setStamps();
069                if (stamps!=null) {
070                    Interaction interaction = (Interaction)invocation;
071                    touch(interaction.wrappee,interaction.getClassItem());
072                }
073                return res;
074            }
075    
076            void touch(Object object, ClassItem cl) {
077                logger.info("touch "+object);
078                stamps.touch(object);
079                if (cl==null) {
080                    cl = ClassRepository.get().getClass(object);
081                }
082                FieldItem[] fields = cl.getFields();
083                for (int i=0; i<fields.length; i++) {
084                    FieldItem field= fields[i];
085                    logger.debug("Testing field "+field);
086                    boolean followed = false;
087                    if (field.isReference()) {
088                        FieldItem opposite = (FieldItem)field.getOppositeRole();
089                        if (opposite!=null && opposite.isAggregation()) {
090                            logger.debug("  opposite is aggregation");
091                            followed = true;
092                            Object touched = fields[i].getThroughAccessor(object);
093                            if (touched!=null) 
094                                touch(touched,null);
095                        }
096                    } 
097    
098                    if (!followed && field.getBoolean(FOLLOW, false)) {
099                        logger.debug("  must be followed");
100                        if (field instanceof CollectionItem) {
101                            Iterator it = ((CollectionItem)field).getActualCollectionThroughAccessor(object).iterator();
102                            while (it.hasNext()) {
103                                Object touched = it.next();
104                                if (touched!=null) 
105                                    touch(touched,null);
106                                else
107                                    logger.debug("  Not touching null value in "+field.getLongName());
108                            }
109                        } else {
110                            Object touched = field.getThroughAccessor(object);
111                            if (touched!=null)
112                                touch(touched,null);
113                            else
114                                logger.info("  Not touching null value "+field.getLongName());
115                        }
116                    }
117                }
118            }
119    
120            public Object construct(ConstructorInvocation invocation) throws Throwable {
121                return invocation.proceed();
122            }
123        }
124    }