001/* 002 * Copyright (C) 2016 Hobrasoft s.r.o. 003 * 004 * This program is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU Affero General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU Affero General Public License for more details. 013 * 014 * You should have received a copy of the GNU Affero General Public License 015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 016 */ 017package cz.hobrasoft.pdfmu.operation; 018 019import cz.hobrasoft.pdfmu.PdfmuUtils; 020import cz.hobrasoft.pdfmu.WritingMapper; 021import cz.hobrasoft.pdfmu.error.ErrorType; 022import cz.hobrasoft.pdfmu.jackson.RpcError; 023import cz.hobrasoft.pdfmu.jackson.RpcError.Data; 024import cz.hobrasoft.pdfmu.jackson.RpcResponse; 025import java.io.IOException; 026import java.util.Map; 027import java.util.logging.Logger; 028import org.apache.commons.lang3.text.StrSubstitutor; 029 030/** 031 * This exception is thrown by {@link Operation#execute(Namespace)} to notify 032 * {@link cz.hobrasoft.pdfmu.Main#main(String[])} that the operation has 033 * encountered a condition it cannot recover from. 034 * 035 * @author <a href="mailto:filip.bartek@hobrasoft.cz">Filip Bartek</a> 036 */ 037public class OperationException extends Exception { 038 039 private static final Logger logger = Logger.getLogger(OperationException.class.getName()); 040 041 // Configuration 042 private static final int defaultErrorCode = -1; 043 044 private ErrorType errorType = null; 045 private Map<String, Object> messageArguments = null; 046 047 public OperationException(ErrorType errorType) { 048 super(errorType.toString()); 049 init(errorType, null); 050 } 051 052 public OperationException(ErrorType errorType, Map.Entry<String, Object>... entries) { 053 super(errorType.toString()); 054 init(errorType, PdfmuUtils.sortedMap(entries)); 055 } 056 057 public OperationException(ErrorType errorType, Map<String, Object> messageArguments) { 058 super(errorType.toString()); 059 init(errorType, messageArguments); 060 } 061 062 public OperationException(ErrorType errorType, Throwable cause) { 063 super(errorType.toString(), cause); 064 init(errorType, null); 065 } 066 067 public OperationException(ErrorType errorType, Throwable cause, Map.Entry<String, Object>... entries) { 068 super(errorType.toString(), cause); 069 init(errorType, PdfmuUtils.sortedMap(entries)); 070 } 071 072 /** 073 * Creates a chained operation exception with error identifier and message 074 * arguments. 075 * 076 * @param errorType the error identifier. 077 * @param cause the original cause. 078 * @param messageArguments the arguments of the message. 079 */ 080 public OperationException(ErrorType errorType, Throwable cause, Map<String, Object> messageArguments) { 081 super(errorType.toString(), cause); 082 init(errorType, messageArguments); 083 } 084 085 private void init(ErrorType errorType, Map<String, Object> messageArguments) { 086 assert errorType != null; 087 this.errorType = errorType; 088 this.messageArguments = messageArguments; 089 } 090 091 /** 092 * Returns the error code associated with this exception 093 * 094 * <p> 095 * The code should uniquely identify the error that caused the exception. 096 * 097 * @return the error code associated with this exception 098 */ 099 public int getCode() { 100 if (errorType != null) { 101 return errorType.getCode(); 102 } else { 103 return defaultErrorCode; 104 } 105 } 106 107 @Override 108 public String getLocalizedMessage() { 109 if (errorType != null) { 110 String pattern = errorType.getMessagePattern(); 111 if (pattern != null) { 112 StrSubstitutor sub = new StrSubstitutor(messageArguments); 113 return sub.replace(pattern); 114 } else { 115 return super.getLocalizedMessage(); 116 } 117 } else { 118 return super.getLocalizedMessage(); 119 } 120 } 121 122 private RpcError getRpcError() { 123 RpcError re = new RpcError(getCode(), getLocalizedMessage()); 124 Throwable cause = getCause(); 125 if (cause != null || messageArguments != null) { 126 re.data = new Data(); 127 if (cause != null) { 128 re.data.causeClass = cause.getClass(); 129 re.data.causeMessage = cause.getLocalizedMessage(); 130 } 131 re.data.arguments = messageArguments; 132 } 133 return re; 134 } 135 136 public void writeInWritingMapper(WritingMapper wm) { 137 RpcResponse response = new RpcResponse(getRpcError()); 138 139 try { 140 wm.writeValue(response); 141 } catch (IOException ex) { 142 logger.severe("Could not write JSON output."); 143 } 144 } 145}