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.commons.factory;
021
022import org.apache.isis.core.commons.ensure.Assert;
023import org.apache.isis.core.commons.lang.ObjectExtensions;
024
025public final class InstanceUtil {
026
027    private InstanceUtil() {
028    }
029
030    public static Object createInstance(final String className) {
031        return createInstance(className, (Class<?>) null, null);
032    }
033
034    public static Object createInstance(final Class<?> cls) {
035        return createInstance(cls, (Class<?>) null, null);
036    }
037
038    public static <T> T createInstance(final String className, final Class<T> requiredClass) {
039        return createInstance(className, (Class<T>) null, requiredClass);
040    }
041
042    public static <T> T createInstance(final Class<?> cls, final Class<T> requiredClass) {
043        return createInstance(cls, (Class<T>) null, requiredClass);
044    }
045
046    public static <T> T createInstance(final String className, final String defaultTypeName, final Class<T> requiredType) {
047        Class<? extends T> defaultType = null;
048        if (defaultTypeName != null) {
049            try {
050                defaultType = ObjectExtensions.asT(Thread.currentThread().getContextClassLoader().loadClass(defaultTypeName));
051                if (defaultType == null) {
052                    throw new InstanceCreationClassException("Failed to load default type '" + defaultTypeName + "'");
053                }
054            } catch (final ClassNotFoundException e) {
055                throw new UnavailableClassException("The default type '" + defaultTypeName + "' cannot be found");
056            } catch (final NoClassDefFoundError e) {
057                throw new InstanceCreationClassException("Default type '" + defaultTypeName + "' found, but is missing a dependent class: " + e.getMessage(), e);
058            }
059        }
060        return createInstance(className, defaultType, requiredType);
061    }
062
063    public static <T> T createInstance(final Class<?> cls, final String defaultTypeName, final Class<T> requiredType) {
064        Class<? extends T> defaultType = null;
065        if (defaultTypeName != null) {
066            defaultType = loadClass(defaultTypeName, requiredType);
067            try {
068                defaultType = ObjectExtensions.asT(Thread.currentThread().getContextClassLoader().loadClass(defaultTypeName));
069                if (defaultType == null) {
070                    throw new InstanceCreationClassException("Failed to load default type '" + defaultTypeName + "'");
071                }
072            } catch (final ClassNotFoundException e) {
073                throw new UnavailableClassException("The default type '" + defaultTypeName + "' cannot be found");
074            } catch (final NoClassDefFoundError e) {
075                throw new InstanceCreationClassException("Default type '" + defaultTypeName + "' found, but is missing a dependent class: " + e.getMessage(), e);
076            }
077        }
078        return createInstance(cls, defaultType, requiredType);
079    }
080
081    public static <T> T createInstance(final String className, final Class<? extends T> defaultType, final Class<T> requiredType) {
082        Assert.assertNotNull("Class to instantiate must be specified", className);
083        Class<?> cls = null;
084        try {
085            cls = Thread.currentThread().getContextClassLoader().loadClass(className);
086            if (cls == null) {
087                throw new InstanceCreationClassException("Failed to load class '" + className + "'");
088            }
089            return createInstance(cls, defaultType, requiredType);
090        } catch (final ClassNotFoundException e) {
091            if (className.indexOf('.') == -1) {
092                throw new UnavailableClassException("The component '" + className + "' cannot be found");
093            }
094            throw new UnavailableClassException("The class '" + className + "' cannot be found");
095        } catch (final NoClassDefFoundError e) {
096            throw new InstanceCreationClassException("Class '" + className + "' found , but is missing a dependent class: " + e.getMessage(), e);
097        }
098    }
099
100    public static <T> T createInstance(final Class<?> cls, final Class<? extends T> defaultType, final Class<T> requiredType) {
101        Assert.assertNotNull("Class to instantiate must be specified", cls);
102        try {
103            if (requiredType == null || requiredType.isAssignableFrom(cls)) {
104                final Class<T> tClass = ObjectExtensions.asT(cls);
105                return tClass.newInstance();
106            } else {
107                throw new InstanceCreationClassException("Class '" + cls.getName() + "' is not of type '" + requiredType + "'");
108            }
109        } catch (final NoClassDefFoundError e) {
110            throw new InstanceCreationClassException("Class '" + cls + "'found , but is missing a dependent class: " + e.getMessage(), e);
111        } catch (final InstantiationException e) {
112            throw new InstanceCreationException("Could not instantiate an object of class '" + cls.getName() + "'; " + e.getMessage());
113        } catch (final IllegalAccessException e) {
114            throw new InstanceCreationException("Could not access the class '" + cls.getName() + "'; " + e.getMessage());
115        }
116    }
117
118    public static Class<?> loadClass(final String className) {
119        Assert.assertNotNull("Class to instantiate must be specified", className);
120        try {
121            return Thread.currentThread().getContextClassLoader().loadClass(className);
122        } catch (final ClassNotFoundException e) {
123            throw new UnavailableClassException("The default type '" + className + "' cannot be found");
124        } catch (final NoClassDefFoundError e) {
125            throw new InstanceCreationClassException("Default type '" + className + "' found, but is missing a dependent class: " + e.getMessage(), e);
126        }
127    }
128
129    public static <R, T extends R> Class<T> loadClass(final String className, final Class<R> requiredType) {
130        Assert.assertNotNull("Class to instantiate must be specified", className);
131        try {
132            final Class<?> loadedClass = loadClass(className);
133            if (requiredType != null && !requiredType.isAssignableFrom(loadedClass)) {
134                throw new InstanceCreationClassException("Class '" + className + "' is not of type '" + requiredType + "'");
135            }
136            return ObjectExtensions.asT(loadedClass);
137        } catch (final NoClassDefFoundError e) {
138            throw new InstanceCreationClassException("Default type '" + className + "' found, but is missing a dependent class: " + e.getMessage(), e);
139        }
140    }
141
142}