All Downloads are FREE. Search and download functionalities are using the official Maven repository.

flex.messaging.util.ClassUtil Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package flex.messaging.util;

import flex.messaging.MessageException;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.SerializationException;
import flex.messaging.validators.DeserializationValidator;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/**
 * Utility class to create instances of Complex Types
 * and handle error conditions consistently across the RemoteObject
 * code base.
 *
 *
 */
public class ClassUtil
{
    private static final int TYPE_NOT_FOUND = 10008;
    private static final int UNEXPECTED_TYPE = 10009;
    private static final int CANNOT_CREATE_TYPE = 10010;
    private static final int SECURITY_ERROR = 10011;
    private static final int UNKNOWN_ERROR = 10012;

    private static final String NULL = "null";

    private ClassUtil()
    {
    }

    /**
     * Create a class of the specified type.
     * Use {@link #createClass(String, ClassLoader)} and explicitly provide the MessageBroker class loader
     *
     * @param type fully qualified class name
     * @return the class instance
     */
    public static Class createClass(String type)
    {
        return createClass(type, null);
    }

    /**
     * Create a class of the specified type using the provided class loader.
     * @param type fully qualified class name
     * @param loader class loader, if null the class loader that loaded ClassUtil is used
     * @return the class instance
     */
    public static Class createClass(String type, ClassLoader loader)
    {
        try
        {
            if (type != null)
                type = type.trim();

            if (loader == null) // will use the loader for this class
                return Class.forName(type);
            return Class.forName(type, true, loader);
        }
        catch (ClassNotFoundException cnf)
        {
            // Cannot invoke type '{type}'
            MessageException ex = new MessageException();
            ex.setMessage(TYPE_NOT_FOUND, new Object[] {type});
            ex.setDetails(TYPE_NOT_FOUND, "0", new Object[] {type});
            ex.setCode(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE);
            throw ex;
        }
    }

    /**
     * Creates the default instance of the class and verifies that it matches
     * with the expected class type, if one passed in.
     *
     * @param cls The class to create.
     * @param expectedInstance The expected class type.
     * @return The default instance of the class.
     */
    public static Object createDefaultInstance(Class cls, Class expectedInstance)
    {
        return ClassUtil.createDefaultInstance(cls, expectedInstance, false /*validate*/);
    }

    /**
     * Creates the default instance of the class and verifies that it matches
     * with the expected class type, if one passed in. It also validates the creation
     * of the instance with the deserialization validator, if one exists.
     *
     * @param cls The class to create.
     * @param expectedInstance The expected class type.
     * @param validate Controls whether the creation of the instance is validated
     * with the deserialization validator.
     * @return The default instance of the class.
     */
    public static Object createDefaultInstance(Class cls, Class expectedInstance, boolean validate)
    {
        if (validate)
            validateCreation(cls);

        String type = cls.getName();
        try
        {
            Object instance = cls.newInstance();

            if (expectedInstance != null && !expectedInstance.isInstance(instance))
            {
                // Given type '{name}' is not of expected type '{expectedName}'.
                MessageException ex = new MessageException();
                ex.setMessage(UNEXPECTED_TYPE, new Object[] {instance.getClass().getName(), expectedInstance.getName()});
                ex.setCode(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE);
                throw ex;
            }

            return instance;
        }
        catch (IllegalAccessException ia)
        {
            boolean details = false;
            StringBuffer message = new StringBuffer("Unable to create a new instance of type ");
            message.append(type);

            //Look for a possible cause...

            // Class might not have a suitable constructor?
            if (!hasValidDefaultConstructor(cls))
            {
                details = true;
            }

            // Unable to create a new instance of type '{type}'.
            MessageException ex = new MessageException();
            ex.setMessage(CANNOT_CREATE_TYPE, new Object[] {type});
            if (details)
            {
                //Types must have a public, no arguments constructor
                ex.setDetails(CANNOT_CREATE_TYPE, "0");
            }
            ex.setCode(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE);
            throw ex;
        }
        catch (InstantiationException ine)
        {
            String variant = null;

            //Look for a possible cause...

            if (cls.isInterface()) // Class is really an interface?
                variant = "1"; // Interfaces cannot be instantiated
            else if (isAbstract(cls))
                variant = "2"; //Abstract types cannot be instantiated.
            else if (!hasValidDefaultConstructor(cls)) // Class might not have a suitable constructor?
                variant = "3"; // Types cannot be instantiated without a public, no arguments constructor.

            MessageException ex = new MessageException();
            ex.setMessage(CANNOT_CREATE_TYPE, new Object[] {type});
            if (variant != null)
                ex.setDetails(CANNOT_CREATE_TYPE, variant);
            ex.setCode(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE);
            throw ex;
        }
        catch (SecurityException se)
        {
            MessageException ex = new MessageException();
            ex.setMessage(SECURITY_ERROR, new Object[] {type});
            ex.setCode(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE);
            ex.setRootCause(se);
            throw ex;
        }
        catch (MessageException me)
        {
            throw me;
        }
        catch (Exception e)
        {
            MessageException ex = new MessageException();
            ex.setMessage(UNKNOWN_ERROR, new Object[] {type});
            ex.setCode(MessageException.CODE_SERVER_RESOURCE_UNAVAILABLE);
            ex.setRootCause(e);
            throw ex;
        }
    }

    public static boolean isAbstract(Class cls)
    {
        try
        {
            if (cls != null)
            {
                int mod = cls.getModifiers();
                return Modifier.isAbstract(mod);
            }
        }
        catch (Throwable t)
        {
            return false;
        }

        return false;
    }

    public static boolean hasValidDefaultConstructor(Class cls)
    {
        try
        {
            if (cls != null)
            {
                Constructor c = cls.getConstructor();
                int mod = c.getModifiers();
                return Modifier.isPublic(mod);
            }
        }
        catch (Throwable t)
        {
            return false;
        }

        return false;
    }

    public static String classLoaderToString(ClassLoader cl)
    {
        if (cl == null)
            return NULL;

        if (cl == ClassLoader.getSystemClassLoader())
            return "system";

        StringBuffer sb = new StringBuffer();
        sb.append("hashCode: " + System.identityHashCode(cl) + " (parent " + ClassUtil.classLoaderToString(cl.getParent()) + ")");
        return sb.toString();
    }

    /**
     * Validates the assignment of a value to an index of an Array or List instance
     * against the deserialization validator. If the assignment is not valid,
     * SerializationException is thrown.
     *
     * @param obj The Array or List instance.
     * @param index The index at which the value is being assigned.
     * @param value The value that is assigned to the index.
     */
    public static void validateAssignment(Object obj, int index, Object value)
    {
        SerializationContext context = SerializationContext.getSerializationContext();
        DeserializationValidator validator = context.getDeserializationValidator();
        if (validator == null)
            return;

        boolean valid = true;
        try
        {
            valid = validator.validateAssignment(obj, index, value);
        }
        catch (Exception e)
        {
            // Assignment validation of the object with type '{0}' for the index '{1}' failed.
            SerializationException se = new SerializationException();
            se.setMessage(10313, new Object[]{obj == null? NULL : obj.getClass().getName(), index});
            se.setRootCause(e);
            throw se;
        }
        if (!valid)
        {
            SerializationException se = new SerializationException();
            se.setMessage(10313, new Object[]{obj == null? NULL : obj.getClass().getName(), index});
            throw se;
        }
    }

    /**
     * Validates the assignment of a property of an instance of a class to a value
     * against the deserialization validator. If the assignment is not valid,
     * SerializationException is thrown.
     *
     * @param obj The class instance whose property is being assigned to a value.
     * @param propName The name of the property that is being assigned.
     * @param value The value that the property is being assigned to.
     */
    public static void validateAssignment(Object obj, String propName, Object value)
    {
        SerializationContext context = SerializationContext.getSerializationContext();
        DeserializationValidator validator = context.getDeserializationValidator();
        if (validator == null)
            return;

        boolean valid = true;
        try
        {
            valid = validator.validateAssignment(obj, propName, value);
        }
        catch (Exception e)
        {
            // Assignment validation of the object with type '{0}' for the property '{1}' failed.
            SerializationException se = new SerializationException();
            se.setMessage(10312, new Object[]{obj == null? NULL : obj.getClass().getName(), propName});
            se.setRootCause(e);
            throw se;
        }
        if (!valid)
        {
            SerializationException se = new SerializationException();
            se.setMessage(10312, new Object[]{obj == null? NULL : obj.getClass().getName(), propName});
            throw se;
        }
    }

    /**
     * Validates the creation of the class instance against the deserialization
     * validator, if one exists. If the class creation is not valid,
     * SerializationException is thrown.
     *
     * @param cls The class to validate.
     */
    public static void validateCreation(Class cls)
    {
        SerializationContext context = SerializationContext.getSerializationContext();
        DeserializationValidator validator = context.getDeserializationValidator();
        if (validator == null)
            return;

        boolean valid = true;
        try
        {
            valid = validator.validateCreation(cls);
        }
        catch (Exception e)
        {
            // Creation validation for class '{0}' failed.
            SerializationException se = new SerializationException();
            se.setMessage(10311, new Object[]{cls == null? NULL : cls.getName()});
            se.setRootCause(e);
            throw se;
        }
        if (!valid)
        {
            // Creation validation for class '{0}' failed.
            SerializationException se = new SerializationException();
            se.setMessage(10311, new Object[]{cls == null? NULL : cls.getName()});
            throw se;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy