001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2016-2018 Michael N. Lipp 004 * 005 * This program is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU Affero General Public License as published by 007 * the Free Software Foundation; either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 013 * for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License along 016 * with this program; if not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jgrapes.core.events; 020 021import java.lang.reflect.InvocationTargetException; 022import org.jgrapes.core.Channel; 023import org.jgrapes.core.Components; 024import org.jgrapes.core.Event; 025 026/** 027 * This event signals that an error occurred while processing an event. 028 */ 029public class Error extends Event<Void> { 030 031 private final Event<?> event; 032 private final String message; 033 private Throwable throwable; 034 035 /** 036 * Creates a new event as a copy of an existing event. Useful 037 * for forwarding an event. Constructors "`<T extend Error> T(T event)`" 038 * must be implemented by all derived classes. 039 * 040 * @param event the event to copy 041 */ 042 public Error(Error event) { 043 this.event = event.event; 044 this.message = event.message; 045 this.throwable = event.throwable; 046 } 047 048 /** 049 * Duplicate the event. Returns a new event with the same class 050 * and the same properties of the given event. Relies on the 051 * proper implementation of constructors "`<T extend Error> T(T event)`" 052 * for derived classes. 053 * 054 * Creating a duplicate id useful for forwarding a derived `Error` while 055 * handling a base class. 056 * 057 * @param <T> the generic type 058 * @param event the event 059 * @return the t 060 */ 061 @SuppressWarnings({ "unchecked", 062 "PMD.AvoidThrowingNewInstanceOfSameException" }) 063 public static <T extends Error> T duplicate(T event) { 064 try { 065 return (T) event.getClass().getConstructor(event.getClass()) 066 .newInstance(event); 067 } catch (InstantiationException | IllegalAccessException 068 | IllegalArgumentException | InvocationTargetException 069 | NoSuchMethodException | SecurityException e) { 070 throw new IllegalArgumentException(e); 071 } 072 } 073 074 /** 075 * Creates a new event. 076 * 077 * @param event the event being processed when the problem occurred 078 * @param message the message 079 */ 080 public Error(Event<?> event, String message) { 081 this.event = event; 082 this.message = message; 083 } 084 085 /** 086 * Creates a new event caused by the given throwable. 087 * 088 * @param event the event being processed when the problem occurred 089 * @param message the message 090 * @param throwable the throwable 091 */ 092 public Error(Event<?> event, String message, Throwable throwable) { 093 this.event = event; 094 this.message = message; 095 this.throwable = throwable; 096 } 097 098 /** 099 * Creates a new event caused by the given throwable. The message 100 * is initialized from the throwable. 101 * 102 * @param event the event being processed when the problem occurred 103 * @param throwable the throwable 104 */ 105 public Error(Event<?> event, Throwable throwable) { 106 this.event = event; 107 this.message = throwable.getMessage() == null 108 ? throwable.getClass().getName() 109 : throwable.getMessage(); 110 this.throwable = throwable; 111 } 112 113 /** 114 * Returns the event that was handled when the problem occurred. 115 * 116 * @return the event 117 */ 118 public Event<?> event() { 119 return event; 120 } 121 122 /** 123 * Returns the message passed to the constructor. 124 * 125 * @return the message 126 */ 127 public String message() { 128 return message; 129 } 130 131 /** 132 * Returns the throwable that caused the problem. 133 * 134 * @return the throwable or {@code null} if the problem wasn't caused 135 * by a throwable. 136 */ 137 public Throwable throwable() { 138 return throwable; 139 } 140 141 /* 142 * (non-Javadoc) 143 * 144 * @see java.lang.Object#toString() 145 */ 146 @Override 147 public String toString() { 148 StringBuilder builder = new StringBuilder(50); 149 builder.append(Components.objectName(this)) 150 .append(" ["); 151 if (channels().length > 0) { 152 builder.append("channels="); 153 builder.append(Channel.toString(channels())); 154 } 155 if (message != null) { 156 builder.append(", message=\"").append(message).append('"'); 157 } 158 if (event != null) { 159 builder.append(", caused by: ").append(event.toString()); 160 } 161 builder.append(']'); 162 return builder.toString(); 163 } 164}