001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.plastic;
014
015import org.apache.tapestry5.internal.plastic.PrimitiveType;
016
017import java.lang.reflect.Method;
018import java.util.concurrent.atomic.AtomicLong;
019
020/**
021 * Utilities for user code making use of Plastic.
022 */
023public class PlasticUtils
024{
025    /**
026     * The {@code toString()} method inherited from Object.
027     */
028    public static final Method TO_STRING = getMethod(Object.class, "toString");
029
030    /**
031     * The MethodDescription version of {@code toString()}.
032     */
033    public static final MethodDescription TO_STRING_DESCRIPTION = new MethodDescription(TO_STRING);
034
035    private static final AtomicLong UID_GENERATOR = new AtomicLong(System.nanoTime());
036
037    /**
038     * Returns a string that can be used as part of a Java identifier and is unique
039     * for this JVM. Currently returns a hexadecimal string and initialized by
040     * System.nanoTime() (but both those details may change in the future).
041     *
042     * Note that the returned value may start with a numeric digit, so it should be used as a <em>suffix</em>, not
043     * <em>prefix</em> of a Java identifier.
044     * 
045     * @return unique id that can be used as part of a Java identifier
046     */
047    public static String nextUID()
048    {
049        return Long.toHexString(PlasticUtils.UID_GENERATOR.getAndIncrement());
050    }
051
052    /**
053     * Converts a type (including array and primitive types) to their type name (the way they are represented in Java
054     * source files).
055     */
056    public static String toTypeName(Class type)
057    {
058        if (type.isArray())
059            return toTypeName(type.getComponentType()) + "[]";
060
061        return type.getName();
062    }
063
064    /** Converts a number of types (usually, arguments to a method or constructor) into their type names. */
065    public static String[] toTypeNames(Class[] types)
066    {
067        String[] result = new String[types.length];
068
069        for (int i = 0; i < result.length; i++)
070            result[i] = toTypeName(types[i]);
071
072        return result;
073    }
074
075    /**
076     * Gets the wrapper type for a given type (if primitive)
077     * 
078     * @param type
079     *            type to look up
080     * @return the input type for non-primitive type, or corresponding wrapper type (Boolean.class for boolean.class,
081     *         etc.)
082     */
083    public static Class toWrapperType(Class type)
084    {
085        assert type != null;
086
087        return type.isPrimitive() ? PrimitiveType.getByPrimitiveType(type).wrapperType : type;
088    }
089
090    /**
091     * Convenience for getting a method from a class.
092     * 
093     * @param declaringClass
094     *            containing class
095     * @param name
096     *            name of method
097     * @param parameterTypes
098     *            types of parameters
099     * @return the Method
100     * @throws RuntimeException
101     *             if any error (such as method not found)
102     */
103    @SuppressWarnings("unchecked")
104    public static Method getMethod(Class declaringClass, String name, Class... parameterTypes)
105    {
106        try
107        {
108            return declaringClass.getMethod(name, parameterTypes);
109        }
110        catch (Exception ex)
111        {
112            throw new RuntimeException(ex);
113        }
114    }
115
116    /**
117     * Uses {@link #getMethod(Class, String, Class...)} and wraps the result as a {@link MethodDescription}.
118     * 
119     * @param declaringClass
120     *            containing class
121     * @param name
122     *            name of method
123     * @param parameterTypes
124     *            types of parameters
125     * @return description for method
126     * @throws RuntimeException
127     *             if any error (such as method not found)
128     */
129    public static MethodDescription getMethodDescription(Class declaringClass, String name, Class... parameterTypes)
130    {
131        return new MethodDescription(getMethod(declaringClass, name, parameterTypes));
132    }
133
134    /**
135     * Determines if the provided type name is a primitive type.
136     *
137     * @param typeName Java type name, such as "boolean" or "java.lang.String"
138     * @return true if primitive
139     */
140    public static boolean isPrimitive(String typeName)
141    {
142        return PrimitiveType.getByName(typeName) != null;
143    }
144
145    /**
146     * If the given class is an inner class, returns the enclosing class.
147     * Otherwise, returns the class name unchanged.
148     */
149    public static String getEnclosingClassName(String className)
150    {
151        int index = className.indexOf('$');
152        return index <= 0 ? className : className.substring(0, index);
153    }
154}