All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almworks.jira.structure.api.StructureException Maven / Gradle / Ivy

There is a newer version: 17.25.3
Show newest version
package com.almworks.jira.structure.api;

import com.almworks.jira.structure.api2g.item.ItemIdentity;
import com.almworks.jira.structure.util.StructureUtil;
import com.atlassian.crowd.embedded.api.User;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.user.ApplicationUser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Locale;

/**
 * 

{@code StructureException} can be thrown for different causes that involve Structure plugin. It usually means that the * operation that is traced back to the user's action, cannot be performed and should be reported as error.

* *

Each exception is associated with a specific value from enumeration {@link StructureError}. Exception may also * carry additional message description and information about affected structure, view or issue. The general method * {@link #getMessage()}, returns all information included with the exception, except for the stack trace and cause. *

* *

Displaying User-Friendly Errors

* *

To display an error on the user interface: use {@link #getLocalizedMessage()} or {@link #getLocalizedMessage(com.atlassian.crowd.embedded.api.User)} * to get a human-friendly error in the user's locale. However, in many cases the error message will not be localized * and the result of {@code getLocalizedMessage()} will contain the problem description as a developer had put it in English. * (It might not be human-friendly even for English audience!)

* *

So for the best result, you should check {@link #isLocalized()} * method and if exception is not localized, use some wrapper text to display the error to the user in a good way: *

* *
 * Java code:
 *   try {
 *     ...
 *   } catch (StructureException e) {
 *     if (e.isLocalized()) {
 *       setDisplayedError(e.getLocalizedMessage());
 *     } else {
 *       setDisplayedError(getText("my.errors.structure-error", e.getLocalizedMessage()));
 *     }
 *   }
 *
 * I18N Properties:
 *  my.errors.structure-error=Some problem happened with structure, sorry! ({0})
 * 
* *

Throwing StructureException

* *

An instance of {@code StructureException} may be created by using one of the available constructors, but * it might be more convenient to start from {@link StructureError} and use chained builder commands, ending with * message specification:

* *
 *   throw StructureError.GENERIC_ERROR.withMessage("cannot foo bar");
 *   ...
 *   throw StructureError.INVALID_JQL.causedBy(caughtException).forStructure(id).withoutMessage();
 *   ...
 *   throw StructureError.VIEW_EDIT_DENIED.forView(id).withLocalizedMessage("error.view.edit.denied", id, name);
 * 
* * @see StructureError */ public class StructureException extends Exception { // used by tests to avoid exceptions private static final boolean ISSUE_LOOKUP_DISABLED = "true".equalsIgnoreCase(System.getProperty("structure.exception.disable.lookup")); private final StructureError myError; private final String myProblemDetails; private final long myStructure; private final long myView; private final long myIssue; private final ItemIdentity myItemId; private final String myMessageKey; private final Object[] myMessageParameters; /** * Constructs an instance of exception. * * @param error structure error code */ public StructureException(@Nullable StructureError error) { this(error, null, null, null, null, null, null, null); } /** * Constructs an instance of exception. * * @param error structure error code * @param message additional message text */ public StructureException(@Nullable StructureError error, @Nullable String message) { this(error, null, null, null, null, null, message, null); } /** * Constructs an instance of exception. * * @param error structure error code * @param structure structure in question */ public StructureException(@Nullable StructureError error, @Nullable Long structure) { this(error, null, structure, null, null, null, null, null); } /** * Constructs an instance of exception. * * @param error structure error code * @param structure structure in question * @param issue related issue */ public StructureException(@Nullable StructureError error, @Nullable Long structure, @Nullable Long issue) { this(error, null, structure, null, issue, null, null, null); } /** * Constructs an instance of exception. * * @param error structure error code * @param structure structure in question * @param issue related issue * @param message additional message text */ public StructureException(@Nullable StructureError error, @Nullable Long structure, @Nullable Long issue, @Nullable String message) { this(error, null, structure, null, issue, null, message, null); } /** * Constructs an instance of exception. For convenience, use one of the overloaded constructors. * * @param error structure error code * @param structure structure in question * @param issue related issue * @param message additional message text * @param cause throwable cause */ public StructureException(@Nullable StructureError error, @Nullable Long structure, @Nullable Long issue, @Nullable String message, @Nullable Throwable cause) { this(error, cause, structure, null, issue, null, message, null); } public StructureException(@Nullable StructureError error, @Nullable Long structure, @Nullable Long issue, @Nullable Long view) { this(error, null, structure, view, issue, null, null, null); } public StructureException(@Nullable StructureError error, @Nullable Long structure, @Nullable Long issue, @Nullable Long view, @Nullable String message) { this(error, null, structure, view, issue, null, message, null); } protected StructureException(StructureError error, @Nullable Throwable cause, @Nullable Long structure, @Nullable Long view, @Nullable Long issue, @Nullable ItemIdentity itemId, @Nullable String message, @Nullable String messageKey, @Nullable Object... messageParameters) { super(createMessage(error, structure, view, issue, message, messageKey, messageParameters), cause); myError = error == null ? StructureError.GENERIC_ERROR : error; // avoid double calculation of root-locale message by providing message that already contains it String details = createDetails(message, messageKey, messageParameters); myProblemDetails = details.isEmpty() ? "error " + myError : details; myStructure = structure == null ? 0L : structure; myView = view == null ? 0L : view; myIssue = issue == null ? 0L : issue; myItemId = itemId; myMessageKey = messageKey; myMessageParameters = messageParameters; } private static String createMessage(StructureError error, Long structure, Long view, Long issue, @Nullable String message, @Nullable String messageKey, @Nullable Object... messageParameters) { StringBuilder b = new StringBuilder(); if (error == null) error = StructureError.GENERIC_ERROR; String details = createDetails(message, messageKey, messageParameters); if (!details.isEmpty()) b.append(details).append(" - "); b.append("structure ").append(error.name()).append(" (code:").append(error.getCode()); if (structure != null && structure > 0) b.append(" structure:").append(structure); if (view != null && view > 0) b.append(" view:").append(view); if (issue != null && issue > 0) { b.append(" issue:").append(issue); if (!ISSUE_LOOKUP_DISABLED) { appendIssueKey(b, issue); } } b.append(')'); return b.toString(); } @NotNull private static String createDetails(String message, String messageKey, Object... messageParameters) { if (message == null) { message = getRootLocaleMessage(messageKey, messageParameters); if (message == null) message = ""; } return message; } private static void appendIssueKey(StringBuilder b, Long issue) { try { IssueManager issueManager = ComponentAccessor.getIssueManager(); MutableIssue io = issueManager.getIssueObject(issue); if (io != null) b.append(" key:").append(io.getKey()); } catch (ThreadDeath e) { throw e; } catch (Throwable e) { // ignore } } private static String getRootLocaleMessage(String messageKey, Object... messageParameters) { // we could use Locale.ROOT here, but it won't work in development environment because there's no StructureMessages.properties try { return StructureUtil.getText(Locale.ENGLISH, null, messageKey, messageParameters); } catch (ThreadDeath e) { throw e; } catch (Throwable e) { // protect from errors and exceptions in the exception initializer return ""; } } // overriding default toString(), which uses getLocalizedMessage() public String toString() { String s = getClass().getName(); String message = getMessage(); return message != null ? s + ": " + message : s; } /** * @return error code */ public StructureError getError() { return myError; } /** * @return the part of {@link #getMessage()} that corresponds to the original description of the problem. * Does not contain structure ID, error code, and related issue information, so is more user-friendly than {@link #getMessage()} * in case when that information can be more suitably described by the caller. * */ public String getProblemDetails() { return myProblemDetails; } /** * @return related structure, or 0 if no structure is related */ public long getStructure() { return myStructure; } public long getView() { return myView; } /** * @return related issue, or 0 if no issue is related */ public long getIssue() { return myIssue; } public ItemIdentity getItemId() { return myItemId; } public boolean isLocalized() { return myMessageKey != null; } @Override public String getLocalizedMessage() { return isLocalized() ? StructureUtil.getTextInCurrentUserLocale(myMessageKey, myMessageParameters) : getProblemDetails(); } public String getLocalizedMessage(@Nullable User user) { return isLocalized() ? StructureUtil.getText(null, user, myMessageKey, myMessageParameters) : getProblemDetails(); } public String getLocalizedMessage(@Nullable ApplicationUser user) { return isLocalized() ? StructureUtil.getText2(null, user, myMessageKey, myMessageParameters) : getProblemDetails(); } public static class Builder { private StructureError myError; private String myMessage; private Long myStructure; private Long myView; private Long myIssue; private ItemIdentity myItemId; private String myMessageKey; private Object[] myMessageParameters; private Throwable myCause; public Builder(StructureError error) { myError = error; } public StructureException withLocalizedMessage(String messageKey, Object... messageParameters) { myMessage = messageKey == null ? "" : getRootLocaleMessage(messageKey, messageParameters); myMessageKey = messageKey; myMessageParameters = messageParameters; return build(); } public StructureException withMessage(String message) { myMessage = message; myMessageKey = null; myMessageParameters = null; return build(); } public StructureException withoutMessage() { myMessage = null; myMessageKey = null; myMessageParameters = null; return build(); } public Builder forStructure(Long structure) { myStructure = structure; return this; } public Builder forView(Long view) { myView = view; return this; } public Builder forIssue(Long issue) { myIssue = issue; return this; } public Builder forItem(ItemIdentity itemId) { myItemId = itemId; return this; } public Builder causedBy(Throwable cause) { myCause = cause; return this; } private StructureException build() { return new StructureException(myError, myCause, myStructure, myView, myIssue, myItemId, myMessage, myMessageKey, myMessageParameters); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy