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