1/* 2 * Copyright 2001-2009 OFFIS, Tammo Freese 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.easymock.internal; 17 18import static java.lang.Character.*; 19 20import java.io.IOException; 21import java.io.Serializable; 22import java.lang.reflect.Array; 23import java.lang.reflect.Method; 24import java.util.ArrayList; 25import java.util.Collection; 26 27import org.easymock.internal.matchers.Captures; 28 29public class Invocation implements Serializable { 30 31 private static final long serialVersionUID = 1604995470419943411L; 32 33 private final Object mock; 34 35 private transient Method method; 36 37 private final Object[] arguments; 38 39 private final Collection<Captures<?>> currentCaptures = new ArrayList<Captures<?>>( 40 0); 41 42 public Invocation(Object mock, Method method, Object[] args) { 43 this.mock = mock; 44 this.method = method; 45 this.arguments = expandVarArgs(method.isVarArgs(), args); 46 } 47 48 private static Object[] expandVarArgs(final boolean isVarArgs, 49 final Object[] args) { 50 if (!isVarArgs) { 51 return args == null ? new Object[0] : args; 52 } 53 if (args[args.length - 1] == null) { 54 return args; 55 } 56 Object[] varArgs = createObjectArray(args[args.length - 1]); 57 final int nonVarArgsCount = args.length - 1; 58 final int varArgsCount = varArgs.length; 59 Object[] newArgs = new Object[nonVarArgsCount + varArgsCount]; 60 System.arraycopy(args, 0, newArgs, 0, nonVarArgsCount); 61 System.arraycopy(varArgs, 0, newArgs, nonVarArgsCount, varArgsCount); 62 return newArgs; 63 } 64 65 private static Object[] createObjectArray(Object array) { 66 if (array instanceof Object[]) { 67 return (Object[]) array; 68 } 69 Object[] result = new Object[Array.getLength(array)]; 70 for (int i = 0; i < Array.getLength(array); i++) { 71 result[i] = Array.get(array, i); 72 } 73 return result; 74 } 75 76 public Object getMock() { 77 return mock; 78 } 79 80 public Method getMethod() { 81 return method; 82 } 83 84 public Object[] getArguments() { 85 return arguments; 86 } 87 88 @Override 89 public boolean equals(Object o) { 90 if (o == null || !o.getClass().equals(this.getClass())) 91 return false; 92 93 Invocation other = (Invocation) o; 94 95 return this.mock.equals(other.mock) && this.method.equals(other.method) 96 && this.equalArguments(other.arguments); 97 } 98 99 @Override 100 public int hashCode() { 101 throw new UnsupportedOperationException("hashCode() is not implemented"); 102 } 103 104 private boolean equalArguments(Object[] arguments) { 105 if (this.arguments.length != arguments.length) { 106 return false; 107 } 108 for (int i = 0; i < this.arguments.length; i++) { 109 Object myArgument = this.arguments[i]; 110 Object otherArgument = arguments[i]; 111 112 if (isPrimitiveParameter(i)) { 113 if (!myArgument.equals(otherArgument)) { 114 return false; 115 } 116 } else { 117 if (myArgument != otherArgument) { 118 return false; 119 } 120 } 121 } 122 return true; 123 } 124 125 private boolean isPrimitiveParameter(int parameterPosition) { 126 Class<?>[] parameterTypes = method.getParameterTypes(); 127 if (method.isVarArgs()) { 128 parameterPosition = Math.min(parameterPosition, 129 parameterTypes.length - 1); 130 } 131 return parameterTypes[parameterPosition].isPrimitive(); 132 } 133 134 @SuppressWarnings("deprecation") 135 public boolean matches(Invocation actual, org.easymock.ArgumentsMatcher matcher) { 136 return this.mock.equals(actual.mock) 137 && this.method.equals(actual.method) 138 && matcher.matches(this.arguments, actual.arguments); 139 } 140 141 @SuppressWarnings("deprecation") 142 public String toString(org.easymock.ArgumentsMatcher matcher) { 143 return getMockAndMethodName() + "(" + matcher.toString(arguments) + ")"; 144 } 145 146 public String getMockAndMethodName() { 147 String mockName = mock.toString(); 148 String methodName = method.getName(); 149 if (toStringIsDefined(mock) && isJavaIdentifier(mockName)) { 150 return mockName + "." + methodName; 151 } else { 152 return methodName; 153 } 154 } 155 156 public void addCapture(Captures<Object> capture, Object value) { 157 capture.setPotentialValue(value); 158 currentCaptures.add(capture); 159 } 160 161 public void validateCaptures() { 162 for (Captures<?> c : currentCaptures) { 163 c.validateCapture(); 164 } 165 } 166 167 public void clearCaptures() { 168 for (Captures<?> c : currentCaptures) { 169 c.setPotentialValue(null); 170 } 171 currentCaptures.clear(); 172 } 173 174 private boolean toStringIsDefined(Object o) { 175 try { 176 o.getClass().getDeclaredMethod("toString", (Class[]) null) 177 .getModifiers(); 178 return true; 179 } catch (SecurityException ignored) { 180 // ///CLOVER:OFF 181 return false; 182 // ///CLOVER:ON 183 } catch (NoSuchMethodException shouldNeverHappen) { 184 // ///CLOVER:OFF 185 throw new RuntimeException("The toString() method could not be found!"); 186 // ///CLOVER:ON 187 } 188 } 189 190 public static boolean isJavaIdentifier(String mockName) { 191 if (mockName.length() == 0 || mockName.indexOf(' ') > -1 192 || !Character.isJavaIdentifierStart(mockName.charAt(0))) { 193 return false; 194 } 195 for (char c : mockName.substring(1).toCharArray()) { 196 if (!isJavaIdentifierPart(c)) { 197 return false; 198 } 199 } 200 return true; 201 } 202 203 private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { 204 stream.defaultReadObject(); 205 try { 206 method = ((MethodSerializationWrapper) stream.readObject()).getMethod(); 207 } catch (NoSuchMethodException e) { 208 // ///CLOVER:OFF 209 throw new IOException(e.toString()); 210 // ///CLOVER:ON 211 } 212 } 213 214 private void writeObject(java.io.ObjectOutputStream stream) throws IOException { 215 stream.defaultWriteObject(); 216 stream.writeObject(new MethodSerializationWrapper(method)); 217 } 218} 219