1
2
3
4
5
6
7
8 /
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class DefaultCacheFactory
82 implements CacheFactorySPI, CacheFactory
83 {
84
85 /*** Type constant for HashMap. */
86 public static final String HASH_MAP_TYPE = "HashMap";
87
88 /*** Type constant for TimeoutMap. */
89 public static final String TIMEOUT_MAP_TYPE = "TimeoutMap";
90
91 /*** Type constant for LRUMap. */
92 public static final String LRU_MAP_TYPE = "LRUMap";
93
94 /*** Type constant for SoftMap. */
95 public static final String SOFT_MAP_TYPE = "SoftMap";
96
97 /*** Type constant for FactoryMap. */
98 public static final String FACTORY_MAP_TYPE = "FactoryMap";
99
100 /*** Type constant for DistributedMap. */
101 public static final String DISTRIBUTED_MAP_TYPE = "DistributedMap";
102
103 /*** Type constant for StatisticsMap. */
104 public static final String STATISTICS_MAP_TYPE = "StatisticsMap";
105
106 /*** Type constant for ForgetFullMap. */
107 public static final String FORGETFULL_MAP_TYPE = "ForgetfullMap";
108
109 /*** The default implementation HashMap implementation. */
110 public static final String HASH_MAP_CLASS_DEFALUT =
111 "java.util.HashMap";
112
113 /*** The default implementation TimeoutMap implementation. */
114 public static final String TIMEOUT_MAP_CLASS_DEFALUT =
115 "org.objectledge.cache.impl.TimeoutMapImpl";
116
117 /*** The default implementation LRUMap implementation. */
118 public static final String LRU_MAP_CLASS_DEFALUT =
119 "org.objectledge.cache.impl.LRUMapImpl";
120
121 /*** The default implementation SoftMap implementation. */
122 public static final String SOFT_MAP_CLASS_DEFALUT =
123 "org.objectledge.cache.impl.SoftMapImpl";
124
125 /*** The default implementation DistributedMap implementation. */
126 public static final String DISTRIBUTED_MAP_CLASS_DEFALUT =
127 "org.objectledge.cache.impl.DistributedMapImpl";
128
129 /*** The default implementation FactoryMap implementation. */
130 public static final String FACTORY_MAP_CLASS_DEFALUT =
131 "org.objectledge.cache.impl.FactoryMapImpl";
132
133 /*** The default implementation StatisticsMap implementation. */
134 public static final String STATISTICS_MAP_CLASS_DEFALUT =
135 "org.objectledge.cache.impl.StatisticsMapImpl";
136
137 /*** The default implementation StatisticsMap implementation. */
138 public static final String FORGETFULL_MAP_CLASS_DEFALUT =
139 "org.objectledge.cache.impl.ForgetfullMapImpl";
140
141
142 /*** The registered StatisticsMaps */
143 private List<StatisticsMap> statistics = new ArrayList<StatisticsMap>();
144
145 /*** Mapping of *_TYPE constants into configured implementation classes. */
146 private Map<String,Class> implClasses = new HashMap<String,Class>();
147
148 /*** instance prepared configurations map. */
149 private Map<String,Configuration> instanceConfigurations = new HashMap<String,Configuration>();
150
151 /*** Factory configurations */
152 private Map<String,Configuration> factoryConfigurations = new HashMap<String,Configuration>();
153
154 /*** Configured map instances. */
155 private Map<String,Map> instances = new HashMap<String,Map>();
156
157 /*** DelayedUpdate queue (target update time -> object)*/
158 private SortedMap<Long,Set<DelayedUpdate>> queue = new TreeMap<Long,Set<DelayedUpdate>>();
159
160 /*** DelayedUpdate queue helper map (object -> target update time)*/
161 private Map<DelayedUpdate,Long> queueHelper = new HashMap<DelayedUpdate,Long>();
162
163 /*** The configuration */
164 private Configuration config;
165
166 /*** The logging facility. */
167 private Logger logger;
168
169 /*** The thread pool */
170 private ThreadPool threadPool;
171
172 /*** The notification */
173 private Notification notification;
174
175 /*** The persistence */
176 private Persistence persistence;
177
178
179
180 /***
181 * Component constructor.
182 *
183 * @param config the configuration.
184 * @param logger the logger.
185 * @param threadPool the thread pool.
186 * @param notification the notification.
187 * @param persistence the persistence.
188 * @throws ConfigurationException thrown if configuration is invalid.
189 * @throws ClassNotFoundException thrown if one of the class not found.
190 */
191 public DefaultCacheFactory(Configuration config, Logger logger,
192 ThreadPool threadPool, Notification notification,
193 Persistence persistence)
194 throws ConfigurationException, ClassNotFoundException
195 {
196 this.config = config;
197 this.logger = logger;
198 this.threadPool = threadPool;
199 this.notification = notification;
200 this.persistence = persistence;
201
202 Map<String, String> classMap = new HashMap<String, String>();
203 classMap.put(HASH_MAP_TYPE, HASH_MAP_CLASS_DEFALUT);
204 classMap.put(TIMEOUT_MAP_TYPE, TIMEOUT_MAP_CLASS_DEFALUT);
205 classMap.put(LRU_MAP_TYPE, LRU_MAP_CLASS_DEFALUT);
206 classMap.put(SOFT_MAP_TYPE, SOFT_MAP_CLASS_DEFALUT);
207 classMap.put(DISTRIBUTED_MAP_TYPE, DISTRIBUTED_MAP_CLASS_DEFALUT);
208 classMap.put(FACTORY_MAP_TYPE, FACTORY_MAP_CLASS_DEFALUT);
209 classMap.put(STATISTICS_MAP_TYPE, STATISTICS_MAP_CLASS_DEFALUT);
210 classMap.put(FORGETFULL_MAP_TYPE, FORGETFULL_MAP_CLASS_DEFALUT);
211
212 Map<String, Class> ifaceMap = new HashMap<String, Class>();
213 ifaceMap.put(HASH_MAP_TYPE, Map.class);
214 ifaceMap.put(TIMEOUT_MAP_TYPE, TimeoutMap.class);
215 ifaceMap.put(LRU_MAP_TYPE, LRUMap.class);
216 ifaceMap.put(SOFT_MAP_TYPE, SoftMap.class);
217 ifaceMap.put(DISTRIBUTED_MAP_TYPE, DistributedMap.class);
218 ifaceMap.put(FACTORY_MAP_TYPE, FactoryMap.class);
219 ifaceMap.put(STATISTICS_MAP_TYPE, StatisticsMap.class);
220 ifaceMap.put(FORGETFULL_MAP_TYPE, ForgetfullMap.class);
221
222 Configuration[] custom = config.getChildren("implementation");
223 for(int i=0; i<custom.length; i++)
224 {
225 String type = custom[i].getAttribute("type");
226 String clazz = custom[i].getAttribute("class");
227 classMap.put(type,clazz);
228 }
229 Iterator it = classMap.keySet().iterator();
230 while(it.hasNext())
231 {
232 String type = (String)it.next();
233 String clazz = (String)classMap.get(type);
234 Class iface = (Class)ifaceMap.get(type);
235 if(iface == null)
236 {
237 iface = Map.class;
238 }
239 initImpl(type, clazz, iface);
240 }
241
242 Configuration[] aliases = config.getChildren("alias");
243 for(int i = 0; i < aliases.length; i++)
244 {
245 String name = aliases[i].getAttribute("name");
246 instanceConfigurations.put(name,aliases[i]);
247 }
248 Configuration[] factories = config.getChildren("factory");
249 for(int i = 0; i < factories.length; i++)
250 {
251 String name = factories[i].getAttribute("name");
252 factoryConfigurations.put(name,factories[i]);
253 }
254 Configuration[] instanceNodes = config.getChildren("instance");
255 for(int i =0; i < instanceNodes.length;i++)
256 {
257 String name = instanceNodes[i].getAttribute("name");
258 Configuration instanceConfig = instanceNodes[i];
259 String alias = instanceNodes[i].getAttribute("alias",null);
260 if(alias != null)
261 {
262 instanceConfig = (Configuration)instanceConfigurations.get(alias);
263 if(instanceConfig == null)
264 {
265 throw new ComponentInitializationError(
266 "cannot find conifured alias: '"+alias+"'");
267 }
268 }
269 Map map = buildInstance(name, instanceConfig);
270 instances.put(name, map);
271 }
272 threadPool.runDaemon(new DelayedUpdateTask());
273 }
274
275
276
277 /***
278 * {@inheritDoc}
279 */
280 public Map getMap(String type)
281 {
282 Class cl = (Class)implClasses.get(type);
283 if(cl == null)
284 {
285 throw new IllegalArgumentException("unknown map type "+type);
286 }
287 try
288 {
289 return (Map)cl.newInstance();
290 }
291
292 catch(VirtualMachineError t)
293 {
294 throw t;
295 }
296 catch(ThreadDeath t)
297 {
298 throw t;
299 }
300 catch(Throwable t)
301 {
302 throw new RuntimeException("failed to instantaite map of type "+type, t);
303 }
304
305 }
306
307 /***
308 * {@inheritDoc}
309 */
310 public synchronized Map getInstance(String name)
311 {
312 Map map = (Map)instances.get(name);
313 if(map == null)
314 {
315 throw new IllegalArgumentException("configuration "+name+
316 " not defined in config file");
317 }
318 return map;
319 }
320
321 /***
322 * {@inheritDoc}
323 */
324 public synchronized Map getInstance(String name, String configAlias)
325 throws ConfigurationException
326 {
327 Map map = (Map)instances.get(name);
328 if(map == null)
329 {
330 Configuration instanceConfiguration =
331 (Configuration)instanceConfigurations.get(configAlias);
332 if(instanceConfiguration == null)
333 {
334 throw new IllegalArgumentException("configuration "+configAlias+
335 " not defined in config file");
336 }
337 map = buildInstance(name, instanceConfiguration);
338 instances.put(name, map);
339 }
340 return map;
341 }
342
343 /***
344 * {@inheritDoc}
345 */
346 public ValueFactory getValueFactory(String factory, String map)
347 {
348 Configuration factoryConfig = (Configuration)factoryConfigurations.get(factory);
349 String fclass = factoryConfig.getAttribute("class",null);
350 Object obj;
351 if(fclass == null)
352 {
353 throw new IllegalArgumentException("factory "+factory+" not defined in config file");
354 }
355 try
356 {
357 obj = Class.forName(fclass).newInstance();
358 }
359 catch(ClassNotFoundException e)
360 {
361 throw new IllegalArgumentException(fclass+" not found");
362 }
363 catch(Exception e)
364 {
365 throw new IllegalArgumentException(fclass+" not found");
366 }
367
368 if(!(obj instanceof ConfigurableValueFactory))
369 {
370 throw new IllegalArgumentException(fclass+" does not implement " +
371 "ConfigurableValueFactory interface");
372 }
373 ((ConfigurableValueFactory)obj).configure(this, map, factoryConfig);
374 return (ValueFactory)obj;
375 }
376
377 /***
378 * {@inheritDoc}
379 */
380 public Map getHashMap()
381 {
382 Map map = getMap(HASH_MAP_TYPE);
383 return map;
384 }
385
386 /***
387 * {@inheritDoc}
388 */
389 public Map getTimeoutMap(long timeoutMillis)
390 {
391 TimeoutMap map = (TimeoutMap)getMap(TIMEOUT_MAP_TYPE);
392 map.setTimeout(timeoutMillis);
393 return map;
394 }
395
396 /***
397 * {@inheritDoc}
398 */
399 public Map getLRUMap(int capacity)
400 {
401 LRUMap map = (LRUMap)getMap(LRU_MAP_TYPE);
402 map.setCapacity(capacity);
403 return map;
404 }
405
406 /***
407 * {@inheritDoc}
408 */
409 public Map getSoftMap(int protect)
410 {
411 SoftMap map = (SoftMap)getMap(SOFT_MAP_TYPE);
412 map.setProtect(protect);
413 return map;
414 }
415
416 /***
417 * {@inheritDoc}
418 */
419 public org.objectledge.cache.DistributedMap getDistributedMap(String name, Map delegate)
420 {
421 DistributedMap map = (DistributedMap)getMap(DISTRIBUTED_MAP_TYPE);
422 map.setDelegate(delegate);
423 map.attach(notification, name);
424 return map;
425 }
426
427 /***
428 * {@inheritDoc}
429 */
430 public Map getFactoryMap(ValueFactory factory, Map delegate)
431 {
432 FactoryMap map = (FactoryMap)getMap(FACTORY_MAP_TYPE);
433 map.setDelegate(delegate);
434 map.setFactory(factory);
435 return map;
436 }
437
438 /***
439 * {@inheritDoc}
440 */
441 public Map getStatisticsMap(String name, Map delegate)
442 {
443 StatisticsMap map = (StatisticsMap)getMap(STATISTICS_MAP_TYPE);
444 map.setDelegate(delegate);
445 map.setName(name);
446 addStatisticsMap(map);
447 return map;
448 }
449
450 /***
451 * {@inheritDoc}
452 */
453 public ValueFactory getPersitenceValueFactory(Class valueClass)
454 {
455 PersistenceValueFactory factory = new PersistenceValueFactory();
456 factory.init(valueClass, persistence);
457 return factory;
458 }
459
460 /***
461 * {@inheritDoc}
462 */
463 public void register(DelayedUpdate object)
464 {
465 synchronized(queue)
466 {
467
468
469 Long target = (Long)queueHelper.get(object);
470 Set<DelayedUpdate> set;
471 if(target != null)
472 {
473 set = queue.get(target);
474 set.remove(object);
475 if(set.isEmpty())
476 {
477 queue.remove(target);
478 }
479 }
480 target = new Long(System.currentTimeMillis()+object.getUpdateLatency());
481 set = queue.get(target);
482 if(set == null)
483 {
484 set = new HashSet<DelayedUpdate>();
485 queue.put(target, set);
486 queueHelper.put(object, target);
487 }
488 set.add(object);
489 queue.notify();
490 }
491 }
492
493 /***
494 * Prints the report on the specified PrintWriter.
495 *
496 * @param out the PrintWriter to print report into.
497 */
498 public void getStatus(PrintWriter out)
499 {
500 synchronized(statistics)
501 {
502 for(int i=0; i<statistics.size(); i++)
503 {
504 out.print(((StatisticsMap)statistics.get(i)).getStatistics());
505 }
506 }
507 }
508
509 /***
510 * {@inheritDoc}
511 */
512 public void addStatisticsMap(StatisticsMap map)
513 {
514 synchronized(statistics)
515 {
516 statistics.add(map);
517 }
518 }
519
520 /***
521 * {@inheritDoc}
522 */
523 public Notification getNotification()
524 {
525 return notification;
526 }
527
528 /***
529 * {@inheritDoc}
530 */
531 public Persistence getPersistence()
532 {
533 return persistence;
534 }
535
536
537 /***
538 * Initializes an entry in the {@link #implClasses} map.
539 *
540 * @param type the map type.
541 * @param className the implementation class name.
542 * @param iface the interface the implementation class must support.
543 * @throws ClassNotFoundException if class couldn't be found.
544 */
545 private void initImpl(String type, String className, Class iface)
546 throws ClassNotFoundException
547 {
548 Class cl = Class.forName(className);
549 String reason = null;
550 int mod = cl.getModifiers();
551 if(Modifier.isInterface(mod) || Modifier.isAbstract(mod))
552 {
553 reason = "it is an abstract or interface class";
554 }
555 try
556 {
557 cl.getConstructor( new Class[] {} );
558 }
559 catch(NoSuchMethodException e)
560 {
561 reason = " it has no public no-arg constructor";
562 }
563 if(!iface.isAssignableFrom(cl))
564 {
565 reason = " it does not implement "+iface.getName()+" interface";
566 }
567 if(reason != null)
568 {
569 throw new ComponentInitializationError(className+" can't be used as "+type+
570 " implementation because "+reason);
571 }
572 implClasses.put(type, cl);
573 }
574
575 /***
576 * Creates a new configurable map instance.
577 *
578 * @param name instance's name.
579 * @param conf inststance's configuration elements.
580 */
581 private Map buildInstance(String name, Configuration conf)
582 throws ConfigurationException
583 {
584 Map previous = null;
585 Map current = null;
586 Configuration[] mapConfigs = conf.getChildren("config");
587 for(int i=0; i < mapConfigs.length; i++)
588 {
589 String num = (i == 0) ? "st" :
590 ( (i == 1) ? "nd" :
591 ( (i == 2) ? "rd" : "th" ) );
592 num = (i+1)+num;
593
594 String s = mapConfigs[i].getValue().trim();
595 int op = s.indexOf('(');
596 int cp = (op > 0) ? s.indexOf(')',op) : -1;
597 if(op < 1 || cp < 0 || cp < s.length() - 1)
598 {
599 throw new IllegalArgumentException(num+" entry in "+name+" configuration "+
600 "is malformed: MapType([config]) expected");
601 }
602 String type = s.substring(0,op);
603 String mapConfig = s.substring(op+1,cp);
604 current = getMap(type);
605 if(i > 0)
606 {
607 if(current instanceof LayeredMap)
608 {
609 ((LayeredMap)current).setDelegate(previous);
610 }
611 else
612 {
613 throw new IllegalArgumentException(type+" was specified as the "+
614 num+" entry in "+name+" configuration, but it's "+
615 "implementation does not support LayeredMap interface");
616 }
617 }
618 if(current instanceof ConfigurableMap)
619 {
620 ((ConfigurableMap)current).configure(this,name,mapConfig);
621 }
622 else
623 {
624 if(mapConfig.length() != 0)
625 {
626 throw new ComponentInitializationError("configuration was specified " +
627 "for the "+num+ " entry in "+name+" configuration, but "+
628 type+" implementation does not support ConfigurableMap interface");
629 }
630 }
631 previous = current;
632 }
633 return current;
634 }
635
636 /***
637 * The task that performs delayed updates.
638 */
639 private class DelayedUpdateTask
640 extends Task
641 {
642 public String getName()
643 {
644 return "Delayed update sheduler";
645 }
646
647 public void process(Context context)
648 {
649 synchronized(queue)
650 {
651 long now;
652 loop: while(!Thread.interrupted())
653 {
654
655 if(queue.size() == 0)
656 {
657 try
658 {
659 queue.wait();
660 }
661 catch(InterruptedException e)
662 {
663 break loop;
664 }
665 }
666
667 now = System.currentTimeMillis();
668 Long first = (Long)queue.firstKey();
669 while(!queue.isEmpty() && first.longValue() <= now)
670 {
671
672
673 Set set = (Set)queue.remove(first);
674 Iterator i = set.iterator();
675 while(i.hasNext())
676 {
677 DelayedUpdate obj = (DelayedUpdate)i.next();
678 queueHelper.remove(obj);
679 try
680 {
681 obj.update();
682 }
683
684 catch(VirtualMachineError e)
685 {
686 throw e;
687 }
688 catch(ThreadDeath e)
689 {
690 throw e;
691 }
692 catch(Throwable e)
693 {
694 logger.error("exception in delayed update thread", e);
695 }
696
697 }
698 if(!queue.isEmpty())
699 {
700 first = (Long)queue.firstKey();
701 }
702 }
703
704 if(!queue.isEmpty())
705 {
706 try
707 {
708 queue.wait(first.longValue() - now);
709 }
710 catch(InterruptedException e)
711 {
712 break loop;
713 }
714 }
715 }
716 }
717 }
718
719 public void terminate(Thread t)
720 {
721 t.interrupt();
722 }
723 }
724 }