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 of a given 
030 * type should be added to the web console page. The console server usually 
031 * responds with a {@link RenderConlet} event that has as payload the
032 * HTML that displays the web console component on the console page.
033 * 
034 * Properties may be passed with the event. The interpretation
035 * of the properties is completely dependent on the handling web console 
036 * component. It is recommended to use {@link String}s as keys and JDK types
037 * as values. This avoids classpath dependencies on the web console component
038 * that is to be added. 
039 * 
040 * The event's result is the web console component id of the new 
041 * web console component instance.
042 * 
043 * ![Event Sequence](AddConletRequestSeq.svg)
044 * 
045 * @startuml AddConletRequestSeq.svg
046 * hide footbox
047 * 
048 * Browser -> WebConsole: "addConlet"
049 * activate WebConsole
050 * WebConsole -> Conlet: AddConletRequest
051 * deactivate WebConsole
052 * activate Conlet
053 * Conlet -> WebConsole: RenderConlet
054 * deactivate Conlet
055 * activate WebConsole
056 * WebConsole -> Browser: "renderConlet"
057 * deactivate WebConsole
058 * 
059 * @enduml
060 * 
061 */
062public class AddConletRequest extends RenderConletRequestBase<String> {
063
064    private final String conletType;
065    private Map<? extends Object, ? extends Object> properties;
066
067    /**
068     * Creates a new event.
069     *
070     * @param renderSupport the render support
071     * @param conletType the type of the web console component
072     * @param renderModes the render modes
073     */
074    public AddConletRequest(RenderSupport renderSupport, String conletType,
075            Set<RenderMode> renderModes) {
076        super(renderSupport, renderModes);
077        this.conletType = conletType;
078    }
079
080    /**
081     * Creates a new event.
082     *
083     * @param renderSupport the render support
084     * @param conletType the type of the web console component
085     * @param renderModes the render modes
086     * @param properties optional values for properties of the 
087     * web console component instance
088     */
089    public AddConletRequest(RenderSupport renderSupport, String conletType,
090            Set<RenderMode> renderModes, Map<?, ?> properties) {
091        super(renderSupport, renderModes);
092        this.conletType = conletType;
093        @SuppressWarnings("unchecked")
094        Map<Object, Object> props = (Map<Object, Object>) properties;
095        this.properties = props;
096    }
097
098    /**
099     * Returns the web console component type
100     * 
101     * @return the web console component type
102     */
103    public String conletType() {
104        return conletType;
105    }
106
107    /**
108     * Returns the properties. Every event returns a mutable map,
109     * thus allowing event handlers to modify the map even if
110     * none was passed to the constructor.
111     */
112    public Map<Object, Object> properties() {
113        if (properties == null) {
114            properties = new HashMap<>();
115        }
116        @SuppressWarnings("unchecked")
117        Map<Object, Object> props = (Map<Object, Object>) properties;
118        return props;
119    }
120
121    /**
122     * Convenience method for adding properties one-by-one.
123     * 
124     * @param key the property key
125     * @param value the property value
126     * @return the event for easy chaining
127     */
128    public AddConletRequest addProperty(Object key, Object value) {
129        properties().put(key, value);
130        return this;
131    }
132
133    /**
134     * Convenience method that performs the given action if a property
135     * with the given key exists.
136     * 
137     * @param key the property key
138     * @param action the action to perform
139     */
140    public AddConletRequest ifPresent(
141            Object key, BiConsumer<Object, Object> action) {
142        if (properties().containsKey(key)) {
143            action.accept(key, properties().get(key));
144        }
145        return this;
146    }
147}