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.commons.discovery.tools;
018    
019    import java.lang.reflect.Constructor;
020    import java.lang.reflect.InvocationTargetException;
021    import java.lang.reflect.Method;
022    import java.lang.reflect.Modifier;
023    
024    import org.apache.commons.discovery.DiscoveryException;
025    
026    import org.apache.commons.discovery.log.DiscoveryLogFactory;
027    import org.apache.commons.logging.Log;
028    
029    
030    /**
031     * @author Richard A. Sitze
032     */
033    public class ClassUtils {
034        private static Log log = DiscoveryLogFactory.newLog(ClassUtils.class);
035        public static void setLog(Log _log) {
036            log = _log;
037        }
038    
039        /**
040         * Get package name.
041         * Not all class loaders 'keep' package information,
042         * in which case Class.getPackage() returns null.
043         * This means that calling Class.getPackage().getName()
044         * is unreliable at best.
045         */
046        public static String getPackageName(Class clazz) {
047            Package clazzPackage = clazz.getPackage();
048            String packageName;
049            if (clazzPackage != null) {
050                packageName = clazzPackage.getName();
051            } else {
052                String clazzName = clazz.getName();
053                packageName = clazzName.substring(0, clazzName.lastIndexOf('.'));
054            }
055            return packageName;
056        }
057        
058        /**
059         * @return Method 'public static returnType methodName(paramTypes)',
060         *         if found to be <strong>directly</strong> implemented by clazz.
061         */
062        public static Method findPublicStaticMethod(Class clazz,
063                                                    Class returnType,
064                                                    String methodName,
065                                                    Class[] paramTypes) {
066            boolean problem = false;
067            Method method = null;
068    
069            // verify '<methodName>(<paramTypes>)' is directly in class.
070            try {
071                method = clazz.getDeclaredMethod(methodName, paramTypes);
072            } catch(NoSuchMethodException e) {
073                problem = true;
074                log.debug("Class " + clazz.getName() + ": missing method '" + methodName + "(...)", e);
075            }
076            
077            // verify 'public static <returnType>'
078            if (!problem  &&
079                !(Modifier.isPublic(method.getModifiers()) &&
080                  Modifier.isStatic(method.getModifiers()) &&
081                  method.getReturnType() == returnType)) {
082                if (log.isDebugEnabled()) {
083                    if (!Modifier.isPublic(method.getModifiers())) {
084                        log.debug(methodName + "() is not public");
085                    }
086                    if (!Modifier.isStatic(method.getModifiers())) {
087                        log.debug(methodName + "() is not static");
088                    }
089                    if (method.getReturnType() != returnType) {
090                        log.debug("Method returns: " + method.getReturnType().getName() + "@@" + method.getReturnType().getClassLoader());
091                        log.debug("Should return:  " + returnType.getName() + "@@" + returnType.getClassLoader());
092                    }
093                }
094                problem = true;
095                method = null;
096            }
097            
098            return method;
099        }
100    
101        /**
102         * Instantiate a new 
103         */    
104        public static Object newInstance(Class impl, Class paramClasses[], Object params[])
105            throws DiscoveryException,
106                   InstantiationException,
107                   IllegalAccessException,
108                   NoSuchMethodException,
109                   InvocationTargetException
110        {
111            if (paramClasses == null || params == null) {
112                return impl.newInstance();
113            } else {
114                Constructor constructor = impl.getConstructor(paramClasses);
115                return constructor.newInstance(params);
116            }
117        }
118        
119        /**
120         * Throws exception if <code>impl</code> does not
121         * implement or extend the SPI.
122         */
123        public static void verifyAncestory(Class spi, Class impl)
124            throws DiscoveryException
125        {
126            if (spi == null) {
127                throw new DiscoveryException("No interface defined!");
128            }
129    
130            if (impl == null) {
131                throw new DiscoveryException("No implementation defined for " + spi.getName());
132            }
133    
134            if (!spi.isAssignableFrom(impl)) {
135                throw new DiscoveryException("Class " + impl.getName() +
136                                             " does not implement " + spi.getName());
137            }
138        }
139    }