001/* 002 * JGrapes Event Driven Framework 003 * Copyright (C) 2017-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.webconsole.base.events; 020 021import java.util.HashMap; 022import java.util.Map; 023import java.util.Set; 024import java.util.function.BiConsumer; 025import org.jgrapes.webconsole.base.Conlet.RenderMode; 026import org.jgrapes.webconsole.base.RenderSupport; 027 028/** 029 * Sent to the console (server) if a new web console component instance 030 * of a given type should be added to the web console page. The console 031 * server usually responds with a {@link RenderConlet} event that has as 032 * payload the HTML that displays the web console component on the console 033 * page. 034 * 035 * Properties may be passed with the event. The interpretation 036 * of the properties is completely dependent on the web console 037 * component that handles the request. It is recommended to use 038 * {@link String}s as keys and JDK types as values. This avoids 039 * classpath dependencies on the web console component that is 040 * to be added. 041 * 042 * {@link AddConletRequest} can also be generated on the server side 043 * to automatically add a conlet in response to some event. Usually, 044 * the origin of the event is not important when handling the event. 045 * Nevertheless, the origin can be determined by calling 046 * {@link #isFrontendRequest()} as it may be important e.g. for 047 * security related checks. 048 * 049 * The event's result is the web console component id of the new 050 * web console component instance. 051 * 052 * ![Event Sequence](AddConletRequestSeq.svg) 053 * 054 * @startuml AddConletRequestSeq.svg 055 * hide footbox 056 * 057 * Browser -> WebConsole: "addConlet" 058 * activate WebConsole 059 * WebConsole -> Conlet: AddConletRequest 060 * deactivate WebConsole 061 * activate Conlet 062 * Conlet -> WebConsole: RenderConlet 063 * deactivate Conlet 064 * activate WebConsole 065 * WebConsole -> Browser: "renderConlet" 066 * deactivate WebConsole 067 * 068 * @enduml 069 * 070 */ 071public class AddConletRequest extends RenderConletRequestBase<String> { 072 073 private final String conletType; 074 private Map<? extends Object, ? extends Object> properties; 075 private boolean frontendRequest; 076 077 /** 078 * Creates a new event. 079 * 080 * @param renderSupport the render support 081 * @param conletType the type of the web console component 082 * @param renderModes the render modes 083 */ 084 public AddConletRequest(RenderSupport renderSupport, String conletType, 085 Set<RenderMode> renderModes) { 086 super(renderSupport, renderModes); 087 this.conletType = conletType; 088 this.properties = new HashMap<>(); 089 } 090 091 /** 092 * Creates a new event. 093 * 094 * @param renderSupport the render support 095 * @param conletType the type of the web console component 096 * @param renderModes the render modes 097 * @param properties optional values for properties of the 098 * web console component instance 099 */ 100 public AddConletRequest(RenderSupport renderSupport, String conletType, 101 Set<RenderMode> renderModes, Map<?, ?> properties) { 102 this(renderSupport, conletType, renderModes); 103 this.properties = new HashMap<>(properties); 104 } 105 106 /** 107 * Marks this event as originating from the browser. 108 * 109 * @return the adds the conlet request 110 */ 111 @SuppressWarnings("PMD.LinguisticNaming") 112 public AddConletRequest setFrontendRequest() { 113 frontendRequest = true; 114 return this; 115 } 116 117 /** 118 * Checks if this request originated from the browser. 119 * 120 * @return true, if is frontend request 121 */ 122 public boolean isFrontendRequest() { 123 return frontendRequest; 124 } 125 126 /** 127 * Returns the web console component type 128 * 129 * @return the web console component type 130 */ 131 public String conletType() { 132 return conletType; 133 } 134 135 /** 136 * Returns the properties. Every event returns a mutable map, 137 * thus allowing event handlers to modify the map even if 138 * none was passed to the constructor. 139 */ 140 public Map<Object, Object> properties() { 141 if (properties == null) { 142 properties = new HashMap<>(); 143 } 144 @SuppressWarnings("unchecked") 145 Map<Object, Object> props = (Map<Object, Object>) properties; 146 return props; 147 } 148 149 /** 150 * Convenience method for adding properties one-by-one. 151 * 152 * @param key the property key 153 * @param value the property value 154 * @return the event for easy chaining 155 */ 156 public AddConletRequest addProperty(Object key, Object value) { 157 properties().put(key, value); 158 return this; 159 } 160 161 /** 162 * Convenience method that performs the given action if a property 163 * with the given key exists. 164 * 165 * @param key the property key 166 * @param action the action to perform 167 */ 168 public AddConletRequest ifPresent( 169 Object key, BiConsumer<Object, Object> action) { 170 if (properties().containsKey(key)) { 171 action.accept(key, properties().get(key)); 172 } 173 return this; 174 } 175}