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}