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 }