/*
 * #%L
 * This file is part of a universal JAAS library, providing a universal JDBC
 * authenticator implementation.
 * %%
 * Copyright (C) 2014 - 2016 Michael Beiter <michael@beiter.org>
 * %%
 * All rights reserved.
 * .
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the copyright holder nor the names of the
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 * .
 * .
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */
package org.beiter.michael.authn.jaas.loginmodules.password.authenticators.jdbc.propsbuilder;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.beiter.michael.authn.jaas.loginmodules.password.authenticators.jdbc.DbProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * This class builds a set of {@link DbProperties} using the settings obtained from a
 * JAAS Properties Map.
 *

 *

 * Use the keys from the various KEY_* fields to properly populate the JAAS Properties Map before calling this class'
 * methods.
 */
// CHECKSTYLE:OFF
// this is flagged in checkstyle with a missing whitespace before '}', which is a bug in checkstyle
// suppress warnings about the long variable names
@SuppressWarnings({"PMD.LongVariable"})
// CHECKSTYLE:ON
public final class JaasBasedDbPropsBuilder {

    /**
     * The logger object for this class
     */
    private static final Logger LOG = LoggerFactory.getLogger(JaasBasedDbPropsBuilder.class);

    // #################
    // # Default values
    // #################

    /**
     * @see DbProperties#setJndiConnectionName(String)
     */
    public static final String DEFAULT_JNDI_NAME = null;

    /**
     * @see DbProperties#setSqlUserQuery(String)
     */
    public static final String DEFAULT_SQL_USER_QUERY = null;

    // #####################
    // # Configuration Keys
    // #####################

    /**
     * @see DbProperties#setJndiConnectionName(String)
     */
    public static final String KEY_JNDI_CONNECTION_NAME = "jaas.jdbc.jndi.name";

    /**
     * @see DbProperties#setSqlUserQuery(String)
     */
    public static final String KEY_SQL_USER_QUERY = "jaas.jdbc.sql.userQuery";

    /**
     * A private constructor to prevent instantiation of this class
     */
    private JaasBasedDbPropsBuilder() {
    }

    /**
     * Creates a set of database properties that use the defaults as specified in this class.
     *
     * @return A set of database properties with (reasonable) defaults
     * @see JaasBasedDbPropsBuilder
     */
    public static DbProperties buildDefault() {

        return build(new ConcurrentHashMap<String, String>());
    }

    /**
     * Initialize a set of database properties based on key / values in a HashMap.
     *
     * @param properties A HashMap with configuration properties as required by the init() method in JAAS,
     *                   using the keys as specified in this class
     * @return A DbProperties object with default values, plus the provided parameters
     * @throws NullPointerException When {@code properties} is {@code null}
     */
    public static DbProperties build(final Map<String, ?> properties) {

        Validate.notNull(properties, "The validated object 'properties' is null");

        final DbProperties dbProps = new DbProperties();
        String tmp = getOption(KEY_JNDI_CONNECTION_NAME, properties);
        if (StringUtils.isNotEmpty(tmp)) { // JNDI connection name can be null or empty
            dbProps.setJndiConnectionName(tmp);
            logValue(KEY_JNDI_CONNECTION_NAME, tmp);
        } else {
            dbProps.setJndiConnectionName(DEFAULT_JNDI_NAME);
            logDefault(KEY_JNDI_CONNECTION_NAME, DEFAULT_JNDI_NAME);
        }

        tmp = getOption(KEY_SQL_USER_QUERY, properties);
        if (StringUtils.isNotEmpty(tmp)) { // sql query cannot be null or empty, defaulting to null to catch it
            dbProps.setSqlUserQuery(tmp);
            logValue(KEY_SQL_USER_QUERY, tmp);
        } else {
            dbProps.setSqlUserQuery(DEFAULT_SQL_USER_QUERY);
            logDefault(KEY_SQL_USER_QUERY, DEFAULT_SQL_USER_QUERY);
        }

        // set the additional properties, preserving the originally provided properties
        // create a defensive copy of the map and all its properties
        // the code looks a little more complicated than a simple "putAll()", but it catches situations
        // where a Map is provided that supports null values (e.g. a HashMap) vs Map implementations
        // that do not (e.g. ConcurrentHashMap).
        final Map<String, String> tempMap = new ConcurrentHashMap<>();
        try {
            for (final Map.Entry<String, ?> entry : properties.entrySet()) {
                final String key = entry.getKey();
                final String value = (String) entry.getValue();

                if (value != null) {
                    tempMap.put(key, value);
                }
            }
        } catch (ClassCastException e) {
            final String error = "The values of the configured JAAS properties must be Strings. "
                    + "Sorry, but we do not support anything else here!";
            throw new IllegalArgumentException(error, e);
        }
        dbProps.setAdditionalProperties(tempMap);

        return dbProps;
    }

    /**
     * Return the value of a JAAS configuration parameter.
     *
     * @param <T>        The type of the element
     * @param key        The key to retrieve from the options
     * @param properties The properties to retrieve values from
     * @return The configuration value for the provided key
     */
    @SuppressWarnings("unchecked")
    private static <T> T getOption(final String key, final Map<String, ?> properties) {

        // private method asserts
        assert key != null : "The key cannot be null";

        return (T) properties.get(key);
    }

    /**
     * Create a log entry when a value has been successfully configured.
     *
     * @param key   The configuration key
     * @param value The value that is being used
     */
    private static void logValue(final String key, final String value) {

        // Fortify will report a violation here because of disclosure of potentially confidential information.
        // However, the configuration keys are not confidential, which makes this a non-issue / false positive.
        if (LOG.isInfoEnabled()) {
            final StringBuilder msg = new StringBuilder("Key found in configuration ('")
                    .append(key)
                    .append("'), using configured value (not disclosed here for security reasons)");
            LOG.info(msg.toString());
        }

        // Fortify will report a violation here because of disclosure of potentially confidential information.
        // The configuration VALUES are confidential. DO NOT activate DEBUG logging in production.
        if (LOG.isDebugEnabled()) {
            final StringBuilder msg = new StringBuilder("Key found in configuration ('")
                    .append(key)
                    .append("'), using configured value ('");
            if (value == null) {
                msg.append("null')");
            } else {
                msg.append(value).append("')");
            }
            LOG.debug(msg.toString());
        }
    }

    /**
     * Create a log entry when a default value is being used in case the propsbuilder key has not been provided in the
     * configuration.
     *
     * @param key          The configuration key
     * @param defaultValue The default value that is being used
     */
    private static void logDefault(final String key, final String defaultValue) {

        // Fortify will report a violation here because of disclosure of potentially confidential information.
        // However, neither the configuration keys nor the default propsbuilder values are confidential, which makes
        // this a non-issue / false positive.
        if (LOG.isInfoEnabled()) {
            final StringBuilder msg = new StringBuilder("Key is not configured ('")
                    .append(key)
                    .append("'), using default value ('");
            if (defaultValue == null) {
                msg.append("null')");
            } else {
                msg.append(defaultValue).append("')");
            }
            LOG.info(msg.toString());
        }
    }
}


/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: subchen@gmail.com
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.lang;

/**
 * Checks whether a path matches a given wildcard pattern.
 * Possible patterns allow to match single characters ('?') or any count of
 * characters ('*'). Wildcard characters can be escaped (by an '\').
 * When matching path, deep tree wildcard also can be used ('**').
 *

 * This method uses recursive matching, as in linux or windows. regexp works the same.
 * This method is very fast, comparing to similar implementations.
 */
public class WildcharPathUtils {
    protected static final String PATH_MATCH = "**";
    protected static final String PATH_SEPARATORS = "/\\";

    /**
     * Matches path against pattern using *, ? and ** wildcards.
     * Both path and the pattern are tokenized on path separators (both \ and /).
     * '**' represents deep tree wildcard, as in Ant.
     */
    public static boolean matchPath(String path, String pattern) {
        String[] pathElements = StringUtils.splitChars(path, PATH_SEPARATORS);
        String[] patternElements = StringUtils.splitChars(pattern, PATH_SEPARATORS);
        return matchTokens(pathElements, patternElements);
    }

    /**
     * Matches path to at least one pattern.
     * Returns index of matched pattern or -1 otherwise.
     * @see #matchPath(String, String)
     */
    public static int matchPathOne(String path, String[] patterns) {
        for (int i = 0; i < patterns.length; i++) {
            if (matchPath(path, patterns[i]) == true) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Match tokenized string and pattern.
     */
    protected static boolean matchTokens(String[] tokens, String[] patterns) {
        int patNdxStart = 0;
        int patNdxEnd = patterns.length - 1;
        int tokNdxStart = 0;
        int tokNdxEnd = tokens.length - 1;

        while (patNdxStart <= patNdxEnd && tokNdxStart <= tokNdxEnd) { // find first **
            String patDir = patterns[patNdxStart];
            if (patDir.equals(PATH_MATCH)) {
                break;
            }
            if (!WildcharUtils.match(tokens[tokNdxStart], patDir)) {
                return false;
            }
            patNdxStart++;
            tokNdxStart++;
        }
        if (tokNdxStart > tokNdxEnd) {
            for (int i = patNdxStart; i <= patNdxEnd; i++) { // string is finished
                if (!patterns[i].equals(PATH_MATCH)) {
                    return false;
                }
            }
            return true;
        }
        if (patNdxStart > patNdxEnd) {
            return false; // string is not finished, but pattern is
        }

        while (patNdxStart <= patNdxEnd && tokNdxStart <= tokNdxEnd) { // to the last **
            String patDir = patterns[patNdxEnd];
            if (patDir.equals(PATH_MATCH)) {
                break;
            }
            if (!WildcharUtils.match(tokens[tokNdxEnd], patDir)) {
                return false;
            }
            patNdxEnd--;
            tokNdxEnd--;
        }
        if (tokNdxStart > tokNdxEnd) {
            for (int i = patNdxStart; i <= patNdxEnd; i++) { // string is finished
                if (!patterns[i].equals(PATH_MATCH)) {
                    return false;
                }
            }
            return true;
        }

        while ((patNdxStart != patNdxEnd) && (tokNdxStart <= tokNdxEnd)) {
            int patIdxTmp = -1;
            for (int i = patNdxStart + 1; i <= patNdxEnd; i++) {
                if (patterns[i].equals(PATH_MATCH)) {
                    patIdxTmp = i;
                    break;
                }
            }
            if (patIdxTmp == patNdxStart + 1) {
                patNdxStart++; // skip **/** situation
                continue;
            }
            // find the pattern between padIdxStart & padIdxTmp in str between strIdxStart & strIdxEnd
            int patLength = (patIdxTmp - patNdxStart - 1);
            int strLength = (tokNdxEnd - tokNdxStart + 1);
            int ndx = -1;
            strLoop: for (int i = 0; i <= strLength - patLength; i++) {
                for (int j = 0; j < patLength; j++) {
                    String subPat = patterns[patNdxStart + j + 1];
                    String subStr = tokens[tokNdxStart + i + j];
                    if (!WildcharUtils.match(subStr, subPat)) {
                        continue strLoop;
                    }
                }

                ndx = tokNdxStart + i;
                break;
            }

            if (ndx == -1) {
                return false;
            }

            patNdxStart = patIdxTmp;
            tokNdxStart = ndx + patLength;
        }

        for (int i = patNdxStart; i <= patNdxEnd; i++) {
            if (!patterns[i].equals(PATH_MATCH)) {
                return false;
            }
        }

        return true;
    }
}


/**
 * Rectangular.java
 *
 * Created on 24.11.2006, 22:16:54 by radek
 */
package org.fit.layout.model;

/**
 * This class represents a general rectangular area.
 *
 * @author radek
 */
public class Rectangular
{
	protected int x1;
	protected int y1;
	protected int x2;
	protected int y2;

	public Rectangular()
	{
		x1 = 0;
		y1 = 0;
		x2 = -1;
		y2 = -1;
	}

	/**
	 * Creates a rectangle at the given coordinates.
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 */
	public Rectangular(int x1, int y1, int x2, int y2)
	{
		this.x1 = Math.min(x1, x2);
		this.x2 = Math.max(x1, x2);
		this.y1 = Math.min(y1, y2);
		this.y2 = Math.max(y1, y2);
	}

    /**
     * Creates an empty rectangle at the given coordinates.
     * @param x1
     * @param y1
     */
	public Rectangular(int x1, int y1)
    {
        this.x1 = x1;
        this.x2 = x1 - 1;
        this.y1 = y1;
        this.y2 = y1 - 1;
    }

	public Rectangular(Rectangular src)
	{
		this.x1 = src.x1;
		this.x2 = src.x2;
		this.y1 = src.y1;
		this.y2 = src.y2;
	}

	public Rectangular(java.awt.Rectangle src)
	{
		this.x1 = src.x;
		this.x2 = src.x + src.width - 1;
		this.y1 = src.y;
		this.y2 = src.y + src.height - 1;
	}

    public void copy(Rectangular src)
    {
        this.x1 = src.x1;
        this.x2 = src.x2;
        this.y1 = src.y1;
        this.y2 = src.y2;
    }

	/**
	 * @return the x1
	 */
	public int getX1()
	{
		return x1;
	}

	/**
	 * @param x1 the x1 to set
	 */
	public void setX1(int x1)
	{
		this.x1 = x1;
	}

	/**
	 * @return the x2
	 */
	public int getX2()
	{
		return x2;
	}

	/**
	 * @param x2 the x2 to set
	 */
	public void setX2(int x2)
	{
		this.x2 = x2;
	}

	/**
	 * @return the y1
	 */
	public int getY1()
	{
		return y1;
	}

	/**
	 * @param y1 the y1 to set
	 */
	public void setY1(int y1)
	{
		this.y1 = y1;
	}

	/**
	 * @return the y2
	 */
	public int getY2()
	{
		return y2;
	}

	/**
	 * @param y2 the y2 to set
	 */
	public void setY2(int y2)
	{
		this.y2 = y2;
	}

	public int getWidth()
	{
		return x2 - x1 + 1;
	}

	public int getHeight()
	{
		return y2 - y1 + 1;
	}

    public int midX()
    {
        return (x2 + x1) / 2;
    }

    public int midY()
    {
        return (y2 + y1) / 2;
    }

    /**
     * Changes the rectangle coordinates by adding the specified X and Y offsets
     * @param xofs the X offset
     * @param yofs the Y offset
     */
    public void move(int xofs, int yofs)
    {
        x1 += xofs;
        y1 += yofs;
        x2 += xofs;
        y2 += yofs;
    }

    public int getArea()
    {
    	int a = getWidth() * getHeight();
    	return (a >= 0) ? a : 0;
    }

    public boolean isEmpty()
    {
    	return x2 < x1 || y2 < y1;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (obj instanceof Rectangular)
        {
            Rectangular r = (Rectangular) obj;
            return r.x1 == x1 && r.y1 == y1 && r.x2 == x2 && r.y2 == y2;
        }
        else
            return false;
    }

    /**
     * Checks if this rectangle entirely contains another rectangle.
     * @param other the other rectangle
     * @return true when the other rectangle is completely contained in this one
     */
    public boolean encloses(Rectangular other)
    {
        return x1 <= other.x1 &&
               y1 <= other.y1 &&
               x2 >= other.x2 &&
               y2 >= other.y2;
    }

    /**
     * Checks if this rectangle entirely contains the X coordinates of another rectangle.
     * @param other the other rectangle
     * @return true when the X coordinates of the other rectangle are completely contained in this one
     */
    public boolean enclosesX(Rectangular other)
    {
        return x1 <= other.x1 &&
               x2 >= other.x2;
    }

    /**
     * Checks if this rectangle entirely contains the Y coordinates of another rectangle.
     * @param other the other rectangle
     * @return true when the Y coordinates of the other rectangle are completely contained in this one
     */
    public boolean enclosesY(Rectangular other)
    {
        return y1 <= other.y1 &&
               y2 >= other.y2;
    }

    /**
     * Checks if this rectangle contains a point.
     * @param x the point X coordinate
     * @param y the point Y coordinate
     * @return true when the point is contained in this one
     */
    public boolean contains(int x, int y)
    {
        return x1 <= x &&
               y1 <= y &&
               x2 >= x &&
               y2 >= y;
    }

	public boolean intersects(Rectangular other)
	{
	    if (this.isEmpty() || other.isEmpty())
	        return false;
	    else
    	    return !(other.x1 > x2
        			|| other.x2 < x1
        			|| other.y1 > y2
        			|| other.y2 < y1);
	}

	public boolean intersectsX(Rectangular other)
	{
        if (this.isEmpty() || other.isEmpty())
            return false;
        else
            return !(other.x1 > x2 || other.x2 < x1);
	}

    public boolean intersectsY(Rectangular other)
    {
        if (this.isEmpty() || other.isEmpty())
            return false;
        else
            return !(other.y1 > y2 || other.y2 < y1);
    }

    /**
     * Computes the intersection of this rectangle with another one.
     * @param other the other rectangle
     * @return the resulting intersection or an empty rectangle when there is no intersection
     */
    public Rectangular intersection(Rectangular other)
    {
    	if (this.intersects(other))
	    {
    		return new Rectangular(Math.max(x1, other.x1),
    							   Math.max(y1, other.y1),
    							   Math.min(x2, other.x2),
    							   Math.min(y2, other.y2));
	    }
	    else
	    {
	        return new Rectangular(); //an empty rectangle
	    }
    }

    /**
     * Computes the union of this rectangle with another one.
     * @param other the other rectangle
     * @return the union rectangle
     */
    public Rectangular union(Rectangular other)
    {
        return new Rectangular(Math.min(x1, other.x1),
                               Math.min(y1, other.y1),
                               Math.max(x2, other.x2),
                               Math.max(y2, other.y2));
    }

    /**
     * Replaces the X coordinates of the rectangle with the X coordinates of another one.
     * @param other the rectangle whose X coordinates will be used
     * @return the resulting rectangle
     */
    public Rectangular replaceX(Rectangular other)
    {
        Rectangular ret = new Rectangular(this);
        ret.x1 = other.x1;
        ret.x2 = other.x2;
        return ret;
    }

    /**
     * Replaces the Y coordinates of the rectangle with the Y coordinates of another one.
     * @param other the rectangle whose Y coordinates will be used
     * @return the resulting rectangle
     */
    public Rectangular replaceY(Rectangular other)
    {
        Rectangular ret = new Rectangular(this);
        ret.y1 = other.y1;
        ret.y2 = other.y2;
        return ret;
    }

    /**
     * If this rectangle intersets with the other one, splits this rectangle horizontally so that it does not intersect with the other one anymore.
     * @param other the rectangle used to split this one
     * @return if this rectangle had to be split in two parts, the second one is returned. Otherwise, null is returned.
     */
    public Rectangular hsplit(Rectangular other)
    {
        if (this.intersects(other))
        {
            Rectangular a = new Rectangular(this);
            Rectangular b = new Rectangular(this);
            if (a.x2 > other.x1 - 1) a.x2 = other.x1 - 1;
            if (b.x1 < other.x2 + 1) b.x1 = other.x2 + 1;
            if (a.isEmpty())
            {
                x1 = b.x1;
                return null;
            }
            else
            {
                x2 = a.x2;
                if (b.isEmpty())
                    return null;
                else
                    return b;
            }
        }
        else
            return null;
    }

    /**
     * If this rectangle intersets with the other one, splits this rectangle horizontally so that it does not intersect with the other one anymore.
     * @param other the rectangle used to split this one
     * @return if this rectangle had to be split in two parts, the second one is returned. Otherwise, null is returned.
     */
    public Rectangular vsplit(Rectangular other)
    {
        if (this.intersects(other))
        {
            Rectangular a = new Rectangular(this);
            Rectangular b = new Rectangular(this);
            if (a.y2 > other.y1 - 1) a.y2 = other.y1 - 1;
            if (b.y1 < other.y2 + 1) b.y1 = other.y2 + 1;
            if (a.isEmpty())
            {
                y1 = b.y1;
                return null;
            }
            else
            {
                y2 = a.y2;
                if (b.isEmpty())
                    return null;
                else
                    return b;
            }
        }
        else
            return null;
    }

    public void expandToEnclose(Rectangular other)
    {
    	if (other.x1 < x1) x1 = other.x1;
    	if (other.y1 < y1) y1 = other.y1;
    	if (other.x2 > x2) x2 = other.x2;
    	if (other.y2 > y2) y2 = other.y2;
    }

	public String toString()
	{
		return "[" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + "]";
	}
}


/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: subchen@gmail.com
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.io;

public class FilenameUtils {

    /**
     * 得到文件名.
     */
    public static String getFilename(final String path) {
        if (path == null) {
            return null;
        }
        int separatorIndex = getFileSeparatorIndex(path);
        return separatorIndex == -1 ? path.substring(separatorIndex + 1) : path;
    }

    /**
     * 得到文件扩展名.
     */
    public static String getFileExtension(final String path) {
        if (path == null) {
            return null;
        }
        int extIndex = path.lastIndexOf('.');
        if (extIndex == -1) {
            return null;
        }
        int folderIndex = getFileSeparatorIndex(path);
        if (folderIndex > extIndex) {
            return null;
        }
        return path.substring(extIndex + 1);
    }

    /**
     * 得到文件 basename (去掉路径，去掉扩展名).
     */
    public static String getFileBasename(final String filename) {
        return removeFileExtension(getFilename(filename));
    }

    /**
     * 删除文件扩展名.
     */
    public static String removeFileExtension(final String path) {
        if (path == null) {
            return null;
        }
        int extIndex = path.lastIndexOf('.');
        if (extIndex == -1) {
            return path;
        }
        int folderIndex = getFileSeparatorIndex(path);
        if (folderIndex > extIndex) {
            return path;
        }
        return path.substring(0, extIndex);
    }

    private static int getFileSeparatorIndex(String path) {
        for (int i = path.length() - 1; i >= 0; i--) {
            char c = path.charAt(i);
            if (c == '/' || c == '\\') {
                return i;
            }
        }
        return -1;
    }
}


/*
 * @(#)ScreenApplet.java	1.13 98/08/28
 * Copyright © 2012 jbundle.org. All rights reserved.
 */
package org.jbundle.jbackup.source;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.util.Properties;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.jbundle.jbackup.JBackupConstants;
import org.jbundle.util.apprunner.PropertyOwner;

/**
 * Main property view screen.
 * From this screen the user selects the model, view, and control.
 */
public class FilesystemSourcePropertyView extends BaseSourcePropertyView
	implements JBackupConstants
{
	private static final long serialVersionUID = 1L;

	protected JTextField m_tfRootPathname = null;

	/*
	 * Constructor.
	 */
	public FilesystemSourcePropertyView()
	{
		super();
	}
	/*
	 * Constructor.
	 */
	public FilesystemSourcePropertyView(PropertyOwner propOwner,Properties properties)
	{
		this();
		this.init(propOwner, properties);
	}
	/*
	 * Initialize.
	 */
	public void init(PropertyOwner propOwner, Properties properties)
	{
		super.init(propOwner, properties);
	}
	/*
	 * Add your property controls to this panel.
	 * Remember to set your own layout manager.
	 * Also, remember to create a new JPanel, and pass it to the super class
	 * so controls of the superclass can be included.
	 * You have a 3 x 3 grid, so add three columns for each control
	 * @param panel This is the panel to add your controls to.
	 */
	public void addControlsToView(JPanel panel)
	{
		panel.setLayout(new BorderLayout());
		JPanel panelMain = this.makeNewPanel(panel, BorderLayout.CENTER);

		panelMain.setLayout(new GridLayout(1, 2));

		panelMain.add(new JLabel("Root pathname: ", JLabel.RIGHT));
		panelMain.add(m_tfRootPathname = new JTextField());

		JPanel panelSub = this.makeNewPanel(panel, BorderLayout.SOUTH);
		super.addControlsToView(panelSub);
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void controlsToProperties()
	{
		super.controlsToProperties();
		String strPathname = m_tfRootPathname.getText();
		m_properties.setProperty(SOURCE_ROOT_PATHNAME_PARAM, strPathname);
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void propertiesToControls()
	{
		super.propertiesToControls();
		String strPathname = m_properties.getProperty(SOURCE_ROOT_PATHNAME_PARAM);
		m_tfRootPathname.setText(strPathname);
	}
	/*
	 * Get the description of this option panel.
	 */
	public String getDescription()
	{
		return "Filesystem source properties";
	}
}


/**
 * AreaGrid.java
 *
 * Created on 29.6.2006, 10:30:36 by burgetr
 */
package org.fit.layout.impl;

import java.util.Arrays;
import java.util.List;

import org.fit.layout.model.Area;
import org.fit.layout.model.AreaTopology;
import org.fit.layout.model.Rectangular;

/**
 * A grid of areas in an abstract parent rectangle.
 * The grid is used as the default area topology.
 *
 * @author burgetr
 */
public class AreaGrid
{
    /** The maximal difference between two lengths that are considered a "being the same" */
    public static final int GRID_THRESHOLD = 0;

    /** Number of columns */
    private int width;

    /** Minimal indentation level */
    private int minindent;

    /** Maximal indentation level */
    private int maxindent;

    /** Array of column widths */
    private int[] cols;

    /** Number of rows */
    private int height;

    /** Array of row heights */
    private int[] rows;

    /** Absolute coordinates of the parent area */
    private Rectangular abspos;

    /** The list of areas laid out in this grid */
    private List<Area> areas;

    /** The target topology where the computed positions will be set */
    private AreaTopology target;

    //================================================================================

    /**
     * Constructs a grid of all the child areas of the given parent area.
     * @param area the parent area whose children will be laid out in the grid
     * @param targetTopology the area topology where the computed grid positions will be set
     */
    public AreaGrid(DefaultArea area, AreaTopology targetTopology)
    {
        abspos = area.getBounds();
        areas = area.getChildren();
        target = targetTopology;
        calculateColumns();
        calculateRows();
    }

    /**
     * Constructs a grid from the list of areas.
     * @param position Absolute position of the grid area
     * @param areas the areas to be laid out in the grid.
     * @param targetTopology the area topology where the computed grid positions will be set
     */
    public AreaGrid(Rectangular position, List<Area> areas, AreaTopology targetTopology)
    {
        this.abspos = position;
        this.areas = areas;
        target = targetTopology;
        calculateColumns();
        calculateRows();
    }

    //================================================================================

    /**
     * Obtains the absolute position where the grid is placed within the page.
     * @return
     */
    public Rectangular getAbsolutePosition()
    {
        return abspos;
    }

    /**
     * @return Returns the cols.
     */
    public int[] getCols()
    {
        return cols;
    }

    /**
     * @return Returns the height.
     */
    public int getHeight()
    {
        return height;
    }

    /**
     * @return Returns the rows.
     */
    public int[] getRows()
    {
        return rows;
    }

    /**
     * @return Returns the width.
     */
    public int getWidth()
    {
        return width;
    }

    public int getMinIndent()
    {
        return minindent;
    }

    public int getMaxIndent()
    {
        return maxindent;
    }

    public String toString()
    {
    	return "Grid " + width + "x" + height;
    }

    /**
     * Finds the offset of the specified column from the grid origin.
     * @param col the column index
     * @return the offset in pixels. Column 0 has always the offset 0.
     */
    public int getColOfs(int col) throws ArrayIndexOutOfBoundsException
    {
    	if (col < width)
    	{
    		int ofs = 0;
    		for (int i = 0; i < col; i++)
    			ofs += cols[i];
    		return ofs;
    	}
    	else if (col == width)
    		return abspos.getWidth();
    	else
    		throw new ArrayIndexOutOfBoundsException(col + ">" + width);
    }

    /**
     * Finds the offset of the specified row from the grid origin.
     * @param col the row index
     * @return the offset in pixels. Row 0 has always the offset 0.
     */
    public int getRowOfs(int row) throws ArrayIndexOutOfBoundsException
    {
    	if (row < height)
    	{
	    	int ofs = 0;
	    	for (int i = 0; i < row; i++)
	    		ofs += rows[i];
	    	return ofs;
    	}
    	else if (row == height)
    		return abspos.getHeight();
    	else
    		throw new ArrayIndexOutOfBoundsException(row + ">" + height);
    }

    /**
     * Computes the coordinates of the specified grid cell relatively to the area top left corner.
     * @param x the column index of the cell
     * @param y the row index of the cell
     * @return the coordinates of the given cell in pixels
     */
    public Rectangular getCellBoundsRelative(int x, int y)
    {
        int x1 = getColOfs(x);
        int y1 = getRowOfs(y);
        int x2 = (x == width-1) ? abspos.getWidth() - 1 : x1 + cols[x] - 1;
        int y2 = (y == height-1) ? abspos.getHeight() - 1 : y1 + rows[y] - 1;
        return new Rectangular(x1, y1, x2, y2);
    }

    /**
     * Computes the absolute coordinates of the specified grid cell.
     * @param x the column index of the cell
     * @param y the row index of the cell
     * @return the coordinates of the given cell in pixels
     */
    public Rectangular getCellBoundsAbsolute(int x, int y)
    {
        int x1 = abspos.getX1() + getColOfs(x);
        int y1 = abspos.getY1() + getRowOfs(y);
        int x2 = ((x == width-1) ? abspos.getX1() + abspos.getWidth() - 1 : x1 + cols[x] - 1);
        int y2 = ((y == height-1) ? abspos.getY1()+ abspos.getHeight() - 1 : y1 + rows[y] - 1);
        return new Rectangular(x1, y1, x2, y2);
    }

    /**
     * Computes the absolute coordinates of the specified area in the grid.
     * @param x1 the column index of the top left cell of the area.
     * @param y1 the row index of the top left cell of the area.
     * @param x2 the column index of the bottom right cell of the area.
     * @param y2 the row index of the bottom right cell of the area.
     * @return the absolute coordinates of the given area in pixels.
     */
    public Rectangular getAreaBoundsAbsolute(int x1, int y1, int x2, int y2)
    {
        final Rectangular end = getCellBoundsAbsolute(x2, y2);
        return new Rectangular(abspos.getX1() + getColOfs(x1), abspos.getY1() + getRowOfs(y1),
                end.getX2(), end.getY2());
    }

    /**
     * Computes the absolute coordinates of the specified area in the grid.
     * @param The area coordinates in the grid.
     * @return the absolute coordinates of the given area in pixels.
     */
    public Rectangular getAreaBoundsAbsolute(Rectangular area)
    {
        return getAreaBoundsAbsolute(area.getX1(), area.getY1(), area.getX2(), area.getY2());
    }

    /**
     * Finds a grid cell that contains the specified point
     * @param x the x coordinate of the specified point
     * @return the X offset of the grid cell that contains the specified absolute
     * x coordinate or -1 when there is no such cell
     */
    public int findCellX(int x)
    {
    	int ofs = abspos.getX1();
    	for (int i = 0; i < cols.length; i++)
    	{
    		ofs += cols[i];
    		if (x < ofs)
    			return i;
    	}
    	return -1;
    }

    /**
     * Finds a grid cell that contains the specified point
     * @param y the y coordinate of the specified point
     * @return the Y offset of the grid cell that contains the specified absolute
     * y coordinate or -1 when there is no such cell
     */
    public int findCellY(int y)
    {
    	int ofs = 0;
    	for (int i = 0; i < rows.length; i++)
    	{
    		ofs += rows[i];
    		if (y < ofs + abspos.getY1())
    			return i;
    	}
    	return -1;
    }

    //================================================================================

    /**
     * @return true if the values are equal in the specified threshold
     */
    private boolean theSame(int val1, int val2)
    {
        return Math.abs(val2 - val1) <= GRID_THRESHOLD;
    }

    /**
     * Goes through the child areas and creates a list of collumns
     */
	private void calculateColumns()
    {
        //create the sorted list of points
        GridPoint points[] = new GridPoint[areas.size() * 2];
        int pi = 0;
        for (Area area : areas)
        {
            points[pi] = new GridPoint(area.getX1(), area, true);
            points[pi+1] = new GridPoint(area.getX2() + 1, area, false);
            pi += 2;
            //X2+1 ensures that the end of one box will be on the same point
            //as the start of the following box
        }
        Arrays.sort(points);

        //calculate the number of columns
        int cnt = 0;
        int last = abspos.getX1();
        for (int i = 0; i < points.length; i++)
            if (!theSame(points[i].value, last))
            {
                last = points[i].value;
                cnt++;
            }
        if (!theSame(last, abspos.getX2()))
        	cnt++; //last column finishes the whole area
        width = cnt;

        //calculate the column widths and the layout
        maxindent = 0;
        minindent = -1;
        cols = new int[width];
        cnt = 0;
        last = abspos.getX1();
        for (int i = 0; i < points.length; i++)
        {
            if (!theSame(points[i].value, last))
            {
                cols[cnt] = points[i].value - last;
                last = points[i].value;
                cnt++;
            }
            if (points[i].begin)
            {
                target.getPosition(points[i].area).setX1(cnt);
                maxindent = cnt;
                if (minindent == -1) minindent = maxindent;
                //points[i].node.getArea().setX1(parent.getArea().getX1() + getColOfs(cnt));
            }
            else
            {
                Rectangular pos = target.getPosition(points[i].area);
                pos.setX2(cnt-1);
                if (pos.getX2() < pos.getX1())
                    pos.setX2(pos.getX1());
                //points[i].node.getArea().setX2(parent.getArea().getX1() + getColOfs(pos.getX2()+1));
            }
        }
        if (!theSame(last, abspos.getX2()))
        	cols[cnt] = abspos.getX2() - last;
        if (minindent == -1)
            minindent = 0;
    }

    /**
     * Goes through the child areas and creates a list of rows
     */
	private void calculateRows()
    {
        //create the sorted list of points
        GridPoint points[] = new GridPoint[areas.size() * 2];
        int pi = 0;
        for (Area area : areas)
        {
            points[pi] = new GridPoint(area.getY1(), area, true);
            points[pi+1] = new GridPoint(area.getY2() + 1, area, false);
            pi += 2;
            //Y2+1 ensures that the end of one box will be on the same point
            //as the start of the following box
        }
        Arrays.sort(points);

        //calculate the number of rows
        int cnt = 0;
        int last = abspos.getY1();
        for (int i = 0; i < points.length; i++)
            if (!theSame(points[i].value, last))
            {
                last = points[i].value;
                cnt++;
            }
        if (!theSame(last, abspos.getY2()))
        	cnt++; //last row finishes the whole area
        height = cnt;

        //calculate the row heights and the layout
        rows = new int[height];
        cnt = 0;
        last = abspos.getY1();
        for (int i = 0; i < points.length; i++)
        {
            if (!theSame(points[i].value, last))
            {
                rows[cnt] = points[i].value - last;
                last = points[i].value;
                cnt++;
            }
            if (points[i].begin)
            {
                target.getPosition(points[i].area).setY1(cnt);
                //points[i].node.getArea().setY1(parent.getArea().getY1() + getRowOfs(cnt));
            }
            else
            {
                Rectangular pos = target.getPosition(points[i].area);
                pos.setY2(cnt-1);
                if (pos.getY2() < pos.getY1())
                    pos.setY2(pos.getY1());
                //points[i].node.getArea().setY2(parent.getArea().getY1() + getRowOfs(pos.getY2()+1));
            }
        }
        if (!theSame(last, abspos.getY2()))
        	rows[cnt] = abspos.getY2() - last;
    }

}

/** A point in the grid */
class GridPoint implements Comparable<GridPoint>
{
    public int value;       //the point position
    public Area area;       //the corresponding visual area
    public boolean begin;   //is it the begining or the end of the node?

    public GridPoint(int value, Area area, boolean begin)
    {
        this.value = value;
        this.area = area;
        this.begin = begin;
    }

    public int compareTo(GridPoint other)
    {
        return value - other.value;
    }
}


/*
 *   Copyright 2015 AML Innovation & Consulting LLC
 *
 *   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.amlinv.jmxutil.polling;

import com.amlinv.jmxutil.MBeanLocationParameterSource;

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

/**
 * Replacer of parameters in strings given the original string and the source of parameter values.
 *
 * Created by art on 8/22/15.
 */
public class ParameterReplacer {
    private final Pattern replaceParamPattern = Pattern.compile("\\$\\{(?<paramName>[^}]*)\\}");

    /**
     * Given a string potentially containing one or more copies of the replacement pattern, ${name}, where name may be
     * any value identifier (e.g. home_dir1), replace each occurrence with the value of the parameter with the enclosed
     * name.
     *
     * @param pattern string potentially containing one or more copies of the replacement pattern.
     * @param parameterSource source of values for parameters for replacement into the given pattern.
     * @return resulting string after replacing parameter values for the replacement pattern.
     */
    public String replaceObjectNameParameters (String pattern, MBeanLocationParameterSource parameterSource) {
        Matcher matcher = replaceParamPattern.matcher(pattern);
        StringBuffer result = new StringBuffer();

        while ( matcher.find() ) {
            String name = matcher.group("paramName");
            String value = parameterSource.getParameter(name);

            if ( value != null ) {
                matcher.appendReplacement(result, value);
            } else {
                matcher.appendReplacement(result, Matcher.quoteReplacement(matcher.group()));
            }
        }

        matcher.appendTail(result);

        return  result.toString();
    }
}


/*
 * #%L
 * This file is part of a common library for a set of universal JAAS modules.
 * %%
 * Copyright (C) 2014 - 2016 Michael Beiter <michael@beiter.org>
 * %%
 * All rights reserved.
 * .
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the copyright holder nor the names of the
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 * .
 * .
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */
package org.beiter.michael.authn.jaas.common.messageq;

import org.apache.commons.lang3.Validate;
import org.beiter.michael.authn.jaas.common.CommonProperties;
import org.beiter.michael.authn.jaas.common.FactoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * A factory to create instances of objects that implement the {@link MessageQ} interface.
 */
public final class MessageQFactory {

    /**
     * The logger object for this class
     */
    private static final Logger LOG = LoggerFactory.getLogger(MessageQFactory.class);

    /**
     * The singleton instance of the message queue
     */
    private static volatile MessageQ messageQInstance;

    /**
     * A private constructor to prevent instantiation of this class
     */
    private MessageQFactory() {
    }

    /**
     * Return a new, fully initialized instance of a {@link MessageQ} class to use for JAAS event messageing.
     *

     * Classes implementing the {@link MessageQ} interface must be thread safe.
     *
     * @param className  The name of a class that implements the Message interface
     * @param properties The properties to initialize the instance with
     * @return An instance of a class implementing the {@link MessageQ} interface
     * @throws FactoryException         When the class cannot be instantiated
     * @throws NullPointerException     When the {@code className} or {@code properties} are {@code null}
     * @throws IllegalArgumentException When {@code className} is empty
     */
    public static MessageQ getInstance(final String className, final CommonProperties properties)
            throws FactoryException {

        Validate.notBlank(className, "The validated character sequence 'className' is null or empty");
        Validate.notNull(properties, "The validated object 'properties' is null");

        final Class<? extends MessageQ> messageClazz;
        try {
            messageClazz = Class.forName(className).asSubclass(MessageQ.class);
        } catch (ClassNotFoundException e) {
            final String error = "Class not found: " + className;
            LOG.warn(error);
            throw new FactoryException(error, e);
        } catch (ClassCastException e) {
            final String error = "The provided registry factory class name ('" + className
                    + "') is not a subclass of '" + MessageQ.class.getCanonicalName() + "'";
            LOG.warn(error);
            throw new FactoryException(error, e);
        }

        final MessageQ messageQ;
        try {
            final Constructor<? extends MessageQ> constructor = messageClazz.getDeclaredConstructor();
            if (!constructor.isAccessible()) {
                final String error = "Constructor of class '" + messageClazz.getCanonicalName()
                        + "' is not accessible, changing the accessible flag to instantiate the class";
                LOG.info(error);
                constructor.setAccessible(true);
            }
            messageQ = constructor.newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException
                | NoSuchMethodException | IllegalArgumentException e) {
            final String error = "Cannot instantiate class '" + messageClazz.getCanonicalName() + "'";
            LOG.warn(error, e);
            throw new FactoryException(error, e);
        }

        messageQ.init(properties);

        return messageQ;
    }

    /**
     * Return a singleton, fully initialized instance of a {@link MessageQ} class to use for JAAS event messageing.
     *

     * Retrieving a singleton by this method will cause the factory to keep state, and store a reference to the
     * singleton for later use. You may reset the factory state using the {@code reset()} method to retrieve a new
     * / different singleton the next time this method is called..
     *

     * Note that any properties of the singleton (e.g. configuration) cannot necessarily be changed easily. You may call
     * the singleton's {@code init()} method, but depending on the implementation provided by the respective class, this
     * may or may not have the expected effect.
     *

     * If you need tight control over the singleton, including its lifecycle and configuration, or you require more than
     * one singleton that are different in their internal state (e.g. with different configurations), then you should
     * create such objects with the {@code getInstance()} method and maintain their state as "singletons" in your
     * application's business logic.
     *

     * Classes implementing the {@link MessageQ} interface must be thread safe.
     *
     * @param className  The name of a class that implements the Message interface
     * @param properties The properties to initialize the instance with
     * @return An instance of a class implementing the {@link MessageQ} interface
     * @throws FactoryException         When the class cannot be instantiated
     * @throws NullPointerException     When the {@code className} or {@code properties} are {@code null}
     * @throws IllegalArgumentException When {@code className} is empty
     */
    @SuppressWarnings("PMD.NonThreadSafeSingleton")
    public static MessageQ getSingleton(final String className, final CommonProperties properties)
            throws FactoryException {

        Validate.notBlank(className, "The validated character sequence 'className' is null or empty");
        Validate.notNull(properties, "The validated object 'properties' is null");

        // The double-check idiom is safe and acceptable here (Bloch, 2nd ed. p 284)
        if (messageQInstance == null) {
            synchronized (MessageQFactory.class) {
                if (messageQInstance == null) {

                    messageQInstance = getInstance(className, properties);
                }
            }
        }

        return messageQInstance;
    }

    /**
     * Resets the internal state of the factory, which causes the
     * {@link MessageQFactory#getSingleton(String, CommonProperties)} method to return a new {@link MessageQ} instance
     * the next time it is called.
     */
    // CHECKSTYLE:OFF
    // this is flagged in checkstyle with a missing whitespace before '}', which is a bug in checkstyle
    @SuppressWarnings({"PMD.NonThreadSafeSingleton", "PMD.NullAssignment"})
    // CHECKSTYLE:ON
    public static void reset() {

        // Unset the instance singleton that has been created earlier
        // The double-check idiom is safe and acceptable here (Bloch, 2nd ed. p 284)
        // null-assignments for de-referencing objects are okay
        if (messageQInstance != null) {
            synchronized (MessageQFactory.class) {
                if (messageQInstance != null) {
                    messageQInstance = null;
                }
            }
        }
    }
}


/*
 * @(#)ScreenApplet.java	1.13 98/08/28
 * Copyright © 2012 jbundle.org. All rights reserved.
 */
package org.jbundle.jbackup.destination;

import java.awt.BorderLayout;
import java.util.Properties;

import javax.swing.JPanel;

import org.jbundle.jbackup.JBackupConstants;
import org.jbundle.util.apprunner.PropertyOwner;
import org.jbundle.util.apprunner.PropertyView;

/**
 * Main property view screen.
 * From this screen the user selects the model, view, and control.
 */
public class BaseDestinationPropertyView extends PropertyView
	implements JBackupConstants
{
	private static final long serialVersionUID = 1L;

	/*
	 * Constructor.
	 */
	public BaseDestinationPropertyView()
	{
		super();
	}
	/*
	 * Constructor.
	 */
	public BaseDestinationPropertyView(PropertyOwner propOwner,Properties properties)
	{
		this();
		this.init(propOwner, properties);
	}
	/*
	 * Initialize.
	 */
	public void init(PropertyOwner propOwner, Properties properties)
	{
		super.init(propOwner, properties);
	}
	/*
	 * Add your property controls to this panel.
	 * Remember to set your own layout manager.
	 * Also, remember to create a new JPanel, and pass it to the super class
	 * so controls of the superclass can be included.
	 * You have a 3 x 3 grid, so add three columns for each control
	 * @param panel This is the panel to add your controls to.
	 */
	public void addControlsToView(JPanel panel)
	{
		panel.setLayout(new BorderLayout());
		this.makeNewPanel(panel, BorderLayout.CENTER);

		JPanel panelSub = this.makeNewPanel(panel, BorderLayout.SOUTH);
		super.addControlsToView(panelSub);
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void controlsToProperties()
	{
		super.controlsToProperties();
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void propertiesToControls()
	{
		super.propertiesToControls();
	}
	/*
	 * Get the description of this option panel.
	 */
	public String getDescription()
	{
		return "Base source properties";
	}
}


/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: subchen@gmail.com
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.dao.jdbclog;

import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Base class for Wrapper to do logging
 */
public class JdbcLogSupport {
    protected static final Logger log = LoggerFactory.getLogger(JdbcLogSupport.class);
    protected static final Set<String> SET_METHODS = new HashSet<String>();
    protected static final Set<String> GET_METHODS = new HashSet<String>();
    protected static final Set<String> UPDATE_METHODS = new HashSet<String>();
    protected static final Set<String> MOVE_METHODS = new HashSet<String>();
    protected static final Set<String> EXECUTE_METHODS = new HashSet<String>();
    protected static final Set<String> RESULTSET_METHODS = new HashSet<String>();
    protected static final AtomicInteger idGenerated = new AtomicInteger(1000);

    protected final int id = idGenerated.getAndIncrement();
    protected final List<Object> paramNameList = new ArrayList<Object>();
    protected final List<Object> paramValueList = new ArrayList<Object>();
    protected final List<String> paramTypeList = new ArrayList<String>();

    static {
        SET_METHODS.add("setString");
        SET_METHODS.add("setInt");
        SET_METHODS.add("setLong");
        SET_METHODS.add("setShort");
        SET_METHODS.add("setByte");
        SET_METHODS.add("setFloat");
        SET_METHODS.add("setBoolean");
        SET_METHODS.add("setDouble");
        SET_METHODS.add("setDate");
        SET_METHODS.add("setTime");
        SET_METHODS.add("setTimestamp");
        SET_METHODS.add("setBytes");
        SET_METHODS.add("setBigDecimal");
        SET_METHODS.add("setAsciiStream");
        SET_METHODS.add("setUnicodeStream");
        SET_METHODS.add("setCharacterStream");
        SET_METHODS.add("setBinaryStream");
        SET_METHODS.add("setBlob");
        SET_METHODS.add("setClob");
        SET_METHODS.add("setArray");
        SET_METHODS.add("setUrl");
        SET_METHODS.add("setRef");
        SET_METHODS.add("setNString");
        SET_METHODS.add("setNClob");
        SET_METHODS.add("setNCharacterStream");
        SET_METHODS.add("setSQLXML");
        SET_METHODS.add("setNull");
        SET_METHODS.add("setObject");

        GET_METHODS.add("getString");
        GET_METHODS.add("getInt");
        GET_METHODS.add("getLong");
        GET_METHODS.add("getShort");
        GET_METHODS.add("getByte");
        GET_METHODS.add("getFloat");
        GET_METHODS.add("getBoolean");
        GET_METHODS.add("getDouble");
        GET_METHODS.add("getDate");
        GET_METHODS.add("getTime");
        GET_METHODS.add("getTimestamp");
        GET_METHODS.add("getBytes");
        GET_METHODS.add("getBigDecimal");
        GET_METHODS.add("getAsciiStream");
        GET_METHODS.add("getUnicodeStream");
        GET_METHODS.add("getCharacterStream");
        GET_METHODS.add("getBinaryStream");
        GET_METHODS.add("getBlob");
        GET_METHODS.add("getClob");
        GET_METHODS.add("getArray");
        GET_METHODS.add("getUrl");
        GET_METHODS.add("getRef");
        GET_METHODS.add("getNString");
        GET_METHODS.add("getNClob");
        GET_METHODS.add("getNCharacterStream");
        GET_METHODS.add("getSQLXML");
        GET_METHODS.add("getNull");
        GET_METHODS.add("getObject");

        UPDATE_METHODS.add("updateString");
        UPDATE_METHODS.add("updateInt");
        UPDATE_METHODS.add("updateLong");
        UPDATE_METHODS.add("updateShort");
        UPDATE_METHODS.add("updateByte");
        UPDATE_METHODS.add("updateFloat");
        UPDATE_METHODS.add("updateBoolean");
        UPDATE_METHODS.add("updateDouble");
        UPDATE_METHODS.add("updateDate");
        UPDATE_METHODS.add("updateTime");
        UPDATE_METHODS.add("updateTimestamp");
        UPDATE_METHODS.add("updateBytes");
        UPDATE_METHODS.add("updateBigDecimal");
        UPDATE_METHODS.add("updateAsciiStream");
        UPDATE_METHODS.add("updateUnicodeStream");
        UPDATE_METHODS.add("updateCharacterStream");
        UPDATE_METHODS.add("updateBinaryStream");
        UPDATE_METHODS.add("updateBlob");
        UPDATE_METHODS.add("updateClob");
        UPDATE_METHODS.add("updateArray");
        UPDATE_METHODS.add("updateUrl");
        UPDATE_METHODS.add("updateRef");
        UPDATE_METHODS.add("updateNString");
        UPDATE_METHODS.add("updateNClob");
        UPDATE_METHODS.add("updateNCharacterStream");
        UPDATE_METHODS.add("updateSQLXML");
        UPDATE_METHODS.add("updateNull");
        UPDATE_METHODS.add("updateObject");

        MOVE_METHODS.add("next");
        MOVE_METHODS.add("previous");
        MOVE_METHODS.add("first");
        MOVE_METHODS.add("last");
        MOVE_METHODS.add("absolute");
        MOVE_METHODS.add("relative");
        MOVE_METHODS.add("afterLast");
        MOVE_METHODS.add("beforeFirst");
        MOVE_METHODS.add("moveToCurrentRow");
        MOVE_METHODS.add("moveToInsertRow");
        MOVE_METHODS.add("close");

        EXECUTE_METHODS.add("execute");
        EXECUTE_METHODS.add("executeUpdate");
        EXECUTE_METHODS.add("executeQuery");
        EXECUTE_METHODS.add("addBatch");

        RESULTSET_METHODS.add("executeQuery");
        RESULTSET_METHODS.add("getResultSet");
    }

    public JdbcLogSupport() {
        log.debug("#{} {}.Create()", id, getClass().getSimpleName());
    }

    protected void addParam(Object param, Object value) {
        paramNameList.add(param);
        paramValueList.add(value);
        paramTypeList.add((value == null) ? "null" : value.getClass().getName());
    }

    protected boolean isParamNotEmpty() {
        return !paramNameList.isEmpty();
    }

    protected String getParamNameList() {
        return paramNameList.toString();
    }

    protected String getParamValueList() {
        return paramValueList.toString();
    }

    protected String getParamTypeList() {
        return paramTypeList.toString();
    }

    protected void resetParamsInfo() {
        paramNameList.clear();
        paramValueList.clear();
        paramTypeList.clear();
    }

    protected String formatSql(String original) {
        return original.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ');
    }

    protected String toString(Method method, Object[] params) {
        StringBuilder sb = new StringBuilder(32);
        sb.append(method.getDeclaringClass().getSimpleName());
        sb.append('.').append(method.getName());
        sb.append('(');
        for (int i = 0; i < params.length; i++) {
            if (i > 0) {
                sb.append(',');
            }
            sb.append(String.valueOf(params[i]));
        }
        sb.append(')');
        return sb.toString();
    }

    /**
     * Examines a Throwable object and gets it's root cause
     *
     * @param t - the exception to examine
     * @return The root cause
     */
    protected Throwable unwrapThrowable(Throwable t) {
        Throwable e = t;
        while (true) {
            if (e instanceof InvocationTargetException) {
                e = ((InvocationTargetException) t).getTargetException();
            } else if (t instanceof UndeclaredThrowableException) {
                e = ((UndeclaredThrowableException) t).getUndeclaredThrowable();
            } else {
                return e;
            }
        }
    }

}


/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: subchen@gmail.com
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.io.buffer;

/**
 * Fast, fast byte buffer.
 * This buffer implementation does not store all data
 * in single array, but in array of chunks.
 */
public class FastByteBuffer {
    private byte[][] buffers = new byte[16][];
    private int buffersCount;
    private int currentBufferIndex = -1;
    private byte[] currentBuffer;
    private int offset;
    private int size;
    private final int minChunkLen;

    /**
     * Creates a new byte buffer. The buffer capacity is
     * initially 1024 bytes, though its size increases if necessary.
     */
    public FastByteBuffer() {
        this.minChunkLen = 1024;
    }

    /**
     * Creates a new byte buffer, with a buffer capacity of
     * the specified size, in bytes.
     *
     * @param size the initial size.
     * @throws IllegalArgumentException if size is negative.
     */
    public FastByteBuffer(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("Invalid size: " + size);
        }
        this.minChunkLen = size;
    }

    /**
     * Prepares next chunk to match new size.
     * The minimal length of new chunk is minChunkLen.
     */
    private void needNewBuffer(int newSize) {
        int delta = newSize - size;
        int newBufferSize = Math.max(minChunkLen, delta);

        currentBufferIndex++;
        currentBuffer = new byte[newBufferSize];
        offset = 0;

        // add buffer
        if (currentBufferIndex >= buffers.length) {
            int newLen = buffers.length << 1;
            byte[][] newBuffers = new byte[newLen][];
            System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
            buffers = newBuffers;
        }
        buffers[currentBufferIndex] = currentBuffer;
        buffersCount++;
    }

    /**
     * Appends byte array to buffer.
     */
    public FastByteBuffer append(byte[] array, int off, int len) {
        int end = off + len;
        if ((off < 0) || (len < 0) || (end > array.length)) {
            throw new IndexOutOfBoundsException();
        }
        if (len == 0) {
            return this;
        }
        int newSize = size + len;
        int remaining = len;

        if (currentBuffer != null) {
            // first try to fill current buffer
            int part = Math.min(remaining, currentBuffer.length - offset);
            System.arraycopy(array, end - remaining, currentBuffer, offset, part);
            remaining -= part;
            offset += part;
            size += part;
        }

        if (remaining > 0) {
            // still some data left
            // ask for new buffer
            needNewBuffer(newSize);

            // then copy remaining
            // but this time we are sure that it will fit
            int part = Math.min(remaining, currentBuffer.length - offset);
            System.arraycopy(array, end - remaining, currentBuffer, offset, part);
            offset += part;
            size += part;
        }

        return this;
    }

    /**
     * Appends byte array to buffer.
     */
    public FastByteBuffer append(byte[] array) {
        return append(array, 0, array.length);
    }

    /**
     * Appends single byte to buffer.
     */
    public FastByteBuffer append(byte element) {
        if ((currentBuffer == null) || (offset == currentBuffer.length)) {
            needNewBuffer(size + 1);
        }

        currentBuffer[offset] = element;
        offset++;
        size++;

        return this;
    }

    /**
     * Appends another fast buffer to this one.
     */
    public FastByteBuffer append(FastByteBuffer buff) {
        if (buff.size == 0) {
            return this;
        }
        for (int i = 0; i < buff.currentBufferIndex; i++) {
            append(buff.buffers[i]);
        }
        append(buff.currentBuffer, 0, buff.offset);
        return this;
    }

    /**
     * Returns buffer size.
     */
    public int size() {
        return size;
    }

    /**
     * Tests if this buffer has no elements.
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Returns current index of inner byte array chunk.
     * Represents the index of last used inner array chunk.
     */
    public int index() {
        return currentBufferIndex;
    }

    /**
     * Returns the offset of last used element in current inner array chunk.
     */
    public int offset() {
        return offset;
    }

    /**
     * Returns byte inner array chunk at given index.
     * May be used for iterating inner chunks in fast manner.
     */
    public byte[] array(int index) {
        return buffers[index];
    }

    /**
     * Resets the buffer content.
     */
    public void clear() {
        size = 0;
        offset = 0;
        currentBufferIndex = -1;
        currentBuffer = null;
        buffersCount = 0;
    }

    /**
     * Creates byte array from buffered content.
     */
    public byte[] toArray() {
        int pos = 0;
        byte[] array = new byte[size];

        if (currentBufferIndex == -1) {
            return array;
        }

        for (int i = 0; i < currentBufferIndex; i++) {
            int len = buffers[i].length;
            System.arraycopy(buffers[i], 0, array, pos, len);
            pos += len;
        }

        System.arraycopy(buffers[currentBufferIndex], 0, array, pos, offset);

        return array;
    }

    /**
     * Creates byte subarray from buffered content.
     */
    public byte[] toArray(int start, int len) {
        int remaining = len;
        int pos = 0;
        byte[] array = new byte[len];

        if (len == 0) {
            return array;
        }

        int i = 0;
        while (start >= buffers[i].length) {
            start -= buffers[i].length;
            i++;
        }

        while (i < buffersCount) {
            byte[] buf = buffers[i];
            int c = Math.min(buf.length - start, remaining);
            System.arraycopy(buf, start, array, pos, c);
            pos += c;
            remaining -= c;
            if (remaining == 0) {
                break;
            }
            start = 0;
            i++;
        }
        return array;
    }

    /**
     * Returns byte element at given index.
     */
    public byte get(int index) {
        if ((index >= size) || (index < 0)) {
            throw new IndexOutOfBoundsException();
        }
        int ndx = 0;
        while (true) {
            byte[] b = buffers[ndx];
            if (index < b.length) {
                return b[index];
            }
            ndx++;
            index -= b.length;
        }
    }
}


package org.wymiwyg.commons.util;
import java.io.IOException;

public class MD5 {
	int buf[];	// These were originally unsigned ints.
				// This Java code makes an effort to avoid sign traps.
				// buf[] is where the hash accumulates.
	long bits;	// This is the count of bits hashed so far.
	byte in[];	// This is a buffer where we stash bytes until we have
				// enough (64) to perform a transform operation.
	int inint[];
				// inint[] used and discarded inside transform(),
				// but why allocate it over and over?
				// (In the C version this is allocated on the stack.)

	public MD5() {
		buf = new int[4];
		// fill the hash accumulator with a seed value
		buf[0] = 0x67452301;
		buf[1] = 0xefcdab89;
		buf[2] = 0x98badcfe;
		buf[3] = 0x10325476;

		// initially, we've hashed zero bits
		bits = 0L;

		in = new byte[64];
		inint = new int[16];
	}

	public void update(byte[] newbuf) {
		update(newbuf, 0, newbuf.length);
	}

	public void update(byte[] newbuf, int length) {
		update(newbuf, 0, length);
	}

	public void update(byte[] newbuf, int bufstart, int buflen) {
		int t;
		int len = buflen;

		// shash old bits value for the "Bytes already in" computation
		// just below.
		t = (int) bits;	// (int) cast should just drop high bits, I hope

		/* update bitcount */
		/* the C code used two 32-bit ints separately, and carefully
		 * ensured that the carry carried.
		 * Java has a 64-bit long, which is just what the code really wants.
		 */
		bits += (long)(len<<3);

		t = (t >>> 3) & 0x3f;	/* Bytes already in this->in */

		/* Handle any leading odd-sized chunks */
		/* (that is, any left-over chunk left by last update() */

		if (t!=0) {
			int p = t;
			t = 64 - t;
			if (len < t) {
				System.arraycopy(newbuf, bufstart, in, p, len);
				return;
			}
			System.arraycopy(newbuf, bufstart, in, p, t);
			transform();
			bufstart += t;
			len -= t;
		}

		/* Process data in 64-byte chunks */
		while (len >= 64) {
			System.arraycopy(newbuf, bufstart, in, 0, 64);
			transform();
			bufstart += 64;
			len -= 64;
		}

		/* Handle any remaining bytes of data. */
		/* that is, stash them for the next update(). */
		System.arraycopy(newbuf, bufstart, in, 0, len);
	}

	/*
	 * Final wrapup - pad to 64-byte boundary with the bit pattern
	 * 1 0* (64-bit count of bits processed, MSB-first)
	 */
	public void md5final(byte[] digest) {
		/* "final" is a poor method name in Java. :v) */
		int count;
		int p;		// in original code, this is a pointer; in this java code
					// it's an index into the array this->in.

	    /* Compute number of bytes mod 64 */
	    count = (int) ((bits >>> 3) & 0x3F);

	    /* Set the first char of padding to 0x80.  This is safe since there is
	       always at least one byte free */
		p = count;
		in[p++] = (byte) 0x80;

	    /* Bytes of padding needed to make 64 bytes */
	    count = 64 - 1 - count;

	    /* Pad out to 56 mod 64 */
	    if (count < 8) {
			/* Two lots of padding:  Pad the first block to 64 bytes */
			zeroByteArray(in, p, count);
			transform();

			/* Now fill the next block with 56 bytes */
			zeroByteArray(in, 0, 56);
	    } else {
			/* Pad block to 56 bytes */
			zeroByteArray(in, p, count - 8);
	    }

	    /* Append length in bits and transform */
		// Could use a PUT_64BIT... func here. This is a fairly
		// direct translation from the C code, where bits was an array
		// of two 32-bit ints.
		int lowbits =	(int) bits;
		int highbits =	(int) (bits >>> 32);
	    PUT_32BIT_LSB_FIRST(in, 56, lowbits);
	    PUT_32BIT_LSB_FIRST(in, 60, highbits);

		transform();
	    PUT_32BIT_LSB_FIRST(digest,  0, buf[0]);
	    PUT_32BIT_LSB_FIRST(digest,  4, buf[1]);
	    PUT_32BIT_LSB_FIRST(digest,  8, buf[2]);
	    PUT_32BIT_LSB_FIRST(digest, 12, buf[3]);

		/* zero sensitive data */
		/* notice this misses any sneaking out on the stack. The C
		 * version uses registers in some spots, perhaps because
		 * they care about this.
		 */
		zeroByteArray(in);
		zeroIntArray(buf);
		bits = 0;
		zeroIntArray(inint);
	}

	public static void main(String args[]) {
		// This main() method was created to easily test
		// this class. It hashes whatever's on System.in.

		byte buf[] = new byte[397];
			// arbitrary buffer length designed to irritate update()
		int rc;
		MD5 md = new MD5();
		byte out[] = new byte[16];
		int i;
		int len = 0;

		try {
			while ((rc = System.in.read(buf, 0, 397)) > 0) {
				md.update(buf, rc);
				len += rc;
			}
		} catch (IOException ex) {
			ex.printStackTrace();
			return;
		}
		md.md5final(out);

		System.out.println("file length: "+len);
		System.out.println("hash: "+dumpBytes(out));
	}

	/////////////////////////////////////////////////////////////////////
	// Below here ye will only finde private functions                 //
	/////////////////////////////////////////////////////////////////////

	// There must be a way to do these functions that's
	// built into Java, and I just haven't noticed it yet.

	private void zeroByteArray(byte[] a) {
		zeroByteArray(a, 0, a.length);
	}

	private void zeroByteArray(byte[] a, int start, int length) {
		setByteArray(a, (byte) 0, start, length);
	}

	private void setByteArray(byte[] a, byte val, int start, int length) {
		int i;
		int end = start+length;
		for (i=start; i<end; i++) {
			a[i] = val;
		}
	}

	private void zeroIntArray(int[] a) {
		zeroIntArray(a, 0, a.length);
	}

	private void zeroIntArray(int[] a, int start, int length) {
		setIntArray(a, (int) 0, start, length);
	}

	private void setIntArray(int[] a, int val, int start, int length) {
		int i;
		int end = start+length;
		for (i=start; i<end; i++) {
			a[i] = val;
		}
	}

	// In the C version, a call to MD5STEP is a macro-in-a-macro.
	// In this Java version, we pass an Fcore object to represent the
	// inner macro, and the MD5STEP() method performs the work of
	// the outer macro. It would be good if this could all get
	// inlined, but it would take a pretty aggressive compiler to
	// inline away the dynamic method lookup made by MD5STEP to
	// get to the Fcore.f function.

	private abstract class Fcore {
		abstract int f(int x, int y, int z);
	}
	private Fcore F1 = new Fcore() {
		int f(int x, int y, int z) { return (z ^ (x & (y ^ z))); }};
	private Fcore F2 = new Fcore() {
		int f(int x, int y, int z) { return (y ^ (z & (x ^ y))); }};
	private Fcore F3 = new Fcore() {
		int f(int x, int y, int z) { return (x ^ y ^ z); }};
	private Fcore F4 = new Fcore() {
		int f(int x, int y, int z) { return (y ^ (x | ~z)); }};

	private int MD5STEP(Fcore f, int w, int x, int y, int z, int data, int s) {
		w += f.f(x, y, z) + data;
		w = w<<s | w>>>(32-s);
		w += x;
		return w;
	}

	private void transform() {
		/* load in[] byte array into an internal int array */
		int i;
		int[] inint = new int[16];

		for (i=0; i<16; i++) {
			inint[i] = GET_32BIT_LSB_FIRST(in, 4*i);
		}

		int a, b, c, d;
		a = buf[0];
		b = buf[1];
		c = buf[2];
		d = buf[3];

	    a = MD5STEP(F1, a, b, c, d, inint[0]	+ 0xd76aa478, 7);
	    d = MD5STEP(F1, d, a, b, c, inint[1]	+ 0xe8c7b756, 12);
	    c = MD5STEP(F1, c, d, a, b, inint[2]	+ 0x242070db, 17);
	    b = MD5STEP(F1, b, c, d, a, inint[3]	+ 0xc1bdceee, 22);
	    a = MD5STEP(F1, a, b, c, d, inint[4]	+ 0xf57c0faf, 7);
	    d = MD5STEP(F1, d, a, b, c, inint[5]	+ 0x4787c62a, 12);
	    c = MD5STEP(F1, c, d, a, b, inint[6]	+ 0xa8304613, 17);
	    b = MD5STEP(F1, b, c, d, a, inint[7]	+ 0xfd469501, 22);
	    a = MD5STEP(F1, a, b, c, d, inint[8]	+ 0x698098d8, 7);
	    d = MD5STEP(F1, d, a, b, c, inint[9]	+ 0x8b44f7af, 12);
	    c = MD5STEP(F1, c, d, a, b, inint[10]	+ 0xffff5bb1, 17);
	    b = MD5STEP(F1, b, c, d, a, inint[11]	+ 0x895cd7be, 22);
	    a = MD5STEP(F1, a, b, c, d, inint[12]	+ 0x6b901122, 7);
	    d = MD5STEP(F1, d, a, b, c, inint[13]	+ 0xfd987193, 12);
	    c = MD5STEP(F1, c, d, a, b, inint[14]	+ 0xa679438e, 17);
	    b = MD5STEP(F1, b, c, d, a, inint[15]	+ 0x49b40821, 22);

	    a = MD5STEP(F2, a, b, c, d, inint[1]	+ 0xf61e2562, 5);
	    d = MD5STEP(F2, d, a, b, c, inint[6]	+ 0xc040b340, 9);
	    c = MD5STEP(F2, c, d, a, b, inint[11]	+ 0x265e5a51, 14);
	    b = MD5STEP(F2, b, c, d, a, inint[0]	+ 0xe9b6c7aa, 20);
	    a = MD5STEP(F2, a, b, c, d, inint[5]	+ 0xd62f105d, 5);
	    d = MD5STEP(F2, d, a, b, c, inint[10]	+ 0x02441453, 9);
	    c = MD5STEP(F2, c, d, a, b, inint[15]	+ 0xd8a1e681, 14);
	    b = MD5STEP(F2, b, c, d, a, inint[4]	+ 0xe7d3fbc8, 20);
	    a = MD5STEP(F2, a, b, c, d, inint[9]	+ 0x21e1cde6, 5);
	    d = MD5STEP(F2, d, a, b, c, inint[14]	+ 0xc33707d6, 9);
	    c = MD5STEP(F2, c, d, a, b, inint[3]	+ 0xf4d50d87, 14);
	    b = MD5STEP(F2, b, c, d, a, inint[8]	+ 0x455a14ed, 20);
	    a = MD5STEP(F2, a, b, c, d, inint[13]	+ 0xa9e3e905, 5);
	    d = MD5STEP(F2, d, a, b, c, inint[2]	+ 0xfcefa3f8, 9);
	    c = MD5STEP(F2, c, d, a, b, inint[7]	+ 0x676f02d9, 14);
	    b = MD5STEP(F2, b, c, d, a, inint[12]	+ 0x8d2a4c8a, 20);

	    a = MD5STEP(F3, a, b, c, d, inint[5]	+ 0xfffa3942, 4);
	    d = MD5STEP(F3, d, a, b, c, inint[8]	+ 0x8771f681, 11);
	    c = MD5STEP(F3, c, d, a, b, inint[11]	+ 0x6d9d6122, 16);
	    b = MD5STEP(F3, b, c, d, a, inint[14]	+ 0xfde5380c, 23);
	    a = MD5STEP(F3, a, b, c, d, inint[1]	+ 0xa4beea44, 4);
	    d = MD5STEP(F3, d, a, b, c, inint[4]	+ 0x4bdecfa9, 11);
	    c = MD5STEP(F3, c, d, a, b, inint[7]	+ 0xf6bb4b60, 16);
	    b = MD5STEP(F3, b, c, d, a, inint[10]	+ 0xbebfbc70, 23);
	    a = MD5STEP(F3, a, b, c, d, inint[13]	+ 0x289b7ec6, 4);
	    d = MD5STEP(F3, d, a, b, c, inint[0]	+ 0xeaa127fa, 11);
	    c = MD5STEP(F3, c, d, a, b, inint[3]	+ 0xd4ef3085, 16);
	    b = MD5STEP(F3, b, c, d, a, inint[6]	+ 0x04881d05, 23);
	    a = MD5STEP(F3, a, b, c, d, inint[9]	+ 0xd9d4d039, 4);
	    d = MD5STEP(F3, d, a, b, c, inint[12]	+ 0xe6db99e5, 11);
	    c = MD5STEP(F3, c, d, a, b, inint[15]	+ 0x1fa27cf8, 16);
	    b = MD5STEP(F3, b, c, d, a, inint[2]	+ 0xc4ac5665, 23);

	    a = MD5STEP(F4, a, b, c, d, inint[0]	+ 0xf4292244, 6);
	    d = MD5STEP(F4, d, a, b, c, inint[7]	+ 0x432aff97, 10);
	    c = MD5STEP(F4, c, d, a, b, inint[14]	+ 0xab9423a7, 15);
	    b = MD5STEP(F4, b, c, d, a, inint[5]	+ 0xfc93a039, 21);
	    a = MD5STEP(F4, a, b, c, d, inint[12]	+ 0x655b59c3, 6);
	    d = MD5STEP(F4, d, a, b, c, inint[3]	+ 0x8f0ccc92, 10);
	    c = MD5STEP(F4, c, d, a, b, inint[10]	+ 0xffeff47d, 15);
	    b = MD5STEP(F4, b, c, d, a, inint[1]	+ 0x85845dd1, 21);
	    a = MD5STEP(F4, a, b, c, d, inint[8]	+ 0x6fa87e4f, 6);
	    d = MD5STEP(F4, d, a, b, c, inint[15]	+ 0xfe2ce6e0, 10);
	    c = MD5STEP(F4, c, d, a, b, inint[6]	+ 0xa3014314, 15);
	    b = MD5STEP(F4, b, c, d, a, inint[13]	+ 0x4e0811a1, 21);
	    a = MD5STEP(F4, a, b, c, d, inint[4]	+ 0xf7537e82, 6);
	    d = MD5STEP(F4, d, a, b, c, inint[11]	+ 0xbd3af235, 10);
	    c = MD5STEP(F4, c, d, a, b, inint[2]	+ 0x2ad7d2bb, 15);
	    b = MD5STEP(F4, b, c, d, a, inint[9]	+ 0xeb86d391, 21);

	    buf[0] += a;
	    buf[1] += b;
	    buf[2] += c;
	    buf[3] += d;
	}

	private int GET_32BIT_LSB_FIRST(byte[] b, int off) {
		return
			((int)(b[off+0]&0xff)) |
			((int)(b[off+1]&0xff) << 8) |
			((int)(b[off+2]&0xff) << 16) |
			((int)(b[off+3]&0xff) << 24);
	}

	private void PUT_32BIT_LSB_FIRST(byte[] b, int off, int value) {
		b[off+0] = (byte) (value 		& 0xff);
		b[off+1] = (byte) ((value >> 8)	& 0xff);
		b[off+2] = (byte) ((value >> 16)& 0xff);
		b[off+3] = (byte) ((value >> 24)& 0xff);
	}

	// These are debug routines I was using while trying to
	// get this code to generate the same hashes as the C version.
	// (IIRC, all the errors were due to the absence of unsigned
	// ints in Java.)
	/*
	private void debugStatus(String m) {
		System.out.println(m+":");
		System.out.println("in: "+dumpBytes(in));
		System.out.println("bits: "+bits);
		System.out.println("buf: "
			+Integer.toHexString(buf[0])+" "
			+Integer.toHexString(buf[1])+" "
			+Integer.toHexString(buf[2])+" "
			+Integer.toHexString(buf[3]));
	}
	*/

	public static String dumpBytes(byte[] bytes) {
		int i;
		StringBuffer sb = new StringBuffer();
		for (i=0; i<bytes.length; i++) {
			if (i%32 == 0 && i!=0) {
				sb.append("\n");
			}
			String s = Integer.toHexString(bytes[i]);
			if (s.length() < 2) {
				s = "0"+s;
			}
			if (s.length() > 2) {
				s = s.substring(s.length()-2);
			}
			sb.append(s);
		}
		return sb.toString();
	}
}


/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: subchen@gmail.com
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.web.mvc.multipart;

import java.io.*;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import jetbrick.io.FilenameUtils;
import jetbrick.io.IoUtils;
import jetbrick.lang.RandomStringUtils;
import jetbrick.lang.StringUtils;
import jetbrick.web.mvc.config.WebConfig;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

public final class FileUploaderUtils {

    public static boolean supported(HttpServletRequest request) {
        return isMultipartContent(request) || isHtml5FileUploadContent(request);
    }

    private static boolean isHtml5FileUploadContent(HttpServletRequest request) {
        String contentDisposition = request.getHeader("content-disposition");
        return contentDisposition != null;
    }

    private static boolean isMultipartContent(HttpServletRequest request) {
        String contextType = request.getHeader("Content-Type");
        return (contextType != null) && (contextType.startsWith("multipart/form-data"));
    }

    public static HttpServletRequest asRequest(HttpServletRequest request) {
        try {
            if (isMultipartContent(request)) {
                return asMultipartRequest(request);
            } else if (isHtml5FileUploadContent(request)) {
                return asHtml5Request(request);
            }
            return request;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // multipart/form-data
    private static MultipartRequest asMultipartRequest(HttpServletRequest request) throws Exception {
        String encoding = request.getCharacterEncoding();

        MultipartRequest req = new MultipartRequest(request);
        ServletFileUpload upload = new ServletFileUpload();
        upload.setHeaderEncoding(encoding);
        FileItemIterator it = upload.getItemIterator(request);

        while (it.hasNext()) {
            FileItemStream item = it.next();
            String fieldName = item.getFieldName();
            InputStream stream = item.openStream();
            try {
                if (item.isFormField()) {
                    req.setParameter(fieldName, Streams.asString(stream, encoding));
                } else {
                    String originalFilename = item.getName();
                    File diskFile = getTempFile(originalFilename);
                    OutputStream fos = new FileOutputStream(diskFile);

                    try {
                        IoUtils.copy(stream, fos);
                    } finally {
                        IoUtils.closeQuietly(fos);
                    }

                    FilePart filePart = new FilePart(fieldName, originalFilename, diskFile);
                    req.addFile(filePart);
                }
            } finally {
                IoUtils.closeQuietly(stream);
            }
        }

        return req;
    }

    // application/octet-stream
    private static MultipartRequest asHtml5Request(HttpServletRequest request) throws Exception {
        String originalFilename = request.getHeader("content-disposition");
        if (originalFilename == null) {
            throw new ServletException("The request is not a html5 file upload request.");
        }
        originalFilename = new String(originalFilename.getBytes("iso8859-1"), request.getCharacterEncoding());
        originalFilename = StringUtils.substringAfter(originalFilename, "; filename=");
        originalFilename = StringUtils.remove(originalFilename, "\"");
        originalFilename = URLDecoder.decode(originalFilename, "utf-8");

        File diskFile = getTempFile(originalFilename);

        InputStream fis = request.getInputStream();
        OutputStream fos = new FileOutputStream(diskFile);
        try {
            IoUtils.copy(fis, fos);
        } finally {
            IoUtils.closeQuietly(fis);
            IoUtils.closeQuietly(fos);
        }

        MultipartRequest req = new MultipartRequest(request);
        FilePart filePart = new FilePart("file", originalFilename, diskFile);
        req.addFile(filePart);
        return req;
    }

    private static File getTempFile(String originalFilename) {
        String fileExt = FilenameUtils.getFileExtension(originalFilename);
        String fileName = RandomStringUtils.randomAlphanumeric(16);
        if (StringUtils.isNotEmpty(fileExt)) {
            fileName = fileName + "." + fileExt;
        }

        File uploaddir = WebConfig.getInstance().getUploaddir();
        return new File(uploaddir, fileName);
    }
}


/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: subchen@gmail.com
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.ioc;

import java.lang.reflect.Modifier;
import java.util.*;
import jetbrick.io.config.Configuration;
import jetbrick.ioc.loaders.IocConfiguration;
import jetbrick.ioc.loaders.IocLoader;
import jetbrick.ioc.objects.*;
import jetbrick.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class MutableIoc implements Ioc {
    private final Logger log = LoggerFactory.getLogger(Ioc.class);
    private final Map<String, IocObject> pool = new HashMap<String, IocObject>();
    private final IocConfiguration config = new IocConfiguration(this);

    public void load(IocLoader loader) {
        loader.load(this);
    }

    public void addConfig(String name, String value) {
        config.put(name, value);
    }

    // 添加用户自定义的对象
    public void addBean(Object beanObject) {
        Validate.notNull(beanObject);
        addBean(beanObject.getClass().getName(), beanObject);
    }

    // 添加用户自定义的对象
    public void addBean(Class<?> beanClass, Object beanObject) {
        Validate.notNull(beanClass);
        addBean(beanClass.getName(), beanObject);
    }

    // 添加用户自定义的对象
    public void addBean(String name, Object beanObject) {
        Validate.notNull(beanObject);
        addBean(name, new ValueObject(beanObject));
    }

    // 添加用户自定义的对象
    public void addBean(String name, IocObject object) {
        Validate.notNull(name);
        Validate.notNull(object);

        log.debug("addBean: {}", name);

        if (pool.put(name, object) != null) {
            log.warn("Duplicated Bean: {}", name);
        }
    }

    // 注册 @IocBean 标注的对象
    public void addBean(Class<?> beanClass) {
        addBean(beanClass, null, true);
    }

    // 注册 @IocBean 标注的对象
    public void addBean(Class<?> beanClass, Configuration properties, boolean singleton) {
        Validate.notNull(beanClass);
        addBean(beanClass.getName(), beanClass, properties, singleton);
    }

    // 注册 @IocBean 标注的对象
    public void addBean(String name, Class<?> beanClass, Configuration properties, boolean singleton) {
        Validate.notNull(name);
        Validate.notNull(beanClass);
        Validate.isFalse(beanClass.isInterface(), "Must not be interface: %s", beanClass.getName());
        Validate.isFalse(Modifier.isAbstract(beanClass.getModifiers()), "Must not be abstract class: %s", beanClass.getName());

        log.debug("addBean: {}", name, beanClass.getName());

        IocObject iocObject = doGetIocObject(beanClass, properties, singleton);
        if (pool.put(name, iocObject) != null) {
            log.warn("Duplicated Bean: {}", name);
        }
    }

    private IocObject doGetIocObject(Class<?> beanClass, Configuration properties, boolean singleton) {
        if (IocFactory.class.isAssignableFrom(beanClass)) {
            if (singleton) {
                return new FactorySingletonObject(this, beanClass, properties);
            } else {
                return new FactoryInstanceObject(this, beanClass, properties);
            }
        } else {
            if (singleton) {
                return new ClassSingletonObject(this, beanClass, properties);
            } else {
                return new ClassInstanceObject(this, beanClass, properties);
            }
        }
    }

    // 获取一个 Bean
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> beanClass) {
        Validate.notNull(beanClass);
        return (T) getBean(beanClass.getName());
    }

    // 获取一个 Bean
    @Override
    public Object getBean(String name) {
        IocObject iocObject = pool.get(name);
        if (iocObject == null) {
            return null;
        }
        return iocObject.getObject();
    }

    @Override
    public <T> T getConfig(String name, Class<T> type) {
        return config.getValue(name, type);
    }

    @Override
    public <T> T getConfig(String name, Class<T> type, T defaultValue) {
        return config.getValue(name, type, defaultValue);
    }

    @Override
    public <T> T getConfig(String name, Class<T> type, String defaultValue) {
        return config.getValue(name, type, defaultValue);
    }

    @Override
    public Object getConfigAsArray(String name, Class<?> elementType) {
        return config.getValueArray(name, elementType);
    }

    @Override
    public <T> List<T> getConfigAsList(String name, Class<T> elementType) {
        return config.getValueList(name, elementType);
    }

    @Override
    public <T> T injectClass(Class<T> beanClass) {
        return injectClass(beanClass, null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T injectClass(Class<T> beanClass, Configuration properties) {
        Validate.notNull(beanClass);

        IocObject iocObject = doGetIocObject(beanClass, properties, true);
        return (T) iocObject.getObject();
    }

    @Override
    public <T> T injectInstance(T beanObject) {
        return injectInstance(beanObject, null);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T injectInstance(T beanObject, Configuration properties) {
        Validate.notNull(beanObject);

        IocObject iocObject = new UninitialedObject(this, beanObject, properties);
        return (T) iocObject.getObject();
    }
}


/*
 * 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 org.hobsoft.microbrowser.jsoup;

import org.hobsoft.microbrowser.spi.AbstractMicrodataProperty;
import org.jsoup.nodes.Element;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * {@code MicrodataItemValue} adapter to a jsoup {@code Element}.
 */
class JsoupMicrodataProperty extends AbstractMicrodataProperty
{
	// ----------------------------------------------------------------------------------------------------------------
	// fields
	// ----------------------------------------------------------------------------------------------------------------

	private final Element element;

	// ----------------------------------------------------------------------------------------------------------------
	// constructors
	// ----------------------------------------------------------------------------------------------------------------

	JsoupMicrodataProperty(Element element)
	{
		this.element = checkNotNull(element, "element");
	}

	// ----------------------------------------------------------------------------------------------------------------
	// Unwrappable methods
	// ----------------------------------------------------------------------------------------------------------------

	public <T> T unwrap(Class<T> type)
	{
		checkArgument(Element.class.equals(type), "Cannot unwrap to: %s", type);

		return type.cast(element);
	}

	// ----------------------------------------------------------------------------------------------------------------
	// AbstractMicrodataProperty methods
	// ----------------------------------------------------------------------------------------------------------------

	@Override
	protected String getElementName()
	{
		return element.nodeName();
	}

	@Override
	protected String getAttribute(String name, boolean absoluteUrl)
	{
		return absoluteUrl ? element.absUrl(name) : element.attr(name);
	}

	@Override
	protected String getText()
	{
		return element.text();
	}
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * 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.thesett.aima.logic.fol.wam.debugger;

import java.util.concurrent.TimeUnit;

import com.thesett.aima.logic.fol.wam.debugger.controller.TopLevelStandaloneController;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ComponentFactoryBuilder;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ControllerLifecycle;

/**
 * Implements the main method for the debugger stand-alone application.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Attach the UI controller to the lifecycle for the application.
 *      {@link StartStopLifecycleBase}, {@link TopLevelStandaloneController}

 *

 *
 * @author Rupert Smith
 */
public class Main extends StartStopLifecycleBase
{
    /** The top-level UI controller for the application. */
    ControllerLifecycle controller =
        new TopLevelStandaloneController(ComponentFactoryBuilder.createComponentFactory(
                ComponentFactoryBuilder.SWING_FACTORY));

    /**
     * Launches the debugger as a stand-alone Swing application.
     *
     * @param args Command line parameters.
     */
    public static void main(String[] args)
    {
        try
        {
            Main main = new Main();

            main.start();

            Runtime.getRuntime().addShutdownHook(main.getShutdownHook());

            main.awaitTermination(1, TimeUnit.DAYS);
        }
        catch (InterruptedException e)
        {
            e = null;
            Thread.currentThread().interrupt();
        }
    }

    /**
     * {@inheritDoc}
     *
     *
Starts the UI.
     */
    public void start()
    {
        controller.open();
        running();
    }

    /**
     * {@inheritDoc}
     *
     *
Closes the UI.
     */
    public void shutdown()
    {
        controller.close();
        terminated();
    }
}