/*
 * #%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.audit;

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 Audit} interface.
 */
public final class AuditFactory {

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

    /**
     * The singleton instance of the audit logger
     */
    private static volatile Audit auditInstance;

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

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

     * Classes implementing the {@link Audit} interface must be thread safe.
     *
     * @param className  The name of a class that implements the Audit interface
     * @param properties The properties to initialize the instance with
     * @return An instance of a class implementing the {@link Audit} 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 Audit 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 Audit> auditClazz;
        try {
            auditClazz = Class.forName(className).asSubclass(Audit.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 '" + Audit.class.getCanonicalName() + "'";
            LOG.warn(error);
            throw new FactoryException(error, e);
        }

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

        audit.init(properties);

        return audit;
    }

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

     * 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 Audit} interface must be thread safe.
     *
     * @param className  The name of a class that implements the Audit interface
     * @param properties The properties to initialize the instance with
     * @return An instance of a class implementing the {@link Audit} 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 Audit 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 (auditInstance == null) {
            synchronized (AuditFactory.class) {
                if (auditInstance == null) {

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

        return auditInstance;
    }

    /**
     * Resets the internal state of the factory, which causes the
     * {@link AuditFactory#getSingleton(String, CommonProperties)} method to return a new {@link Audit} 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 (auditInstance != null) {
            synchronized (AuditFactory.class) {
                if (auditInstance != null) {
                    auditInstance = null;
                }
            }
        }
    }
}


/*
 * @(#)DeclarationScanner.java	1.5 04/04/20
 *
 * Copyright (c) 2004, Sun Microsystems, Inc.
 * 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 Sun Microsystems, Inc. nor the names of
 *       its 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 OWNER
 * OR CONTRIBUTORS 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.
 */

package com.sun.mirror.util;

import com.sun.mirror.declaration.*;

/**
 * A visitor for declarations that scans declarations contained within
 * the given declaration.  For example, when visiting a class, the
 * methods, fields, constructors, and nested types of the class are
 * also visited.
 * <p/>
 * <p> To control the processing done on a declaration, users of this
 * class pass in their own visitors for pre and post processing.  The
 * preprocessing visitor is called before the contained declarations
 * are scanned; the postprocessing visitor is called after the
 * contained declarations are scanned.
 *
 * @author Joseph D. Darcy
 * @author Scott Seligman
 * @version 1.5 04/04/20
 * @since 1.5
 */

class DeclarationScanner implements DeclarationVisitor {
	protected DeclarationVisitor pre;
	protected DeclarationVisitor post;

	DeclarationScanner(DeclarationVisitor pre, DeclarationVisitor post) {
		this.pre = pre;
		this.post = post;
	}

	/**
	 * Visits a declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitDeclaration(Declaration d) {
		d.accept(pre);
		d.accept(post);
	}

	/**
	 * Visits a package declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitPackageDeclaration(PackageDeclaration d) {
		d.accept(pre);

		for (ClassDeclaration classDecl : d.getClasses()) {
			classDecl.accept(this);
		}

		for (InterfaceDeclaration interfaceDecl : d.getInterfaces()) {
			interfaceDecl.accept(this);
		}

		d.accept(post);
	}

	/**
	 * Visits a member or constructor declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitMemberDeclaration(MemberDeclaration d) {
		visitDeclaration(d);
	}

	/**
	 * Visits a type declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitTypeDeclaration(TypeDeclaration d) {
		d.accept(pre);

		for (TypeParameterDeclaration tpDecl : d.getFormalTypeParameters()) {
			tpDecl.accept(this);
		}

		for (FieldDeclaration fieldDecl : d.getFields()) {
			fieldDecl.accept(this);
		}

		for (MethodDeclaration methodDecl : d.getMethods()) {
			methodDecl.accept(this);
		}

		for (TypeDeclaration typeDecl : d.getNestedTypes()) {
			typeDecl.accept(this);
		}

		d.accept(post);
	}

	/**
	 * Visits a class declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitClassDeclaration(ClassDeclaration d) {
		d.accept(pre);

		for (TypeParameterDeclaration tpDecl : d.getFormalTypeParameters()) {
			tpDecl.accept(this);
		}

		for (FieldDeclaration fieldDecl : d.getFields()) {
			fieldDecl.accept(this);
		}

		for (MethodDeclaration methodDecl : d.getMethods()) {
			methodDecl.accept(this);
		}

		for (TypeDeclaration typeDecl : d.getNestedTypes()) {
			typeDecl.accept(this);
		}

		for (ConstructorDeclaration ctorDecl : d.getConstructors()) {
			ctorDecl.accept(this);
		}

		d.accept(post);
	}

	/**
	 * Visits an enum declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitEnumDeclaration(EnumDeclaration d) {
		visitClassDeclaration(d);
	}

	/**
	 * Visits an interface declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitInterfaceDeclaration(InterfaceDeclaration d) {
		visitTypeDeclaration(d);
	}

	/**
	 * Visits an annotation type declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration d) {
		visitInterfaceDeclaration(d);
	}

	/**
	 * Visits a field declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitFieldDeclaration(FieldDeclaration d) {
		visitMemberDeclaration(d);
	}

	/**
	 * Visits an enum constant declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitEnumConstantDeclaration(EnumConstantDeclaration d) {
		visitFieldDeclaration(d);
	}

	/**
	 * Visits a method or constructor declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitExecutableDeclaration(ExecutableDeclaration d) {
		d.accept(pre);

		for (TypeParameterDeclaration tpDecl : d.getFormalTypeParameters()) {
			tpDecl.accept(this);
		}

		for (ParameterDeclaration pDecl : d.getParameters()) {
			pDecl.accept(this);
		}

		d.accept(post);
	}

	/**
	 * Visits a constructor declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitConstructorDeclaration(ConstructorDeclaration d) {
		visitExecutableDeclaration(d);
	}

	/**
	 * Visits a method declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitMethodDeclaration(MethodDeclaration d) {
		visitExecutableDeclaration(d);
	}

	/**
	 * Visits an annotation type element declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitAnnotationTypeElementDeclaration(
			AnnotationTypeElementDeclaration d) {
		visitMethodDeclaration(d);
	}

	/**
	 * Visits a parameter declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitParameterDeclaration(ParameterDeclaration d) {
		visitDeclaration(d);
	}

	/**
	 * Visits a type parameter declaration.
	 *
	 * @param d the declaration to visit
	 */
	public void visitTypeParameterDeclaration(TypeParameterDeclaration d) {
		visitDeclaration(d);
	}
}


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

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import org.jbundle.jbackup.destination.BaseDestination;
import org.jbundle.jbackup.source.BaseSource;
import org.jbundle.jbackup.util.Util;
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 MainPropertyView extends PropertyView
	implements ActionListener, JBackupConstants, ItemListener
{
	private static final long serialVersionUID = 1L;

	protected static final String[] m_rgstrSources = {
		"Filesystem",
		"Zip"};
	protected static final String[] m_rgstrDestinations = {
		"Filesystem",
		"Zip",
		"Ftp",
		"Http",
		"Debug"};
	protected JComboBox m_comboSource = null;
	protected JComboBox m_comboDestination = null;
	protected JButton m_buttonSource = null;
	protected JButton m_buttonDestination = null;

	/*
	 * Constructor.
	 */
	public MainPropertyView()
	{
		super();
	}
	/*
	 * Constructor.
	 */
	public MainPropertyView(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(2, 3));

		String strSource = m_properties.getProperty(SOURCE_PARAM);
		if (strSource == null)
			strSource = m_rgstrSources[0];
		panelMain.add(new JLabel("Source: ", JLabel.RIGHT));
		panelMain.add(m_comboSource = (JComboBox)this.makeControlPopup(m_rgstrSources, strSource));
		panelMain.add(m_buttonSource = (JButton)new JButton("Change settings..."));

		String strDestination = m_properties.getProperty(DESTINATION_PARAM);
		if (strDestination == null)
			strDestination = m_rgstrDestinations[0];
		panelMain.add(new JLabel("Destination: ", JLabel.RIGHT));
		panelMain.add(m_comboDestination = (JComboBox)this.makeControlPopup(m_rgstrDestinations, strDestination));
		panelMain.add(m_buttonDestination = (JButton)new JButton("Change settings..."));

		JPanel panelSub = this.makeNewPanel(panel, BorderLayout.SOUTH);
		super.addControlsToView(panelSub);
	}
	/*
	 * Add listeners to the controls.
	 */
	public void addListeners()
	{
		super.addListeners();
		m_buttonSource.addActionListener(this);
		m_comboSource.addItemListener(this);
		m_buttonDestination.addActionListener(this);
		m_comboDestination.addItemListener(this);
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void controlsToProperties()
	{
		String strSelection = (String)m_comboSource.getSelectedItem();
		m_properties.setProperty(SOURCE_PARAM, strSelection);
		strSelection = (String)m_comboDestination.getSelectedItem();
		m_properties.setProperty(DESTINATION_PARAM, strSelection);
		super.controlsToProperties();
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void propertiesToControls()
	{
		m_comboSource.setSelectedItem(m_properties.getProperty(SOURCE_PARAM));
		if (m_comboSource.getSelectedIndex() == -1)
		{
			m_comboSource.setSelectedIndex(0);
			m_properties.setProperty(SOURCE_PARAM, m_comboSource.getSelectedItem().toString());
		}
		m_comboDestination.setSelectedItem(m_properties.getProperty(DESTINATION_PARAM));
		if (m_comboDestination.getSelectedIndex() == -1)
		{
			m_comboDestination.setSelectedIndex(0);
			m_properties.setProperty(DESTINATION_PARAM, m_comboDestination.getSelectedItem().toString());
		}
		super.propertiesToControls();
	}
	/*
	 * User pressed a button.
	 */
	public void actionPerformed(ActionEvent e)
	{
		PropertyOwner propOwner = null;
		String strClass = null;
		Object objClass = null;
		if (e.getSource() == m_buttonSource)
		{
			strClass = m_properties.getProperty(Scanner.SOURCE_PARAM);
			objClass = Util.makeObjectFromClassName(Object.class.getName(), SOURCE_PARAM, strClass);
			if (objClass instanceof BaseSource)	// Always
				((BaseSource)objClass).init(m_properties);
		}
		else if (e.getSource() == m_buttonDestination)
		{
			strClass = m_properties.getProperty(Scanner.DESTINATION_PARAM);
			objClass = Util.makeObjectFromClassName(Object.class.getName(), DESTINATION_PARAM, strClass);
			if (objClass instanceof BaseDestination)	// Always
				((BaseDestination)objClass).init(m_properties);
		}
		if (objClass instanceof PropertyOwner)
			propOwner = (PropertyOwner)objClass;
		if (propOwner != null)
		{
			this.controlsToProperties();
			PropertyView panel = propOwner.getPropertyView(m_properties);
			if (panel == null)	// Default
				panel = new PropertyView(m_propOwner, m_properties);
			if (JOptionPane.showConfirmDialog(null, panel, panel.getDescription(), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
			{
				panel.controlsToProperties();
				propOwner.setProperties(m_properties);	// Send the property owner the new settings
			}
		}
	}
	/*
	 * One of the popup's changed
	 */
	public void itemStateChanged(final java.awt.event.ItemEvent p1)
	{
		super.itemStateChanged(p1);
		this.controlsToProperties();	// Make sure they are up-to-date
	}
	/*
	 * Get the description of this option panel.
	 */
	public String getDescription()
	{
		return "Main properties";
	}
}


/*
 * #%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.propsbuilder;

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

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

/**
 * This class builds a set of {@link CommonProperties} 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 JaasBasedCommonPropsBuilder {

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

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

    /**
     * @see CommonProperties#setAuditClassName(String)
     */
    public static final String DEFAULT_AUDIT_CLASS_NAME =
            "org.beiter.michael.authn.jaas.common.audit.SampleAuditLogger";

    /**
     * @see CommonProperties#setAuditEnabled(boolean)
     */
    public static final boolean DEFAULT_AUDIT_IS_ENABLED = false;

    /**
     * @see CommonProperties#setAuditSingleton(boolean)
     */
    public static final boolean DEFAULT_AUDIT_IS_SINGLETON = true;

    /**
     * @see CommonProperties#setMessageQueueClassName(String)
     */
    public static final String DEFAULT_MESSAGEQ_CLASS_NAME =
            "org.beiter.michael.authn.jaas.common.messageq.SampleMessageLogger";

    /**
     * @see CommonProperties#setMessageQueueEnabled(boolean)
     */
    public static final boolean DEFAULT_MESSAGEQ_IS_ENABLED = false;

    /**
     * @see CommonProperties#setMessageQueueSingleton(boolean)
     */
    public static final boolean DEFAULT_MESSAGEQ_IS_SINGLETON = true;

    /**
     * @see CommonProperties#setPasswordAuthenticatorClassName(String)
     */
    public static final String DEFAULT_PASSWORD_AUTHENTICATOR_CLASS_NAME = null;

    /**
     * @see CommonProperties#setPasswordAuthenticatorSingleton(boolean)
     */
    public static final boolean DEFAULT_PASSWORD_AUTHENTICATOR_IS_SINGLETON = true;

    /**
     * @see CommonProperties#setPasswordValidatorClassName(String)
     */
    public static final String DEFAULT_PASSWORD_VALIDATOR_CLASS_NAME = null;

    /**
     * @see CommonProperties#setPasswordValidatorSingleton(boolean)
     */
    public static final boolean DEFAULT_PASSWORD_VALIDATOR_IS_SINGLETON = true;

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

    /**
     * @see CommonProperties#setAuditClassName(String)
     */
    public static final String KEY_AUDIT_CLASS_NAME = "jaas.audit.class";

    /**
     * @see CommonProperties#setAuditEnabled(boolean)
     */
    public static final String KEY_AUDIT_IS_ENABLED = "jaas.audit.isEnabled";

    /**
     * @see CommonProperties#setAuditSingleton(boolean) (boolean)
     */
    public static final String KEY_AUDIT_IS_SINGLETON = "jaas.audit.isSingleton";

    /**
     * @see CommonProperties#setMessageQueueClassName(String)
     */
    public static final String KEY_MESSAGEQ_CLASS_NAME = "jaas.messageq.class";

    /**
     * @see CommonProperties#setMessageQueueEnabled(boolean)
     */
    public static final String KEY_MESSAGEQ_IS_ENABLED = "jaas.messageq.isEnabled";

    /**
     * @see CommonProperties#setMessageQueueSingleton(boolean)
     */
    public static final String KEY_MESSAGEQ_IS_SINGLETON = "jaas.messageq.isSingleton";

    /**
     * @see CommonProperties#setPasswordAuthenticatorClassName(String)
     */
    // Fortify will report a violation here for handling a hardcoded password, which is not the case.
    // This is a non-issue / false positive.
    public static final String KEY_PASSWORD_AUTHENTICATOR_CLASS_NAME = "jaas.password.authenticator.class";

    /**
     * @see CommonProperties#setPasswordAuthenticatorSingleton(boolean)
     */
    // Fortify will report a violation here for handling a hardcoded password, which is not the case.
    // This is a non-issue / false positive.
    public static final String KEY_PASSWORD_AUTHENTICATOR_IS_SINGLETON = "jaas.password.authenticator.isSingleton";

    /**
     * @see CommonProperties#setPasswordValidatorClassName(String)
     */
    // Fortify will report a violation here for handling a hardcoded password, which is not the case.
    // This is a non-issue / false positive.
    public static final String KEY_PASSWORD_VALIDATOR_CLASS_NAME = "jaas.password.validator.class";

    /**
     * @see CommonProperties#setPasswordValidatorSingleton(boolean)
     */
    // Fortify will report a violation here for handling a hardcoded password, which is not the case.
    // This is a non-issue / false positive.
    public static final String KEY_PASSWORD_VALIDATOR_IS_SINGLETON = "jaas.password.validator.isSingleton";

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

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

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

    /**
     * Initialize a set of common 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 {@link CommonProperties} object with default values, plus the provided parameters
     * @throws NullPointerException When {@code properties} is {@code null}
     */
    // CHECKSTYLE:OFF
    // this is flagged in checkstyle with a missing whitespace before '}', which is a bug in checkstyle
    // suppress warnings about this method being too long (not much point in splitting up this one!)
    // suppress warnings about this method being too complex (can't extract a generic subroutine to reduce exec paths)
    @SuppressWarnings({"PMD.ExcessiveMethodLength", "PMD.NPathComplexity", "PMD.CyclomaticComplexity", "PMD.StdCyclomaticComplexity", "PMD.ModifiedCyclomaticComplexity"})
    // CHECKSTYLE:ON
    public static CommonProperties build(final Map<String, ?> properties) {

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

        final CommonProperties commonProps = new CommonProperties();
        String tmp = getOption(KEY_AUDIT_CLASS_NAME, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setAuditClassName(tmp);
            logValue(KEY_AUDIT_CLASS_NAME, tmp);
        } else {
            commonProps.setAuditClassName(DEFAULT_AUDIT_CLASS_NAME);
            logDefault(KEY_AUDIT_CLASS_NAME, DEFAULT_AUDIT_CLASS_NAME);
        }

        tmp = getOption(KEY_AUDIT_IS_ENABLED, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setAuditEnabled(Boolean.parseBoolean(tmp));
            logValue(KEY_AUDIT_IS_ENABLED, tmp);
        } else {
            commonProps.setAuditEnabled(DEFAULT_AUDIT_IS_ENABLED);
            logDefault(KEY_AUDIT_IS_ENABLED, String.valueOf(DEFAULT_AUDIT_IS_ENABLED));
        }

        tmp = getOption(KEY_AUDIT_IS_SINGLETON, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setAuditSingleton(Boolean.parseBoolean(tmp));
            logValue(KEY_AUDIT_IS_SINGLETON, tmp);
        } else {
            commonProps.setAuditSingleton(DEFAULT_AUDIT_IS_SINGLETON);
            logDefault(KEY_AUDIT_IS_SINGLETON, String.valueOf(DEFAULT_AUDIT_IS_SINGLETON));
        }

        tmp = getOption(KEY_MESSAGEQ_CLASS_NAME, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setMessageQueueClassName(tmp);
            logValue(KEY_MESSAGEQ_CLASS_NAME, tmp);
        } else {
            commonProps.setMessageQueueClassName(DEFAULT_MESSAGEQ_CLASS_NAME);
            logDefault(KEY_MESSAGEQ_CLASS_NAME, DEFAULT_MESSAGEQ_CLASS_NAME);
        }

        tmp = getOption(KEY_MESSAGEQ_IS_ENABLED, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setMessageQueueEnabled(Boolean.parseBoolean(tmp));
            logValue(KEY_MESSAGEQ_IS_ENABLED, tmp);
        } else {
            commonProps.setMessageQueueEnabled(DEFAULT_MESSAGEQ_IS_ENABLED);
            logDefault(KEY_MESSAGEQ_IS_ENABLED, String.valueOf(DEFAULT_MESSAGEQ_IS_ENABLED));
        }

        tmp = getOption(KEY_MESSAGEQ_IS_SINGLETON, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setMessageQueueSingleton(Boolean.parseBoolean(tmp));
            logValue(KEY_MESSAGEQ_IS_SINGLETON, tmp);
        } else {
            commonProps.setMessageQueueSingleton(DEFAULT_MESSAGEQ_IS_SINGLETON);
            logDefault(KEY_MESSAGEQ_IS_SINGLETON, String.valueOf(DEFAULT_MESSAGEQ_IS_SINGLETON));
        }

        tmp = getOption(KEY_PASSWORD_AUTHENTICATOR_CLASS_NAME, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setPasswordAuthenticatorClassName(tmp);
            logValue(KEY_PASSWORD_AUTHENTICATOR_CLASS_NAME, tmp);
        } else {
            commonProps.setPasswordAuthenticatorClassName(DEFAULT_PASSWORD_AUTHENTICATOR_CLASS_NAME);
            logDefault(KEY_PASSWORD_AUTHENTICATOR_CLASS_NAME, DEFAULT_PASSWORD_AUTHENTICATOR_CLASS_NAME);
        }

        tmp = getOption(KEY_PASSWORD_AUTHENTICATOR_IS_SINGLETON, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setPasswordAuthenticatorSingleton(Boolean.parseBoolean(tmp));
            logValue(KEY_PASSWORD_AUTHENTICATOR_IS_SINGLETON, tmp);
        } else {
            commonProps.setPasswordAuthenticatorSingleton(DEFAULT_PASSWORD_AUTHENTICATOR_IS_SINGLETON);
            logDefault(KEY_PASSWORD_AUTHENTICATOR_IS_SINGLETON,
                    String.valueOf(DEFAULT_PASSWORD_AUTHENTICATOR_IS_SINGLETON));
        }

        tmp = getOption(KEY_PASSWORD_VALIDATOR_CLASS_NAME, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setPasswordValidatorClassName(tmp);
            logValue(KEY_PASSWORD_VALIDATOR_CLASS_NAME, tmp);
        } else {
            commonProps.setPasswordValidatorClassName(DEFAULT_PASSWORD_VALIDATOR_CLASS_NAME);
            logDefault(KEY_PASSWORD_VALIDATOR_CLASS_NAME, DEFAULT_PASSWORD_VALIDATOR_CLASS_NAME);
        }

        tmp = getOption(KEY_PASSWORD_VALIDATOR_IS_SINGLETON, properties);
        if (StringUtils.isNotEmpty(tmp)) {
            commonProps.setPasswordValidatorSingleton(Boolean.parseBoolean(tmp));
            logValue(KEY_PASSWORD_VALIDATOR_IS_SINGLETON, tmp);
        } else {
            commonProps.setPasswordValidatorSingleton(DEFAULT_PASSWORD_VALIDATOR_IS_SINGLETON);
            logDefault(KEY_PASSWORD_VALIDATOR_IS_SINGLETON, String.valueOf(DEFAULT_PASSWORD_VALIDATOR_IS_SINGLETON));
        }

        // 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);
        }
        commonProps.setAdditionalProperties(tempMap);

        return commonProps;
    }

    /**
     * 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());
        }
    }
}


/*
 * @(#)DeclarationFilter.java	1.2 04/07/19
 *
 * Copyright (c) 2004, Sun Microsystems, Inc.
 * 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 Sun Microsystems, Inc. nor the names of
 *       its 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 OWNER
 * OR CONTRIBUTORS 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.
 */

package com.sun.mirror.util;

import java.util.ArrayList;
import java.util.Collection;

import com.sun.mirror.declaration.Declaration;
import com.sun.mirror.declaration.Modifier;

import static com.sun.mirror.declaration.Modifier.*;

/**
 * A filter for selecting just the items of interest
 * from a collection of declarations.
 * The filter is said to select or to match those declarations.
 * Filters can be created in several ways:
 * by the static methods described below,
 * by negating or composing existing filters,
 * or by subclasses that implement arbitrary matching rules.
 *

 *
 A subclass can create an arbitrary filter simply by implementing
 * the {@link #matches(Declaration)} method.
 *

 *
 Examples.
 *
 Selecting the <tt>public</tt> declarations from a collection:
 *

 *     result = FILTER_PUBLIC.filter(decls);

 * Selecting class declarations (including enums):
 *

 *     classFilter = DeclarationFilter.getFilter(ClassDeclaration.class);
 *     result = classFilter.filter(decls);

 * Selecting class declarations but excluding enums:
 *

 *     enumFilter = DeclarationFilter.getFilter(EnumDeclaration.class);
 *     compoundFilter = classFilter.and(enumFilter.not());
 *     result = compoundFilter.filter(decls);

 * Selecting declarations named "Bob":
 *

 *     nameFilter = new DeclarationFilter() {
 *                      public boolean matches(Declaration d) {
 *                          return d.getSimpleName().equals("Bob");
 *                      }
 *                  };
 *     result = nameFilter.filter(decls);

 *
 * @author Joseph D. Darcy
 * @author Scott Seligman
 * @version 1.2 04/07/19
 * @since 1.5
 */

public class DeclarationFilter {

	// Predefined filters for convenience.

	/**
	 * A filter that selects only <tt>public</tt> declarations.
	 */
	public static final DeclarationFilter FILTER_PUBLIC =
			new AccessFilter(PUBLIC);

	/**
	 * A filter that selects only <tt>protected</tt> declarations.
	 */
	public static final DeclarationFilter FILTER_PROTECTED =
			new AccessFilter(PROTECTED);

	/**
	 * A filter that selects only <tt>public</tt> or <tt>protected</tt>
	 * declarations.
	 */
	public static final DeclarationFilter FILTER_PUBLIC_OR_PROTECTED =
			new AccessFilter(PUBLIC, PROTECTED);

	/**
	 * A filter that selects only package-private (default)
	 * declarations.
	 */
	public static final DeclarationFilter FILTER_PACKAGE =
			new AccessFilter();

	/**
	 * A filter that selects only <tt>private</tt> declarations.
	 */
	public static final DeclarationFilter FILTER_PRIVATE =
			new AccessFilter(PRIVATE);

	/**
	 * Constructs an identity filter:  one that selects all declarations.
	 */
	public DeclarationFilter() {
	}

	// Methods to create a filter.

	/**
	 * Returns a filter that selects declarations containing all of a
	 * collection of modifiers.
	 *
	 * @param mods the modifiers to match (non-null)
	 * @return a filter that matches declarations containing <tt>mods</tt>
	 */
	public static DeclarationFilter getFilter(
			final Collection<Modifier> mods) {
		return new DeclarationFilter() {
			public boolean matches(Declaration d) {
				return d.getModifiers().containsAll(mods);
			}
		};
	}

	/**
	 * Returns a filter that selects declarations of a particular kind.
	 * For example, there may be a filter that selects only class
	 * declarations, or only fields.
	 * The filter will select declarations of the specified kind,
	 * and also any subtypes of that kind; for example, a field filter
	 * will also select enum constants.
	 *
	 * @param kind the kind of declarations to select
	 * @return a filter that selects declarations of a particular kind
	 */
	public static DeclarationFilter getFilter(
			final Class<? extends Declaration> kind) {
		return new DeclarationFilter() {
			public boolean matches(Declaration d) {
				return kind.isInstance(d);
			}
		};
	}

	/**
	 * Returns a filter that selects those declarations selected
	 * by both this filter and another.
	 *
	 * @param f filter to be composed with this one
	 * @return a filter that selects those declarations selected by
	 *         both this filter and another
	 */
	public DeclarationFilter and(DeclarationFilter f) {
		final DeclarationFilter f1 = this;
		final DeclarationFilter f2 = f;
		return new DeclarationFilter() {
			public boolean matches(Declaration d) {
				return f1.matches(d) && f2.matches(d);
			}
		};
	}

	/**
	 * Returns a filter that selects those declarations selected
	 * by either this filter or another.
	 *
	 * @param f filter to be composed with this one
	 * @return a filter that selects those declarations selected by
	 *         either this filter or another
	 */
	public DeclarationFilter or(DeclarationFilter f) {
		final DeclarationFilter f1 = this;
		final DeclarationFilter f2 = f;
		return new DeclarationFilter() {
			public boolean matches(Declaration d) {
				return f1.matches(d) || f2.matches(d);
			}
		};
	}

	/**
	 * Returns a filter that selects those declarations not selected
	 * by this filter.
	 *
	 * @return a filter that selects those declarations not selected
	 *         by this filter
	 */
	public DeclarationFilter not() {
		return new DeclarationFilter() {
			public boolean matches(Declaration d) {
				return !DeclarationFilter.this.matches(d);
			}
		};
	}

	// Methods to apply a filter.

	/**
	 * Tests whether this filter matches a given declaration.
	 * The default implementation always returns <tt>true</tt>;
	 * subclasses should override this.
	 *
	 * @param decl the declaration to match
	 * @return <tt>true</tt> if this filter matches the given declaration
	 */
	public boolean matches(Declaration decl) {
		return true;
	}

	/**
	 * Returns the declarations matched by this filter.
	 * The result is a collection of the same type as the argument;
	 * the {@linkplain #filter(Collection, Class) two-parameter version}
	 * of <tt>filter</tt> offers control over the result type.
	 *
	 * @param <D>   type of the declarations being filtered
	 * @param decls declarations being filtered
	 * @return the declarations matched by this filter
	 */
	public <D extends Declaration> Collection<D> filter(Collection<D> decls) {
		ArrayList<D> res = new ArrayList<D>(decls.size());
		for (D d : decls) {
			if (matches(d)) {
				res.add(d);
			}
		}
		return res;
	}

	/**
	 * Returns the declarations matched by this filter, with the result
	 * being restricted to declarations of a given kind.
	 * Similar to the simpler
	 * {@linkplain #filter(Collection) single-parameter version}
	 * of <tt>filter</tt>, but the result type is specified explicitly.
	 *
	 * @param <D>     type of the declarations being returned
	 * @param decls   declarations being filtered
	 * @param resType type of the declarations being returned --
	 *                the reflective view of <tt>D</tt>
	 * @return the declarations matched by this filter, restricted to those
	 *         of the specified type
	 */
	public <D extends Declaration> Collection<D>
	filter(Collection<? extends Declaration> decls, Class<D> resType) {
		ArrayList<D> res = new ArrayList<D>(decls.size());
		for (Declaration d : decls) {
			if (resType.isInstance(d) && matches(d)) {
				res.add(resType.cast(d));
			}
		}
		return res;
	}

	/*
		 * A filter based on access modifiers.
		 */
	private static class AccessFilter extends DeclarationFilter {

		// The first access modifier to filter on, or null if we're looking
		// for declarations with no access modifiers.
		private Modifier mod1 = null;

		// The second access modifier to filter on, or null if none.
		private Modifier mod2 = null;

		// Returns a filter that matches declarations with no access
		// modifiers.
		AccessFilter() {
		}

		// Returns a filter that matches m.
		AccessFilter(Modifier m) {
			mod1 = m;
		}

		// Returns a filter that matches either m1 or m2.
		AccessFilter(Modifier m1, Modifier m2) {
			mod1 = m1;
			mod2 = m2;
		}

		public boolean matches(Declaration d) {
			Collection<Modifier> mods = d.getModifiers();
			if (mod1 == null) {    // looking for package private
				return !(mods.contains(PUBLIC) ||
						mods.contains(PROTECTED) ||
						mods.contains(PRIVATE));
			}
			return mods.contains(mod1) &&
					(mod2 == null || mods.contains(mod2));
		}
	}
}


/**
 * 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.servlet.map;

import java.util.*;

public abstract class StringEnumeratedMap<V> implements Map<String, V> {
    private volatile Map<String, V> map;

    @Override
    public boolean containsKey(Object key) {
        return get(key) != null;
    }

    @Override
    public boolean containsValue(Object value) {
        return getAsMap().containsValue(value);
    }

    @Override
    public V get(Object key) {
        return getAttribute(key.toString());
    }

    @Override
    public boolean isEmpty() {
        return getAsMap().isEmpty();
    }

    @Override
    public int size() {
        return getAsMap().size();
    }

    @Override
    public Set<Map.Entry<String, V>> entrySet() {
        return getAsMap().entrySet();
    }

    @Override
    public Set<String> keySet() {
        return getAsMap().keySet();
    }

    @Override
    public Collection<V> values() {
        return getAsMap().values();
    }

    @Override
    public synchronized V put(String key, V value) {
        map = null;
        V previous = get(key);
        setAttribute(key, value);
        return previous;
    }

    @Override
    public synchronized void putAll(Map<? extends String, ? extends V> m) {
        map = null;
        for (Map.Entry<? extends String, ? extends V> e : m.entrySet()) {
            setAttribute(e.getKey(), e.getValue());
        }
    }

    @Override
    public synchronized V remove(Object key) {
        map = null;
        V value = get(key);
        removeAttribute(key.toString());
        return value;
    }

    @Override
    public synchronized void clear() {
        map = null;
        Enumeration<String> keys = getAttributeNames();
        while (keys.hasMoreElements()) {
            removeAttribute(keys.nextElement());
        }
    }

    protected abstract Enumeration<String> getAttributeNames();

    protected abstract V getAttribute(String name);

    protected abstract void setAttribute(String name, V value);

    protected abstract void removeAttribute(String name);

    // double check for map
    protected Map<String, V> getAsMap() {
        Map<String, V> result = map;
        if (result == null) {
            synchronized (this) {
                result = map;
                if (result == null) {
                    map = (result = initialize());
                }
            }
        }
        return result;
    }

    private Map<String, V> initialize() {
        Map<String, V> map = new HashMap<String, V>();
        for (Enumeration<String> e = getAttributeNames(); e.hasMoreElements();) {
            String key = e.nextElement();
            V value = getAttribute(key);
            map.put(key, value);
        }
        return map;
    }
}


/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.rockagen.commons.util;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Reflex Utils
 *
 * @author RA
 * @since JDK1.6
 */
public class ReflexUtil {

	// ~ Instance fields ==================================================

	/**
	 *
	 */
	private static final Logger log = LoggerFactory.getLogger(ReflexUtil.class);

	// ~ Constructors ==================================================

	/**
	 */
	private ReflexUtil() {
	}

	// ~ Methods ==================================================

	/**
	 *
	 * Direct reading the object attribute values,the private / protected
	 * modifiers will be ignoring.if getter function exist,return getter
	 * function value
If recursively is true, will looking from all class
	 * hierarchy

	 *
	 * @param object object
	 * @param fieldName field name
	 * @param recursively recursively
	 * @return object
	 */
	public static Object getFieldValue(final Object object, String fieldName,
			boolean recursively) {

		Object result = null;
		if (object == null)
			return null;

		Field field = ClassUtil.getDeclaredField(object.getClass(), fieldName,
				recursively);
		if (field == null) {
			log.debug("Could not find field [ {} ] on target [ {} ]",
					fieldName, object.getClass().getSimpleName());
			return null;
		}

		String methodName = "get" + CommUtil.capitalize(fieldName);
		Method method = ClassUtil.getDeclaredMethod(object.getClass(),
				recursively, methodName);
		if (method != null) {
			try {
				makeAccessible(method);
				result = method.invoke(object);
				return result;
			} catch (InvocationTargetException e) {
				log.debug("Could not find method [ {} ] on target [ {} ]",
						methodName, object.getClass().getSimpleName());
			}catch (IllegalAccessException e) {
				// Will not happen
			}
		}

		makeAccessible(field);
		try {
			result = field.get(object);
		}catch (IllegalAccessException e) {
			// Will not happen
		}
		return result;
	}

	/**
	 * Direct writing the object attribute values, the private / protected
	 * modifiers will be ignoring,if setter function exist,return setter
	 * function value.
If recursively is true, will looking from all class
	 * hierarchy

	 *
	 * @param object object
	 * @param fieldName field name
	 * @param value value
	 * @param recursively recursively
	 */
	public static void setFieldValue(final Object object, String fieldName,
			final Object value, boolean recursively) {

		if (object == null)
			return;

		Field field = ClassUtil.getDeclaredField(object.getClass(), fieldName,
				recursively);

		if (field == null) {
			log.debug("Could not find field [ {} ] on target [ {} ]",
					fieldName, object.getClass().getSimpleName());
			return;
		}

		String methodName = "set" + CommUtil.capitalize(fieldName);

		Method method = ClassUtil.getDeclaredMethod(object.getClass(),
				recursively, methodName,
				value == null ? Object.class : value.getClass());
		if (method != null) {
			try {
				makeAccessible(method);
				method.invoke(object, value);
				return;
			} catch (InvocationTargetException e) {
				log.debug("Could not find method [ {} ] on target [ {} ]",
						methodName, object.getClass().getSimpleName());
			} catch (NullPointerException e) {
				log.debug("{} field: [ {} ] is null", object.getClass()
						.getSimpleName(), fieldName);
			}catch (IllegalAccessException e) {
				// Will not happen
			}

		}

		makeAccessible(field);

		try {
			field.set(object, value);
		}catch (NullPointerException e) {
			log.debug("{} field: [ {} ] is null", object.getClass()
					.getSimpleName(), fieldName);
		} catch (IllegalAccessException e) {
			// Will not happen
		}
	}

	/**
	 * set attribute is accessible
	 *
	 * @param field {@link java.lang.reflect.Field}
	 */
	public static void makeAccessible(final Field field) {
		if (!Modifier.isPublic(field.getModifiers())
				|| !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
			field.setAccessible(true);
		}
	}

	/**
	 * set method is accessible
	 *
	 * @param method {@link java.lang.reflect.Method}
	 */
	public static void makeAccessible(final Method method) {
		if (!Modifier.isPublic(method.getModifiers())
				|| !Modifier
						.isPublic(method.getDeclaringClass().getModifiers())) {
			method.setAccessible(true);
		}
	}

	/**
	 * set constructor is accessible
	 * @param constructor {@link java.lang.reflect.Constructor}
	 * @param <T> t
	 */
	public static <T> void makeAccessible(final Constructor<T> constructor) {
		if (!Modifier.isPublic(constructor.getModifiers())
				|| !Modifier.isPublic(constructor.getDeclaringClass()
						.getModifiers())) {
			constructor.setAccessible(true);
		}
	}

	/**
	 * obtained the parent class generic parameter types
	 *

	 * for example:
	 *

	 *
	 *  ClassB<T> extends ClassA<T>
	 *
	 *
	 * @param clazz {@link java.lang.Class}
	 * @return Types
	 */
	public static Type[] getSuperClassGenricTypes(final Class<?> clazz) {

		Type[] temp = { Object.class };
		// eg: ClassA<T>
		if (clazz == null)
			return null;
		Type type = clazz.getGenericSuperclass();

		if (type instanceof ParameterizedType) {

			return ((ParameterizedType) type).getActualTypeArguments();

		} else {
			log.warn(
					"{} 's superclass not ParameterizedType",
					clazz);
			return temp;
		}
	}

	/**
	 * obtained the parent class generic parameter type
	 *

	 * for example:
	 *

	 *
	 *  ClassB<T> extends ClassA<T>
	 *
	 *
	 * @param clazz {@link java.lang.Class}
	 * @param index
	 *            start 0
	 * @return Type
	 */
	public static Type getSuperClassGenricType(final Class<?> clazz, int index) {
		Type[] types = getSuperClassGenricTypes(clazz);
		if (index < 0) {
			log.warn(
					"{}'s index must be greater than 0,return the 0",
					clazz == null ? Object.class.getSimpleName() : clazz
							.getSimpleName());
			return types[0];
		} else if (index > types.length) {
			log.warn(
					"{}'s index in {} not found,return the last",
					clazz == null ? Object.class.getSimpleName() : clazz
							.getSimpleName(), index);
			return types[types.length - 1];
		} else {
			return types[index];
		}
	}

	/**
	 * obtained the parent class generic parameter classes
	 *

	 * for example:
	 *

	 *
	 *  ClassB<T> extends ClassA<T>
	 *
	 *
	 * @param clazz {@link java.lang.Class}
	 * @return Classes
	 */
	public static Class<?>[] getSuperClassGenricClasses(final Class<?> clazz) {

		Type[] types = getSuperClassGenricTypes(clazz);
		Class<?>[] clazzs = new Class<?>[types.length];
		for (int i = 0; i < types.length; i++) {
			clazzs[i] = (Class<?>) types[i];
		}
		return clazzs;

	}

	/**
	 * obtained the parent class generic parameter class
	 *

	 * for example:
	 *

	 *
	 *  ClassB<T> extends ClassA<T>
	 *
	 *
	 * @param clazz {@link java.lang.Class}
	 * @param index
	 *            start 0
	 * @return Class
	 */
	public static Class<?> getSuperClassGenricClass(final Class<?> clazz,
			int index) {
		return (Class<?>) getSuperClassGenricType(clazz, index);
	}

    /**
     * obtained the interface generic parameter types
     *

     * for example:
     *

     *
     *  ClassB<T> implements ClassA<T>
     *
     *
     * @param clazz {@link java.lang.Class}
     * @return Types
     */
    public static Type[] getInterfacesGenricTypes(final Class<?> clazz) {
        if (clazz == null)
            return null;
        Type[] types=clazz.getGenericInterfaces();

        Type[] gtypes=new Type[0];
        for(Type t:types){
            if (t instanceof ParameterizedType) {
                Type[] gts=((ParameterizedType) t).getActualTypeArguments();
                int olen=gtypes.length;
                int ilen=gts.length;
                Type[] tmp=new Type[olen+ilen];
                System.arraycopy(gtypes,0,tmp,0,olen);
                System.arraycopy(gts, 0, tmp, olen, ilen);
                gtypes=tmp;
             }
        }
        return gtypes;
    }

    /**
     * obtained the interface generic parameter type
     *

     * for example:
     *

     *
     *  ClassB<T> implements ClassA<T>
     *
     *
     * @param clazz {@link java.lang.Class}
     * @param index
     *            start 0
     * @return Type
     */
    public static Type getInterfacesGenricType(final Class<?> clazz, int index) {
        Type[] types = getInterfacesGenricTypes(clazz);
        if (index < 0) {
            log.warn(
                    "{}'s index must be greater than 0,return the 0",
                    clazz == null ? Object.class.getSimpleName() : clazz
                            .getSimpleName());
            return types[0];
        } else if (index > types.length) {
            log.warn(
                    "{}'s index in {} not found,return the last",
                    clazz == null ? Object.class.getSimpleName() : clazz
                            .getSimpleName(), index);
            return types[types.length - 1];
        } else {
            return types[index];
        }
    }

    /**
     * obtained the interface generic parameter classes
     *

     * for example:
     *

     *
     *  ClassB<T> implements ClassA<T>
     *
     *
     * @param clazz {@link java.lang.Class}
     * @return Classes
     */
    public static Class<?>[] getInterfacesGenricClasses(final Class<?> clazz) {

        Type[] types = getInterfacesGenricTypes(clazz);
        Class<?>[] clazzs = new Class<?>[types.length];
        for (int i = 0; i < types.length; i++) {
            clazzs[i] =(Class<?>)types[i];
        }
        return clazzs;

    }

    /**
     * obtained the interface generic parameter class
     *

     * for example:
     *

     *
     *  ClassB<T> implements ClassA<T>
     *
     *
     * @param clazz {@link java.lang.Class}
     * @param index
     *            start 0
     * @return Class
     */
    public static Class<?> getInterfacesGenricClass(final Class<?> clazz,
                                                    int index) {
        return (Class<?>) getInterfacesGenricType(clazz, index);
    }

	/**
	 * Create new instance of specified class and type from a map
note:
	 * clazz must write setter

	 *
	 * @param clazz {@link java.lang.Class}
	 * @param paramsMap
	 *            attributes
	 * @param accessible accesible
	 * @param <T> t
	 * @return instance
	 */
	public static <T> T getBasicInstance(final Class<T> clazz,
			final Map<String, Object> paramsMap, boolean accessible) {

		if (clazz != null && paramsMap != null && paramsMap.size() > 0) {

			T instance = ClassUtil.getInstance(clazz, accessible);

			for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
				String key = entry.getKey();
				if (CommUtil.isBlank(key)) {
					continue;
				}
				key = CommUtil.uncapitalize(key);

				setFieldValue(instance, key, entry.getValue(), false);

			}
			return instance;
		} else {
			return 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.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 ZipDestinationPropertyView extends BaseDestinationPropertyView
	implements JBackupConstants
{
	private static final long serialVersionUID = 1L;

	protected JTextField m_tfRootPathname = null;
	protected JTextField m_tfFilename = null;
	protected JTextField m_tfMaxSize = null;

	/*
	 * Constructor.
	 */
	public ZipDestinationPropertyView()
	{
		super();
	}
	/*
	 * Constructor.
	 */
	public ZipDestinationPropertyView(PropertyOwner propOwner,Properties properties)
	{
		this();
		this.init(propOwner, properties);
	}
	/*
	 * Initialize.
	 */
	public void init(PropertyOwner propOwner, Properties properties)
	{
//		String strPathname = properties.getProperty(ZIPOUT_FILENAME_PARAM);
		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(3, 2));

		panelMain.add(new JLabel("Zip directory: ", JLabel.RIGHT));
		panelMain.add(m_tfRootPathname = new JTextField());

		panelMain.add(new JLabel("Zip filename: ", JLabel.RIGHT));
		panelMain.add(m_tfFilename = new JTextField());

		panelMain.add(new JLabel("Max size: ", JLabel.RIGHT));
		panelMain.add(m_tfMaxSize = 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(ZIPOUT_PATHNAME_PARAM, strPathname);
		String strFilename = m_tfFilename.getText();
		m_properties.setProperty(ZIPOUT_FILENAME_PARAM, strFilename);
		String strMaxSize = m_tfMaxSize.getText();
		m_properties.setProperty(MAX_SIZE_PARAM, strMaxSize);
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void propertiesToControls()
	{
		super.propertiesToControls();
		String strPathname = m_properties.getProperty(ZIPOUT_PATHNAME_PARAM);
		m_tfRootPathname.setText(strPathname);

		String strFilename = m_properties.getProperty(ZIPOUT_FILENAME_PARAM);
		m_tfFilename.setText(strFilename);

		String strMaxSize = m_properties.getProperty(MAX_SIZE_PARAM);
		m_tfMaxSize.setText(strMaxSize);
	}
	/*
	 * Get the description of this option panel.
	 */
	public String getDescription()
	{
		return "Base source properties";
	}
}


/*
 * DirScanner.java
 *
 * Created on January 29, 2000, 6:33 AM

 * Copyright © 2012 jbundle.org. All rights reserved.
 */
package org.jbundle.jbackup.destination;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;

import org.jbundle.jbackup.source.SourceFile;
import org.jbundle.jbackup.util.Util;
import org.jbundle.util.apprunner.PropertyView;

/**
 * Directory scanner.
 * This class is a utility for scanning through a directory tree.
 * @author  Administrator
 * @version
 */
public class FilesystemDestination extends BaseDestination
	implements DestinationFile
{
	protected String m_strPathname = null;

	/*
	 * Constructor
	 */
	public FilesystemDestination()
	{
		super();
	}
	/**
	 * Creates new DirScanner.
	 * @param lMaxZipFileSize If zip file is going to be larger than this, split it up into smaller files.
	 */
	public FilesystemDestination(Properties properties)
	{
		this();
		this.init(properties);
	}
	/*
	 * Set up everything to start processing
	 */
	public void init(Properties properties)
	{
		super.init(properties);
		String strPathname = properties.getProperty(DEST_ROOT_PATHNAME_PARAM);
		if (strPathname == null)
		{
			strPathname = System.getProperties().getProperty("java.io.tmpdir", "c:/Temp");
			if (strPathname != null)
				if (!strPathname.endsWith(File.separator))
					strPathname += File.separator;
			properties.setProperty(DEST_ROOT_PATHNAME_PARAM, strPathname);
		}
	}
	/*
	 * Set up everything to start processing
	 */
	public void initTransfer(Properties properties)
	{
		super.initTransfer(properties);
		m_strPathname = properties.getProperty(DEST_ROOT_PATHNAME_PARAM);
		if ((m_strPathname == null)
			|| (m_strPathname.length() == 0))
				m_strPathname = "";		// No prefix
		else if ((m_strPathname.lastIndexOf(System.getProperties().getProperty("file.separator")) != m_strPathname.length() - 1)
			&& (m_strPathname.lastIndexOf('/') != m_strPathname.length() - 1))
				m_strPathname += System.getProperties().getProperty("file.separator");	// Must end in a path separator
	}
	/*
	 * Close everything down after processing.
	 */
	public void finishTransfer(Properties properties)
	{
		super.finishTransfer(properties);
	}
	/*
	 * Add this file to the destination.
	 * Note: Only supply the file or the stream, not both. Supply the object that is easier, given
	 * the source. This dual option is given to allow destinations that require File objects from
	 * (such as FTP or HTTP) Having to write the inStream to a physical file before processing it.
	 * @param file Source file.
	 * @param inStream Source stream.
	 * @param strpath Full path of the source file (including the filename).
	 * @param strFilename Filename.
	 * @param lStreamLength Length of the stream (-1 if unknown).
	 */
	public long addNextFile(SourceFile source)
	{
		String strPath = source.getFilePath();
		long lStreamLength = source.getStreamLength();

        InputStream inStream = source.makeInStream();
		try	{
			strPath = m_strPathname + strPath;
			File file = new File(strPath);
			file.mkdirs();
			if (file.exists())
				file.delete();
			file.createNewFile();
			OutputStream outStream = new FileOutputStream(file);
			lStreamLength = Util.copyStream(inStream, outStream);
			outStream.close();
		} catch (IOException ex)	{
			ex.printStackTrace();
		}
		return lStreamLength;
	}
	/*
	 * Get the panel to change the properties for this object.
	 */
	public PropertyView getPropertyView(Properties properties)
	{
		return new FilesystemDestinationPropertyView(this, properties);
	}
}


/*
 * DirScanner.java
 *
 * Created on January 29, 2000, 6:33 AM

 * Copyright © 2012 jbundle.org. All rights reserved.
 */
package org.jbundle.jbackup.source;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Properties;

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

/**
 * Directory scanner.
 * This class is a utility for scanning through a directory tree.
 * @author  Administrator
 * @version
 */
public class BaseSource extends Object
	implements SourceFileList, PropertyOwner, JBackupConstants
{
	public static char gchSeparator = '/';

	protected Date m_dateLastBackup = null;		// Date Filter (optional)
	protected FilenameFilter m_Filter = null;	// File filter (optional)

	protected SourceFile m_nextPend = null;		// For hasNext support.

	/*
	 * Constructor
	 */
	public BaseSource()
	{
		super();
	}
	/*
	 * Constructor
	 */
	public BaseSource(Properties properties)
	{
		this();
		this.init(properties);
	}
	/*
	 * Set up everything to start processing
	 */
	public void init(Properties properties)
	{
	}
	/*
	 * Set up everything to start processing
	 */
	public void initTransfer(Properties properties)
	{
		boolean bIncremental = false;
		String strSelected = properties.getProperty(BACKUP_INCREMENTAL_PARAM);
		if (TRUE.equalsIgnoreCase(strSelected))
			bIncremental = true;
		String strDate = properties.getProperty(BACKUPDATE_PARAM);
		if (bIncremental)	// If incremental, set the "filter date".
			m_dateLastBackup = Util.stringToDate(strDate);
		m_Filter = Util.makeFilter(properties);
	}
	/*
	 * Close everything down after processing.
	 */
	public void finishTransfer(Properties properties)
	{
		String strDateLastBackup = Util.dateToString(new Date());
		properties.setProperty(BACKUPDATE_PARAM, strDateLastBackup);
	}
	/*
	 * Get the panel to change the properties for this object.
	 */
	public PropertyView getPropertyView(Properties properties)
	{
		return new BaseSourcePropertyView(this, properties);
	}
	/*
	 * Set the properties on this object.
	 */
	public void setProperties(final java.util.Properties p1) {
	}
	/** Returns <tt>true</tt> if the iteration has more elements. (In other
	 * words, returns <tt>true</tt> if <tt>next</tt> would return an element
	 * rather than throwing an exception.)
	 *
	 * @return <tt>true</tt> if the iterator has more elements.
	 */
	public boolean hasNext() {
		if (m_nextPend != null)
			return true;
		m_nextPend = this.next();
		if (m_nextPend == null)
			return false;
		else
			return true;
	}
	/** Returns the next element in the interation.
	 * (Returns a SourceFileObject).
	 *
	 * @returns the next element in the interation.
	 * @exception NoSuchElementException iteration has no more elements.
	 */
	public boolean isPend()
	{
		return (m_nextPend != null);
	}
	/** Returns the next element in the interation.
	 * (Returns a SourceFileObject).
	 * <pre>
	 * 	public Object next()
	 * {
	 *	if (this.isPend())
	 *		return this.getPend();
	 *	return null;
	 *}
	 * </pre>
	 *
	 * @returns the next element in the interation.
	 * @exception NoSuchElementException iteration has no more elements.
	 */
	public SourceFile getPend()
	{
		SourceFile nextPend = m_nextPend;
		m_nextPend = null;
		return nextPend;
	}
	/** Returns the next element in the interation.
	 * (Returns a SourceFileObject).
	 */
	public SourceFile next()
	{
		if (this.isPend())
			return this.getPend();
		return null;
	}
	/**
	 * Removes from the underlying collection the last element returned by the
	 * iterator (optional operation).  This method can be called only once per
	 * call to <tt>next</tt>.  The behavior of an iterator is unspecified if
	 * the underlying collection is modified while the iteration is in
	 * progress in any way other than by calling this method.
	 *
	 * @exception UnsupportedOperationException if the <tt>remove</tt>
	 * 		  operation is not supported by this Iterator.
	 *
	 * @exception IllegalStateException if the <tt>next</tt> method has not
	 * 		  yet been called, or the <tt>remove</tt> method has already
	 * 		  been called after the last call to the <tt>next</tt>
	 * 		  method.
	 */
	public void remove() {
		// Not implemented
	}
	/*
	 * Should I skip this file?
	 * Override this.
	 */
	public boolean skipFile(File inFile)
	{
		if (m_dateLastBackup != null)
		{		// Check the date
			Date dateLastMod = new Date(inFile.lastModified());
			if (dateLastMod.before(m_dateLastBackup))
				return true;	// Skip it
		}
		return false;	// Don't skip it
	}
}


/*
 * @(#)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.awt.GridLayout;
import java.awt.event.ActionListener;
import java.util.Properties;

import javax.swing.JCheckBox;
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 DebugDestinationPropertyView extends BaseDestinationPropertyView
	implements ActionListener, JBackupConstants
{
	private static final long serialVersionUID = 1L;

	protected JTextField m_tfLogFilename = null;
	protected JCheckBox m_cbFileLength = null;

	/*
	 * Constructor.
	 */
	public DebugDestinationPropertyView()
	{
		super();
	}
	/*
	 * Constructor.
	 */
	public DebugDestinationPropertyView(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("Log filename: ", JLabel.RIGHT));
		panelMain.add(m_tfLogFilename = new JTextField());

		panelMain.add(m_cbFileLength = new JCheckBox("Calc file length?"));

		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_tfLogFilename.getText();
		m_properties.setProperty(LOG_FILENAME_PARAM, strPathname);
		boolean bSelected = m_cbFileLength.isSelected();
		if (bSelected)
			m_properties.setProperty(CALC_FILE_LENGTH_PARAM, TRUE);
		else
			m_properties.setProperty(CALC_FILE_LENGTH_PARAM, FALSE);
	}
	/*
	 * Set the properties to the current control values.
	 */
	public void propertiesToControls()
	{
		super.propertiesToControls();
		String strPathname = m_properties.getProperty(LOG_FILENAME_PARAM);
		m_tfLogFilename.setText(strPathname);
		boolean bSelected = true;
		String strSelected = m_properties.getProperty(CALC_FILE_LENGTH_PARAM);
		if (FALSE.equalsIgnoreCase(strSelected))
			bSelected = false;
		m_cbFileLength.setSelected(bSelected);
	}
	/*
	 * Get the description of this option panel.
	 */
	public String getDescription()
	{
		return "Debug destination 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.orm;

import java.sql.*;
import java.util.*;
import java.util.Date;
import javax.sql.DataSource;
import jetbrick.dao.DbException;
import jetbrick.dao.TransactionException;
import jetbrick.dao.dialect.SqlDialect;
import jetbrick.dao.orm.handlers.*;
import jetbrick.dao.orm.mappers.*;
import jetbrick.dao.orm.tx.*;
import jetbrick.dao.orm.utils.DbUtils;
import jetbrick.dao.orm.utils.PreparedStatementCreator;
import jetbrick.lang.Validate;

/**
 * 数据库操作。单例使用
 */
@SuppressWarnings("unchecked")
public class DbHelper {
    private static final boolean ALLOW_NESTED_TRANSACTION = System.getProperty("jetbrick.orm.transaction.nested.disabled") == null;

    // 当前线程(事务)
    private final ThreadLocal<JdbcTransaction> transationHandler = new ThreadLocal<JdbcTransaction>();
    private final DataSource dataSource;
    private final SqlDialect dialect;

    public DbHelper(DataSource dataSource) {
        this.dataSource = dataSource;
        this.dialect = doGetDialet();
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * 启动一个事务(默认支持子事务)
     */
    public Transaction transaction() {
        if (transationHandler.get() != null) {
            if (ALLOW_NESTED_TRANSACTION) {
                return new JdbcNestedTransaction(transationHandler.get().getConnection());
            }
            throw new TransactionException("Can't begin a nested transaction.");
        }
        try {
            JdbcTransaction tx = new JdbcTransaction(dataSource.getConnection(), transationHandler);
            transationHandler.set(tx);
            return tx;
        } catch (SQLException e) {
            throw new TransactionException(e);
        }
    }

    /**
     * 获取一个当前线程的连接(事务中)，如果没有，则新建一个。
     */
    private Connection getConnection() {
        JdbcTransaction tx = transationHandler.get();
        try {
            if (tx == null) {
                return dataSource.getConnection();
            } else {
                return tx.getConnection();
            }
        } catch (SQLException e) {
            throw new DbException(e);
        }
    }

    /**
     * 释放一个连接，如果 Connection 不在事务中，则关闭它，否则不处理。
     */
    private void closeConnection(Connection conn) {
        if (transationHandler.get() == null) {
            // not in transaction
            DbUtils.closeQuietly(conn);
        }
    }

    public <T> List<T> queryAsList(RowMapper<T> rowMapper, String sql, Object... parameters) {
        Validate.notNull(rowMapper, "rowMapper is null.");

        ResultSetHandler<List<T>> rsh = new RowListHandler<T>(rowMapper);
        return query(rsh, sql, parameters);
    }

    public <T> List<T> queryAsList(Class<T> beanClass, String sql, Object... parameters) {
        Validate.notNull(beanClass, "beanClass is null.");

        RowMapper<T> rowMapper = getRowMapper(beanClass);
        return queryAsList(rowMapper, sql, parameters);
    }

    public <T> T queryAsObject(RowMapper<T> rowMapper, String sql, Object... parameters) {
        ResultSetHandler<T> rsh = new SingleRowHandler<T>(rowMapper);
        return query(rsh, sql, parameters);
    }

    public <T> T queryAsObject(Class<T> beanClass, String sql, Object... parameters) {
        Validate.notNull(beanClass, "beanClass is null.");

        RowMapper<T> rowMapper = getRowMapper(beanClass);
        return queryAsObject(rowMapper, sql, parameters);
    }

    public Integer queryAsInt(String sql, Object... parameters) {
        return queryAsObject(Integer.class, sql, parameters);
    }

    public Long queryAsLong(String sql, Object... parameters) {
        return queryAsObject(Long.class, sql, parameters);
    }

    public String queryAsString(String sql, Object... parameters) {
        return queryAsObject(String.class, sql, parameters);
    }

    public Boolean queryAsBoolean(String sql, Object... parameters) {
        return queryAsObject(Boolean.class, sql, parameters);
    }

    public Date queryAsDate(String sql, Object... parameters) {
        return queryAsObject(Date.class, sql, parameters);
    }

    public Map<String, Object> queryAsMap(String sql, Object... parameters) {
        return queryAsObject(Map.class, sql, parameters);
    }

    public <T> T[] queryAsArray(Class<T> arrayComponentClass, String sql, Object... parameters) {
        try {
            Class<T[]> clazz = (Class<T[]>) Class.forName("[" + arrayComponentClass.getName());
            return queryAsObject(clazz, sql, parameters);
        } catch (ClassNotFoundException e) {
            throw new DbException(e);
        }
    }

    public <T> Pagelist<T> queryAsPagelist(PageInfo pageInfo, Class<T> beanClass, String sql, Object... parameters) {
        Validate.notNull(beanClass, "beanClass is null.");

        RowMapper<T> rowMapper = getRowMapper(beanClass);
        return queryAsPagelist(pageInfo, rowMapper, sql, parameters);
    }

    public <T> Pagelist<T> queryAsPagelist(PageInfo pageInfo, RowMapper<T> rowMapper, String sql, Object... parameters) {
        Validate.notNull(pageInfo, "pageInfo is null.");
        Validate.notNull(rowMapper, "rowMapper is null.");

        PagelistImpl<T> pagelist = new PagelistImpl<T>(pageInfo);
        if (pageInfo.getTotalCount() < 0) {
            String count_sql = DbUtils.get_sql_select_count(sql);
            int count = queryAsInt(count_sql, parameters);
            pagelist.setTotalCount(count);
        }

        List<T> items = Collections.emptyList();
        if (pagelist.getTotalCount() > 0) {
            String page_sql = dialect.sql_pagelist(sql, pagelist.getFirstResult(), pagelist.getPageSize());
            PagelistHandler<T> rsh = new PagelistHandler<T>(rowMapper);
            if (page_sql == null) {
                // 如果不支持分页，那么使用原始的分页方法 ResultSet.absolute(first)
                rsh.setFirstResult(pagelist.getFirstResult());
            } else {
                // 使用数据库自身的分页SQL语句，将直接返回某一个
                rsh.setFirstResult(0);
                sql = page_sql;
            }
            rsh.setMaxResults(pagelist.getPageSize());
            items = query(rsh, sql, parameters);
        }
        pagelist.setItems(items);

        return pagelist;
    }

    public <T> T query(ResultSetHandler<T> rsh, String sql, Object... parameters) {
        Validate.notNull(rsh, "rsh is null.");
        Validate.notNull(sql, "sql is null.");

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        T result = null;

        try {
            conn = getConnection();
            ps = PreparedStatementCreator.createPreparedStatement(conn, sql, parameters);
            rs = ps.executeQuery();
            result = rsh.handle(rs);
        } catch (SQLException e) {
            throw new DbException(e).set("sql", sql).set("parameters", parameters);
        } finally {
            DbUtils.closeQuietly(rs);
            DbUtils.closeQuietly(ps);
            closeConnection(conn);
        }

        return result;
    }

    public int execute(String sql, Object... parameters) {
        Validate.notNull(sql, "sql is null.");

        Connection conn = null;
        PreparedStatement ps = null;
        int rows = 0;

        try {
            conn = getConnection();
            ps = PreparedStatementCreator.createPreparedStatement(conn, sql, parameters);
            rows = ps.executeUpdate();
        } catch (SQLException e) {
            throw new DbException(e).set("sql", sql).set("parameters", parameters);
        } finally {
            DbUtils.closeQuietly(ps);
            closeConnection(conn);
        }

        return rows;
    }

    public int[] executeBatch(String sql, List<Object[]> parameters) {
        Validate.notNull(sql, "sql is null.");

        Connection conn = null;
        PreparedStatement ps = null;
        int[] rows;

        try {
            conn = getConnection();
            ps = conn.prepareStatement(sql);
            for (Object[] parameter : parameters) {
                for (int i = 0; i < parameter.length; i++) {
                    ps.setObject(i + 1, parameter[i]);
                }
                ps.addBatch();
            }
            rows = ps.executeBatch();
        } catch (SQLException e) {
            throw new DbException(e).set("sql", sql).set("parameters", parameters);
        } finally {
            DbUtils.closeQuietly(ps);
            closeConnection(conn);
        }

        return rows;
    }

    public void execute(ConnectionCallback callback) {
        Connection conn = null;
        try {
            conn = getConnection();
            callback.execute(conn);
        } catch (SQLException e) {
            throw new DbException(e);
        } finally {
            closeConnection(conn);
        }
    }

    /**
     * 判断表是否已经存在
     */
    public boolean tableExist(String name) {
        Connection conn = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            DatabaseMetaData metaData = conn.getMetaData();
            rs = metaData.getTables(null, null, name.toUpperCase(), new String[] { "TABLE" });
            return rs.next();
        } catch (SQLException e) {
            throw new DbException(e);
        } finally {
            DbUtils.closeQuietly(rs);
            closeConnection(conn);
        }
    }

    public SqlDialect getDialect() {
        return dialect;
    }

    private SqlDialect doGetDialet() {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            String name = conn.getMetaData().getDatabaseProductName();
            return SqlDialect.getDialect(name);
        } catch (SQLException e) {
            throw new DbException(e);
        } finally {
            DbUtils.closeQuietly(conn);
        }
    }

    public <T> RowMapper<T> getRowMapper(Class<T> beanClass) {
        RowMapper<T> rowMapper;
        if (beanClass.isArray()) {
            rowMapper = (RowMapper<T>) new ArrayRowMapper();
        } else if (beanClass.getName().equals("java.util.Map")) {
            rowMapper = (RowMapper<T>) new MapRowMapper();
        } else if (beanClass.getName().startsWith("java.")) {
            rowMapper = new SingleColumnRowMapper<T>(beanClass);
        } else {
            rowMapper = new BeanRowMapper<T>(beanClass);
        }
        return rowMapper;
    }
}