001/*
002 * Ad Hoc Polling Application
003 * Copyright (C) 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.net.URI;
022import java.net.URL;
023import java.time.Instant;
024import java.util.Optional;
025import org.jdrupes.httpcodec.protocols.http.HttpRequest;
026import org.jgrapes.core.Event;
027import org.jgrapes.http.Session;
028import org.jgrapes.http.events.Request.In.Get;
029import org.jgrapes.io.IOSubchannel;
030import org.jgrapes.webconsole.base.RenderSupport;
031import org.jgrapes.webconsole.base.ResourceByUrl;
032import org.jgrapes.webconsole.base.ResourceNotModified;
033import org.jgrapes.webconsole.base.ResourceProvided;
034import org.jgrapes.webconsole.base.ResourceResult;
035
036/**
037 * An event that signals the request for a resource by the browser.
038 * 
039 * This event is effectively a "transformed" {@link Get}. It 
040 * simplifies handling of such an event by web console components, because
041 * they can simply set a result of type {@link ResourceResult} and
042 * thus need no knowledge about generating all the events required to 
043 * properly respond to a {@link Get}.
044 * 
045 * The complete sequence of events is shown in the diagram.
046 * 
047 * ![Resource Response Sequence](ResourceResponseSeq.svg)
048 * 
049 * Of course, due to internal buffering, the "Response Header" data
050 * and the "Response body" data may collapse in a single message
051 * that is sent to the browser (in case of a small resource).
052 * 
053 * If a value is provided by {@link #ifModifiedSince()},
054 * and the resource has not changed since the given instant,
055 * a resource provider may set {@link ResourceNotModified} as
056 * result. This information will be forwarded to the browser.
057 * For a result of type {@link ResourceByUrl}, the check
058 * for modification will be made automatically, using information
059 * derived from the {@link URL}.
060 * 
061 * Handlers of {@link ResourceRequest} events use usually only
062 * the information provided by {@link #resourceUri()}. The other
063 * items are needed by the handler of the {@link ResourceRequestCompleted}
064 * event (the web console) to generate the response for the {@link Get}.
065 * 
066 * If none of the provided {@link ResourceResult} type matches the
067 * requirements of the resource provider, it can set
068 * {@link ResourceProvided} as result. This signals that it genertes
069 * the response itself.
070 * 
071 * ![Extended Resource Response Sequence](ResourceResponseSelfSeq.svg)
072 * 
073 * @startuml ResourceResponseSeq.svg
074 * hide footbox
075 * 
076 * activate WebConsole
077 * actor Framework
078 * WebConsole -> ResourceProvider: ResourceRequest
079 * activate ResourceProvider
080 * deactivate ResourceProvider
081 * deactivate WebConsole
082 * Framework -> WebConsole: ResourceRequestCompleted
083 * activate WebConsole
084 * WebConsole -> Browser: "Response Header"
085 * loop until end of data
086 *     WebConsole -> Browser: Output
087 *     WebConsole -> Browser: "Response body"
088 *     deactivate WebConsole
089 * end loop
090 * deactivate ResourceProvider
091 * deactivate Browser
092 * @enduml
093 * 
094 * @startuml ResourceResponseSelfSeq.svg
095 * hide footbox
096 * 
097 * activate WebConsole
098 * actor Framework
099 * WebConsole -> ResourceProvider: ResourceRequest
100 * activate ResourceProvider
101 * Framework -> WebConsole: ResourceRequestCompleted
102 * deactivate WebConsole
103 * ResourceProvider -> Browser: "Response Header"
104 * loop until end of data
105 *     ResourceProvider -> Browser: Output
106 *     ResourceProvider -> Browser: "Response body"
107 *     deactivate WebConsole
108 * end loop
109 * deactivate ResourceProvider
110 * deactivate Browser
111 * 
112 * @enduml
113 */
114@SuppressWarnings("PMD.DataClass")
115public class ResourceRequest extends Event<ResourceResult> {
116
117    private final URI resourceUri;
118    private final Instant ifModifiedSince;
119    private final HttpRequest httpRequest;
120    private final IOSubchannel httpChannel;
121    private final RenderSupport renderSupport;
122    private final Session session;
123
124    /**
125     * Creates a new request, including the associated 
126     * {@link ResourceRequestCompleted} event.
127     * 
128     * @param resourceUri the requested resource
129     * @param httpRequest the original HTTP request
130     * @param httpChannel the channel that the HTTP request was received on
131     * @param renderSupport the render support
132     */
133    public ResourceRequest(URI resourceUri, Instant ifModifiedSince,
134            HttpRequest httpRequest, IOSubchannel httpChannel,
135            Session session, RenderSupport renderSupport) {
136        this.resourceUri = resourceUri;
137        this.ifModifiedSince = ifModifiedSince;
138        this.httpRequest = httpRequest;
139        this.httpChannel = httpChannel;
140        this.renderSupport = renderSupport;
141        this.session = session;
142        new ResourceRequestCompleted(this);
143    }
144
145    /**
146     * @return the resourceUri
147     */
148    public URI resourceUri() {
149        return resourceUri;
150    }
151
152    /**
153     * If not null, this value may be used to decide if the
154     * resource must be refreshed.
155     *
156     * @return the instant
157     */
158    public Optional<Instant> ifModifiedSince() {
159        return Optional.ofNullable(ifModifiedSince);
160    }
161
162    /**
163     * Returns the "raw" request as provided by the HTTP decoder.
164     * 
165     * @return the request
166     */
167    public HttpRequest httpRequest() {
168        return httpRequest;
169    }
170
171    /**
172     * @return the httpChannel
173     */
174    public IOSubchannel httpChannel() {
175        return httpChannel;
176    }
177
178    /**
179     * Returns the render support.
180     * 
181     * @return the render support
182     */
183    public RenderSupport renderSupport() {
184        return renderSupport;
185    }
186
187    /**
188     * Returns the (browser) session.
189     *
190     * @return the session
191     */
192    public Session session() {
193        return session;
194    }
195}