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);
+        }
+    }
+
+}