001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.component; 017 018import java.io.Serializable; 019import java.lang.reflect.Method; 020 021import org.apache.commons.lang.StringUtils; 022import org.kuali.rice.core.api.exception.RiceRuntimeException; 023import org.kuali.rice.krad.datadictionary.Copyable; 024import org.kuali.rice.krad.datadictionary.parse.BeanTag; 025import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 026import org.springframework.util.MethodInvoker; 027import org.springframework.util.ReflectionUtils; 028 029/** 030 * Extends <code>MethodInvoker</code> to add properties for specifying 031 * a method for invocation within the UIF 032 * 033 * @author Kuali Rice Team (rice.collab@kuali.org) 034 */ 035@BeanTag(name = "methodConfig", parent = "Uif-MethodInvokerConfig") 036public class MethodInvokerConfig extends MethodInvoker implements Serializable, Copyable { 037 private static final long serialVersionUID = 6626790175367500081L; 038 039 private String staticMethod; 040 private Class[] argumentTypes; 041 042 /** 043 * {@inheritDoc} 044 */ 045 @Override 046 public void prepare() throws ClassNotFoundException, NoSuchMethodException { 047 if ((getTargetObject() == null) && (getTargetClass() != null)) { 048 try { 049 setTargetObject(getTargetClass().newInstance()); 050 } catch (Exception e) { 051 throw new RiceRuntimeException("Unable to create new intance of target class", e); 052 } 053 } 054 055 super.prepare(); 056 } 057 058 /** 059 * Set a fully qualified static method name to invoke, 060 * e.g. "example.MyExampleClass.myExampleMethod". 061 * Convenient alternative to specifying targetClass and targetMethod. 062 * 063 * @return static method to invoke 064 */ 065 @BeanTagAttribute 066 public String getStaticMethod() { 067 return staticMethod; 068 } 069 070 /** 071 * Override to catch a set staticMethod since super does 072 * not contain a getter 073 * 074 * @param staticMethod static method to invoke 075 */ 076 @Override 077 public void setStaticMethod(String staticMethod) { 078 super.setStaticMethod(staticMethod); 079 this.staticMethod = staticMethod; 080 } 081 082 /** 083 * Declared argument types for the method to be invoked, if not set the types will 084 * be retrieved based on the target class and target name 085 * 086 * @return method argument types 087 */ 088 @BeanTagAttribute(type= BeanTagAttribute.AttributeType.LISTVALUE) 089 public Class[] getArgumentTypes() { 090 if (argumentTypes == null) { 091 return getMethodArgumentTypes(); 092 } 093 094 return argumentTypes; 095 } 096 097 /** 098 * Setter for the method argument types that should be invoked 099 * 100 * @param argumentTypes 101 */ 102 public void setArgumentTypes(Class[] argumentTypes) { 103 this.argumentTypes = argumentTypes; 104 } 105 106 /** 107 * {@inheritDoc} 108 */ 109 @BeanTagAttribute 110 @Override 111 public Class getTargetClass() { 112 return super.getTargetClass(); 113 } 114 115 /** 116 * {@inheritDoc} 117 */ 118 @BeanTagAttribute 119 @Override 120 public Object getTargetObject() { 121 return super.getTargetObject(); 122 } 123 124 /** 125 * {@inheritDoc} 126 */ 127 @BeanTagAttribute 128 @Override 129 public String getTargetMethod() { 130 return super.getTargetMethod(); 131 } 132 133 /** 134 * {@inheritDoc} 135 */ 136 @BeanTagAttribute 137 @Override 138 public Object[] getArguments() { 139 return super.getArguments(); 140 } 141 142 /** 143 * Finds the method on the target class that matches the target name and 144 * returns the declared parameter types 145 * 146 * @return method parameter types 147 */ 148 protected Class[] getMethodArgumentTypes() { 149 if (StringUtils.isNotBlank(staticMethod)) { 150 int lastDotIndex = this.staticMethod.lastIndexOf('.'); 151 if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length()) { 152 throw new IllegalArgumentException("staticMethod must be a fully qualified class plus method name: " + 153 "e.g. 'example.MyExampleClass.myExampleMethod'"); 154 } 155 String className = this.staticMethod.substring(0, lastDotIndex); 156 String methodName = this.staticMethod.substring(lastDotIndex + 1); 157 try { 158 setTargetClass(resolveClassName(className)); 159 } catch (ClassNotFoundException e) { 160 throw new RuntimeException("Unable to get class for name: " + className); 161 } 162 setTargetMethod(methodName); 163 } 164 165 Method matchingCandidate = findMatchingMethod(); 166 if (matchingCandidate != null) { 167 return matchingCandidate.getParameterTypes(); 168 } 169 170 Method[] candidates = ReflectionUtils.getAllDeclaredMethods(getTargetClass()); 171 for (Method candidate : candidates) { 172 if (candidate.getName().equals(getTargetMethod())) { 173 return candidate.getParameterTypes(); 174 } 175 } 176 177 return null; 178 } 179 180 /** 181 * @see Copyable#clone() 182 */ 183 @Override 184 public MethodInvokerConfig clone() throws CloneNotSupportedException { 185 return (MethodInvokerConfig) super.clone(); 186 } 187 188}