001: // ============================================================================
002: // $Id: GetProperty.java,v 1.13 2006/01/08 00:52:25 davidahall Exp $
003: // Copyright (c) 2002-2005 David A. Hall
004: // ============================================================================
005: // The contents of this file are subject to the Common Development and
006: // Distribution License (CDDL), Version 1.0 (the License); you may not use this
007: // file except in compliance with the License. You should have received a copy
008: // of the the License along with this file: if not, a copy of the License is
009: // available from Sun Microsystems, Inc.
010: //
011: // http://www.sun.com/cddl/cddl.html
012: //
013: // From time to time, the license steward (initially Sun Microsystems, Inc.) may
014: // publish revised and/or new versions of the License. You may not use,
015: // distribute, or otherwise make this file available under subsequent versions
016: // of the License.
017: //
018: // Alternatively, the contents of this file may be used under the terms of the
019: // GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
020: // case the provisions of the LGPL are applicable instead of those above. If you
021: // wish to allow use of your version of this file only under the terms of the
022: // LGPL, and not to allow others to use your version of this file under the
023: // terms of the CDDL, indicate your decision by deleting the provisions above
024: // and replace them with the notice and other provisions required by the LGPL.
025: // If you do not delete the provisions above, a recipient may use your version
026: // of this file under the terms of either the CDDL or the LGPL.
027: //
028: // This library is distributed in the hope that it will be useful,
029: // but WITHOUT ANY WARRANTY; without even the implied warranty of
030: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
031: // ============================================================================
032:
033: package net.sf.jga.fn.property;
034:
035: import java.lang.reflect.InvocationTargetException;
036: import java.lang.reflect.Method;
037: import java.text.MessageFormat;
038: import net.sf.jga.fn.EvaluationException;
039: import net.sf.jga.fn.UnaryFunctor;
040:
041: /**
042: * Unary Functor that returns the value of the named property for the argument.
043: * The property name and type are set at construction.
044: * <p>
045: * Copyright © 2002-2005 David A. Hall
046: *
047: * @author <a href="mailto:davidahall@users.sourceforge.net">David A. Hall</a>
048: **/
049:
050: public class GetProperty<T, R> extends UnaryFunctor<T, R> {
051:
052: static final long serialVersionUID = -6249123644692001840L;
053:
054: // The name of the property to be returned
055: private String _propName;
056:
057: // The name of the method corresponding to the property
058: private String _methName;
059:
060: // The class from which the property is retrieved.
061: private Class<T> _argtype;
062:
063: // The method called to get the property
064: private transient Method _meth;
065:
066: /**
067: * Builds a GetProperty for the given property, using the given class to
068: * find the desired method.
069: * @throws IllegalArgumentException if the property name is null or empty,
070: * or if there is no getter method for the given property name.
071: */
072: public GetProperty(Class<T> argclass, String propName) {
073: if (propName == null || propName.length() == 0) {
074: throw new IllegalArgumentException(
075: "Must supply property name");
076: }
077:
078: _argtype = argclass;
079:
080: if (propName.startsWith("get")) {
081: _methName = propName;
082: _propName = propName.substring(3);
083: } else if (argclass.equals(Boolean.class)
084: && propName.startsWith("is")) {
085: _methName = propName;
086: _propName = propName.substring(2);
087: } else {
088: _propName = propName;
089: _methName = "get" + propName;
090: }
091:
092: try {
093: _meth = argclass.getMethod(_methName, new Class[0]);
094: } catch (NoSuchMethodException x) {
095: String msg = "class {0} does not have property \"{1}\"";
096: Object[] args = new Object[] { argclass.getName(), propName };
097: IllegalArgumentException iax = new IllegalArgumentException(
098: MessageFormat.format(msg, args));
099: iax.initCause(x);
100: throw iax;
101: }
102: }
103:
104: /**
105: * Returns the name of the property that this functor retrieves.
106: */
107: public String getPropertyName() {
108: return _propName;
109: }
110:
111: // Unary interface
112:
113: /**
114: * Returns the value of the designated property of the argument
115: * @return the value of the designated property of the argument
116: * @throws EvaluationException if the argument does not have the designated
117: * public property, or if it is not of the correct type.
118: */
119: public R fn(T arg) {
120: try {
121: // @SuppressWarnings
122: // There's nothing we can do about this other than warn the users
123: // to make sure that they don't use an inappropriate return type
124: R val = (R) getMethod().invoke(arg, new Object[0]);
125: return val;
126: } catch (ClassCastException x) {
127: String msg = "{0}.{1} returns type {2}";
128: Method m = getMethod();
129: Object[] args = new Object[] { _argtype.getName(),
130: m.getName(), m.getReturnType().getName() };
131: throw new EvaluationException(MessageFormat.format(msg,
132: args), x);
133: } catch (IllegalAccessException x) {
134: String msg = "{0}.{1} is not accessible";
135: Object[] args = new Object[] { _argtype.getName(),
136: getMethod().getName() };
137: throw new EvaluationException(MessageFormat.format(msg,
138: args), x);
139: } catch (InvocationTargetException x) {
140: String msg = "{0}.{1} failed : " + x.getMessage();
141: Object[] args = new Object[] { _argtype.getName(),
142: getMethod().getName() };
143: throw new EvaluationException(MessageFormat.format(msg,
144: args), x);
145: }
146: }
147:
148: private Method getMethod() {
149: if (_meth == null) {
150: try {
151: _meth = _argtype.getMethod(_methName, new Class[0]);
152: } catch (NoSuchMethodException x) {
153: String msg = "class {0} does not have method {1}";
154: Object[] args = new Object[] { _argtype.getName(),
155: _methName };
156: throw new EvaluationException(MessageFormat.format(msg,
157: args), x);
158: }
159: }
160:
161: return _meth;
162: }
163:
164: /**
165: * Calls the Visitor's <code>visit(GetProperty)</code> method, if it
166: * implements the nested Visitor interface.
167: */
168: public void accept(net.sf.jga.fn.Visitor v) {
169: if (v instanceof GetProperty.Visitor)
170: ((GetProperty.Visitor) v).visit(this );
171: else
172: v.visit(this );
173: }
174:
175: // Object overrides
176:
177: public String toString() {
178: return "GetProperty[" + _propName + "]";
179: }
180:
181: // AcyclicVisitor
182:
183: /**
184: * Interface for classes that may interpret a <b>GetProperty</b>
185: * function.
186: */
187: public interface Visitor extends net.sf.jga.fn.Visitor {
188: public void visit(GetProperty host);
189: }
190: }
|