package org.sigmah.shared.dispatch; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import org.sigmah.client.i18n.I18N; import org.sigmah.client.util.ToStringBuilder; import com.google.gwt.core.client.GWT; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.rpc.IsSerializable; import org.sigmah.client.ui.notif.N10N; /** * <p> * Functional command exception. * </p> * <p> * Exception thrown by services when a <em>functional</em> issue is detected and an appropriate message should be * displayed. * </p> * * @author Denis Colliot (dcolliot@ideia.fr) */ public class FunctionalException extends CommandException { /** * The functional error codes with corresponding {@code i18n} messages. * * @author Denis Colliot (dcolliot@ideia.fr) */ public static enum ErrorCode implements IsSerializable { /** * Authentication failure.<br> * No parameters. *//** * Authentication failure.<br> * No parameters. */ AUTHENTICATION_FAILURE, // -- // Admin - OrgUnits. // -- /** * Cannot reference an OrgUnit's parent as itself. <br> * No parameters. */ ADMIN_MOVE_ORG_UNIT_ITSELF_AS_PARENT, /** * Cycle detected while moving an OrgUnit within its hierarchy. <br> * No parameters. */ ADMIN_MOVE_ORG_UNIT_CYCLE_DETECTED, /** * Cannot remove an OrgUnit with children. <br> * No parameters. */ ADMIN_REMOVE_ORG_UNIT_HAS_CHILDREN, /** * Cannot remove an OrgUnit with related projects. <br> * No parameters. */ ADMIN_REMOVE_ORG_UNIT_HAS_PROJECTS, /** * Cannot remove a <b>root</b> OrgUnit. <br> * No parameters. */ ADMIN_REMOVE_ORG_UNIT_IS_ROOT, /** * Cannot create a user with an existing email. <br> * {0} = existing email. */ ADMIN_USER_DUPLICATE_EMAIL, // -- // Admin - Backup // -- /** * Cannot create a new archive file. * {0} = Archive path. */ ADMIN_BACKUP_ARCHIVE_CREATION_FAILED, // -- // Project updates. // -- /** * Cannot update because access rights are insufficient. */ ACCESS_DENIED, /** * A conflict happened while modifying a project. * Parameters: * - a list of error messages. */ UPDATE_CONFLICT, // -- // Importation schemes. // -- /** * Cannot delete an importation scheme because it is linked to project * models or org unit models. <br> * No parameters. */ IMPORTATION_SCHEME_IS_LINKED, /** * A column reference defined for a variable is invalid. <br> * No parameters. */ IMPORT_INVALID_COLUMN_REFERENCE, ; } /** * Returns the functional exception message. * Method {@link FunctionalException#getParameter(int)} can be used to populate message dynamic parameters. * * @param exception * The functional exception that may embed message parameter(s). * @param errorCode * Functional error code (cannot be {@code null}). * @return the functional exception message. */ private static String getMessage(final FunctionalException exception, final ErrorCode errorCode) { switch (errorCode) { case AUTHENTICATION_FAILURE: return I18N.CONSTANTS.loginConnectErrorBadLogin(); case ADMIN_MOVE_ORG_UNIT_ITSELF_AS_PARENT: return I18N.CONSTANTS.adminOrgUnitMoveErrorItself(); case ADMIN_MOVE_ORG_UNIT_CYCLE_DETECTED: return I18N.CONSTANTS.adminOrgUnitMoveErrorCycle(); case ADMIN_REMOVE_ORG_UNIT_HAS_CHILDREN: return I18N.CONSTANTS.adminOrgUnitRemoveHasChildren(); case ADMIN_REMOVE_ORG_UNIT_HAS_PROJECTS: return I18N.CONSTANTS.adminOrgUnitRemoveHasProjects(); case ADMIN_REMOVE_ORG_UNIT_IS_ROOT: return I18N.CONSTANTS.adminOrgUnitRemoveIsRoot(); case ADMIN_USER_DUPLICATE_EMAIL: return I18N.MESSAGES.existingEmailAddress(exception.getParameter(0)); case ADMIN_BACKUP_ARCHIVE_CREATION_FAILED: return I18N.MESSAGES.adminBackupArchiveCreationFailed(exception.getParameter(0)); case ACCESS_DENIED: return I18N.MESSAGES.accessDeniedError(exception.getParameter(0), exception.getParameter(1), exception.getParameter(2)); case UPDATE_CONFLICT: final SafeHtmlBuilder ulBuilder = new SafeHtmlBuilder(); ulBuilder.appendHtmlConstant("<ul class=\"" + N10N.CSS_LIST + "\">"); for(final String error : exception.parameters) { ulBuilder.appendHtmlConstant("<li>").appendEscapedLines(error).appendHtmlConstant("</li>"); } ulBuilder.appendHtmlConstant("</ul>"); return I18N.MESSAGES.conflictError(ulBuilder.toSafeHtml().asString()); case IMPORTATION_SCHEME_IS_LINKED: return I18N.MESSAGES.adminImportationSchemesWarnModelsLinked(exception.getParameter(0)); case IMPORT_INVALID_COLUMN_REFERENCE: return I18N.MESSAGES.importInvalidColumnReference(exception.getParameter(0)); default: return errorCode.toString(); } } /** * Returns the functional exception title. * Method {@link FunctionalException#getParameter(int)} can be used to populate title dynamic parameters. * * @param exception * The functional exception that may embed title parameter(s).. * @param errorCode * Functional error code (cannot be {@code null}). * @return the functional exception title, or {@code null} to use the default title. */ private static String getTitle(final FunctionalException exception, final ErrorCode errorCode) { switch (errorCode) { case ADMIN_MOVE_ORG_UNIT_ITSELF_AS_PARENT: case ADMIN_MOVE_ORG_UNIT_CYCLE_DETECTED: return I18N.CONSTANTS.adminOrgUnitMoveFailed(); case ADMIN_REMOVE_ORG_UNIT_HAS_CHILDREN: case ADMIN_REMOVE_ORG_UNIT_HAS_PROJECTS: case ADMIN_REMOVE_ORG_UNIT_IS_ROOT: return I18N.CONSTANTS.adminOrgUnitRemoveUnavailable(); default: return null; // Default title. } } /** * Serial version UID. */ private static final long serialVersionUID = -324930495914540987L; /** * This exception {@code errorType}. Cannot be {@code null} (assertion). * * @see ErrorCode */ private ErrorCode errorCode; /** * The error message relative parameters. Can be {@code null}. * They are used to populate dynamic message parameters (be careful with order). */ protected String[] parameters; protected FunctionalException() { // Serialization. } /** * Builds a {@link FunctionalException} according to the given message-relative {@link ErrorCode}. * * @param errorCode * See {@link #errorCode}. * @param parameters * See {@link #parameters}. */ public FunctionalException(ErrorCode errorCode, String... parameters) { this(null, errorCode, parameters); } /** * Builds a {@link FunctionalException} according to the given message-relative {@link ErrorCode}. * * @param cause * Exception that triggered this error. * @param errorCode * See {@link #errorCode}. * @param parameters * See {@link #parameters}. */ public FunctionalException(Throwable cause, ErrorCode errorCode, String... parameters) { super(cause); assert errorCode != null : "Error code is required."; this.errorCode = errorCode; this.parameters = parameters; } /** * {@inheritDoc} */ @Override public final String toString() { final ToStringBuilder builder = new ToStringBuilder(this); builder.append("Exception", "FunctionalException"); builder.append("Error code", errorCode); return builder.toString(); } /** * Returns the error message parameter specified at given {@code index}. * * @param index * The parameter index. * @return the error message parameter specified at given {@code index}. Returns {@code null} if no parameter has been * provided or {@code index} is out of bounds. * @see #parameters */ public final String getParameter(int index) { if (parameters == null || index >= parameters.length || index < 0) { return null; } return parameters[index]; } /** * Returns the number of parameters set into the current exception. * * @return the number of parameters set into the current exception. */ public final int getParameterCount() { return parameters != null ? parameters.length : 0; } /** * Returns the current functional exception corresponding {@link ErrorCode}. * * @return The {@link ErrorCode} (never {@code null}). */ public final ErrorCode getErrorCode() { return errorCode; } /** * Returns the functional error corresponding title (if any). * * @return The functional error corresponding title (if any), or {@code null}. */ public final String getTitle() { if (!GWT.isClient()) { return null; } return getTitle(this, errorCode); } /** * {@inheritDoc} */ @Override public final String getMessage() { if (!GWT.isClient()) { return toString(); // Displays exception class name and error code. } return getMessage(this, errorCode); } /** * Verify if the actual error is of the given type * * @param errorCode * Functional error code. * @return result of the comparison */ public final boolean is(ErrorCode errorCode) { return this.errorCode == errorCode; } }