KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tcspring > DistributableBeanFactoryMixin


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tcspring;
6
7 import org.apache.commons.logging.Log;
8 import org.apache.commons.logging.LogFactory;
9 import org.springframework.beans.factory.support.AbstractBeanDefinition;
10 import org.springframework.beans.factory.support.ChildBeanDefinition;
11
12 import com.tc.object.TCClass;
13 import com.tc.object.bytecode.ByteCodeUtil;
14 import com.tc.object.bytecode.Manageable;
15 import com.tc.object.bytecode.Manager;
16 import com.tc.object.bytecode.ManagerUtil;
17 import com.tc.object.bytecode.hook.DSOContext;
18 import com.tc.object.config.DSOSpringConfigHelper;
19 import com.tc.object.field.TCField;
20
21 import java.io.PrintWriter JavaDoc;
22 import java.io.StringWriter JavaDoc;
23 import java.io.UnsupportedEncodingException JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26 import java.security.MessageDigest JavaDoc;
27 import java.security.NoSuchAlgorithmException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35
36 /**
37  * Holds a unique ID for all the instance the mixin is applied to. Usage: 1. Call addLocation() 1 or more times 2. call
38  * registerBeanDefinitions() once 3. Call getters (is...() or get...()) as many times as you like
39  *
40  * @author Eugene Kuleshov
41  * @author Jonas Bon&#233;r TODO performance optimization of the access to <code>DSOSpringConfigHelper</code>
42  */

43 public final class DistributableBeanFactoryMixin implements DistributableBeanFactory {
44
45   private final transient Log logger = LogFactory.getLog(getClass());
46
47   private final String JavaDoc appName;
48   private final DSOContext dsoContext;
49
50   private List JavaDoc springConfigHelpers = Collections.synchronizedList(new ArrayList JavaDoc());
51
52   private Map JavaDoc beanDefinitions = Collections.synchronizedMap(new HashMap JavaDoc());
53
54   private String JavaDoc id;
55   private List JavaDoc locations = new ArrayList JavaDoc();
56
57   private boolean isClustered = false;
58   private Map JavaDoc clusteredBeans = new HashMap JavaDoc();
59
60   private final ManagerUtilWrapper managerUtilWrapper;
61   private final Set JavaDoc nonDistributables;
62
63   public DistributableBeanFactoryMixin() {
64     ApplicationHelper applicationHelper = new ApplicationHelper(getClass());
65     if (applicationHelper.isDSOApplication()) {
66       this.appName = applicationHelper.getAppName();
67       this.dsoContext = applicationHelper.getDsoContext();
68     } else {
69       this.appName = null;
70       this.dsoContext = null;
71     }
72
73     this.managerUtilWrapper = new ManagerUtilWrapperImpl();
74
75     // NonDistributableObjectRegistry nonDistributableObjectRegistry = NonDistributableObjectRegistry.getInstance();
76
// if (nonDistributableObjectRegistry.isAdded() == false) {
77
// ManagerUtil.addTraverseTest(nonDistributableObjectRegistry);
78
// nonDistributableObjectRegistry.setAdded();
79
// }
80
// this.nonDistributables = nonDistributableObjectRegistry.getNondistributables();
81
this.nonDistributables = Collections.EMPTY_SET;
82   }
83
84   protected DistributableBeanFactoryMixin(String JavaDoc appName, DSOContext dsoContext, ManagerUtilWrapper managerUtilWrapper,
85                                           Set JavaDoc nonDistributables) {
86     this.appName = appName;
87     this.dsoContext = dsoContext;
88     this.managerUtilWrapper = managerUtilWrapper;
89     this.nonDistributables = nonDistributables;
90   }
91
92   public boolean isClustered() {
93     return isClustered;
94   }
95
96   public String JavaDoc getAppName() {
97     return appName;
98   }
99
100   public String JavaDoc getId() {
101     return id;
102   }
103
104   public List JavaDoc getLocations() {
105     return locations;
106   }
107
108   public List JavaDoc getSpringConfigHelpers() {
109     return this.springConfigHelpers;
110   }
111
112   public boolean isDistributedEvent(String JavaDoc className) {
113     for (Iterator JavaDoc it = this.springConfigHelpers.iterator(); it.hasNext();) {
114       DSOSpringConfigHelper springConfigHelper = (DSOSpringConfigHelper) it.next();
115       if (springConfigHelper.isDistributedEvent(className)) { return true; }
116     }
117     return false;
118   }
119
120   public boolean isDistributedScoped(String JavaDoc beanName) {
121     AbstractBeanDefinition definition = (AbstractBeanDefinition) beanDefinitions.get(beanName);
122     // method definition.isPrototype() is Spring 2.0+
123
return definition != null && !definition.isSingleton() && !definition.isPrototype();
124   }
125
126   public boolean isDistributedSingleton(String JavaDoc beanName) {
127     AbstractBeanDefinition definition = (AbstractBeanDefinition) beanDefinitions.get(beanName);
128     return definition != null && definition.isSingleton();
129   }
130
131   public boolean isDistributedBean(String JavaDoc beanName) {
132     for (Iterator JavaDoc it = this.springConfigHelpers.iterator(); it.hasNext();) {
133       DSOSpringConfigHelper springConfigHelper = (DSOSpringConfigHelper) it.next();
134       if (springConfigHelper.isDistributedBean(beanName)) {
135         logger.debug(id + " bean " + beanName + " is distributed");
136         return true;
137       }
138     }
139     logger.debug(id + " bean " + beanName + " is NOT distributed");
140     return false;
141   }
142
143   public boolean isDistributedField(String JavaDoc beanName, String JavaDoc fieldName) {
144     for (Iterator JavaDoc it = this.springConfigHelpers.iterator(); it.hasNext();) {
145       DSOSpringConfigHelper springConfigHelper = (DSOSpringConfigHelper) it.next();
146       if (springConfigHelper.isDistributedField(beanName, fieldName)) {
147         logger.debug(id + " field " + fieldName + " in bean " + beanName + " is distributed");
148         return true;
149       }
150     }
151     logger.debug(id + " field " + fieldName + " in bean " + beanName + " is NOT distributed");
152     return false;
153   }
154
155   public void addLocation(String JavaDoc location) {
156     this.locations.add(location);
157   }
158
159   private String JavaDoc calculateId(DSOSpringConfigHelper config) {
160     if (config != null && config.getRootName() != null) { return config.getRootName(); }
161
162     StringWriter JavaDoc sw = new StringWriter JavaDoc();
163     PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
164     pw.println("app " + this.appName);
165     for (Iterator JavaDoc iter = locations.iterator(); iter.hasNext();) {
166       String JavaDoc loc = (String JavaDoc) iter.next();
167       pw.println("params " + loc);
168     }
169
170     if (config != null && config.isLocationInfoEnabled()) {
171       new Throwable JavaDoc().printStackTrace(pw);
172     }
173
174     return getDigest(sw.toString());
175   }
176
177   private void determineIfClustered() {
178     for (Iterator JavaDoc iter = this.dsoContext.getDSOSpringConfigHelpers().iterator(); iter.hasNext();) {
179       DSOSpringConfigHelper config = (DSOSpringConfigHelper) iter.next();
180       if (config.isMatchingApplication(this.appName) && isMatchingLocations(config)) {
181         this.springConfigHelpers.add(config);
182         this.isClustered = true;
183         this.id = calculateId(config);
184         logger.info(id + " Matching locations:" + locations);
185       }
186     }
187
188     if (this.isClustered) {
189       logger.info(id + " Context is distributed");
190     } else {
191       this.id = calculateId(null);
192       logger.info(id + " Context is NOT distributed");
193     }
194   }
195
196   private boolean isMatchingLocations(DSOSpringConfigHelper config) {
197     for (Iterator JavaDoc iter = locations.iterator(); iter.hasNext();) {
198       String JavaDoc location = (String JavaDoc) iter.next();
199       if (config.isMatchingConfig(location)) { return true; }
200     }
201     return false;
202   }
203
204   public void registerBeanDefinitions(Map JavaDoc beanMap) {
205     determineIfClustered();
206
207     if (!this.isClustered) { return; }
208
209     for (Iterator JavaDoc it = springConfigHelpers.iterator(); it.hasNext();) {
210       DSOSpringConfigHelper configHelper = (DSOSpringConfigHelper) it.next();
211       if (configHelper.isMatchingApplication(this.appName)) {
212         registerDistributedEvents(configHelper.getDistributedEvents());
213         registerDistributedBeans(configHelper.getDistributedBeans(), beanMap);
214       }
215     }
216
217     String JavaDoc lockName = "@spring_context_" + this.id;
218
219     managerUtilWrapper.beginLock(lockName, Manager.LOCK_TYPE_WRITE);
220     try {
221       this.clusteredBeans = (Map JavaDoc) managerUtilWrapper.lookupOrCreateRoot("tc:spring_context:" + this.id,
222                                                                         this.clusteredBeans);
223     } finally {
224       managerUtilWrapper.commitLock(lockName);
225     }
226   }
227
228   protected void registerDistributedEvents(final List JavaDoc distributedEvents) {
229     ClassHierarchyWalker walker = new ClassHierarchyWalker(id, dsoContext);
230
231     for (Iterator JavaDoc eventIterator = distributedEvents.iterator(); eventIterator.hasNext();) {
232       String JavaDoc event = (String JavaDoc) eventIterator.next();
233       // instrument only exact classes to avoid conflicts
234
if (event.indexOf('*') == -1) {
235         walker.walkClass(event, getClass().getClassLoader());
236       }
237     }
238   }
239
240   protected void registerDistributedBeans(Map JavaDoc distributedBeans, Map JavaDoc beanMap) {
241     ClassHierarchyWalker walker = new ClassHierarchyWalker(id, dsoContext);
242
243     for (Iterator JavaDoc beanMapIterator = beanMap.entrySet().iterator(); beanMapIterator.hasNext();) {
244       Map.Entry JavaDoc entry = (Map.Entry JavaDoc) beanMapIterator.next();
245       String JavaDoc beanName = (String JavaDoc) entry.getKey();
246       AbstractBeanDefinition definition = (AbstractBeanDefinition) entry.getValue();
247
248       Set JavaDoc excludedFields = (Set JavaDoc) distributedBeans.get(beanName);
249       if (excludedFields != null) {
250         beanDefinitions.put(beanName, definition); // need to unregister on reload/destroy
251

252         String JavaDoc beanClassName = getBeanClassName(definition, beanMap);
253
254         walker.walkClass(beanClassName, getClass().getClassLoader());
255
256         logger.info(this.id + " registering transient fields for " + beanName + " " + beanClassName);
257         for (Iterator JavaDoc fieldIterator = excludedFields.iterator(); fieldIterator.hasNext();) {
258           String JavaDoc fieldName = (String JavaDoc) fieldIterator.next();
259           logger.info(this.id + " adding transient field " + beanClassName + "." + fieldName);
260           dsoContext.addTransient(beanClassName, fieldName);
261         }
262       }
263
264       // process bean metadata
265
// String[] names = definition.attributeNames();
266
// for (int i = 0; i < names.length; i++) {
267
// String name = names[i];
268
// Object value = definition.getAttribute(name);
269
// if ("com.terracotta.Distributed".equals(name)) {
270
// // TODO handle singleton attribute
271
//
272
// } else if ("com.terracotta.Transient".equals(name)) {
273
// // TODO handle transient attribute
274
//
275
// } else if ("com.terracotta.AutoLock".equals(name)) {
276
// // TODO handle autolock attribute
277
//
278
// } else {
279
// // etc...
280
//
281
// }
282
// }
283
}
284   }
285
286   /**
287    * Get bean's class name. If necessary, walk to the parent beans.
288    */

289   static String JavaDoc getBeanClassName(AbstractBeanDefinition definition, Map JavaDoc beanMap) {
290     String JavaDoc beanClassName = definition.getBeanClassName();
291     if (beanClassName == null && definition instanceof ChildBeanDefinition) {
292       String JavaDoc parent = ((ChildBeanDefinition) definition).getParentName();
293       definition = (AbstractBeanDefinition) beanMap.get(parent);
294       if (definition != null) { return getBeanClassName(definition, beanMap); }
295     }
296     return beanClassName;
297   }
298
299   private String JavaDoc getDigest(String JavaDoc s) {
300     try {
301       MessageDigest JavaDoc digest = MessageDigest.getInstance("MD5");
302       digest.update(s.getBytes("ASCII"));
303       byte[] b = digest.digest();
304
305       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
306       String JavaDoc hex = "0123456789ABCDEF";
307       for (int i = 0; i < b.length; i++) {
308         int n = b[i];
309         sb.append(hex.charAt((n & 0xF) >> 4)).append(hex.charAt(n & 0xF));
310       }
311       return sb.toString();
312
313     } catch (NoSuchAlgorithmException JavaDoc e) {
314       // should never happens
315
throw new RuntimeException JavaDoc(e.getMessage());
316     } catch (UnsupportedEncodingException JavaDoc e) {
317       // should never happens
318
throw new RuntimeException JavaDoc(e.getMessage());
319     }
320   }
321
322   public BeanContainer getBeanContainer(ComplexBeanId beanId) {
323     ManagerUtil.monitorEnter(this.clusteredBeans, Manager.LOCK_TYPE_READ);
324     try {
325       return (BeanContainer) clusteredBeans.get(beanId);
326     } finally {
327       ManagerUtil.monitorExit(this.clusteredBeans);
328     }
329   }
330
331   public BeanContainer putBeanContainer(ComplexBeanId beanId, BeanContainer container) {
332     ManagerUtil.monitorEnter(this.clusteredBeans, Manager.LOCK_TYPE_WRITE);
333     try {
334       return (BeanContainer) clusteredBeans.put(beanId, container);
335     } finally {
336       ManagerUtil.monitorExit(this.clusteredBeans);
337     }
338   }
339
340   public BeanContainer removeBeanContainer(ComplexBeanId beanId) {
341     ManagerUtil.monitorEnter(this.clusteredBeans, Manager.LOCK_TYPE_WRITE);
342     try {
343       return (BeanContainer) clusteredBeans.remove(beanId);
344     } finally {
345       ManagerUtil.monitorExit(this.clusteredBeans);
346     }
347   }
348
349   public void initializeBean(ComplexBeanId beanId, Object JavaDoc bean, BeanContainer container) {
350     logger.info(getId() + " Initializing distributed bean " + beanId);
351
352     // TODO make initialization from shadow local copy optional
353

354     Object JavaDoc distributed = container.getBean();
355     try {
356       copyTransientFields(beanId.getBeanName(), bean, distributed, distributed.getClass(), ((Manageable) distributed)
357           .__tc_managed().getTCClass());
358     } catch (Throwable JavaDoc e) {
359       // TODO should we fail here?
360
logger.warn(getId() + " Error when copying transient fields to " + beanId, e);
361     }
362   }
363
364   private void copyTransientFields(String JavaDoc beanName, Object JavaDoc sourceBean, Object JavaDoc targetBean, Class JavaDoc targetClass,
365                                    TCClass tcClass) throws IllegalAccessException JavaDoc {
366     if (tcClass.isLogical()) { return; }
367
368     Field[] declaredFields = targetClass.getDeclaredFields();
369     for (int i = 0; i < declaredFields.length; i++) {
370       Field f = declaredFields[i];
371
372       if ((f.getModifiers() & (Modifier.FINAL | Modifier.STATIC | Modifier.NATIVE)) != 0) {
373         continue;
374       }
375
376       String JavaDoc fieldName = f.getName();
377       if (fieldName.startsWith(ByteCodeUtil.TC_FIELD_PREFIX)) {
378         continue;
379       }
380
381       TCField tcf = tcClass.getField(targetClass.getName() + "." + fieldName);
382       f.setAccessible(true);
383       Object JavaDoc value = f.get(sourceBean);
384
385       if (tcf == null || !tcf.isPortable() || !this.isDistributedField(beanName, fieldName)
386           || nonDistributables.contains(value)) {
387         logger.info(this.getId() + " Initializing field " + fieldName + " in bean " + beanName);
388         f.set(targetBean, value);
389       }
390     }
391
392     Class JavaDoc superclass = targetClass.getSuperclass();
393     TCClass tcsuperclass = tcClass.getSuperclass();
394     if (superclass != null && tcsuperclass != null) {
395       copyTransientFields(beanName, sourceBean, targetBean, superclass, tcsuperclass);
396     }
397   }
398
399   interface ManagerUtilWrapper {
400     void beginLock(String JavaDoc lockId, int type);
401
402     Object JavaDoc lookupOrCreateRoot(String JavaDoc name, Object JavaDoc object);
403
404     void commitLock(String JavaDoc lockId);
405   }
406
407   private static class ManagerUtilWrapperImpl implements ManagerUtilWrapper {
408
409     public ManagerUtilWrapperImpl() {
410       //
411
}
412
413     public void beginLock(String JavaDoc lockId, int type) {
414       ManagerUtil.beginLock(lockId, type);
415     }
416
417     public Object JavaDoc lookupOrCreateRoot(String JavaDoc name, Object JavaDoc object) {
418       return ManagerUtil.lookupOrCreateRoot(name, object);
419     }
420
421     public void commitLock(String JavaDoc lockId) {
422       ManagerUtil.commitLock(lockId);
423     }
424
425   }
426
427 }
428
Popular Tags