001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.isis.core.progmodel.facets;
018    
019    import java.lang.reflect.Method;
020    import java.lang.reflect.Modifier;
021    
022    import org.apache.isis.core.metamodel.facetapi.MethodRemover;
023    import org.apache.isis.core.metamodel.methodutils.MethodScope;
024    
025    public final class MethodFinderUtils {
026    
027        private MethodFinderUtils() {
028        }
029    
030        public static Method findMethodWithOrWithoutParameters(final Class<?> type, final MethodScope classMethod,
031            final String name, final Class<?> returnType, final Class<?>[] paramTypes) {
032            Method method = MethodFinderUtils.findMethod(type, classMethod, name, returnType, paramTypes);
033            if (method == null) {
034                method =
035                    MethodFinderUtils.findMethod(type, classMethod, name, returnType,
036                        MethodPrefixBasedFacetFactoryAbstract.NO_PARAMETERS_TYPES);
037            }
038            return method;
039        }
040    
041        /**
042         * Returns a specific public methods that: have the specified prefix; have the specified return type, or void, if
043         * canBeVoid is true; and has the specified number of parameters. If the returnType is specified as null then the
044         * return type is ignored.
045         * 
046         * @param paramTypes
047         *            the set of parameters the method should have, if null then is ignored
048         */
049        public static Method findMethod(final Class<?> type, final MethodScope methodScope, final String name,
050            final Class<?> returnType, final Class<?>[] paramTypes) {
051            Method method;
052            try {
053                method = type.getMethod(name, paramTypes);
054            } catch (final SecurityException e) {
055                return null;
056            } catch (final NoSuchMethodException e) {
057                return null;
058            }
059    
060            final int modifiers = method.getModifiers();
061    
062            // check for public modifier
063            if (!Modifier.isPublic(modifiers)) {
064                return null;
065            }
066    
067            // check for scope modifier
068            if (!methodScope.matchesScopeOf(method)) {
069                return null;
070            }
071    
072            // check for name
073            if (!method.getName().equals(name)) {
074                return null;
075            }
076    
077            // check for return type
078            if (returnType != null && returnType != method.getReturnType()) {
079                return null;
080            }
081    
082            // check params (if required)
083            if (paramTypes != null) {
084                final Class<?>[] parameterTypes = method.getParameterTypes();
085                if (paramTypes.length != parameterTypes.length) {
086                    return null;
087                }
088    
089                for (int c = 0; c < paramTypes.length; c++) {
090                    if ((paramTypes[c] != null) && (paramTypes[c] != parameterTypes[c])) {
091                        return null;
092                    }
093                }
094            }
095    
096            return method;
097        }
098    
099        protected static boolean doesNotMatchScope(final MethodScope methodScope, final Method method) {
100            return methodScope.doesNotMatchScope(method);
101        }
102    
103        public static Method findMethod(final Class<?> type, final MethodScope methodScope, final String name,
104            final Class<?> returnType) {
105            try {
106                final Method[] methods = type.getMethods();
107                for (final Method method2 : methods) {
108                    final Method method = method2;
109                    final int modifiers = method.getModifiers();
110                    // check for public modifier
111                    if (!Modifier.isPublic(modifiers)) {
112                        continue;
113                    }
114    
115                    // check correct scope (static vs instance)
116                    if (!methodScope.matchesScopeOf(method)) {
117                        continue;
118                    }
119    
120                    // check for name
121                    if (!method.getName().equals(name)) {
122                        continue;
123                    }
124    
125                    // check for return type
126                    if (returnType != null && returnType != method.getReturnType()) {
127                        continue;
128                    }
129                    return method;
130                }
131            } catch (final SecurityException e) {
132                return null;
133            }
134            return null;
135        }
136    
137        public static void removeMethod(final MethodRemover methodRemover, final Method method) {
138            if (methodRemover != null && method != null) {
139                methodRemover.removeMethod(method);
140            }
141        }
142    
143        public static Class<?>[] paramTypesOrNull(final Class<?> type) {
144            return type == null ? null : new Class[] { type };
145        }
146    
147        public static boolean allParametersOfSameType(final Class<?>[] params) {
148            final Class<?> firstParam = params[0];
149            for (int i = 1; i < params.length; i++) {
150                if (params[i] != firstParam) {
151                    return false;
152                }
153            }
154            return true;
155        }
156    
157    }