001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2016-2026 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 013 * License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along 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 public static <T extends Error> T duplicate(T event) { 063 try { 064 return (T) event.getClass().getConstructor(event.getClass()) 065 .newInstance(event); 066 } catch (InstantiationException | IllegalAccessException 067 | IllegalArgumentException | InvocationTargetException 068 | NoSuchMethodException | SecurityException e) { 069 throw new IllegalArgumentException(e); 070 } 071 } 072 073 /** 074 * Creates a new event. 075 * 076 * @param event the event being processed when the problem occurred 077 * @param message the message 078 */ 079 public Error(Event<?> event, String message) { 080 this.event = event; 081 this.message = message; 082 } 083 084 /** 085 * Creates a new event caused by the given throwable. 086 * 087 * @param event the event being processed when the problem occurred 088 * @param message the message 089 * @param throwable the throwable 090 */ 091 public Error(Event<?> event, String message, Throwable throwable) { 092 this.event = event; 093 this.message = message; 094 this.throwable = throwable; 095 } 096 097 /** 098 * Creates a new event caused by the given throwable. The message 099 * is initialized from the throwable. 100 * 101 * @param event the event being processed when the problem occurred 102 * @param throwable the throwable 103 */ 104 public Error(Event<?> event, Throwable throwable) { 105 this.event = event; 106 this.message = throwable.getMessage() == null 107 ? throwable.getClass().getName() 108 : throwable.getMessage(); 109 this.throwable = throwable; 110 } 111 112 /** 113 * Returns the event that was handled when the problem occurred. 114 * 115 * @return the event 116 */ 117 public Event<?> event() { 118 return event; 119 } 120 121 /** 122 * Returns the message passed to the constructor. 123 * 124 * @return the message 125 */ 126 public String message() { 127 return message; 128 } 129 130 /** 131 * Returns the throwable that caused the problem. 132 * 133 * @return the throwable or {@code null} if the problem wasn't caused 134 * by a throwable. 135 */ 136 public Throwable throwable() { 137 return throwable; 138 } 139 140 /* 141 * (non-Javadoc) 142 * 143 * @see java.lang.Object#toString() 144 */ 145 @Override 146 public String toString() { 147 StringBuilder builder = new StringBuilder(50); 148 builder.append(Components.objectName(this)) 149 .append(" ["); 150 if (channels().length > 0) { 151 builder.append("channels=").append(Channel.toString(channels())); 152 } 153 if (message != null) { 154 builder.append(", message=\"").append(message).append('"'); 155 } 156 if (event != null) { 157 builder.append(", caused by: ").append(event.toString()); 158 } 159 builder.append(']'); 160 return builder.toString(); 161 } 162}