001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.config;
006:
007: import com.tc.logging.TCLogger;
008: import com.tc.logging.TCLogging;
009:
010: import java.lang.reflect.Method;
011: import java.lang.reflect.Modifier;
012: import java.lang.reflect.Constructor;
013: import java.util.HashMap;
014: import java.util.HashSet;
015: import java.util.Map;
016: import java.util.Set;
017:
018: /**
019: * Allows a class to visit a L1DSOConfig to augment/adjust it
020: */
021: public class ConfigVisitor {
022: private final Map visited = new HashMap();
023: private final TCLogger logger = TCLogging.getLogger(getClass());
024:
025: public static final String VISIT_METHOD_NAME = "visitL1DSOConfig";
026: public static final String VISIT_INSTANCE_METHOD_NAME = "instanceVisitL1DSOConfig";
027: public static final Class[] VISIT_METHOD_PARAMETERS = new Class[] {
028: ConfigVisitor.class, DSOClientConfigHelper.class };
029: public static final Class[] VISIT_METHOD_PARAMETERS_WITH_ATTRIBUTES = new Class[] {
030: ConfigVisitor.class, DSOClientConfigHelper.class, Map.class };
031: public static final String VISIT_DSO_APPLICATION_CONFIG_METHOD_NAME = "visitDSOApplicationConfig";
032: public static final Class[] VISIT_DSO_APPLICATION_CONFIG_METHOD_PARAMETERS = new Class[] {
033: ConfigVisitor.class, DSOApplicationConfig.class };
034:
035: public void visitDSOApplicationConfig(DSOApplicationConfig config,
036: Class clazz) {
037: if (checkAndSetVisited(config, clazz)) {
038: return;
039: }
040: doVisit(clazz, VISIT_DSO_APPLICATION_CONFIG_METHOD_NAME,
041: VISIT_DSO_APPLICATION_CONFIG_METHOD_PARAMETERS,
042: new Object[] { this , config });
043: }
044:
045: public void visit(DSOClientConfigHelper config, Visitable v) {
046: if (checkAndSetVisited(config, v)) {
047: return;
048: }
049: v.visit(this , config);
050: }
051:
052: public void visit(DSOClientConfigHelper config, Class clazz) {
053: if (checkAndSetVisited(config, clazz)) {
054: return;
055: }
056: Object[] args = new Object[] { this , config };
057: // use instance visiting if available, otherwise do class visiting
058: if (!doInstanceVisit(clazz, VISIT_INSTANCE_METHOD_NAME,
059: VISIT_METHOD_PARAMETERS, args))
060: doVisit(clazz, VISIT_METHOD_NAME, VISIT_METHOD_PARAMETERS,
061: new Object[] { this , config });
062: }
063:
064: public void visit(DSOClientConfigHelper config, Class clazz,
065: Map optionalAttributes) {
066: if (checkAndSetVisited(config, clazz)) {
067: return;
068: }
069: Object[] args = new Object[] { this , config };
070: // use instance visiting if available, otherwise do class visiting
071: if (!doInstanceVisit(clazz, VISIT_INSTANCE_METHOD_NAME,
072: VISIT_METHOD_PARAMETERS, args))
073: doVisit(clazz, VISIT_METHOD_NAME,
074: VISIT_METHOD_PARAMETERS_WITH_ATTRIBUTES,
075: new Object[] { this , config, optionalAttributes });
076: }
077:
078: // instance visiting only works if clazz defines a niladic constructor
079: private boolean doInstanceVisit(Class clazz, String methodName,
080: Class[] parameters, Object[] arguments) {
081: boolean result = false;
082: try {
083: Method visitMethod = clazz.getMethod(
084: VISIT_INSTANCE_METHOD_NAME, parameters);
085: System.out.println("instance configuration method found");
086: Constructor construct = clazz.getConstructor(new Class[0]);
087: Object instance = construct.newInstance(new Object[0]);
088: visitMethod.setAccessible(true);
089: visitMethod.invoke(instance, arguments);
090: result = true;
091: } catch (NoSuchMethodException e) {
092: // nothing to do
093: } catch (Exception e) {
094: throw new RuntimeException(e);
095: }
096: return result;
097: }
098:
099: private void doVisit(Class clazz, String methodName,
100: Class[] parameters, Object[] arguments) {
101: while (clazz != null) {
102: try {
103: // look for instance method first
104: Method visitMethod = clazz.getMethod(methodName,
105: parameters);
106: if (Modifier.isStatic(visitMethod.getModifiers())) {
107: visitMethod.setAccessible(true);
108: logger.info("Visiting: " + clazz.getName());
109: visitMethod.invoke(null, arguments);
110: }
111: } catch (NoSuchMethodException e) {
112: if (!Object.class.getName().equals(clazz.getName())) {
113: StringBuffer paramString = new StringBuffer();
114: for (int i = 0; i < parameters.length; i++) {
115: if (i > 0) {
116: paramString.append(",");
117: }
118: paramString.append(parameters[i].getName());
119: }
120: logger.info("Visit method not defined: "
121: + clazz.getName() + "." + methodName + "("
122: + paramString + ")");
123: }
124: continue;
125: } catch (Exception e) {
126: throw new RuntimeException(e);
127: } finally {
128: clazz = clazz.getSuperclass();
129: }
130: }
131: }
132:
133: private boolean checkAndSetVisited(Object config, Class clazz) {
134: return checkAndSetVisited(config, clazz.getName());
135: }
136:
137: private boolean checkAndSetVisited(Object config, Visitable v) {
138: return checkAndSetVisited(config, v.getClass());
139: }
140:
141: private boolean checkAndSetVisited(Object config, Object key) {
142: Set set;
143: synchronized (visited) {
144: set = getOrCreateVisitedFor(key);
145: }
146: synchronized (set) {
147: boolean rv = !set.add(config);
148: if (rv) {
149: logger.warn("Already visited: " + key);
150: }
151: return rv;
152: }
153: }
154:
155: private Set getOrCreateVisitedFor(Object key) {
156: synchronized (visited) {
157: Set set = (Set) visited.get(key);
158: if (set == null) {
159: set = new HashSet();
160: visited.put(key, set);
161: }
162: return set;
163: }
164: }
165:
166: }
|