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.portal.base.events;
020
021import java.util.HashMap;
022import java.util.Map;
023import java.util.function.BiConsumer;
024
025import org.jgrapes.portal.base.Portlet.RenderMode;
026import org.jgrapes.portal.base.RenderSupport;
027
028/**
029 * Sent to the portal (server) if a new portlet instance of a given 
030 * type should be added to the portal page. The portal server usually 
031 * responds with a {@link RenderPortlet} event that has as payload the
032 * HTML that displays the portlet on the portal page.
033 * 
034 * Properties may be passed with the event. The interpretation
035 * of the properties is completely dependent on the handling portlet.
036 * It is recommended to use {@link String}s as keys and JDK types
037 * as values. This avoids classpath dependencies on the portlet
038 * that is to be added. 
039 * 
040 * The event's result is the portlet id of the new portlet instance.
041 * 
042 * ![Event Sequence](AddPortletRequestSeq.svg)
043 * 
044 * @startuml AddPortletRequestSeq.svg
045 * hide footbox
046 * 
047 * Browser -> Portal: "addPortlet"
048 * activate Portal
049 * Portal -> Portlet: AddPortletRequest
050 * deactivate Portal
051 * activate Portlet
052 * Portlet -> Portal: RenderPortlet
053 * deactivate Portlet
054 * activate Portal
055 * Portal -> Browser: "renderPortlet"
056 * deactivate Portal
057 * 
058 * @enduml
059 * 
060 */
061public class AddPortletRequest extends RenderPortletRequestBase<String> {
062
063    private final String portletType;
064    private boolean foreground = true;
065    private Map<? extends Object, ? extends Object> properties;
066
067    /**
068     * Creates a new event.
069     * 
070     * @param renderSupport the render support
071     * @param portletType the type of the portlet
072     * @param mode the view mode that is requested
073     */
074    public AddPortletRequest(RenderSupport renderSupport, String portletType,
075            RenderMode mode) {
076        super(renderSupport, mode);
077        this.portletType = portletType;
078    }
079
080    /**
081     * Creates a new event.
082     * 
083     * @param renderSupport the render support
084     * @param portletType the type of the portlet
085     * @param mode the view mode that is requested
086     * @param properties optional values for properties of the portlet instance
087     */
088    public AddPortletRequest(RenderSupport renderSupport, String portletType,
089            RenderMode mode, Map<?, ?> properties) {
090        super(renderSupport, mode);
091        this.portletType = portletType;
092        @SuppressWarnings("unchecked")
093        Map<Object, Object> props = (Map<Object, Object>) properties;
094        this.properties = props;
095    }
096
097    /**
098     * Determines if the portlet will be put in the foreground.
099     * Defaults to `true` for added portlets as they are most likely
100     * supposed to be seen. 
101     *
102     * @param foreground the foreground
103     * @return the event for easy chaining
104     */
105    public AddPortletRequest setForeground(boolean foreground) {
106        this.foreground = foreground;
107        return this;
108    }
109
110    /**
111     * Returns the portlet type
112     * 
113     * @return the portlet type
114     */
115    public String portletType() {
116        return portletType;
117    }
118
119    /**
120     * Returns the properties. Every event returns a mutable map,
121     * thus allowing event handlers to modify the map even if
122     * none was passed to the constructor.
123     */
124    public Map<Object, Object> properties() {
125        if (properties == null) {
126            properties = new HashMap<>();
127        }
128        @SuppressWarnings("unchecked")
129        Map<Object, Object> props = (Map<Object, Object>) properties;
130        return props;
131    }
132
133    /**
134     * Convenience method for adding properties one-by-one.
135     * 
136     * @param key the property key
137     * @param value the property value
138     * @return the event for easy chaining
139     */
140    public AddPortletRequest addProperty(Object key, Object value) {
141        properties().put(key, value);
142        return this;
143    }
144
145    /**
146     * Convenience method that performs the given action if a property
147     * with the given key exists.
148     * 
149     * @param key the property key
150     * @param action the action to perform
151     */
152    public AddPortletRequest ifPresent(
153            Object key, BiConsumer<Object, Object> action) {
154        if (properties().containsKey(key)) {
155            action.accept(key, properties().get(key));
156        }
157        return this;
158    }
159
160    @Override
161    public boolean isForeground() {
162        return foreground;
163    }
164
165}