package jargs.gnu;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Vector;

/**
 * Largely GNU-compatible command-line options parser. Has short (-v) and
 * long-form (--verbose) option support, and also allows options with
 * associated values (-d 2, --debug 2, --debug=2). Option processing
 * can be explicitly terminated by the argument '--'.
 *
 * @author Steve Purcell
 * @version $Revision: 1.10 $
 */
public class CmdLineParser {

    /**
     * Base class for exceptions that may be thrown when options are parsed
     */
    public static abstract class OptionException extends Exception {
        OptionException(String msg) { super(msg); }
    }

    /**
     * Thrown when the parsed command-line contains an option that is not
     * recognised. getMessage() returns
     * an error string suitable for reporting the error to the user (in
     * English).
     */
    public static class UnknownOptionException extends OptionException {
        UnknownOptionException( String optionName ) {
            this(optionName, "Unknown option '" + optionName + "'");
        }

        UnknownOptionException( String optionName, String msg ) {
            super(msg);
            this.optionName = optionName;
        }

        /**
         * @return the name of the option that was unknown (e.g. "-u")
         */
        public String getOptionName() { return this.optionName; }
        private String optionName = null;
    }

    /**
     * Thrown when the parsed commandline contains multiple concatenated
     * short options, such as -abcd, where one is unknown.
     * getMessage() returns an english human-readable error
     * string.
     * @author Vidar Holen
     */
    public static class UnknownSuboptionException
        extends UnknownOptionException {
        private char suboption;

        UnknownSuboptionException( String option, char suboption ) {
            super(option, "Illegal option: '"+suboption+"' in '"+option+"'");
            this.suboption=suboption;
        }
        public char getSuboption() { return suboption; }
    }

    /**
     * Thrown when the parsed commandline contains multiple concatenated
     * short options, such as -abcd, where one or more requires a value.
     * getMessage() returns an english human-readable error
     * string.
     * @author Vidar Holen
     */
    public static class NotFlagException extends UnknownOptionException {
        private char notflag;

        NotFlagException( String option, char unflaggish ) {
            super(option, "Illegal option: '"+option+"', '"+
                  unflaggish+"' requires a value");
            notflag=unflaggish;
        }

        /**
         * @return the first character which wasn't a boolean (e.g 'c')
         */
        public char getOptionChar() { return notflag; }
    }

    /**
     * Thrown when an illegal or missing value is given by the user for
     * an option that takes a value. getMessage() returns
     * an error string suitable for reporting the error to the user (in
     * English).
     */
    public static class IllegalOptionValueException extends OptionException {
        public IllegalOptionValueException( Option opt, String value ) {
            super("Illegal value '" + value + "' for option " +
                  (opt.shortForm() != null ? "-" + opt.shortForm() + "/" : "") +
                  "--" + opt.longForm());
            this.option = opt;
            this.value = value;
        }

        /**
         * @return the name of the option whose value was illegal (e.g. "-u")
         */
        public Option getOption() { return this.option; }

        /**
         * @return the illegal value
         */
        public String getValue() { return this.value; }
        private Option option;
        private String value;
    }

    /**
     * Representation of a command-line option
     */
    public static abstract class Option {

        protected Option( String longForm, boolean wantsValue ) {
            this(null, longForm, wantsValue);
        }

        protected Option( char shortForm, String longForm,
                          boolean wantsValue ) {
            this(new String(new char[]{shortForm}), longForm, wantsValue);
        }

        private Option( String shortForm, String longForm, boolean wantsValue ) {
            if ( longForm == null )
                throw new IllegalArgumentException("Null longForm not allowed");
            this.shortForm = shortForm;
            this.longForm = longForm;
            this.wantsValue = wantsValue;
        }

        public String shortForm() { return this.shortForm; }

        public String longForm() { return this.longForm; }

        /**
         * Tells whether or not this option wants a value
         */
        public boolean wantsValue() { return this.wantsValue; }

        public final Object getValue( String arg, Locale locale )
            throws IllegalOptionValueException {
            if ( this.wantsValue ) {
                if ( arg == null ) {
                    throw new IllegalOptionValueException(this, "");
                }
                return this.parseValue(arg, locale);
            }
            else {
                return Boolean.TRUE;
            }
        }

        /**
         * Override to extract and convert an option value passed on the
         * command-line
         */
        protected Object parseValue( String arg, Locale locale )
            throws IllegalOptionValueException {
            return null;
        }

        private String shortForm = null;
        private String longForm = null;
        private boolean wantsValue = false;

        public static class BooleanOption extends Option {
            public BooleanOption( char shortForm, String longForm ) {
                super(shortForm, longForm, false);
            }
            public BooleanOption( String longForm ) {
                super(longForm, false);
            }
        }

        /**
         * An option that expects an integer value
         */
        public static class IntegerOption extends Option {
            public IntegerOption( char shortForm, String longForm ) {
                super(shortForm, longForm, true);
            }
            public IntegerOption( String longForm ) {
                super(longForm, true);
            }
            protected Object parseValue( String arg, Locale locale )
                throws IllegalOptionValueException {
                try {
                    return new Integer(arg);
                }
                catch (NumberFormatException e) {
                    throw new IllegalOptionValueException(this, arg);
                }
            }
        }

        /**
         * An option that expects a long integer value
         */
        public static class LongOption extends Option {
            public LongOption( char shortForm, String longForm ) {
                super(shortForm, longForm, true);
            }
            public LongOption( String longForm ) {
                super(longForm, true);
            }
            protected Object parseValue( String arg, Locale locale )
                throws IllegalOptionValueException {
                try {
                    return new Long(arg);
                }
                catch (NumberFormatException e) {
                    throw new IllegalOptionValueException(this, arg);
                }
            }
        }

        /**
         * An option that expects a floating-point value
         */
        public static class DoubleOption extends Option {
            public DoubleOption( char shortForm, String longForm ) {
                super(shortForm, longForm, true);
            }
            public DoubleOption( String longForm ) {
                super(longForm, true);
            }
            protected Object parseValue( String arg, Locale locale )
                throws IllegalOptionValueException {
                try {
                    NumberFormat format = NumberFormat.getNumberInstance(locale);
                    Number num = (Number)format.parse(arg);
                    return new Double(num.doubleValue());
                }
                catch (ParseException e) {
                    throw new IllegalOptionValueException(this, arg);
                }
            }
        }

        /**
         * An option that expects a string value
         */
        public static class StringOption extends Option {
            public StringOption( char shortForm, String longForm ) {
                super(shortForm, longForm, true);
            }
            public StringOption( String longForm ) {
                super(longForm, true);
            }
            protected Object parseValue( String arg, Locale locale ) {
                return arg;
            }
        }
    }

    /**
     * Add the specified Option to the list of accepted options
     */
    public final Option addOption( Option opt ) {
        if ( opt.shortForm() != null )
            this.options.put("-" + opt.shortForm(), opt);
        this.options.put("--" + opt.longForm(), opt);
        return opt;
    }

    /**
     * Convenience method for adding a string option.
     * @return the new Option
     */
    public final Option addStringOption( char shortForm, String longForm ) {
        return addOption(new Option.StringOption(shortForm, longForm));
    }

    /**
     * Convenience method for adding a string option.
     * @return the new Option
     */
    public final Option addStringOption( String longForm ) {
        return addOption(new Option.StringOption(longForm));
    }

    /**
     * Convenience method for adding an integer option.
     * @return the new Option
     */
    public final Option addIntegerOption( char shortForm, String longForm ) {
        return addOption(new Option.IntegerOption(shortForm, longForm));
    }

    /**
     * Convenience method for adding an integer option.
     * @return the new Option
     */
    public final Option addIntegerOption( String longForm ) {
        return addOption(new Option.IntegerOption(longForm));
    }

    /**
     * Convenience method for adding a long integer option.
     * @return the new Option
     */
    public final Option addLongOption( char shortForm, String longForm ) {
        return addOption(new Option.LongOption(shortForm, longForm));
    }

    /**
     * Convenience method for adding a long integer option.
     * @return the new Option
     */
    public final Option addLongOption( String longForm ) {
        return addOption(new Option.LongOption(longForm));
    }

    /**
     * Convenience method for adding a double option.
     * @return the new Option
     */
    public final Option addDoubleOption( char shortForm, String longForm ) {
        return addOption(new Option.DoubleOption(shortForm, longForm));
    }

    /**
     * Convenience method for adding a double option.
     * @return the new Option
     */
    public final Option addDoubleOption( String longForm ) {
        return addOption(new Option.DoubleOption(longForm));
    }

    /**
     * Convenience method for adding a boolean option.
     * @return the new Option
     */
    public final Option addBooleanOption( char shortForm, String longForm ) {
        return addOption(new Option.BooleanOption(shortForm, longForm));
    }

    /**
     * Convenience method for adding a boolean option.
     * @return the new Option
     */
    public final Option addBooleanOption( String longForm ) {
        return addOption(new Option.BooleanOption(longForm));
    }

    /**
     * Equivalent to {@link #getOptionValue(CmdLineParser.Option, Object) getOptionValue(o,
     * null)}.
     */
    public final Object getOptionValue( Option o ) {
        return getOptionValue(o, null);
    }

    /**
     * @return the parsed value of the given Option, or null if the
     * option was not set
     */
    public final Object getOptionValue( Option o, Object def ) {
        Vector v = (Vector)values.get(o.longForm());

        if (v == null) {
            return def;
        }
        else if (v.isEmpty()) {
            return null;
        }
        else {
            Object result = v.elementAt(0);
            v.removeElementAt(0);
            return result;
        }
    }

    /**
     * @return A Vector giving the parsed values of all the occurrences of the
     * given Option, or an empty Vector if the option was not set.
     */
    public final Vector getOptionValues( Option option ) {
        Vector result = new Vector();

        while (true) {
            Object o = getOptionValue(option, null);

            if (o == null) {
                return result;
            }
            else {
                result.addElement(o);
            }
        }
    }

    /**
     * @return the non-option arguments
     */
    public final String[] getRemainingArgs() {
        return this.remainingArgs;
    }

    /**
     * Extract the options and non-option arguments from the given
     * list of command-line arguments. The default locale is used for
     * parsing options whose values might be locale-specific.
     */
    public final void parse( String[] argv )
        throws IllegalOptionValueException, UnknownOptionException {

        // It would be best if this method only threw OptionException, but for
        // backwards compatibility with old user code we throw the two
        // exceptions above instead.

        parse(argv, Locale.getDefault());
    }

    /**
     * Extract the options and non-option arguments from the given
     * list of command-line arguments. The specified locale is used for
     * parsing options whose values might be locale-specific.
     */
    public final void parse( String[] argv, Locale locale )
        throws IllegalOptionValueException, UnknownOptionException {

        // It would be best if this method only threw OptionException, but for
        // backwards compatibility with old user code we throw the two
        // exceptions above instead.

        Vector otherArgs = new Vector();
        int position = 0;
        this.values = new Hashtable(10);
        while ( position < argv.length ) {
            String curArg = argv[position];
            if ( curArg.startsWith("-") ) {
                if ( curArg.equals("--") ) { // end of options
                    position += 1;
                    break;
                }
                String valueArg = null;
                if ( curArg.startsWith("--") ) { // handle --arg=value
                    int equalsPos = curArg.indexOf("=");
                    if ( equalsPos != -1 ) {
                        valueArg = curArg.substring(equalsPos+1);
                        curArg = curArg.substring(0,equalsPos);
                    }
                } else if(curArg.length() > 2) {  // handle -abcd
                    for(int i=1; i<curArg.length(); i++) {
                        Option opt=(Option)this.options.get
                            ("-"+curArg.charAt(i));
                        if(opt==null) throw new
                            UnknownSuboptionException(curArg,curArg.charAt(i));
                        if(opt.wantsValue()) throw new
                            NotFlagException(curArg,curArg.charAt(i));
                        addValue(opt, opt.getValue(null,locale));

                    }
                    position++;
                    continue;
                }

                Option opt = (Option)this.options.get(curArg);
                if ( opt == null ) {
                    throw new UnknownOptionException(curArg);
                }
                Object value = null;
                if ( opt.wantsValue() ) {
                    if ( valueArg == null ) {
                        position += 1;
                        if ( position < argv.length ) {
                            valueArg = argv[position];
                        }
                    }
                    value = opt.getValue(valueArg, locale);
                }
                else {
                    value = opt.getValue(null, locale);
                }

                addValue(opt, value);

                position += 1;
            }
            else {
                otherArgs.addElement(curArg);
                position += 1;
            }
        }
        for ( ; position < argv.length; ++position ) {
            otherArgs.addElement(argv[position]);
        }

        this.remainingArgs = new String[otherArgs.size()];
        otherArgs.copyInto(remainingArgs);
    }

    private void addValue(Option opt, Object value) {
        String lf = opt.longForm();

        Vector v = (Vector)values.get(lf);

        if (v == null) {
            v = new Vector();
            values.put(lf, v);
        }

        v.addElement(value);
    }

    private String[] remainingArgs = null;
    private Hashtable options = new Hashtable(10);
    private Hashtable values = new Hashtable(10);
}


/*
 *
 *  AbstractCharsetdetector.java, provides the default implementation
 *  for the high-level codepage detection method of interface ICodepageProcessor.
 *
 *  Copyright (C) Achim Westermann, created on 19.07.2004, 21:45:47
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this collection are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the cpDetector code in [sub] packages info.monitorenter and
 * cpdetector.
 *
 * The Initial Developer of the Original Code is
 * Achim Westermann <achim.westermann@gmx.de>.
 *
 * Portions created by the Initial Developer are Copyright (c) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** *
 *
 *  If you modify or optimize the code in a useful way please let me know.
 *  Achim.Westermann@gmx.de
 *
 */
package info.monitorenter.cpdetector.io;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;

/**
 *

 * This implementation provides the default implementation for the high-level codepage detection method
 * {@link #open(java.net.URL)}of the implemented interface ICodepageProcessor.
 *

 *

 * Also the Comparable interface implementation is provided here by comparing the class-name strings of the
 * implementations.
 *

 *
 * @author Achim Westermann
 *
 */
public abstract class AbstractCodepageDetector implements ICodepageDetector {
    /**
     *
     */
    public AbstractCodepageDetector() {
        super();
    }

    /**
     * Delegates to {@link #detectCodepage(java.io.InputStream, int)} with a buffered input stream.
     *

     *
     * @see info.monitorenter.cpdetector.io.ICodepageDetector#detectCodepage(java.net.URL)
     */
    public Charset detectCodepage(final URL url) throws IOException {
        Charset result;
        BufferedInputStream in = new BufferedInputStream(url.openStream());
        result = this.detectCodepage(in, Integer.MAX_VALUE);
        in.close();
        return result;

    }

    /**
     * A default delegation to {@link #detectCodepage(java.net.URL)}that opens the document specified by the given URL with the
     * detected codepage.
     *

     *
     * @see ICodepageDetector#open(java.net.URL)
     */
    public final Reader open(final URL url) throws IOException {
        Reader ret = null;
        Charset cs = this.detectCodepage(url);
        if (cs != null) {
            ret = new InputStreamReader(new BufferedInputStream(url.openStream()), cs);
        }
        return ret;
    }

    /**
     * @see Comparable#compareTo(Object)
     */
    public int compareTo(final Object o) {
        String other = o.getClass().getName();
        String mine = this.getClass().getName();
        return mine.compareTo(other);
    }
}


package com.xiongyingqi.util;

/**
 * 堆栈帮助类
 *
 * @author 瑛琪 xiongyingqi.com
 * @version 2013-8-28 下午3:51:58
 */
public class StackTraceHelper {
    /**
     * 打印出调用堆栈

     * 2013-8-28 下午3:52:17
     */
    public static void printStackTrace() {
        Throwable throwable = new Throwable();
        StackTraceElement[] stackTraceElements = throwable.getStackTrace();
        StackTraceElement[] stackTraceElementsTarget = new StackTraceElement[stackTraceElements.length - 1];
        // for (int i = 1, j = 0; i < stackTraceElements.length; i++) {
        // StackTraceElement stackTraceElement = stackTraceElements[i];
        // System.out.println(stackTraceElement.getClassName());
        // System.out.println(stackTraceElement.getFileName());
        // System.out.println(stackTraceElement.getMethodName());
        // System.out.println(stackTraceElement.getLineNumber());
        // System.out.println("    at " + stackTraceElement.getClassName() + "."
        // + stackTraceElement.getMethodName() + "(" +
        // stackTraceElement.getFileName() + ":" +
        // stackTraceElement.getLineNumber() + ")");
        // }
        System.arraycopy(stackTraceElements, 1, stackTraceElementsTarget, 0,
                stackTraceElementsTarget.length);
        System.out.println(" ----------------------- StackTrace Info ----------------------- ");
        System.out.print(buildStackTrace(stackTraceElementsTarget));
    }

    /**
     * 组织堆栈信息，将堆栈数组拼接成字符串

     * 2013-8-28 下午3:50:50
     *
     * @param stackTraceElements
     * @return String
     */
    public static String buildStackTrace(StackTraceElement[] stackTraceElements) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < stackTraceElements.length; i++) {
            StackTraceElement stackTraceElement = stackTraceElements[i];
            builder.append("    at ");
            builder.append(stackTraceElement.getClassName());
            builder.append(".");
            builder.append(stackTraceElement.getMethodName());
            builder.append("(");
            builder.append(stackTraceElement.getFileName());
            builder.append(":");
            builder.append(stackTraceElement.getLineNumber());
            builder.append(")");
            builder.append(StringHelper.line());
        }
        return builder.toString();
    }

    /**
     * 返回不包括本类调用堆栈的当前堆栈

     * 2013-7-26 下午6:09:09
     *
     * @return
     */
    public static StackTraceElement[] getStackTrace() {
        Throwable throwable = new Throwable();
        StackTraceElement[] stackTraceElements = throwable.getStackTrace();
        StackTraceElement[] stackTraceElementsTarget = new StackTraceElement[stackTraceElements.length];
        System.arraycopy(stackTraceElements, 0, stackTraceElementsTarget, 0,
                stackTraceElementsTarget.length);
        return stackTraceElementsTarget;
    }

    /**
     * 获取间接调用的类名

     * 比如A方法调用B方法，B方法再调用whoInvoke()方法，这样B方法内就能返回A方法在那个类下
     *
     * @return
     */
    public static Class whoInvoke() {
        Throwable throwable = new Throwable();
        StackTraceElement[] stackTraceElements = throwable.getStackTrace();
        StackTraceElement stackTraceElement = stackTraceElements[2];
        try {
            return Class.forName(stackTraceElement.getClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        printStackTrace();
        StackTraceElement[] stackTraceElements = getStackTrace();
        for (int i = 1; i < stackTraceElements.length; i++) {
            StackTraceElement stackTraceElement = stackTraceElements[i];
            // System.out.println(stackTraceElement.getClassName());
            // System.out.println(stackTraceElement.getFileName());
            // System.out.println(stackTraceElement.getMethodName());
            // System.out.println(stackTraceElement.getLineNumber());
            System.out.println("    at " + stackTraceElement.getClassName() + "."
                    + stackTraceElement.getMethodName() + "(" + stackTraceElement.getFileName()
                    + ":" + stackTraceElement.getLineNumber() + ")");
        }
        // Long.parseLong("s");
    }
}


package com.xiongyingqi;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by 瑛琪xiongyingqi.com on 2014/5/6 0006.
 */
public class Logger {
    private static Map<String, org.apache.log4j.Logger> nameLoggerMap = new HashMap<String, org.apache.log4j.Logger>();

    // ---------------------------- debug　----------------------------
    public static void debug(Object object, Object message) {
        Class clazz = object.getClass();
        debug(clazz, message);
    }

    public static void debug(Class clazz, Object message) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        if (logger.isDebugEnabled()) {
            logger.debug(message);
        }
    }

    public static void debug(Object object, Object message, Throwable cause) {
        Class clazz = object.getClass();
        debug(clazz, message, cause);
    }

    public static void debug(Class clazz, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        if (logger.isDebugEnabled()) {
            logger.debug(message, cause);
        }
    }

    public static void debug(String name, Object message) {
        org.apache.log4j.Logger logger = getLogger(name);
        if (logger.isDebugEnabled()) {
            logger.debug(message);
        }
    }

    public static void debug(Object message) {
        debug(whoInvoke(), message);
    }

    public static void debug(String name, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(name);
        if (logger.isDebugEnabled()) {
            logger.debug(message, cause);
        }
    }

    // ---------------------------- info　----------------------------

    public static void info(Object object, Object message) {
        info(object.getClass(), message);
    }

    public static void info(Class clazz, Object message) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        if (logger.isInfoEnabled()) {
            logger.info(message);
        }
    }

    public static void info(Object object, Object message, Throwable cause) {
        Class clazz = object.getClass();
        info(clazz, message, cause);
    }

    public static void info(Class clazz, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        if (logger.isInfoEnabled()) {
            logger.info(message, cause);
        }
    }

    public static void info(String name, Object message) {
        org.apache.log4j.Logger logger = getLogger(name);
        if (logger.isInfoEnabled()) {
            logger.info(message);
        }
    }

    public static void info(String name, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(name);
        if (logger.isInfoEnabled()) {
            logger.info(message, cause);
        }
    }

    public static void info(Object message) {
        info(whoInvoke(), message);
    }

    // ---------------------------- warn　----------------------------
    public static void warn(Object object, Object message) {
        warn(object.getClass(), message);
    }

    public static void warn(Class clazz, Object message) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        logger.warn(message);
    }

    public static void warn(Object object, Object message, Throwable cause) {
        warn(object.getClass(), message, cause);
    }

    public static void warn(Class clazz, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        logger.warn(message, cause);
    }

    public static void warn(String name, Object message) {
        org.apache.log4j.Logger logger = getLogger(name);
        logger.warn(message);
    }

    public static void warn(String name, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(name);
        logger.warn(message, cause);
    }

    public static void warn(Object message) {
        warn(whoInvoke(), message);
    }

    // ---------------------------- error　----------------------------
    public static void error(Object object, Object message) {
        error(object.getClass(), message);
    }

    public static void error(Class clazz, Object message) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        if (message instanceof Throwable) {
            logger.error("Common Logger", (Throwable) message);
        } else {
            logger.error(message);
        }
    }

    public static void error(Object object, Object message, Throwable cause) {
        error(object.getClass(), message, cause);
    }

    public static void error(Class clazz, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(clazz);
        logger.warn(message, cause);
    }

    public static void error(String name, Object message) {
        org.apache.log4j.Logger logger = getLogger(name);
        logger.warn(message);
    }

    public static void error(String name, Object message, Throwable cause) {
        org.apache.log4j.Logger logger = getLogger(name);
        logger.warn(message, cause);
    }

    public static void error(Object message) {
        error(whoInvoke(), message);
    }

    public static void error(Throwable throwable) {
        error(whoInvoke(), "", throwable);
    }

    /**
     * 获取间接调用的类名

     * 比如A方法调用B方法，B方法再调用whoInvoke()方法，这样B方法内就能返回A方法在那个类下
     *
     * @return
     */
    private static Class whoInvoke() {
        Throwable throwable = new Throwable();
        StackTraceElement[] stackTraceElements = throwable.getStackTrace();
        StackTraceElement stackTraceElement = stackTraceElements[2];
        try {
            return Class.forName(stackTraceElement.getClassName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static org.apache.log4j.Logger getLogger(Class clazz) {
        return getLogger(clazz.getName());
    }

    private static org.apache.log4j.Logger getLogger(String name) {
        org.apache.log4j.Logger logger = nameLoggerMap.get(name);
        if (logger == null) {
            logger = org.apache.log4j.Logger.getLogger(name);
        }
        return logger;
    }

}


/**
 * WebSocketForJavaEE7
 */
package com.xiongyingqi.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;

/**
 * @author xiongyingqi xiongyingqi.com
 * @version 2014年2月25日 下午12:05:17
 */
public class AnnotationHelper {
    public static <T extends Annotation> boolean isAnnotationType(Class<?> clazz,
                                                                  Class<T> annotationClass) {
        return clazz.isAnnotationPresent(annotationClass);
    }

    public static <T extends Annotation> T readAnnotationValue(Class<?> clazz,
                                                               Class<T> annotationClass) {
        if (isAnnotationType(clazz, annotationClass)) {
            T t = clazz.getAnnotation(annotationClass);
            return t;
        } else {
            return null;
        }
    }

    /**
     * 读取field的注解值（包括get、set方法）
     * @param field
     * @param annotationClass
     * @param <T>
     * @return
     */
    public static <T extends Annotation> T readAnnotationValueOnField(Field field, Class<T> annotationClass) {
        if (field.isAnnotationPresent(annotationClass)) {
            T t = field.getAnnotation(annotationClass);
            return t;
        } else {
            Method method = EntityHelper.findGetMethod(field);
            if (method.isAnnotationPresent(annotationClass)) {
                T t = method.getAnnotation(annotationClass);
                return t;
            }
            return null;
        }
    }

    public static Collection<? super Annotation> readAnnotationsOnField(Field field) {
        Collection<? super Annotation> annotations = new HashSet();

        Annotation[] annotationArray = field.getAnnotations();
        if (annotationArray != null && annotationArray.length > 0) {
            Collections.addAll(annotations, annotationArray);
            return annotations;
        }

        Method method = EntityHelper.findGetMethod(field);
        Annotation[] methodAnnotations = method.getAnnotations();
        if (methodAnnotations != null && methodAnnotations.length > 0) {
            Collections.addAll(annotations, methodAnnotations);
            return annotations;
        }

        return null;
    }

    /**
     * 在类内搜索所有的字段的annotationClass注解值
     *
     * @param clazz
     * @param annotationClass
     * @param <T>
     * @return
     */
    public static <T extends Annotation> Collection<T> readAnnotationsInClass(Class<?> clazz, Class<T> annotationClass) {
        Collection<T> collection = null;

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            T t = readAnnotationValueOnField(field, annotationClass);
            if (t == null) {
                continue;
            }

            if (collection == null) {
                collection = new ArrayList<T>();
            }

            collection.add(t);
        }

        return collection;
    }

    /**
     * 在类内搜索使用annotationClass注解的字段（包括在get、set方法上注解）
     * @param inClazz
     * @param annotationClass
     * @param <T>
     * @return
     */
    public static <T extends Annotation> Collection<Field> getFieldsWithAnnotationInClass(Class<?> inClazz, Class<T> annotationClass) {
        Collection<Field> fieldCollection = null;

        Field[] fields = inClazz.getDeclaredFields();
        for (Field field : fields) {
            if(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
                continue;
            }
            T t = readAnnotationValueOnField(field, annotationClass);
            if (t == null) {
                continue;
            }

            if (fieldCollection == null) {
                fieldCollection = new ArrayList<Field>();
            }

            fieldCollection.add(field);
        }

        return fieldCollection;
    }

}


/**
 * openfire_src
 */
package com.xiongyingqi.util;

import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;

/**
 * @author XiongYingqi
 * @version 2013-6-17 上午11:19:19
 */
public class StringHelper {

    /**
     * 从第一个字符开始比较两个字符串的大小（按照单个字符的ascii码比较），例如： "abc"大于"aac"、"1234"小于"2234"、"1234"大于"123"、"223"大于"1234"
     *
     * @param firstString  第一个字符串
     * @param secondString 第二个字符串
     * @return 如果第一个字符串小于第二个字符串，则返回true，否则返回false
     */
    public static boolean compareNumberString(String firstString, String secondString) {
        Assert.notNull(firstString, "第一个字符串为空！");
        Assert.notNull(secondString, "第二个字符串为空！");
        char[] chars1 = firstString.toCharArray();
        char[] chars2 = secondString.toCharArray();
        int length1 = chars1.length;
        int length2 = chars2.length;
        int maxLength = length1 > length2 ? length1 : length2;
        for (int i = 0; i < maxLength; i++) {
            int value1 = -1;
            int value2 = -1;
            if (i < length1) {
                value1 = chars1[i];
            }

            if (i < length2) {
                value2 = chars2[i];
            }

            if(value1 < value2){
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    public static String encode(String str, String charset) {
        String content = null;
        try {
            content = new String(str.getBytes("ISO-8859-1"), charset);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return content;
    }

    /**
     * 判断字符串不为空，并且字符串内容不为空
     *
     * @param input
     * @return
     */
    public static boolean notNullAndNotEmpty(String input) {
        return input != null && !"".equals(input.trim());
    }

    /**
     * 计算数组的hashCode

     * 2013-10-25 上午11:06:57
     *
     * @param stringArray
     * @return
     */
    public static int hashCodeOfStringArray(String[] stringArray) {
        if (stringArray == null) {
            return 0;
        }
        int hashCode = 17;
        for (int i = 0; i < stringArray.length; i++) {
            String value = stringArray[i];
            hashCode = hashCode * 31 + (value == null ? 0 : value.hashCode());
        }
        return hashCode;
    }

    /**
     * 判断字符串是否为空，或者字符串内容为空
     *
     * @param input
     * @return
     */
    public static boolean nullOrEmpty(String input) {
        return input == null || "".equals(input.trim());
    }

    /**
     * 换行符

     * 2013-8-14 下午1:20:06
     *
     * @return
     */
    public static String line() {
        String lineSeparator = java.security.AccessController.doPrivileged(
                new sun.security.action.GetPropertyAction("line.separator"));
//		String lineSeparator = System.getProperty("line.separator");
        return lineSeparator;
    }

    /**
     *

     * 2013-8-28 下午5:26:24
     *
     * @param str
     * @return
     */
    public static String convertEncode(String str) {
        if (nullOrEmpty(str)) {
            return null;
        }
        try {
            return new String(str.getBytes(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * StringReader转换为字符串

     * 2013-9-2 下午9:03:29
     *
     * @param reader
     * @return
     */
    public String stringReaderToString(StringReader reader) {
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[128];
        int length = -1;
        try {
            while ((length = reader.read(buffer)) != -1) {
                if (buffer.length != length) {
                    System.arraycopy(buffer, 0, buffer, 0, length);
                }
                builder.append(buffer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            reader.close();
        }
        return builder.toString();
    }

    public static String replaceFirst(String content, String target, String replacement) {
        int index = content.indexOf(target);
        if (index < 0) {
            return content;
        }
        StringBuilder builder = new StringBuilder();
        String front = content.substring(0, index);
        String last = content.substring(index + target.length());
        return builder.append(front).append(replacement).append(last).toString();
    }

    public static String UUID() {
        return java.util.UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static void main(String[] args) {
        System.out.println(replaceFirst("asfasf.ccc.bbb.ccc.cccc.", "ccc.", "dddd."));
        //"abc"大于"aac"、"1234"小于"2234"、"1234"大于"123"、"223"大于"1234"
        System.out.println(compareNumberString("", ""));
        System.out.println(compareNumberString("abc", "aac"));
        System.out.println(compareNumberString("1234", "2234"));
        System.out.println(compareNumberString("1234", "123"));
        System.out.println(compareNumberString("223", "1234"));
    }
}


/*
 *  SingletonLoader.java a dynamic class instantiation algorithm
 *  with singleton instantiation support.
 *
 *  Copyright (C) Achim Westermann, created on 20.07.2004, 11:14:49
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this collection are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the cpDetector code in [sub] packages info.monitorenter and
 * cpdetector.
 *
 * The Initial Developer of the Original Code is
 * Achim Westermann <achim.westermann@gmx.de>.
 *
 * Portions created by the Initial Developer are Copyright (c) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** *
 *
 * If you modify or optimize the code in a useful way please let me know.
 * Achim.Westermann@gmx.de
 */
package info.monitorenter.cpdetector.reflect;

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

/**
 *

 * A stateless helper that performs dynamic class loading and instantiation with support for invoking
 * Singleton-retrieval methods of classes if detected.
 *

 *

 * Before invoking someClass.newInstance() the loaded class is inspected for methods, that are public,
 * static, parameterless, contain the substring "intance" in their name (case-insensitive) and return an instance of the
 * same type.
 *

 *

 * If such a method is found, it is considered to be a singleton retrieval method and will be invoked instead of trying
 * to use the default constructor triggered by newInstance() (which then should be private if it is
 * really a singleton.
 *

 *

 * This class is in turn a singleton as it only contains procedural code. For possible desireable future configuration
 * requirements, the single public method is not declared static but bound to the singleton instance.
 *

 *
 * @author Achim Westermann
 *
 */
public final class SingletonLoader {

    private static SingletonLoader instance = null;

    private Object[] dummyParameters = new Object[0];

    /**
     * Singleton retrieval
     */
    private SingletonLoader() {
        super();
    }

    public static SingletonLoader getInstance() {
        if (instance == null) {
            instance = new SingletonLoader();
        }
        return instance;
    }

    /**
     * High-level method for instantiation of a new instance of the class specified by the given fully qualified class
     * name with singleton retrieval support. Delegates to {@link #newInstance(Class)}.
     *
     */
    public Object newInstance(String fullyQualifiedClassName) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        Object ret = this.newInstance(Class.forName(fullyQualifiedClassName));
        return ret;
    }

    /**
     * Dynamic instantiation of the given type with singleton retrieval support as described in this class description.
     *
     */
    public Object newInstance(Class c) throws InstantiationException, IllegalAccessException {
        Object ret = null;
        Method[] methods = c.getDeclaredMethods();
        Method m;
        int modifiers;
        // searching for static methods:
        for (int i = 0; i < methods.length; i++) {
            m = methods[i];
            modifiers = m.getModifiers();
            if ((modifiers & Modifier.STATIC) != 0) {
                // searching for public access:
                if ((modifiers & Modifier.PUBLIC) != 0) {
                    // searching for no parameters:
                    if (m.getParameterTypes().length == 0) {
                        // searching for return type:
                        if (m.getReturnType() == c) {
                            // searching for substring "instance" in method name:
                            if (m.getName().toLowerCase().indexOf("instance") != -1) {
                                try {
                                    // Finally we found a singleton method:
                                    // we are static and don't need an instance.
                                    ret = m.invoke(null, dummyParameters);
                                } catch (IllegalArgumentException e) {
                                    // This will not happen:
                                    // we ensured that no arguments are needed.
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    // This will not happen (only in applet context perhaps or with some
                                    // SecurityManager):
                                    // we ensured public access.
                                    e.printStackTrace();
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }
        // check, if we found a singleton:
        if (ret == null) {
            // try to invoke the default constructor:
            Constructor[] constructors = c.getConstructors();
            Constructor con = null;
            // search for a parameterless constructor:
            for (int i = 0; i < constructors.length; i++) {
                con = constructors[i];
                if (con.getParameterTypes().length == 0) {
                    // see, if public:
                    modifiers = con.getModifiers();
                    try {
                        if ((modifiers & Modifier.PUBLIC) == 0) {
                            // try to set accessible:
                            con.setAccessible(true);
                        }
                        // invokes the default constructor
                        ret = c.newInstance();
                    } catch (SecurityException se) {
                        // damn
                    }
                }
            }
        }
        if (ret == null) {
            System.err.println("Unable to instantiate: " + c.getName()
                    + ": no singleton method, no public default constructor.");
        }
        return ret;
    }

}


/*
 *  ${file_name} of project cpdetector, <purpose>
 *  Copyright ${year} (C) Achim Westermann, created on 03.06.2004.
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this collection are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the cpDetector code in [sub] packages info.monitorenter and
 * cpdetector.
 *
 * The Initial Developer of the Original Code is
 * Achim Westermann <achim.westermann@gmx.de>.
 *
 * Portions created by the Initial Developer are Copyright (c) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** *
 */
package info.monitorenter.cpdetector.io;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 *

 * A proxy that delegate the codepage detection to all it's delegates. The first
 * one (added in code-order) that does not return a null {@link java.nio.charset.Charset}from
 * it's delegate method {@link #detectCodepage(java.net.URL)}wins the race and determines
 * the codpage of the document specified by the given URL.
 *

 *

 * If an underlying {@link info.monitorenter.cpdetector.io.ICodepageDetector}throws an
 * {@link java.io.IOException}, the delegation search will be terminated by
 * throwing this exception.
 *

 *
 * @author Achim Westermann
 *
 */
public final class CodepageDetectorProxy extends AbstractCodepageDetector {

  /** serialVersionUID */
  private static final long serialVersionUID = -7389424614984024701L;

  /**
   * Singleton instance.
   */
  private static CodepageDetectorProxy instance = null;

  /**
   * The set of {@link info.monitorenter.cpdetector.io.ICodepageDetector}instances that this proxy will delegate
   * to. These instances will be invoked in order to find the codepage until the
   * first instance returns a valid codepage. If an {@link java.io.IOException}is thrown
   * the search will terminate early (assuming that the execption is related to
   * a general problem with the given URL.
   */
  private Set<ICodepageDetector> detectors = new LinkedHashSet<ICodepageDetector>();

  /**
   * Singleton constructor. For internal use only.
   */
  private CodepageDetectorProxy() {
    super();
  }

  /**
   * Singleton retrieval method.
   *

   * Be sure to configure the instance returned at a single location in your
   * code to avoid unpredictable application - wide side effects.
   *

   *
   * @return the sole instance in this VM.
   */
  public static CodepageDetectorProxy getInstance() {
    if (CodepageDetectorProxy.instance == null) {
      CodepageDetectorProxy.instance = new CodepageDetectorProxy();
    }
    return CodepageDetectorProxy.instance;
  }

  /**
   * Adds the given instance to this proxie's detection capability.
   *

   *
   * Remember that the order of added ICodepageDetector instances is important
   * for the internal delegation (see class description).
   *

   *
   */
  public boolean add(ICodepageDetector detector) {
    return this.detectors.add(detector);
  }

  /**
   * @param url
   *          Should link to a file containing textual document. No check for
   *          images or other resources is made.
   * @throws java.io.IOException
   *           If a problem with the url - handling occurs.
   */
  public Charset detectCodepage(final URL url) throws IOException {
    Charset ret = null;
    Iterator<ICodepageDetector> detectorIt = this.detectors.iterator();
    while (detectorIt.hasNext()) {
      ret = detectorIt.next().detectCodepage(url);
      if (ret != null) {
        if (ret != UnknownCharset.getInstance()) {
          if (ret instanceof UnsupportedCharset) {
            // TODO: Debug logging: found illegal charset tag or encoding
            // declaration.
          } else {
            break;
          }
        }
      }
    }
    return ret;
  }

  /**
   *

   * Detects the codepage by iteratively delegating the call to all internal
   * {@link info.monitorenter.cpdetector.io.ICodepageDetector} instances added by
   * {@link #add(info.monitorenter.cpdetector.io.ICodepageDetector)}.
   *

   *

   * The given InputStream has to support mark such that the call
   * {@link java.io.InputStream#mark(int)} with argument length does not throw an
   * exception. This is needed, as the stream has to be resetted to the
   * beginning for each internal delegate that tries to detect.
   *

   *

   * If this is impossible (large documents), prefer using
   * {@link #detectCodepage(java.net.URL)}.
   *

   *
   * @param in
   *          An InputStream for the document, that supports mark and a
   *          readlimit of argument length.
   *
   * @param length
   *          The amount of bytes to take into account. This number shouls not
   *          be longer than the amount of bytes retrievable from the
   *          InputStream but should be as long as possible to give the fallback
   *          detection (chardet) more hints to guess.
   *
   *
   * @throws IllegalArgumentException
   *           if more bytes had to be read from the input stream than param
   *           length or the given input stream does not support marking.
   */
  public Charset detectCodepage(final InputStream in, final int length) throws IOException, IllegalArgumentException {

    if (!in.markSupported()) {
      throw new IllegalArgumentException("The given input stream (" + in.getClass().getName() + ") has to support for marking.");
    }
    Charset ret = null;
    int markLimit = length;
    Iterator<ICodepageDetector> detectorIt = this.detectors.iterator();
    while (detectorIt.hasNext()) {
      in.mark(markLimit);
      ret = detectorIt.next().detectCodepage(in, length);
      // if more bytes have been read than marked (length) this will throw an
      // exception:
      try {
        in.reset();
      } catch (IOException ioex) {
        IllegalStateException ise = new IllegalStateException(
            "More than the given length had to be read and the given stream could not be reset. Undetermined state for this detection.");
        ise.initCause(ioex);
        throw ise;

      }
      if (ret != null) {
        if (ret != UnknownCharset.getInstance()) {
          if (ret instanceof UnsupportedCharset) {
            // TODO: Debug logging: found illegal charset tag or encoding
            // declaration.
          } else {
            break;
          }
        }
      }
    }
    return ret;
  }

  /**
   * @see Object#toString()
   */
  public String toString() {
    StringBuffer ret = new StringBuffer();
    Iterator<ICodepageDetector> it = this.detectors.iterator();
    int i = 1;
    while (it.hasNext()) {
      ret.append(i);
      ret.append(") ");
      ret.append(it.next().getClass().getName());
      ret.append("\n");
      i++;
    }
    return ret.toString();
  }

}


package com.xiongyingqi.util;

/**
 * Created by 瑛琪xiongyingqi.com on 2014/4/2 0002.
 */

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;

import java.lang.reflect.Field;

public class AopTargetUtils {

    /**
     * 获取 目标对象
     *
     * @param proxy 代理对象
     * @return
     * @throws Exception
     */
    public static Object getTarget(Object proxy) throws Exception {

        if (!AopUtils.isAopProxy(proxy)) {
            return proxy;//不是代理对象
        }

        if (AopUtils.isJdkDynamicProxy(proxy)) {
            return getJdkDynamicProxyTargetObject(proxy);
        } else { //cglib
            return getCglibProxyTargetObject(proxy);
        }

    }

    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        h.setAccessible(true);
        Object dynamicAdvisedInterceptor = h.get(proxy);

        Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();

        return target;
    }

    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
        Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
        h.setAccessible(true);
        AopProxy aopProxy = (AopProxy) h.get(proxy);

        Field advised = aopProxy.getClass().getDeclaredField("advised");
        advised.setAccessible(true);

        Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();

        return target;
    }

}


package com.xiongyingqi.util;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CalendarHelper {
    // private static Calendar anotherCalendar = Calendar.getInstance();
    // private static Calendar calendar = Calendar.getInstance();

    public static final long SECOND = 1000;
    public static final long MINUTE = 60 * SECOND;
    public static final long HOUR = 60 * MINUTE;
    public static final long DAY = 24 * HOUR;
    public static final long MONTH = 30 * DAY;
    public static final long YEAR = 12 * MONTH;
    public static final DateCalculator YEARS_BEFORE = new DateCalculator(1 * YEAR, 2000 * YEAR,
            "{0}年前");
    public static final DateCalculator MONTHS_BEFORE = new DateCalculator(1 * MONTH, 12 * MONTH,
            "{0}个月前");
    public static final DateCalculator DAYS_BEFORE = new DateCalculator(3 * DAY, 30 * DAY, "{0}天前");
    public static final DateCalculator THE_DAY_BEFORE_YESTERDAY = new DateCalculator(2 * DAY,
            3 * DAY, "前天");
    public static final DateCalculator YESTERDAY = new DateCalculator(1 * DAY, 2 * DAY, "昨天");
    public static final DateCalculator HOURS_BEFORE = new DateCalculator(1 * HOUR, 24 * HOUR,
            "{0}小时前");
    public static final DateCalculator HALF_HOUR_BEFORE = new DateCalculator(30 * MINUTE,
            60 * MINUTE, "半小时左右");
    public static final DateCalculator JUST_NOW = new DateCalculator(0, 30 * MINUTE, "刚刚");

    // static{
    // final DateCaculator YEARS_BEFORE = new DateCaculator(1 * YEAR, 2000 *
    // YEAR, "刚刚");
    // final DateCaculator MONTHS_BEFORE = new DateCaculator(1 * MONTH, 12 *
    // MONTH, "约{0}个月");
    // final DateCaculator DAYS_BEFORE = new DateCaculator(1 * DAY, 30 * DAY,
    // "{0}天前");
    // final DateCaculator HOURS_BEFORE = new DateCaculator(45 * MINUTE, 24 *
    // HOUR, "{0}小时前");
    // final DateCaculator HALF_HOUR_BEFORE = new DateCaculator(30 * MINUTE, 45
    // * MINUTE, "半小时左右");
    // final DateCaculator JUST_NOW = new DateCaculator(0, 30 * MINUTE, "刚刚");
    // }

    /**
     * 返回指定日期距离现在的毫秒数
     *
     * @param thenDate
     * @return
     */
    public static long compareDate(Date thenDate) {
        return compareDate(new Date(), thenDate);
    }

    /**
     * 返回两个日期的毫秒之差
     *
     * @param nearDate
     * @param farDate
     * @return
     */
    public static long compareDate(Date nearDate, Date farDate) {
        long nearMilli = nearDate.getTime();
        long farMilli = farDate.getTime();
        long result = nearMilli - farMilli;
        if (result < 0) {
            result = -result;
        }
        return result;
    }

    /**
     * 计算指定日期到现在的时间计算
     *
     * @param date
     * @return
     */
    public static String caculatorDateToString(Date date) {
        long milliSecond = compareDate(date);
        List dateCaculators = DateCalculator.getDateCalculators();
        for (Iterator iterator = dateCaculators.iterator(); iterator.hasNext(); ) {
            DateCalculator dateCalculator = (DateCalculator) iterator.next();
            if (milliSecond >= dateCalculator.getMinMilliSecond()
                    && milliSecond <= dateCalculator.getMaxMilliSecond()) {
                String displayStr = dateCalculator.getDisplayStr();
                long numberOfUnit = 0;
                if (dateCalculator.getMinMilliSecond() == 0) { // 分母为零，则直接为0
                    numberOfUnit = 0;
                } else {
                    numberOfUnit = milliSecond / dateCalculator.getMinMilliSecond();
                }

                // 替代所有{0}
                Pattern p = Pattern.compile("(\\{.+?\\})");
                Matcher m = p.matcher(displayStr);
                displayStr = m.replaceAll(numberOfUnit + "");

                // displayStr = displayStr.replace("\\{0\\}", numberOfUnit +
                // "");
                return displayStr;
            }
        }
        return milliSecond + "";
    }

    /**
     * @param beforeDate
     * @param afterDate
     * @return
     */
    public static boolean compareTwoDate(Date beforeDate, Date afterDate) {
        if (beforeDate == null && afterDate == null) {
            return false;
        }
        Calendar beforeCalendar = Calendar.getInstance();
        beforeCalendar.setTime(beforeDate);
        Calendar afterCalendar = Calendar.getInstance();
        afterCalendar.setTime(afterDate);
        return (afterCalendar.compareTo(beforeCalendar) > 0);
    }

    static class DateCalculator {
        private long minMilliSecond;
        private long maxMilliSecond;
        private String displayStr;
        private static List dateCalculators;

        public DateCalculator(long minMilliSecond, long maxMilliSecond, String displayStr) {
            this.minMilliSecond = minMilliSecond;
            this.maxMilliSecond = maxMilliSecond;
            this.displayStr = displayStr;
            if (dateCalculators == null) {
                dateCalculators = new ArrayList();
            }
            dateCalculators.add(this);
        }

        /**
         * @return the dateCalculators
         */
        public static List getDateCalculators() {
            return dateCalculators;
        }

        /**
         * @return the minMilliSecond
         */
        public long getMinMilliSecond() {
            return minMilliSecond;
        }

        /**
         * @param minMilliSecond the minMilliSecond to set
         */
        public void setMinMilliSecond(long minMilliSecond) {
            this.minMilliSecond = minMilliSecond;
        }

        /**
         * @return the maxMilliSecond
         */
        public long getMaxMilliSecond() {
            return maxMilliSecond;
        }

        /**
         * @param maxMilliSecond the maxMilliSecond to set
         */
        public void setMaxMilliSecond(long maxMilliSecond) {
            this.maxMilliSecond = maxMilliSecond;
        }

        /**
         * @return the displayStr
         */
        public String getDisplayStr() {
            return displayStr;
        }

    }

    public static void main(String[] args) {
        Date date = DateHelper.strToDateLong("2013-04-03 10:44:12");
        String rs = caculatorDateToString(date);
        System.out.println(rs);

        Date date2 = DateHelper.strToDateLong("2013-06-02 15:33:12");
        String rs2 = caculatorDateToString(date2);
        System.out.println(rs2);

        Date date5 = DateHelper.strToDateLong("2013-06-03 15:33:12");
        String rs5 = caculatorDateToString(date5);
        System.out.println(rs5);

        Date date3 = DateHelper.strToDateLong("2012-04-03 10:44:12");
        String rs3 = caculatorDateToString(date3);
        System.out.println(rs3);
    }

}


/*
 * Entry.java, base data container for mapping two elements.
 * Copyright (C) 2003 - 2010 Achim Westermann.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * If you modify or optimize the code in a useful way please let me know.
 * Achim.Westermann@gmx.de
 */
package info.monitorenter.util;

/**
 *

 * I have written implementations of <tt>java.util.Map.Entry</tt> in form of
 *

 *
Static inner classes.

 *
Non-static inner classes.

 *
Non-public classes.

 *
Anonymous classes.

 *

 *

 * Almost all implementations were plainforward and not hiding any complexity.
 * One could not downcast them to get more methods, and they were replaceable.

 * That's it! Finally i decided to hardcode it here... .
 *

 *

 * But don't you start writing methods like:
 *
 *

 * public Entry getEntry(String name);
 *
 * public void setEntry(Entry entry);
 *

 *
 * Try sticking to the interface <tt>java.util.Map.Entry</tt>.
 *
 * @see java.util.Map.Entry
 *
 * @param <V>
 *          the key type.
 *
 * @param <K>
 *          the value type.
 *
 * @author Achim Westermann
 */
public final class Entry<V, K> implements java.util.Map.Entry<V, K> {

  /** The key instance. */
  private final V m_key;

  /** The value instance. */
  private K m_value;

  /**
   * Creates an instance with the given key and value.
   *

   *
   * @param key
   *          the key instance to use.
   *
   * @param value
   *          the value instance to use.
   */
  public Entry(final V key, final K value) {
    this.m_key = key;
    this.m_value = value;
  }

  /**
   * @see Object#equals(Object)
   */
  @SuppressWarnings("unchecked")
  @Override
  public boolean equals(final Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (this.getClass() != obj.getClass()) {
      return false;
    }
    final Entry<V,K> other = (Entry<V,K>) obj;
    if (this.m_key == null) {
      if (other.m_key != null) {
        return false;
      }
    } else if (!this.m_key.equals(other.m_key)) {
      return false;
    }
    if (this.m_value == null) {
      if (other.m_value != null) {
        return false;
      }
    } else if (!this.m_value.equals(other.m_value)) {
      return false;
    }
    return true;
  }

  /**
   * Maybe null!
   *
   * @see java.util.Map.Entry#getKey()
   */
  public V getKey() {
    return this.m_key;
  }

  /**
   * Maybe null!
   *
   * @see java.util.Map.Entry#getValue()
   */
  public K getValue() {
    return this.m_value;
  }

  /**
   * @see Object#hashCode()
   */
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((this.m_key == null) ? 0 : this.m_key.hashCode());
    result = prime * result + ((this.m_value == null) ? 0 : this.m_value.hashCode());
    return result;
  }

  /**
   * Sets a new value instance overwriting the old value which is returned.
   *

   *
   * You may use null. But you will get it back next call!
   *

   *
   * @see java.util.Map.Entry#setValue(Object)
   *
   * @return the previous value instance.
   */
  public K setValue(final K value) {
    final K ret = this.m_value;
    this.m_value = value;
    return ret;
  }

}


package com.xiongyingqi.qrcode;

import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Created by 瑛琪xiongyingqi.com on 2014/10/17 0017.
 */
public class QRCodeGenerator {
    public static void main(String[] args) throws IOException {
        System.out.println(System.getProperty("java.io.tmpdir"));
    }

    private Profile profile;

    private QRCodeGenerator() {

    }

    public static QRCodeGenerator newGenerator() {
        QRCodeGenerator qrCodeGenerator = new QRCodeGenerator();
        qrCodeGenerator.profile = new Profile();
        qrCodeGenerator.characterSet("UTF-8")
                .errorCorrectionLevel(ErrorCorrectionLevel.H)
                .logoFlag(false)
                .format("png")
                .margin(0)
                .width(300)
                .height(300)
                .path(System.getProperty("java.io.tmpdir"));
        return qrCodeGenerator;
    }

    /**
     * 二维码内容
     */
    public QRCodeGenerator content(String content) {
        this.profile.setContent(content);
        return this;
    }

    /**
     * 图片的宽度
     */
    public QRCodeGenerator width(int width) {
        this.profile.setWidth(width);
        return this;
    }

    /**
     * 图片的高度
     */
    public QRCodeGenerator height(int height) {
        this.profile.setHeight(height);
        return this;
    }

    /**
     * 生成图片的地址（不包含图片名称）
     */
    public QRCodeGenerator path(String path) {
        this.profile.setPath(path);
        return this;
    }

    /**
     * logo文件路径
     */
    public QRCodeGenerator logoPath(String logoPath) {
        this.profile.setLogoPath(logoPath);
        return this;
    }

    /**
     * 生成图片的格式，例如:jpg，png
     */
    public QRCodeGenerator format(String format) {
        this.profile.setFormat(format);
        return this;
    }

    /**
     * 纠错级别
     */
    public QRCodeGenerator errorCorrectionLevel(ErrorCorrectionLevel errorCorrectionLevel) {
        this.profile.setErrorCorrectionLevel(errorCorrectionLevel);
        return this;
    }

    /**
     * 编码格式
     */
    public QRCodeGenerator characterSet(String characterSet) {
        this.profile.setCharacterSet(characterSet);
        return this;
    }

    /**
     * 二维码边缘留白
     */
    public QRCodeGenerator margin(int margin) {
        this.profile.setWidth(margin);
        return this;
    }

    /**
     * 是否中间贴logo图，如果设置了该值为true，则必须设置logoPath
     *
     * @return
     */
    public QRCodeGenerator logoFlag(boolean logoFlag) {
        this.profile.setLogoFlag(logoFlag);
        return this;
    }

    /**
     * 生成文件
     *
     * @return 返回二维码文件
     */
    public File generate() {
        QRCode qrCode = new QRCode();
        File file = qrCode.encode(profile);
        return file;
    }

    public OutputStream generateOutputStream() throws IOException, WriterException {
        QRCode qrCode = new QRCode();
        OutputStream outputStream = qrCode.encodeToOutputStream(profile);
        return outputStream;
    }

}


package com.xiongyingqi.util;

import java.io.File;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Created by 瑛琪xiongyingqi.com on 2014/10/21 0021.
 */
public class PackageScanner {
    private Collection<Package> packages;
    private Collection<Class<? extends Annotation>> orAnnotations;
    private Collection<Class<? extends Annotation>> andAnnotations;
    private Collection<String> startWithStrings;
    private Collection<String> endWithStrings;
    private Collection<Class<?>> orImplementsInterface;
    private Collection<Class<?>> andImplementsInterface;
    private boolean recursive;

    private PackageScanner() {
    }

    public static PackageScanner newScanner() {
        PackageScanner packageScanner = new PackageScanner();
        packageScanner.packages = new ArrayList<Package>();
        packageScanner.orAnnotations = new ArrayList<Class<? extends Annotation>>();
        packageScanner.andAnnotations = new ArrayList<Class<? extends Annotation>>();
        packageScanner.startWithStrings = new ArrayList<String>();
        packageScanner.endWithStrings = new ArrayList<String>();
        packageScanner.orImplementsInterface = new ArrayList<Class<?>>();
        packageScanner.andImplementsInterface = new ArrayList<Class<?>>();

        packageScanner.recursive = true;
        return packageScanner;
    }

    /**
     * 增加扫描的包
     *
     * @param pkg
     * @return
     */
    public PackageScanner addPackage(String pkg) {
        Package aPackage = Package.getPackage(pkg);
        addPackage(aPackage);
        return this;
    }

    /**
     * 增加扫描的包
     *
     * @param pkg
     * @return
     */
    public PackageScanner addPackage(Package pkg) {
        packages.add(pkg);
        return this;
    }

    /**
     * 是否递归子包
     *
     * @param recursive
     */
    public PackageScanner recursive(boolean recursive) {
        this.recursive = recursive;
        return this;
    }

    /**
     * 或者类被annotation注解
     *
     * @return
     */
    public PackageScanner orAnnotation(Class<? extends Annotation> annotation) {
        orAnnotations.add(annotation);
        return this;
    }

    /**
     * 并且类被annotation注解
     *
     * @param annotation
     * @return
     */
    public PackageScanner andAnnotation(Class<? extends Annotation> annotation) {
        andAnnotations.add(annotation);
        return this;
    }

    /**
     * 并且类实现接口
     *
     * @param interfc
     * @return
     */
    public PackageScanner andInterface(Class<?> interfc) {
        andImplementsInterface.add(interfc);
        return this;
    }

    /**
     * 或者类实现接口
     *
     * @param interfc
     * @return
     */
    public PackageScanner orInterface(Class<?> interfc) {
        orImplementsInterface.add(interfc);
        return this;
    }

    /**
     * @param startWithString
     * @return
     */
    public PackageScanner orStartWithString(String startWithString) {
        if (StringHelper.nullOrEmpty(startWithString)) {
            return this;
        }
        startWithStrings.add(startWithString);
        return this;
    }

    public PackageScanner orEndWithString(String endWithString) {
        if (StringHelper.nullOrEmpty(endWithString)) {
            return this;
        }
        endWithStrings.add(endWithString);
        return this;
    }

    /**
     * 开始扫描
     *
     * @return
     */
    public Collection<Class<?>> scan() {
        Assert.notEmpty(packages, "待扫描的包为空！");
        Collection<Class<?>> classes = new ArrayList<Class<?>>();
        ClassLookupHelper.ClassFileFilter classFileFilter = new ClassLookupHelper.ClassFileFilter() {
            @Override
            public boolean accept(String klassName, File file, ClassLoader loader) {
                return true;
            }

            @Override
            public boolean accept(String klassName, JarFile jar, JarEntry entry, ClassLoader loader) {
                return true;
            }
        };
        for (Package pkg : packages) {
            Set<Class<?>> scanClasses = ClassLookupHelper.getClasses(pkg, recursive, classFileFilter);
            for (Class<?> scanClass : scanClasses) {
                if (isAnnotationPassed(scanClass) && isStartWithPassed(scanClass) && isInterfacePassed(scanClass)) {
                    classes.add(scanClass);
                }
            }
        }
        return classes;
    }

    private boolean isStartWithPassed(Class<?> clazz) {
        // 如果是需要判断开始和结尾，则初始值为false
        if (true ^ (CollectionHelper.notNullAndHasSize(startWithStrings) || CollectionHelper.notNullAndHasSize(endWithStrings))) {// 如果需要判断的为空，则通过
            return true;
        }

        for (String startWithString : startWithStrings) {
            if (clazz.getSimpleName().startsWith(startWithString)) {
                return true;
            }
        }

        for (String endWithString : endWithStrings) {
            if (clazz.getSimpleName().endsWith(endWithString)) {
                return true;
            }
        }

        return false;
    }

    private boolean isAnnotationPassed(Class<?> clazz) {
        //true ^ true = false, true ^ false = true
        boolean flag = true ^ (CollectionHelper.notNullAndHasSize(orAnnotations) || CollectionHelper.notNullAndHasSize(andAnnotations));// 如果判断是否需要注解，则初始值为false

        for (Class<? extends Annotation> orAnnotation : orAnnotations) {
            boolean annotationPresent = clazz.isAnnotationPresent(orAnnotation);
            if (annotationPresent) {
                flag = true;
                break;
            }
        }

        for (Class<? extends Annotation> andAnnotation : andAnnotations) {
            boolean annotationPresent = clazz.isAnnotationPresent(andAnnotation);
            if (!annotationPresent) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    private boolean isInterfacePassed(Class<?> clazz) {
        //true ^ true = false, true ^ false = true
        boolean flag = true ^ (CollectionHelper.notNullAndHasSize(orImplementsInterface) || CollectionHelper.notNullAndHasSize(andImplementsInterface));// 如果判断是否需要注解，则初始值为false

        for (Class<?> orInterface : orImplementsInterface) {
            boolean isImplementsInterface = ClassHelper.isImplementsInterface(clazz, orInterface);
//            EntityHelper.print("clazz: " + clazz + ", isImplementsInterface: " + isImplementsInterface);
            if (isImplementsInterface) {
                flag = true;
                break;
            }
        }

        for (Class<?> andInterface : andImplementsInterface) {
            boolean isImplementsInterface = ClassHelper.isImplementsInterface(clazz, andInterface);
            if (!isImplementsInterface) {
                flag = false;
                break;
            }
            flag = true;
        }
        return flag;
    }

    public static void main(String[] args) {
        Collection<Class<?>> scan = PackageScanner.newScanner().addPackage(PackageScanner.class.getPackage()).orAnnotation(Deprecated.class).scan();
        System.out.println(scan);
        Collection<Class<?>> scan2 = PackageScanner.newScanner().addPackage(ArrayList.class.getPackage()).andInterface(Collection.class).scan();
        System.out.println(scan2);
    }

}


/*
 *  FileFilterExtensions.java of project cpdetector, <purpose>
 *  Copyright 2004 (C) Achim Westermann, created on 02.06.2004.
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this collection are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the cpDetector code in [sub] packages info.monitorenter and
 * cpdetector.
 *
 * The Initial Developer of the Original Code is
 * Achim Westermann <achim.westermann@gmx.de>.
 *
 * Portions created by the Initial Developer are Copyright (c) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** *
 */
package info.monitorenter.cpdetector.io;

import java.io.File;
import java.io.FileFilter;
import java.util.StringTokenizer;

/**
 *

 * Configureable implementation of {@link java.io.FileFilter} used for
 * selection of the test documents under the collection root.
 *

 *

 * Kept private because no state-verification is performed: The configuration
 * may (but shouldn't) be made at runtime.
 *

 * @author Achim Westermann
 */
public final class FileFilterExtensions implements FileFilter {
	private String[] m_extensions;
	public FileFilterExtensions(String[] extensionsWithoutDot) throws IllegalArgumentException {
		this.verify(extensionsWithoutDot);
		this.m_extensions = extensionsWithoutDot;
	}

	/**
	 * @param extensions The array with the Strings of m_extensions.
	 * @throws IllegalArgumentException If a String of the array is null or contains a dot ('.').
	 */
	private void verify(String[] extensions) throws IllegalArgumentException {
		String current;
		StringBuffer msg = new StringBuffer();
		for (int i = extensions.length - 1; i >= 0; i--) {
			current = extensions[i];
			if (current == null) {
				msg.append("Extension at index " + i + " is null!\n");
			} else if (current.indexOf('.') != -1) {
				msg.append("Extension \"" + current + "\" contains a dot!\n");
			}
		}
		if (msg.length() > 0) {
			throw new IllegalArgumentException(msg.toString());
		}
	}

	/* (non-Javadoc)
	 * @see java.io.FileFilter#accept(java.io.File)
	 */
	public boolean accept(File pathname) {
		boolean ret = false;
		// search for extension without dot.
		StringTokenizer tokenizer = new StringTokenizer(pathname.getAbsolutePath(), ".");
		String extension = "no.txt"; // a dot, because verify will not allow these tokens: won't accept, if no extension in pathname.
		while (tokenizer.hasMoreElements()) {
			extension = tokenizer.nextToken();
		}
		for (int i = this.m_extensions.length - 1; i >= 0; i--) {
			if (this.m_extensions[i].equals(extension)) {
				ret = true;
				break;
			}
		}
		return ret;
	}

}


package com.xiongyingqi.qrcode;

/**
 * Created by 瑛琪xiongyingqi.com on 2014/10/17 0017.
 */

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Hashtable;
import java.util.UUID;

public class QRCode {

    private static final int BLACK = 0xff000000;
    private static final int WHITE = 0xFFFFFFFF;

    /**
     * 生成QRCode二维码
     */
    public File encode(Profile profile) {
        try {
            File isFile = new File(profile.getPath());
            if (!isFile.exists()) {
                isFile.mkdirs();
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String fileName = UUID.randomUUID() + "." + profile.getFormat();
//            String url = zxing.getPath() + fileName;
            File file = new File(profile.getPath(), fileName);
//            writeToFile(bitMatrix, profile.getFormat(), file, profile.isLogoFlag(), profile.getLogoPath());
            BufferedImage bufferedImage = encodeToBufferedImage(profile);
            ImageIO.write(bufferedImage, profile.getFormat(), file);
            return file;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public OutputStream encodeToOutputStream(Profile profile) throws IOException, WriterException {
        OutputStream outputStream = new ByteArrayOutputStream();
        BufferedImage bufferedImage = encodeToBufferedImage(profile);
        ImageIO.write(bufferedImage, profile.getFormat(), outputStream);
        return outputStream;
    }

    private BufferedImage encodeToBufferedImage(Profile profile) throws WriterException, IOException {
        BitMatrix bitMatrix = encodeToBitMatrix(profile);
        BufferedImage bufferedImage = getBufferedImage(bitMatrix, profile.isLogoFlag(), profile.getLogoPath());
        return bufferedImage;
    }

    private BitMatrix encodeToBitMatrix(Profile profile) throws WriterException {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
            /*设置纠错级别(L 7%~M 15%~Q 25%~H 30%),纠错级别越高存储的信息越少*/
        hints.put(EncodeHintType.ERROR_CORRECTION, profile.getErrorCorrectionLevel());
            /*设置编码格式*/
        hints.put(EncodeHintType.CHARACTER_SET, profile.getCharacterSet());
            /*设置边缘空白*/
        hints.put(EncodeHintType.MARGIN, profile.getMargin());

        BitMatrix bitMatrix = new MultiFormatWriter().encode(profile.getContent(), BarcodeFormat.QR_CODE, profile.getWidth(), profile.getHeight(), hints);
        return bitMatrix;
    }

    public BufferedImage getBufferedImage(BitMatrix bitMatrix, boolean isLogo, String logoPath) throws IOException {
        BufferedImage bi = toBufferedImageContents(bitMatrix);
        if (isLogo && logoPath != null && !logoPath.isEmpty() && new File(logoPath).exists()) {
            int width_4 = bitMatrix.getWidth() / 4;
            int width_8 = width_4 / 2;
            int height_4 = bitMatrix.getHeight() / 4;
            int height_8 = height_4 / 2;
            /*返回由指定矩形区域定义的子图像*/
            BufferedImage bi2 = bi.getSubimage(width_4 + width_8, height_4 + height_8, width_4, height_4);
            /*获取一个绘图工具笔*/
            Graphics2D g2 = bi2.createGraphics();
            /*读取logo图片信息*/
            Image img = ImageIO.read(new File(logoPath));//实例化一个Image对象。
            /*当前图片的宽与高*/
            int currentImgWidth = img.getWidth(null);
            int currentImgHeight = img.getHeight(null);
            /*处理图片的宽与高*/
            int resultImgWidth = 0;
            int resultImgHeight = 0;
            if (currentImgWidth != width_4) {
                resultImgWidth = width_4;
            }
            if (currentImgHeight != width_4) {
                resultImgHeight = width_4;
            }
            /*绘制图片*/
            g2.drawImage(img, 0, 0, resultImgWidth, resultImgHeight, null);
            g2.dispose();
            bi.flush();
        }
        return bi;
    }

    /**
     * 生成二维码图片
     *
     * @param bitMatrix
     * @param format    图片格式
     * @param file      生成二维码图片位置
     * @param isLogo    是否要加logo图
     * @param logoPath  logo图片地址
     * @throws IOException
     */
//    public void writeToFile(BitMatrix bitMatrix, String format, File file, boolean isLogo, String logoPath) throws IOException {
//        BufferedImage bi = toBufferedImageContents(bitMatrix);
//        if (isLogo && logoPath != null && !logoPath.isEmpty() && new File(logoPath).exists()) {
//            int width_4 = bitMatrix.getWidth() / 4;
//            int width_8 = width_4 / 2;
//            int height_4 = bitMatrix.getHeight() / 4;
//            int height_8 = height_4 / 2;
//            /*返回由指定矩形区域定义的子图像*/
//            BufferedImage bi2 = bi.getSubimage(width_4 + width_8, height_4 + height_8, width_4, height_4);
//            /*获取一个绘图工具笔*/
//            Graphics2D g2 = bi2.createGraphics();
//            /*读取logo图片信息*/
//            Image img = ImageIO.read(new File(logoPath));//实例化一个Image对象。
//            /*当前图片的宽与高*/
//            int currentImgWidth = img.getWidth(null);
//            int currentImgHeight = img.getHeight(null);
//            /*处理图片的宽与高*/
//            int resultImgWidth = 0;
//            int resultImgHeight = 0;
//            if (currentImgWidth != width_4) {
//                resultImgWidth = width_4;
//            }
//            if (currentImgHeight != width_4) {
//                resultImgHeight = width_4;
//            }
//            /*绘制图片*/
//            g2.drawImage(img, 0, 0, resultImgWidth, resultImgHeight, null);
//            g2.dispose();
//            bi.flush();
//        }
//        ImageIO.write(bi, format, file);
//    }

    /**
     * 生成二维码内容
     *
     * @param bitMatrix
     * @return
     */
    public BufferedImage toBufferedImageContents(BitMatrix bitMatrix) {
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) == true ? BLACK : WHITE);
            }
        }
        return image;
    }

    public String decode(InputStream inputStream) throws IOException, NotFoundException {
        return decode(ImageIO.read(inputStream));
    }

    public String decode(BufferedImage image) throws NotFoundException {
        /*判断是否是图片*/
        if (image == null) {
            System.out.println("Could not decode image");
        }
            /*解析二维码用到的辅助类*/
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
            /*解码设置编码方式为：UTF-8*/
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");

        Result result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        return resultStr;
    }

    /**
     * 解析二维码
     *
     * @param path 图片的绝对路径
     */
    public String decode(String path) throws IOException, NotFoundException {
        if (path == null || path.equals("")) {
            System.out.println("文件路径不能为空!");
        }
        File file = new File(path);
        BufferedImage image = ImageIO.read(file);
            /*判断是否是图片*/
        if (image != null) {
            return decode(image);
        }
        return null;
    }

}


/*
 * Copyright 2002-2012 the original author or authors.
 *
 * Licensed 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 com.xiongyingqi.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

/**
 * Support class for throttling concurrent access to a specific resource.
 *

 *
Designed for use as a base class, with the subclass invoking
 * the {@link #beforeAccess()} and {@link #afterAccess()} methods at
 * appropriate points of its workflow. Note that {@code afterAccess}
 * should usually be called in a finally block!
 *

 *
The default concurrency limit of this support class is -1
 * ("unbounded concurrency"). Subclasses may override this default;
 * check the javadoc of the concrete class that you're using.
 *
 * @author Juergen Hoeller
 * @see #setConcurrencyLimit
 * @see #beforeAccess()
 * @see #afterAccess()
 * @see org.springframework.aop.interceptor.ConcurrencyThrottleInterceptor
 * @see java.io.Serializable
 * @since 1.2.5
 */
@SuppressWarnings("serial")
public abstract class ConcurrencyThrottleSupport implements Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     */
    public static final int UNBOUNDED_CONCURRENCY = -1;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     */
    public static final int NO_CONCURRENCY = 0;

    /**
     * Transient to optimize serialization
     */
    protected transient Log logger = LogFactory.getLog(getClass());

    private transient Object monitor = new Object();

    private int concurrencyLimit = UNBOUNDED_CONCURRENCY;

    private int concurrencyCount = 0;

    /**
     * Set the maximum number of concurrent access attempts allowed.
     * -1 indicates unbounded concurrency.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     *
NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyLimit = concurrencyLimit;
    }

    /**
     * Return the maximum number of concurrent access attempts allowed.
     */
    public int getConcurrencyLimit() {
        return this.concurrencyLimit;
    }

    /**
     * Return whether this throttle is currently active.
     *
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     */
    public boolean isThrottleActive() {
        return (this.concurrencyLimit > 0);
    }

    /**
     * To be invoked before the main execution logic of concrete subclasses.
     *
This implementation applies the concurrency throttle.
     *
     * @see #afterAccess()
     */
    protected void beforeAccess() {
        if (this.concurrencyLimit == NO_CONCURRENCY) {
            throw new IllegalStateException(
                    "Currently no invocations allowed - concurrency limit set to NO_CONCURRENCY");
        }
        if (this.concurrencyLimit > 0) {
            boolean debug = logger.isDebugEnabled();
            synchronized (this.monitor) {
                boolean interrupted = false;
                while (this.concurrencyCount >= this.concurrencyLimit) {
                    if (interrupted) {
                        throw new IllegalStateException("Thread was interrupted while waiting for invocation access, " +
                                "but concurrency limit still does not allow for entering");
                    }
                    if (debug) {
                        logger.debug("Concurrency count " + this.concurrencyCount +
                                " has reached limit " + this.concurrencyLimit + " - blocking");
                    }
                    try {
                        this.monitor.wait();
                    } catch (InterruptedException ex) {
                        // Re-interrupt current thread, to allow other threads to react.
                        Thread.currentThread().interrupt();
                        interrupted = true;
                    }
                }
                if (debug) {
                    logger.debug("Entering throttle at concurrency count " + this.concurrencyCount);
                }
                this.concurrencyCount++;
            }
        }
    }

    /**
     * To be invoked after the main execution logic of concrete subclasses.
     *
     * @see #beforeAccess()
     */
    protected void afterAccess() {
        if (this.concurrencyLimit >= 0) {
            synchronized (this.monitor) {
                this.concurrencyCount--;
                if (logger.isDebugEnabled()) {
                    logger.debug("Returning from throttle at concurrency count " + this.concurrencyCount);
                }
                this.monitor.notify();
            }
        }
    }

    //---------------------------------------------------------------------
    // Serialization support
    //---------------------------------------------------------------------

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        // Rely on default serialization, just initialize state after deserialization.
        ois.defaultReadObject();

        // Initialize transient fields.
        this.logger = LogFactory.getLog(getClass());
        this.monitor = new Object();
    }

}