001 /* JAPI - (Yet anothr (hopefully) useful) Java API
002 *
003 * Copyright (C) 2004-2006 Christian Hujer
004 *
005 * This program is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU General Public License as
007 * published by the Free Software Foundation; either version 2 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but
011 * WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013 * General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program; if not, write to the Free Software
017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018 * 02111-1307, USA.
019 */
020
021 package net.sf.japi.swing;
022
023 import java.awt.event.ActionEvent;
024 import java.lang.reflect.InvocationTargetException;
025 import java.lang.reflect.Method;
026 import javax.swing.AbstractAction;
027 import javax.swing.Icon;
028
029 /** Action implementation which invokes the desired method using Reflection.
030 * Usage example:
031 * <pre>
032 * class SomeClass {
033 * SomeClass() {
034 * ReflectionAction action = new ReflectionAction();
035 * action.putValue(REFLECTION_TARGET, this);
036 * action.putValue(REFLECTION_METHOD_NAME, "myAction");
037 * new JMenuItem(action);
038 * }
039 * void myAction() {
040 * // do something
041 * }
042 * }
043 * </pre>
044 * Note that because of Reflection this Action is slightly slower than implementing your own Action instance, but in most cases this really does not
045 * matter at all.
046 * @author <a href="mailto:Christian.Hujer@itcqis.com">Christian Hujer</a>
047 */
048 public final class ReflectionAction extends AbstractAction {
049
050 /** The key used for storing the target object to invoke the method on.
051 * Value Type: {@link Object}.
052 */
053 public static final String REFLECTION_TARGET = "ReflectionTarget";
054
055 /** The key used for storing the method name to use when searching for a method using reflection.
056 * Value Type: {@link String} (checked).
057 */
058 public static final String REFLECTION_METHOD_NAME = "ReflectionMethodName";
059
060 /** The key used for storing the method object to use when invoking the method.
061 * Value Type: {@link Method} (checked).
062 */
063 public static final String REFLECTION_METHOD = "ReflectionMethod";
064
065 /** Serial Version. */
066 @SuppressWarnings({"AnalyzingVariableNaming"})
067 private static final long serialVersionUID = 1L;
068
069 /** Create an uninitialized ReflectionAction. */
070 public ReflectionAction() {
071 }
072
073 /** Create a ReflectionAction with method and target.
074 * @param methodName Name of method to invoke
075 * @param target Target object to invoke method at
076 */
077 public ReflectionAction(final String methodName, final Object target) {
078 putValue(REFLECTION_METHOD_NAME, methodName);
079 putValue(REFLECTION_TARGET, target);
080 }
081
082 /** {@inheritDoc}
083 * This implementation checks the type of <var>newValue</var> if the <var>key</var> is {@link #REFLECTION_METHOD_NAME} or {@link
084 * #REFLECTION_METHOD}, so you'll know of errors quite soon.
085 * @throws IllegalArgumentException if <var>newValue</var> is of the wrong type
086 */
087 @Override public void putValue(final String key, final Object newValue) throws IllegalArgumentException {
088 if (REFLECTION_METHOD_NAME.equals(key)) {
089 if (!(newValue == null || newValue instanceof String)) {
090 throw new IllegalArgumentException("Value for key REFLECTION_METHOD_NAME must be of type " + String.class.getName() + " but was " + newValue.getClass().getName());
091 }
092 putValue(REFLECTION_METHOD, null);
093 }
094 if (REFLECTION_METHOD.equals(key)) {
095 if (!(newValue == null || newValue instanceof Method)) {
096 if (newValue instanceof String) {
097 throw new IllegalArgumentException("Value for key REFLECTION_METHOD must be of type " + Method.class.getName() + " but was " + String.class.getName() + " so you might want to use the key REFLECTION_METHOD_NAME instead.");
098 } else {
099 throw new IllegalArgumentException("Value for key REFLECTION_METHOD must be of type " + Method.class.getName() + " but was " + newValue.getClass().getName());
100 }
101 }
102 }
103 if (REFLECTION_TARGET.equals(key)) {
104 if (newValue == null) {
105 putValue(REFLECTION_METHOD, null);
106 }
107 }
108 super.putValue(key, newValue);
109 }
110
111 /** Defines an <code>Action</code> object with the specified description string and a the specified icon.
112 * @param name description string
113 * @param icon icon
114 * @param methodName Name of method to invoke
115 * @param target Target object to invoke method at
116 */
117 public ReflectionAction(final String name, final Icon icon, final String methodName, final Object target) {
118 super(name, icon);
119 putValue(REFLECTION_METHOD_NAME, methodName);
120 putValue(REFLECTION_TARGET, target);
121 }
122
123 /** {@inheritDoc}
124 * The implementation of this method first looks whether the Action is enabled.
125 * If it isn't, the method simply returns.
126 * Otherwise, instance and method are looked up.
127 * If both are null, the method again returns.
128 * If the method is null, it is reflected upon the instance usign the method name. If the method name is null, the method returns.
129 * Finally the method is invoked upon the instance, which may be null for static methods.
130 * @throws RuntimeException with cause in case the invocation of the method threw an exception
131 */
132 public void actionPerformed(final ActionEvent e) {
133 if (!isEnabled()) { return; }
134 final Object instance = getValue(REFLECTION_TARGET);
135 Method method = (Method) getValue(REFLECTION_METHOD);
136 if (instance == null && method == null) {
137 return;
138 } // it's okay if method is not null but instance is null because it might be a static method?
139 if (method == null) {
140 final String methodName = (String) getValue(REFLECTION_METHOD_NAME);
141 if (methodName == null) {
142 return;
143 }
144 try {
145 method = instance.getClass().getMethod(methodName);
146 putValue(REFLECTION_METHOD, method);
147 } catch (final NoSuchMethodException ex) {
148 assert false : ex;
149 return;
150 }
151 }
152 try {
153 method.invoke(instance);
154 } catch (final IllegalAccessException ex) {
155 assert false : ex;
156 } catch (final InvocationTargetException ex) {
157 throw new RuntimeException(ex.getCause());
158 }
159 }
160
161 /** {@inheritDoc} */
162 @Override protected Object clone() throws CloneNotSupportedException {
163 return super.clone();
164 }
165
166 } // class ReflectionAction