001 /* 002 Copyright (C) 2001-2003 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, but 010 WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 USA */ 018 019 package org.objectweb.jac.core; 020 021 import java.util.Arrays; 022 import java.util.Collection; 023 import java.util.HashSet; 024 import java.util.Iterator; 025 import java.util.List; 026 import java.util.Vector; 027 import org.apache.log4j.Logger; 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.ExtArrays; 034 import org.objectweb.jac.util.Predicate; 035 import org.objectweb.jac.util.Strings; 036 037 /** 038 * This class allows the JAC applications to access objects that are 039 * managed within the current VM or that can be defined outside of it 040 * by the currently woven aspects. 041 * 042 * <p>By default, the object repository methods only return the JAC 043 * objects that are accessible through the 044 * <code>JacObject.getObject</code> methods. However, since it upcalls 045 * the <code>ACManager.whenGetObjects()</code> method, all the aspect 046 * components can change the returned object set. 047 * 048 * <p>As typical examples: 049 * 050 * <ul><li>the persistence aspects may load objects that correspond to 051 * the get filter so that the application can see the objects stored 052 * in the database 053 * 054 * <li>the owning aspect can remove some objects from the returned 055 * collection if the current user is not allowed to access them 056 * 057 * <li>the distribution aspect can initiate a distributed seek over 058 * all the containers of the topology to add some objects that 059 * correspond to the filter but that may have not been declared yet in 060 * this VM</ul> 061 * 062 * @see ACManager#whenGetObjects(Collection,ClassItem) 063 * @see AspectComponent#whenGetObjects(Collection,ClassItem) 064 */ 065 066 public class ObjectRepository { 067 static Logger logger = Logger.getLogger("repository"); 068 static Logger loggerGet = Logger.getLogger("repository.getobjects"); 069 070 /** Memorize the JAC object instances of the system. */ 071 transient static org.objectweb.jac.util.WeakHashMap instances = new org.objectweb.jac.util.WeakHashMap(); 072 073 /** Fast access for the JAC objects. Integer -> Object */ 074 transient static java.util.WeakHashMap reverseInstances = new java.util.WeakHashMap(); 075 076 /** The number of created JAC objects. */ 077 transient static int instancecount = 0; 078 079 public static void register(Object wrappee) { 080 // This test is not useful anymore since register should be 081 // called only once 082 //if(instances.contains(wrappee)) return; 083 // do not register collections 084 if (wrappee instanceof org.objectweb.jac.lib.java.util.Vector || 085 wrappee instanceof org.objectweb.jac.lib.java.util.HashSet || 086 wrappee instanceof org.objectweb.jac.lib.java.util.Hashtable || 087 wrappee instanceof org.objectweb.jac.lib.java.util.HashMap) { 088 return; 089 } 090 //System.out.println("registering "+wrappee); 091 Integer inst = new Integer(instancecount++); 092 instances.put(inst,wrappee); 093 logger.debug(wrappee+"->"+inst); 094 reverseInstances.put(wrappee,inst); 095 } 096 097 /** 098 * This method deletes the given JAC object by removing it from 099 * the different collections it has been inserted into by the 100 * system. 101 * 102 * <p>The JAVA GC, will then be able to free it from memory on its 103 * next run. 104 */ 105 public static void delete(Wrappee object) { 106 logger.debug("delete "+object); 107 // remove from system list 108 instances.remove(reverseInstances.get(object)); 109 reverseInstances.remove(object); 110 // remove from name repository 111 NameRepository.get().unregisterObject(object); 112 ACManager.getACM().whenDeleted(object); 113 } 114 115 public static void free(Wrappee object) { 116 // remove from system list 117 instances.remove(object); 118 reverseInstances.remove(object); 119 // remove from name repository 120 NameRepository.get().unregisterObject(object); 121 ACManager.getACM().whenFree(object); 122 } 123 124 /** 125 * This method returns the nth object that has been created 126 * in the Jac system. 127 * 128 * @param nth the object index 129 * @return the requested object 130 */ 131 public static Object getMemoryObject(int nth) { 132 return instances.get(new Integer(nth)); 133 } 134 135 136 /** 137 * This method returns the index of anobject that has been created 138 * in the Jac system. 139 * 140 * @param obj the object 141 * @return the index of the object 142 */ 143 public static int getMemoryObjectIndex(Object obj) { 144 return ((Integer)reverseInstances.get(obj)).intValue(); 145 } 146 147 148 /** 149 * This method returns the object counter of the Jac system (last 150 * created object is <code>getObject(objectCount()-1)</code>). 151 * 152 * @return the number of created objects 153 */ 154 public static int memoryObjectCount() { 155 return instances.size(); //instancecount; 156 } 157 158 159 /** 160 * This method returns all the JAC objects that are in the current 161 * JVM memory (use <code>getObjects()</code> to get all the objects 162 * handled by the woven aspects -- such as distribution or 163 * persistence). 164 * 165 * @return all the JAC objects in memory 166 * 167 * @see #getObjects() 168 * @see #getObjects(ClassItem) 169 * @see #getMemoryObjects(ClassItem) 170 */ 171 public static Collection getMemoryObjects() { 172 return instances.values(); 173 } 174 175 176 /** 177 * This method returns all the Jac objects of a given type as an 178 * array. 179 * 180 * @param type the type to get 181 * @return all the Jac objects of a given type 182 * 183 * @see #getObjects() 184 * @see #getObjects(ClassItem) 185 * @see #getMemoryObjects(ClassItem) 186 */ 187 public static Object[] getMemoryObjects(String type) { 188 ClassItem cl = null; 189 try { 190 cl = ClassRepository.get().getClass(type); 191 } catch( Exception e ) { 192 e.printStackTrace(); 193 return ExtArrays.emptyObjectArray; 194 } 195 return getMemoryObjects(cl); 196 } 197 198 199 /** 200 * This method returns all the JAC objects of a given type as an 201 * array. 202 * 203 * @param cl the type to get 204 * @return all the JAC objects of a given type 205 * 206 * @see #getObjects() 207 * @see #getObjects(ClassItem) 208 * @see #getMemoryObjects() 209 */ 210 public static Object[] getMemoryObjects(ClassItem cl) { 211 Vector objects = new Vector(); 212 213 Class type = cl.getActualClass(); 214 Iterator it = getMemoryObjects().iterator(); 215 while(it.hasNext()) { 216 Object cur = it.next(); 217 if (type.isAssignableFrom(cur.getClass())) { 218 objects.add(cur); 219 } 220 } 221 222 logger.debug("getMemoryObjects("+cl+") -> "+objects); 223 return objects.toArray(); 224 } 225 226 /** 227 * This method returns all the JAC objects that match any of the 228 * given types. 229 * 230 * @param types the types to get 231 * @return all the JAC objects that match any of the given types 232 */ 233 public static Object[] getMemoryObjects(String[] types) { 234 Vector objects = new Vector(); 235 for (int i=0; i<types.length; i++) { 236 try { 237 objects.addAll( 238 Arrays.asList( 239 getMemoryObjects(ClassRepository.get().getClass(types[i]))) ); 240 } catch( Exception e ) { 241 e.printStackTrace(); 242 } 243 } 244 return objects.toArray(); 245 } 246 247 /** 248 * This method returns all the Jac objects that match any of the 249 * given types. 250 * 251 * @param types the types to get 252 * @return all the Jac objects that match any of the given types 253 */ 254 public static Object[] getMemoryObjects(ClassItem[] types) { 255 Vector objects = new Vector(); 256 for (int i=0; i<types.length; i++) { 257 objects.addAll( Arrays.asList(getMemoryObjects(types[i])) ); 258 } 259 return objects.toArray(); 260 } 261 262 /** 263 * Gets all the instantiated JAC objects on the current VM and on 264 * all the external objects sources known by the aspects (maybe 265 * resticed by some aspects). 266 * 267 * @return a collection of acessible objects 268 * 269 * @see #getObjects(ClassItem) 270 * @see #getMemoryObjects() 271 */ 272 public static Collection getObjects() { 273 HashSet objects = new HashSet(instances.values()); 274 ((ACManager)ACManager.get()).whenGetObjects(objects,null); 275 return objects; 276 } 277 278 /** 279 * Gets all the JAC objects instances of a given class on the 280 * current VM and on all the external objects sources known by the 281 * aspects (maybe resticed by some aspects). 282 * 283 * @return a collection of acessible instances of <code>cl</code> 284 * 285 * @see #getObjects(Class) 286 */ 287 public static Collection getObjects(ClassItem cl) { 288 loggerGet.debug("getObjects "+cl); 289 String repName = (String)cl.getAttribute(RttiAC.REPOSITORY_NAME); 290 CollectionItem repCollection = 291 (CollectionItem)cl.getAttribute(RttiAC.REPOSITORY_COLLECTION); 292 Object repository = null; 293 if (repName!=null) { 294 repository = NameRepository.get().getObject(repName); 295 if (repository==null) 296 loggerGet.error(cl+": no such repository object "+repName); 297 } 298 if (repository!=null && repCollection!=null) { 299 loggerGet.debug("Using repository "+repName+"."+repCollection.getName()); 300 return FieldItem.getPathLeaves(repCollection,repository); 301 } else { 302 List objects = new Vector(Arrays.asList(getMemoryObjects(cl))); 303 ((ACManager)ACManager.get()).whenGetObjects(objects,cl); 304 return objects; 305 } 306 } 307 308 /** 309 * Gets all the JAC objects instances of a given class on the 310 * current VM and on all the external objects sources known by the 311 * aspects (maybe resticed by some aspects). 312 * 313 * @return a collection of acessible instances of <code>cl</code> 314 * @see #getObjects(ClassItem) */ 315 public static Collection getObjects(Class cl) { 316 return getObjects(ClassRepository.get().getClass(cl)); 317 } 318 319 /** 320 * Get all instances of a class whose field relation contains the 321 * given value. If a repository has been defined for the class, 322 * only objects belonging to the repository are returned. 323 * 324 * @param cl the class 325 * @param relation the relation 326 * @param value the value that the relation must contain 327 * 328 * @see org.objectweb.jac.core.rtti.RttiConf#defineRepository(ClassItem,String,CollectionItem) 329 */ 330 public static Collection getObjectsWhere(ClassItem cl, 331 FieldItem relation, Object value) { 332 loggerGet.debug("getObjectsWhere "+cl+","+relation+","+value); 333 Collection objects = getObjects(cl); 334 Vector result = new Vector(); 335 FieldItem field = relation.getField(); 336 Iterator it = objects.iterator(); 337 while (it.hasNext()) { 338 Object object = it.next(); 339 for (Iterator j=relation.getSubstances(object).iterator(); 340 j.hasNext();) { 341 Object substance = j.next(); 342 if (field instanceof CollectionItem) { 343 if (((CollectionItem)field). 344 getActualCollectionThroughAccessor(substance).contains(value)) { 345 result.add(object); 346 break; 347 } 348 } else if (field.isReference()) { 349 if (field.getThroughAccessor(substance)==value) { 350 result.add(object); 351 break; 352 } 353 } else { 354 Object testedValue = field.getThroughAccessor(substance); 355 if ((value==null && testedValue==null) || (value!=null && value.equals(testedValue))) { 356 result.add(object); 357 break; 358 } 359 } 360 } 361 } 362 return result; 363 } 364 365 366 /** 367 * Get all instances of class cl which match a predicate 368 * @param cl the class 369 * @param filter the predicate to be matched 370 * @return a collection whose all items are such that filter(item)==true 371 */ 372 public static Collection getObjectsWhere(ClassItem cl, Predicate filter) { 373 loggerGet.debug("getObjectsWhere "+cl+","+filter.getClass().getName()); 374 Collection objects = getObjects(cl); 375 Vector result = new Vector(); 376 Iterator it = objects.iterator(); 377 while (it.hasNext()) { 378 Object object = it.next(); 379 if (filter.apply(object)) { 380 result.add(object); 381 } 382 } 383 return result; 384 } 385 386 public void dump() { 387 } 388 389 }