mitm.djigzo.web.components.CertificateGrid.java Source code

Java tutorial

Introduction

Here is the source code for mitm.djigzo.web.components.CertificateGrid.java

Source

/*
 * Copyright (c) 2008-2012, Martijn Brinkers, Djigzo.
 * 
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3, 19 November 2007 as published by the Free Software 
 * Foundation.
 *
 * Djigzo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public 
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 * 
 * If you modify this Program, or any covered work, by linking or 
 * combining it with saaj-api-1.3.jar, saaj-impl-1.3.jar, 
 * wsdl4j-1.6.1.jar (or modified versions of these libraries), 
 * containing parts covered by the terms of Common Development and 
 * Distribution License (CDDL), Common Public License (CPL) the 
 * licensors of this Program grant you additional permission to 
 * convey the resulting work.
 */
package mitm.djigzo.web.components;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import mitm.application.djigzo.ws.CertificateValidatorResult;
import mitm.common.util.CollectionUtils;
import mitm.common.ws.WebServiceCheckedException;
import mitm.djigzo.web.beans.X509CertificateBean;
import mitm.djigzo.web.common.YesNo;
import mitm.djigzo.web.grid.AbstractCertificateGridDataSource;

import org.apache.commons.lang.StringUtils;
import org.apache.tapestry5.Asset;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentEventCallback;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.IncludeStylesheet;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.corelib.components.Grid;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.BeanModelSource;

@IncludeStylesheet("context:styles/components/certificateGrid.css")
public class CertificateGrid {
    /*
     * All column names
     */
    public static final String SELECT_COLUMN = "select";
    public static final String DELETE_COLUMN = "delete";
    public static final String EMAIL_COLUMN = "email";
    public static final String SUBJECT_COLUMN = "subject";
    public static final String NOT_BEFORE_COLUMN = "notBefore";
    public static final String NOT_AFTER_COLUMN = "notAfter";
    public static final String EXPIRED_COLUMN = "expired";
    public static final String KEY_USAGE_COLUMN = "keyUsage";
    public static final String EXTENDED_KEY_USAGE_COLUMN = "extendedKeyUsage";
    public static final String ISSUER_COLUMN = "issuer";
    public static final String SERIAL_NUMBER_HEX_COLUMN = "serialNumberHex";
    public static final String THUMBPRINT_SHA1_COLUMN = "thumbprintSHA1";
    public static final String CA_COLUMN = "ca";
    public static final String PATH_LENGTH_CONSTRAINT = "pathLengthConstraint";
    public static final String SUBJECT_KEY_IDENTIFIER_COLUMN = "subjectKeyIdentifier";
    public static final String THUMBPRINT_COLUMN = "thumbprint";
    public static final String PUBLIC_KEY_LENGTH_COLUMN = "publicKeyLength";
    public static final String PUBLIC_KEY_ALGORITHM_COLUMN = "publicKeyAlgorithm";
    public static final String SIGNATURE_ALGORITHM_COLUMN = "signatureAlgorithm";
    public static final String URI_DISTRIBUTION_POINT_NAMES_COLUMN = "uRIDistributionPointNames";
    public static final String KEYALIAS_COLUMN = "keyalias";
    public static final String CTL_STATUS_COLUMN = "ctlStatus";
    public static final String INFO_COLUMN = "info";

    /*
     * All events
     */
    public static final String DELETE_EVENT = "certificateGrid-delete";
    public static final String SUBJECT_CLICKED_EVENT = "certificateGrid-subjectClicked";
    public static final String CERTIFICATE_VALIDATOR_RESULT_EVENT = "certificateGrid-certificateValidatorResult";
    public static final String IS_DISABLED_EVENT = "certificateGrid-isDisabled";
    public static final String IN_USE_EVENT = "certificateGrid-inUse";
    public static final String ROW_CLASS_EVENT = "certificateGrid-rowClass";

    @Parameter(required = true)
    private AbstractCertificateGridDataSource source;

    @Parameter(value = "certificate-not-trusted", defaultPrefix = BindingConstants.LITERAL)
    private String notTrustedRowClass;

    @Parameter(defaultPrefix = BindingConstants.LITERAL)
    private String trustedRowClass;

    @Parameter(value = "certificate-revoked", defaultPrefix = BindingConstants.LITERAL)
    private String revokedRowClass;

    /*
     * The certificate currently being drawn by the grid (is set by the grid component)
     */
    private X509CertificateBean certificate;

    /*
     * Stores the CertificateValidatorResult for the current certificate because we
     * need it more than once and it is an expensive call.
     */
    private CertificateValidatorResult certificateValidatorResult;

    /*
     * The certificate for which the CertificateValidatorResult was cached.
     */
    private X509CertificateBean cachedForCertificate;

    @Parameter(defaultPrefix = BindingConstants.LITERAL, value = SELECT_COLUMN + "," + DELETE_COLUMN + ","
            + EMAIL_COLUMN + "," + SUBJECT_COLUMN + "," + EXPIRED_COLUMN + "," + NOT_BEFORE_COLUMN + ","
            + NOT_AFTER_COLUMN + "," + KEY_USAGE_COLUMN + "," + EXTENDED_KEY_USAGE_COLUMN + "," + ISSUER_COLUMN
            + "," + SERIAL_NUMBER_HEX_COLUMN + "," + THUMBPRINT_SHA1_COLUMN + "," + CA_COLUMN + ","
            + PATH_LENGTH_CONSTRAINT + "," + SUBJECT_KEY_IDENTIFIER_COLUMN + "," + THUMBPRINT_COLUMN + ","
            + SIGNATURE_ALGORITHM_COLUMN + "," + PUBLIC_KEY_LENGTH_COLUMN + "," + PUBLIC_KEY_ALGORITHM_COLUMN + ","
            + URI_DISTRIBUTION_POINT_NAMES_COLUMN + "," + KEYALIAS_COLUMN + "," + CTL_STATUS_COLUMN + ","
            + INFO_COLUMN)
    private String reorder;

    @Parameter(defaultPrefix = BindingConstants.LITERAL)
    private String exclude;

    /*
     * The grid will be volatile because the checkbox states will be set using Ajax.
     */
    @SuppressWarnings("unused")
    @Component(parameters = { "source = source", "model = model", "row = certificate", "rowClass = rowClass",
            "reorder = prop:reorder", "rowsPerPage = inherit:rowsPerPage", "pagerPosition = inherit:pagerPosition",
            "exclude = prop:exclude", "volatile = true" })
    private Grid grid;

    @Inject
    private BeanModelSource beanModelSource;

    @Inject
    private ComponentResources resources;

    @Inject
    @Path("context:icons/cross.png")
    private Asset deleteAsset;

    @Inject
    @Path("context:icons/key.png")
    private Asset keyAsset;

    @Inject
    @Path("context:icons/exclamation.png")
    private Asset keyNotAccessibleAsset;

    @Inject
    @Path("context:icons/whitelisted.png")
    private Asset whitelistedAsset;

    @Inject
    @Path("context:icons/blacklisted.png")
    private Asset blacklistedAsset;

    public void setCertificate(X509CertificateBean certificate) {
        this.certificate = certificate;

        /*
         * Reset the cached certificateValidatorResult because we have a new certificate
         */
        certificateValidatorResult = null;
    }

    public X509CertificateBean getCertificate() {
        return certificate;
    }

    public AbstractCertificateGridDataSource getSource() {
        return source;
    }

    public Asset getDeleteAsset() {
        return deleteAsset;
    }

    public Asset getKeyAsset() {
        return keyAsset;
    }

    public Asset getKeyNotAccessibleAsset() {
        return keyNotAccessibleAsset;
    }

    public Asset getWhitelistedAsset() {
        return whitelistedAsset;
    }

    public Asset getBlacklistedAsset() {
        return blacklistedAsset;
    }

    public CertificateValidatorResult getCertificateValidatorResult() throws WebServiceCheckedException {
        return getCertificateValidatorResult(certificate);
    }

    public CertificateValidatorResult getCertificateValidatorResult(X509CertificateBean certificate)
            throws WebServiceCheckedException {
        if (certificateValidatorResult != null && certificate != null && certificate.equals(cachedForCertificate)) {
            /* We have a cached value. */
            return certificateValidatorResult;
        }

        /*
         * The default result to use when there is not event handler
         */
        certificateValidatorResult = new CertificateValidatorResult(false, false, true, false, false,
                "Unknown status.");

        final List<CertificateValidatorResult> resultHolder = new LinkedList<CertificateValidatorResult>();

        ComponentEventCallback<CertificateValidatorResult> callback = new ComponentEventCallback<CertificateValidatorResult>() {
            @Override
            public boolean handleResult(CertificateValidatorResult result) {
                resultHolder.add(result);

                return true;
            }
        };

        resources.triggerEvent(CERTIFICATE_VALIDATOR_RESULT_EVENT, new Object[] { certificate }, callback);

        if (resultHolder.size() > 0) {
            certificateValidatorResult = resultHolder.get(0);

            cachedForCertificate = certificate;
        }

        return certificateValidatorResult;
    }

    protected boolean isDisabled(String column) {
        boolean disabled = false;

        final List<YesNo> resultHolder = new LinkedList<YesNo>();

        ComponentEventCallback<YesNo> callback = new ComponentEventCallback<YesNo>() {
            @Override
            public boolean handleResult(YesNo result) {
                resultHolder.add(result);

                return true;
            }
        };

        resources.triggerEvent(IS_DISABLED_EVENT, new Object[] { certificate, column }, callback);

        if (resultHolder.size() > 0) {
            disabled = resultHolder.get(0) == YesNo.YES;
        }

        return disabled;
    }

    /*
     * Returns true if the currently handled certificate is in use 
     */
    public boolean isInUse() {
        boolean inUse = false;

        if (certificate != null) {
            inUse = isInUse(certificate.getThumbprint());
        }

        return inUse;
    }

    /**
     * Returns true if certificate with thumbprint is in use 
     */
    public boolean isInUse(String thumbprint) {
        boolean inUse = false;

        final List<YesNo> resultHolder = new LinkedList<YesNo>();

        ComponentEventCallback<YesNo> callback = new ComponentEventCallback<YesNo>() {
            @Override
            public boolean handleResult(YesNo result) {
                resultHolder.add(result);

                return true;
            }
        };

        resources.triggerEvent(IN_USE_EVENT, new Object[] { thumbprint }, callback);

        if (resultHolder.size() > 0) {
            inUse = resultHolder.get(0) == YesNo.YES;
        }

        return inUse;
    }

    protected String fireRowClassEvent(CertificateValidatorResult certificateValidatorResult) {
        String rowClass = null;

        final List<String> resultHolder = new LinkedList<String>();

        ComponentEventCallback<String> callback = new ComponentEventCallback<String>() {
            @Override
            public boolean handleResult(String result) {
                resultHolder.add(result);

                return true;
            }
        };

        resources.triggerEvent(ROW_CLASS_EVENT, new Object[] { certificate, certificateValidatorResult }, callback);

        if (resultHolder.size() > 0) {
            rowClass = resultHolder.get(0);
        }

        return rowClass;
    }

    public String getRowClass() throws WebServiceCheckedException {
        CertificateValidatorResult certificateValidatorResult = getCertificateValidatorResult(certificate);

        String rowClass = fireRowClassEvent(certificateValidatorResult);

        if (StringUtils.isEmpty(rowClass)) {
            /*
             * The event did not return a rowClass so use default
             */
            if (certificateValidatorResult.isRevoked()) {
                return revokedRowClass;
            }

            rowClass = certificateValidatorResult.isValid() ? trustedRowClass : notTrustedRowClass;
        }

        return rowClass;
    }

    public String getInfo() throws WebServiceCheckedException {
        return getCertificateValidatorResult(certificate).getFailureMessage();
    }

    public String getCTLStatus() throws WebServiceCheckedException {
        CertificateValidatorResult validatorResult = getCertificateValidatorResult(certificate);

        if (validatorResult.isWhiteListed()) {
            return "whitelisted";
        } else if (validatorResult.isBlackListed()) {
            return "blacklisted";
        }

        return null;
    }

    public BeanModel<X509CertificateBean> getModel() {
        BeanModel<X509CertificateBean> model = beanModelSource.createDisplayModel(X509CertificateBean.class,
                resources.getMessages());

        model.add(DELETE_COLUMN, null);
        model.add(SELECT_COLUMN, null);
        model.add(CTL_STATUS_COLUMN, null);
        model.add(INFO_COLUMN, null);

        /*
         * Disable all sorting
         */
        for (String column : model.getPropertyNames()) {
            model.get(column).sortable(false);
        }

        return model;
    }

    @OnEvent(component = "deleteCertificate")
    protected void deleteCertificate(String thumbprint) {
        resources.triggerEvent(DELETE_EVENT, new Object[] { thumbprint }, null);
    }

    @OnEvent(component = "subjectLink")
    protected void viewCertificate(String thumbprint) {
        resources.triggerEvent(SUBJECT_CLICKED_EVENT, new Object[] { thumbprint }, null);
    }

    public String getReorder() {
        if (exclude == null) {
            return reorder;
        }
        /*
         * We need to remove all columns that are excluded because the Grid does not allow
         * a column to be on the reorder list and on the exclude list.
         * 
         * I have reported an issue about this:
         *       https://issues.apache.org/jira/browse/TAPESTRY-2564
         */
        Set<String> allItems = CollectionUtils.asLinkedHashSet(reorder.split("\\s*,\\s*"));

        Set<String> toRemove = CollectionUtils.asLinkedHashSet(exclude.split("\\s*,\\s*"));

        allItems.removeAll(toRemove);

        return StringUtils.join(allItems, ",");
    }

    public String getExclude() {
        return exclude;
    }

    public boolean isSelectDisabled() {
        return isDisabled(SELECT_COLUMN);
    }
}