zkbind/src/main/java/org/zkoss/bind/impl/MiscUtil.java

Summary

Maintainability
B
6 hrs
Test Coverage
/* MiscUtil.java

    Purpose:
        
    Description:
        
    History:
        2012/4/12 Created by dennis

Copyright (C) 2011 Potix Corporation. All Rights Reserved.
 */
package org.zkoss.bind.impl;

import java.lang.reflect.Method;

import org.zkoss.lang.Classes;
import org.zkoss.lang.Library;
import org.zkoss.util.resource.Location;
import org.zkoss.zk.ui.AbstractComponent;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.metainfo.Annotation;

/**
 * internal use only misc util
 * 
 * @author dennis
 * 
 */
public class MiscUtil {

    public static String toSimpleMethodSignature(Method method) {
        // only keep the method name and parameter type
        StringBuilder sb = new StringBuilder();

        sb.append(method.getName() + "(");
        Class<?>[] params = method.getParameterTypes();
        for (int j = 0; j < params.length; j++) {
            sb.append(getTypeName(params[j]));
            if (j < (params.length - 1))
                sb.append(",");
        }
        sb.append(")");
        return sb.toString();
    }

    @SuppressWarnings("rawtypes")
    static String getTypeName(Class type) {
        if (type.isArray()) {
            try {
                Class cl = type;
                int dimensions = 0;
                while (cl.isArray()) {
                    dimensions++;
                    cl = cl.getComponentType();
                }
                StringBuilder sb = new StringBuilder();
                sb.append(cl.getName());
                for (int i = 0; i < dimensions; i++) {
                    sb.append("[]");
                }
                return sb.toString();
            } catch (Throwable e) { /* FALLTHRU */
            }
        }
        return type.getName();
    }

    @SuppressWarnings("unchecked")
    public static <T> T newInstanceFromProperty(String key, String def, Class<T> type) {
        String clz = Library.getProperty(key, def);
        if (clz != null) {
            final Object v;
            try {
                v = Classes.newInstance(Classes.getContextClassLoader(type).loadClass(clz), null);
            } catch (Exception ex) {
                throw UiException.Aide.wrap(ex);
            }

            if (!type.isAssignableFrom(v.getClass()))
                throw new UiException(type + " must be implemented by " + v);
            return (T) v;
        }
        return null;
    }

    public static String formatLocationMessage(String message, Object obj) {
        if (obj == null)
            return message;
        if (obj instanceof Component) {
            return formatLocationMessage(message, (Component) obj);
        } else if (obj instanceof Annotation) {
            return formatLocationMessage(message, (Annotation) obj);
        } else if (obj instanceof Location) {
            return formatLocationMessage(message, (Location) obj);
        } else {
            return formatLocationMessage(message, (Location) null);
        }
    }

    public static String formatLocationMessage(String message, Component comp) {
        if (comp == null)
            return message;
        return formatLocationMessage(message, toComponentLocation(comp), false);
    }
    
    public static String formatLocationMessage(String message, Annotation anno) {
        if (anno == null)
            return message;
        return formatLocationMessage(message, anno.getLocation(), true);
    }
    
    public static String formatLocationMessage(String message, Location loc) {
        return formatLocationMessage(message, loc, true);
    }
    
    private static String formatLocationMessage(String message, Location loc, boolean showColumn) {
        if (loc == null)
            return message;
        String path = loc.getPath();
        int ln = loc.getLineNumber();
        int cn = loc.getColumnNumber();
        StringBuilder sb = new StringBuilder();
        if (message != null) {
            sb.append(message);
        }
        sb.append(" at [").append(path);
        if (ln >= 0) {
            sb.append(", line:").append(ln);
            if (showColumn && cn >= 0) {
                sb.append(", nearby column: ").append(cn);
            }
        }
        sb.append("]");
        return sb.toString();
    }

    private static Location toComponentLocation(Component comp) {
        if (comp instanceof AbstractComponent) {
            Annotation anno = ((AbstractComponent) comp).getAnnotation(null, "ZKLOC");
            return anno == null ? null : anno.getLocation();
        }
        return null;
    }

    //utility to prevent nested location info in exception
    public static RuntimeException mergeExceptionInfo(Exception ex, Object loc) {
        Location location = null;
        boolean showColumn = true;
        if (loc instanceof Component) {
            location = toComponentLocation((Component) loc);
            showColumn = false;
        } else if (loc instanceof Annotation) {
            location = ((Annotation) loc).getLocation();
        } else if (loc instanceof Location) {
            location = (Location) loc;
        }

        if (location == null) {
            if (ex instanceof RuntimeException) {
                return (RuntimeException) ex;
            } else {
                throw UiException.Aide.wrap(ex, ex.getMessage());
            }
        } else {
            String orgMsg = ex.getMessage();
            String msg = formatLocationMessage(null, location, showColumn);
            if (orgMsg != null && orgMsg.endsWith(msg)) {
                //don't append if the location info is the same.
                if (ex instanceof RuntimeException) {
                    return (RuntimeException) ex;
                } else {
                    throw UiException.Aide.wrap(ex, ex.getMessage());
                }
            } else {
                msg = ex.getClass().getName() + ": " + formatLocationMessage(orgMsg, location, showColumn);
                //no way to change exception's message, so use the most common UiException
                throw UiException.Aide.wrap(ex, msg);
            }

        }
    }
}