001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.isis.core.metamodel.adapter.util; 021 022import java.lang.reflect.Method; 023import java.util.List; 024import java.util.Map; 025 026import com.google.common.collect.Lists; 027 028import org.apache.isis.core.commons.lang.ClassExtensions; 029import org.apache.isis.core.commons.lang.ListExtensions; 030import org.apache.isis.core.commons.lang.MethodExtensions; 031import org.apache.isis.core.commons.lang.MethodUtil; 032import org.apache.isis.core.metamodel.adapter.ObjectAdapter; 033import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager; 034 035public final class AdapterInvokeUtils { 036 037 private AdapterInvokeUtils() { 038 } 039 040 public static void invokeAll(final List<Method> methods, final ObjectAdapter adapter) { 041 MethodUtil.invoke(methods, AdapterUtils.unwrap(adapter)); 042 } 043 044 public static Object invoke(final Method method, final ObjectAdapter adapter) { 045 return MethodExtensions.invoke(method, AdapterUtils.unwrap(adapter)); 046 } 047 048 public static Object invoke(final Method method, final ObjectAdapter adapter, final Object arg0) { 049 return MethodExtensions.invoke(method, AdapterUtils.unwrap(adapter), new Object[] {arg0}); 050 } 051 052 public static Object invoke(final Method method, final ObjectAdapter adapter, final ObjectAdapter arg0Adapter) { 053 return invoke(method, adapter, AdapterUtils.unwrap(arg0Adapter)); 054 } 055 056 public static Object invoke(final Method method, final ObjectAdapter adapter, final ObjectAdapter[] argumentAdapters) { 057 return MethodExtensions.invoke(method, AdapterUtils.unwrap(adapter), AdapterUtils.unwrap(argumentAdapters)); 058 } 059 060 public static Object invoke(final Method method, final ObjectAdapter adapter, final Map<Integer, ObjectAdapter> argumentAdapters) { 061 return invoke(method, adapter, asArray(argumentAdapters, method.getParameterTypes().length)); 062 } 063 064 private static ObjectAdapter[] asArray(Map<Integer, ObjectAdapter> argumentAdapters, int length) { 065 ObjectAdapter[] args = new ObjectAdapter[length]; 066 for (final Map.Entry<Integer, ObjectAdapter> entry : argumentAdapters.entrySet()) { 067 final Integer paramNum = entry.getKey(); 068 if(paramNum < length) { 069 args[paramNum] = entry.getValue(); 070 } 071 } 072 return args; 073 } 074 075 /** 076 * Invokes the method, adjusting arguments as required to make them fit the method's parameters. 077 * 078 * <p> 079 * That is: 080 * <ul> 081 * <li>if the method declares parameters but arguments are missing, then will provide 'null' defaults for these. 082 * <li>if the method does not declare all parameters for arguments, then truncates arguments. 083 * </ul> 084 */ 085 public static Object invokeAutofit(final Method method, final ObjectAdapter target, List<ObjectAdapter> argumentsIfAvailable, final AdapterManager adapterManager) { 086 final List<ObjectAdapter> args = Lists.newArrayList(); 087 if(argumentsIfAvailable != null) { 088 args.addAll(argumentsIfAvailable); 089 } 090 091 adjust(method, args, adapterManager); 092 093 final ObjectAdapter[] argArray = args.toArray(new ObjectAdapter[]{}); 094 return AdapterInvokeUtils.invoke(method, target, argArray); 095 } 096 097 private static void adjust(final Method method, final List<ObjectAdapter> args, final AdapterManager adapterManager) { 098 final Class<?>[] parameterTypes = method.getParameterTypes(); 099 ListExtensions.adjust(args, parameterTypes.length); 100 101 for(int i=0; i<parameterTypes.length; i++) { 102 final Class<?> cls = parameterTypes[i]; 103 if(args.get(i) == null && cls.isPrimitive()) { 104 final Object object = ClassExtensions.toDefault(cls); 105 final ObjectAdapter adapter = adapterManager.adapterFor(object); 106 args.set(i, adapter); 107 } 108 } 109 } 110 111 /** 112 * Invokes the method, adjusting arguments as required. 113 * 114 * <p> 115 * That is: 116 * <ul> 117 * <li>if the method declares parameters but no arguments are provided, then will provide 'null' defaults for these. 118 * <li>if the method does not declare parameters but arguments were provided, then will ignore those argumens. 119 * </ul> 120 */ 121 @SuppressWarnings("unused") 122 private static Object invokeWithDefaults(final Method method, final ObjectAdapter adapter, final ObjectAdapter[] argumentAdapters) { 123 final int numParams = method.getParameterTypes().length; 124 ObjectAdapter[] adapters; 125 126 if(argumentAdapters == null || argumentAdapters.length == 0) { 127 adapters = new ObjectAdapter[numParams]; 128 } else if(numParams == 0) { 129 // ignore any arguments, even if they were supplied. 130 // eg used by contributee actions, but 131 // underlying service 'default' action declares no params 132 adapters = new ObjectAdapter[0]; 133 } else if(argumentAdapters.length == numParams){ 134 adapters = argumentAdapters; 135 } else { 136 throw new IllegalArgumentException("Method has " + numParams + " params but " + argumentAdapters.length + " arguments provided"); 137 } 138 139 return AdapterInvokeUtils.invoke(method, adapter, adapters); 140 } 141 142}