You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by pa...@apache.org on 2017/05/25 22:28:55 UTC
svn commit: r1796219 -
/sling/whiteboard/pauls/gush/servlet/src/main/java/org/apache/sling/whiteboard/pauls/gush/servlet/Session.java
Author: pauls
Date: Thu May 25 22:28:54 2017
New Revision: 1796219
URL: http://svn.apache.org/viewvc?rev=1796219&view=rev
Log:
Add some scaffolding for session handling with heartbeat
Added:
sling/whiteboard/pauls/gush/servlet/src/main/java/org/apache/sling/whiteboard/pauls/gush/servlet/Session.java
Added: sling/whiteboard/pauls/gush/servlet/src/main/java/org/apache/sling/whiteboard/pauls/gush/servlet/Session.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/pauls/gush/servlet/src/main/java/org/apache/sling/whiteboard/pauls/gush/servlet/Session.java?rev=1796219&view=auto
==============================================================================
--- sling/whiteboard/pauls/gush/servlet/src/main/java/org/apache/sling/whiteboard/pauls/gush/servlet/Session.java (added)
+++ sling/whiteboard/pauls/gush/servlet/src/main/java/org/apache/sling/whiteboard/pauls/gush/servlet/Session.java Thu May 25 22:28:54 2017
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.whiteboard.pauls.gush.servlet;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.WriteListener;
+
+import org.apache.sling.api.resource.observation.ExternalResourceChangeListener;
+import org.apache.sling.api.resource.observation.ResourceChange;
+import org.apache.sling.api.resource.observation.ResourceChangeListener;
+
+public class Session implements Runnable, WriteListener, ResourceChangeListener, ExternalResourceChangeListener {
+ private final long m_heartbeat;
+ private final long m_poll;
+ private final AtomicBoolean m_changed = new AtomicBoolean(true);
+ private final Queue<byte[]> m_pendingWrites = new ConcurrentLinkedQueue<>();
+ private final ScheduledExecutorService m_exec;
+ private volatile long m_lastWrite = 0;
+ private volatile AsyncContext m_ac;
+ private volatile Function<AsyncContext, byte[]> m_handler;
+
+ public Session(AsyncContext ac, ScheduledExecutorService exec, long heartbeatInterval, long interval) {
+ m_exec = exec;
+ m_heartbeat = heartbeatInterval;
+ m_poll = interval;
+ }
+
+ public void start(AsyncContext ac, Function<AsyncContext, byte[]> handler) {
+ m_handler = handler;
+ m_ac = ac;
+ m_exec.execute(this);
+ }
+
+ public void stop() {
+ m_ac.complete();
+ }
+
+ @Override
+ public synchronized void onWritePossible() throws IOException {
+ while (m_ac.getResponse().getOutputStream().isReady()) {
+ byte[] pending = m_pendingWrites.poll();
+ if (pending != null) {
+ m_ac.getResponse().getOutputStream().write(pending);
+ m_lastWrite = System.currentTimeMillis();
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ @Override
+ public synchronized void onError(Throwable t) {
+ m_ac.complete();
+ }
+
+ @Override
+ public void onChange(List<ResourceChange> changes) {
+ m_changed.set(true);
+ }
+
+ @Override
+ public void run() {
+ boolean run = m_changed.getAndSet(false);
+
+ try {
+ do {
+ if (run)
+ {
+ m_pendingWrites.offer(m_handler.apply(m_ac));
+ }
+ else if (System.currentTimeMillis() - m_lastWrite > m_heartbeat)
+ {
+ m_pendingWrites.offer(new byte[] {':'});
+ }
+
+ onWritePossible();
+
+ run = m_changed.getAndSet(false);
+ } while (run);
+
+ m_exec.schedule(this, m_poll, TimeUnit.MILLISECONDS);
+
+ } catch (IOException e) {
+ onError(e);
+ }
+ }
+
+}