001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.gbean.runtime;
017:
018: import java.lang.reflect.Method;
019:
020: import org.apache.geronimo.gbean.DynamicGAttributeInfo;
021: import org.apache.geronimo.gbean.DynamicGBean;
022: import org.apache.geronimo.gbean.GAttributeInfo;
023: import org.apache.geronimo.gbean.InvalidConfigurationException;
024: import org.apache.geronimo.kernel.ClassLoading;
025:
026: /**
027: * @version $Rev: 549825 $ $Date: 2007-06-22 07:17:31 -0700 (Fri, 22 Jun 2007) $
028: */
029: public class GBeanAttribute {
030: private final GBeanInstance gbeanInstance;
031:
032: private final String name;
033:
034: private final Class type;
035:
036: private final boolean readable;
037:
038: private final MethodInvoker getInvoker;
039:
040: private final boolean writable;
041:
042: private final MethodInvoker setInvoker;
043:
044: private final boolean isConstructorArg;
045:
046: private final boolean persistent;
047:
048: private final boolean manageable;
049:
050: private Object persistentValue;
051:
052: /**
053: * Is this a special attribute like objectName, classLoader or gbeanContext?
054: * Special attributes are injected at startup just like persistent attrubutes, but are
055: * otherwise unmodifiable.
056: */
057: private final boolean special;
058:
059: private final boolean framework;
060:
061: private final boolean dynamic;
062:
063: private final GAttributeInfo attributeInfo;
064:
065: static GBeanAttribute createSpecialAttribute(
066: GBeanAttribute attribute, GBeanInstance gbeanInstance,
067: String name, Class type, Object value) {
068: return new GBeanAttribute(attribute, gbeanInstance, name, type,
069: value);
070: }
071:
072: private GBeanAttribute(GBeanAttribute attribute,
073: GBeanInstance gbeanInstance, String name, Class type,
074: Object value) {
075: this .special = true;
076: this .framework = false;
077: this .dynamic = false;
078:
079: if (gbeanInstance == null || name == null || type == null) {
080: throw new IllegalArgumentException("null param(s) supplied");
081: }
082:
083: // if we have an attribute verify the gbean instance, name and types match
084: if (attribute != null) {
085: assert (gbeanInstance == attribute.gbeanInstance);
086: assert (name.equals(attribute.name));
087: if (type != attribute.type) {
088: throw new InvalidConfigurationException(
089: "Special attribute " + name
090: + " must have the type "
091: + type.getName() + ", but is "
092: + attribute.type.getName()
093: + ": targetClass="
094: + gbeanInstance.getType().getName());
095: }
096: if (attribute.isPersistent()) {
097: throw new InvalidConfigurationException(
098: "Special attributes must not be persistent:"
099: + " name=" + name + ", targetClass="
100: + gbeanInstance.getType().getName());
101: }
102: }
103:
104: this .gbeanInstance = gbeanInstance;
105: this .name = name;
106: this .type = type;
107:
108: // getter
109: this .getInvoker = null;
110: this .readable = true;
111:
112: // setter
113: if (attribute != null) {
114: this .setInvoker = attribute.setInvoker;
115: this .isConstructorArg = attribute.isConstructorArg;
116: } else {
117: this .setInvoker = null;
118: this .isConstructorArg = false;
119: }
120: this .writable = false;
121:
122: // persistence
123: this .persistent = false;
124: initializePersistentValue(value);
125:
126: // not manageable
127: this .manageable = false;
128:
129: // create an attribute info for this gbean
130: if (attribute != null) {
131: GAttributeInfo attributeInfo = attribute.getAttributeInfo();
132: this .attributeInfo = new GAttributeInfo(this .name,
133: this .type.getName(), this .persistent,
134: this .manageable, this .readable, this .writable,
135: attributeInfo.getGetterName(), attributeInfo
136: .getSetterName());
137: } else {
138: this .attributeInfo = new GAttributeInfo(this .name,
139: this .type.getName(), this .persistent,
140: this .manageable, this .readable, this .writable,
141: null, null);
142: }
143: }
144:
145: static GBeanAttribute createFrameworkAttribute(
146: GBeanInstance gbeanInstance, String name, Class type,
147: MethodInvoker getInvoker) {
148: return new GBeanAttribute(gbeanInstance, name, type,
149: getInvoker, null, false, null, true);
150: }
151:
152: static GBeanAttribute createFrameworkAttribute(
153: GBeanInstance gbeanInstance, String name, Class type,
154: MethodInvoker getInvoker, MethodInvoker setInvoker,
155: boolean persistent, Object persistentValue,
156: boolean manageable) {
157: return new GBeanAttribute(gbeanInstance, name, type,
158: getInvoker, setInvoker, persistent, persistentValue,
159: manageable);
160: }
161:
162: private GBeanAttribute(GBeanInstance gbeanInstance, String name,
163: Class type, MethodInvoker getInvoker,
164: MethodInvoker setInvoker, boolean persistent,
165: Object persistentValue, boolean manageable) {
166: this .special = false;
167: this .framework = true;
168: this .dynamic = false;
169:
170: if (gbeanInstance == null || name == null || type == null) {
171: throw new IllegalArgumentException("null param(s) supplied");
172: }
173:
174: this .gbeanInstance = gbeanInstance;
175: this .name = name;
176: this .type = type;
177:
178: // getter
179: this .getInvoker = getInvoker;
180: this .readable = (this .getInvoker != null);
181:
182: // setter
183: this .setInvoker = setInvoker;
184: this .isConstructorArg = false;
185: this .writable = (this .setInvoker != null);
186:
187: // persistence
188: this .persistent = persistent;
189: initializePersistentValue(persistentValue);
190:
191: // manageable
192: this .manageable = manageable;
193:
194: // create an attribute info for this gbean
195: attributeInfo = new GAttributeInfo(this .name, this .type
196: .getName(), this .persistent, this .manageable,
197: this .readable, this .writable, null, null);
198: }
199:
200: public GBeanAttribute(GBeanInstance gbeanInstance,
201: GAttributeInfo attributeInfo, boolean isConstructorArg)
202: throws InvalidConfigurationException {
203: this .special = false;
204: this .framework = false;
205:
206: if (gbeanInstance == null || attributeInfo == null) {
207: throw new IllegalArgumentException("null param(s) supplied");
208: }
209: if (!attributeInfo.isReadable() && !attributeInfo.isWritable()
210: && !attributeInfo.isPersistent() && !isConstructorArg) {
211: throw new InvalidConfigurationException(
212: "An attribute must be readable, writable, persistent or a constructor arg: "
213: + " name=" + attributeInfo.getName()
214: + " targetClass="
215: + gbeanInstance.getType().getName());
216: }
217: this .gbeanInstance = gbeanInstance;
218: this .attributeInfo = attributeInfo;
219: this .name = attributeInfo.getName();
220: this .isConstructorArg = isConstructorArg;
221: try {
222: this .type = ClassLoading.loadClass(attributeInfo.getType(),
223: gbeanInstance.getClassLoader());
224: } catch (ClassNotFoundException e) {
225: throw new InvalidConfigurationException(
226: "Could not load attribute class: "
227: + attributeInfo.getType(), e);
228: }
229: this .persistent = attributeInfo.isPersistent();
230: this .manageable = attributeInfo.isManageable();
231:
232: readable = attributeInfo.isReadable();
233: writable = attributeInfo.isWritable();
234:
235: // If attribute is persistent or not tagged as unreadable, search for a
236: // getter method
237: if (attributeInfo instanceof DynamicGAttributeInfo) {
238: this .dynamic = true;
239: if (readable) {
240: getInvoker = new DynamicGetterMethodInvoker(name);
241: } else {
242: getInvoker = null;
243: }
244: if (writable) {
245: setInvoker = new DynamicSetterMethodInvoker(name);
246: } else {
247: setInvoker = null;
248: }
249: } else {
250: this .dynamic = false;
251: if (attributeInfo.getGetterName() != null) {
252: try {
253: String getterName = attributeInfo.getGetterName();
254: Method getterMethod = gbeanInstance.getType()
255: .getMethod(getterName, null);
256:
257: if (!getterMethod.getReturnType().equals(type)) {
258: if (getterMethod.getReturnType().getName()
259: .equals(type.getName())) {
260: throw new InvalidConfigurationException(
261: "Getter return type in wrong classloader: type: "
262: + type
263: + " wanted in classloader: "
264: + type.getClassLoader()
265: + " actual: "
266: + getterMethod
267: .getReturnType()
268: .getClassLoader());
269: } else {
270: throw new InvalidConfigurationException(
271: "Getter method of wrong type: "
272: + getterMethod
273: .getReturnType()
274: + " expected "
275: + getDescription());
276: }
277: }
278: if (AbstractGBeanReference.NO_PROXY) {
279: getInvoker = new ReflectionMethodInvoker(
280: getterMethod);
281: } else {
282: getInvoker = new FastMethodInvoker(getterMethod);
283: }
284: } catch (NoSuchMethodException e) {
285: throw new InvalidConfigurationException(
286: "Getter method not found "
287: + getDescription(), e);
288: }
289: } else {
290: getInvoker = null;
291: }
292:
293: // If attribute is persistent or not tagged as unwritable, search
294: // for a setter method
295: if (attributeInfo.getSetterName() != null) {
296: try {
297: String setterName = attributeInfo.getSetterName();
298: Method setterMethod = gbeanInstance
299: .getType()
300: .getMethod(setterName, new Class[] { type });
301: if (AbstractGBeanReference.NO_PROXY) {
302: setInvoker = new ReflectionMethodInvoker(
303: setterMethod);
304: } else {
305: setInvoker = new FastMethodInvoker(setterMethod);
306: }
307: } catch (NoSuchMethodException e) {
308: throw new InvalidConfigurationException(
309: "Setter method not found "
310: + getDescription(), e);
311: }
312: } else {
313: setInvoker = null;
314: }
315: }
316:
317: initializePersistentValue(null);
318: }
319:
320: private void initializePersistentValue(Object value) {
321: if (persistent || special) {
322: if (value == null && type.isPrimitive() && isConstructorArg) {
323: if (type == Boolean.TYPE) {
324: value = Boolean.FALSE;
325: } else if (type == Byte.TYPE) {
326: value = new Byte((byte) 0);
327: } else if (type == Short.TYPE) {
328: value = new Short((short) 0);
329: } else if (type == Integer.TYPE) {
330: value = new Integer(0);
331: } else if (type == Long.TYPE) {
332: value = new Long(0);
333: } else if (type == Character.TYPE) {
334: value = new Character((char) 0);
335: } else if (type == Float.TYPE) {
336: value = new Float(0);
337: } else /** if (type == Double.TYPE) */
338: {
339: value = new Double(0);
340: }
341: }
342: persistentValue = value;
343: }
344: }
345:
346: public String getName() {
347: return name;
348: }
349:
350: public GAttributeInfo getAttributeInfo() {
351: return attributeInfo;
352: }
353:
354: public boolean isReadable() {
355: return readable;
356: }
357:
358: public boolean isWritable() {
359: return writable;
360: }
361:
362: public Class getType() {
363: return type;
364: }
365:
366: public boolean isFramework() {
367: return framework;
368: }
369:
370: public boolean isDynamic() {
371: return dynamic;
372: }
373:
374: public boolean isPersistent() {
375: return persistent;
376: }
377:
378: public boolean isManageable() {
379: return manageable;
380: }
381:
382: public boolean isSpecial() {
383: return special;
384: }
385:
386: public void inject(Object target) throws Exception {
387: if ((persistent || special) && !isConstructorArg && writable
388: && persistentValue != null) {
389: setValue(target, persistentValue);
390: }
391: }
392:
393: public Object getPersistentValue() {
394: if (!persistent && !special) {
395: throw new IllegalStateException(
396: "Attribute is not persistent " + getDescription());
397: }
398: return persistentValue;
399: }
400:
401: public void setPersistentValue(Object persistentValue) {
402: if (!persistent && !special) {
403: throw new IllegalStateException(
404: "Attribute is not persistent " + getDescription());
405: }
406:
407: if (persistentValue == null && type.isPrimitive()) {
408: throw new IllegalArgumentException(
409: "Cannot assign null to a primitive attribute. "
410: + getDescription());
411: }
412:
413: // @todo actually check type
414: this .persistentValue = persistentValue;
415: }
416:
417: public Object getValue(Object target) throws Exception {
418: if (!readable) {
419: if (persistent) {
420: return persistentValue;
421: } else {
422: throw new IllegalStateException(
423: "This attribute is not readable. "
424: + getDescription());
425: }
426: }
427:
428: if (special) {
429: return persistentValue;
430: }
431:
432: // get the target to invoke
433: if (target == null && !framework) {
434: throw new IllegalStateException(
435: "GBean does not have a target instance to invoke. "
436: + getDescription());
437: }
438:
439: // call the getter
440: Object value = getInvoker.invoke(target, null);
441: return value;
442: }
443:
444: public void setValue(Object target, Object value) throws Exception {
445: if (!writable) {
446: if (persistent) {
447: throw new IllegalStateException(
448: "This persistent attribute is not modifable while the gbean is running. "
449: + getDescription());
450: } else {
451: throw new IllegalStateException(
452: "This attribute is not writable. "
453: + getDescription());
454: }
455: }
456:
457: // the value can not be null for primitives
458: if (value == null && type.isPrimitive()) {
459: throw new IllegalArgumentException(
460: "Cannot assign null to a primitive attribute. "
461: + getDescription());
462: }
463:
464: // @todo actually check type
465:
466: // get the target to invoke
467: if (target == null && !framework) {
468: throw new IllegalStateException(
469: "GBean does not have a target instance to invoke. "
470: + getDescription());
471: }
472:
473: // call the setter
474: setInvoker.invoke(target, new Object[] { value });
475: }
476:
477: public String getDescription() {
478: return "Attribute Name: " + getName() + ", Type: " + getType()
479: + ", GBeanInstance: " + gbeanInstance.getName();
480: }
481:
482: private static final class DynamicGetterMethodInvoker implements
483: MethodInvoker {
484: private final String name;
485:
486: public DynamicGetterMethodInvoker(String name) {
487: this .name = name;
488: }
489:
490: public Object invoke(Object target, Object[] arguments)
491: throws Exception {
492: return ((DynamicGBean) target).getAttribute(name);
493: }
494: }
495:
496: private static final class DynamicSetterMethodInvoker implements
497: MethodInvoker {
498: private final String name;
499:
500: public DynamicSetterMethodInvoker(String name) {
501: this .name = name;
502: }
503:
504: public Object invoke(Object target, Object[] arguments)
505: throws Exception {
506: ((DynamicGBean) target).setAttribute(name, arguments[0]);
507: return null;
508: }
509: }
510: }
|