001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.marshall.sse;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import org.apache.juneau.commons.bean.*;
022
023/**
024 * Represents a single <a class="doclink" href="https://html.spec.whatwg.org/multipage/server-sent-events.html">Server-Sent Event</a>
025 * (SSE) frame on the wire.
026 *
027 * <p>
028 * Each event maps to a sequence of <c>field: value</c> lines terminated by a blank line in the
029 * <c>text/event-stream</c> wire format:
030 * <p class='bcode'>
031 * event: progress
032 * data: {"step":4,"total":10}
033 * id: 42
034 * retry: 5000
035 *
036 * </p>
037 *
038 * <p>
039 * The payload field {@link #getData() data} is a <b>pre-serialized</b> {@link String} — the SSE
040 * serializer does not compose with a delegate marshaller. Callers that need a typed payload should
041 * serialize it themselves (e.g. via {@link org.apache.juneau.marshall.marshaller.Json#of(Object) Json.of(x)})
042 * and assign the resulting string to {@link #setData(String) setData(...)}. The serializer will
043 * split that string on {@code \n} into multiple <c>data:</c> lines per spec.
044 *
045 * <h5 class='figure'>Example: build and serialize an event:</h5>
046 * <p class='bjava'>
047 *    SseEvent <jv>event</jv> = <jk>new</jk> SseEvent()
048 *       .setEvent(<js>"progress"</js>)
049 *       .setData(Json.<jsm>of</jsm>(Map.of(<js>"step"</js>, 4, <js>"total"</js>, 10)))
050 *       .setId(<js>"42"</js>)
051 *       .setRetry(5000L);
052 *
053 *    String <jv>wire</jv> = Sse.<jsm>of</jsm>(<jv>event</jv>);
054 * </p>
055 *
056 * <h5 class='section'>Notes:</h5><ul>
057 *    <li class='note'>This class is not thread safe.
058 * </ul>
059 *
060 * <h5 class='section'>See Also:</h5><ul>
061 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Sse">SSE</a>
062 *    <li class='link'><a class="doclink" href="https://html.spec.whatwg.org/multipage/server-sent-events.html">WHATWG HTML §9.2 — Server-sent events</a>
063 * </ul>
064 */
065@BeanType(properties = "event,data,id,retry")
066public class SseEvent {
067
068   /** Default event-type name dispatched by the WHATWG <c>EventSource</c> when no <c>event:</c> field is present. */
069   public static final String DEFAULT_EVENT = "message";
070
071   private String event;
072   private String data;
073   private String id;
074   private Long retry;
075
076   /**
077    * Constructor.
078    */
079   public SseEvent() {}
080
081   /**
082    * Constructor.
083    *
084    * @param event The event-type name. Can be <jk>null</jk> (dispatches as {@value #DEFAULT_EVENT}).
085    * @param data The payload string. Can be <jk>null</jk> (no <c>data:</c> lines emitted).
086    */
087   public SseEvent(String event, String data) {
088      this.event = event;
089      this.data = data;
090   }
091
092   /**
093    * Returns the event-type name.
094    *
095    * @return The event-type name, or <jk>null</jk> if not set.
096    */
097   public String getEvent() {
098      return event;
099   }
100
101   /**
102    * Sets the event-type name.
103    *
104    * @param value The event-type name. Can be <jk>null</jk> to unset.
105    * @return This object.
106    */
107   public SseEvent setEvent(String value) {
108      event = value;
109      return this;
110   }
111
112   /**
113    * Returns the data payload (pre-serialized string).
114    *
115    * @return The data payload, or <jk>null</jk> if not set.
116    */
117   public String getData() {
118      return data;
119   }
120
121   /**
122    * Sets the data payload.
123    *
124    * @param value The pre-serialized payload string. Can be <jk>null</jk> to unset.
125    * @return This object.
126    */
127   public SseEvent setData(String value) {
128      data = value;
129      return this;
130   }
131
132   /**
133    * Returns the last-event-id value.
134    *
135    * @return The id, or <jk>null</jk> if not set.
136    */
137   public String getId() {
138      return id;
139   }
140
141   /**
142    * Sets the last-event-id value.
143    *
144    * @param value The id. Can be <jk>null</jk> to unset.
145    * @return This object.
146    */
147   public SseEvent setId(String value) {
148      id = value;
149      return this;
150   }
151
152   /**
153    * Returns the reconnect-delay hint in milliseconds.
154    *
155    * @return The retry value, or <jk>null</jk> if not set.
156    */
157   public Long getRetry() {
158      return retry;
159   }
160
161   /**
162    * Sets the reconnect-delay hint in milliseconds.
163    *
164    * @param value The retry value. Can be <jk>null</jk> to unset.
165    * @return This object.
166    */
167   public SseEvent setRetry(Long value) {
168      retry = value;
169      return this;
170   }
171
172   @Override /* Overridden from Object */
173   public boolean equals(Object o) {
174      if (this == o)
175         return true;
176      if (!(o instanceof SseEvent o2))
177         return false;
178      return eq(event, o2.event)
179         && eq(data, o2.data)
180         && eq(id, o2.id)
181         && eq(retry, o2.retry);
182   }
183
184   @Override /* Overridden from Object */
185   public int hashCode() {
186      return h(event, data, id, retry);
187   }
188
189   @Override /* Overridden from Object */
190   public String toString() {
191      return "SseEvent[event=" + event + ",data=" + data + ",id=" + id + ",retry=" + retry + "]";
192   }
193}