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}