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