tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kpreis...@apache.org
Subject svn commit: r1530298 [1/2] - in /tomcat/trunk/webapps/examples: WEB-INF/classes/websocket/drawboard/ WEB-INF/classes/websocket/drawboard/wsmessages/ websocket/
Date Tue, 08 Oct 2013 14:46:54 GMT
Author: kpreisser
Date: Tue Oct  8 14:46:53 2013
New Revision: 1530298

URL: http://svn.apache.org/r1530298
Log:
svn:eol-style = native
Sorry for the noise.

Modified:
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/WsConfigListener.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java   (contents, props changed)
    tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java   (contents, props changed)
    tomcat/trunk/webapps/examples/websocket/drawboard.xhtml   (contents, props changed)

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java Tue Oct  8 14:46:53 2013
@@ -1,124 +1,124 @@
-/*
- *  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 websocket.drawboard;
-
-import java.util.LinkedList;
-
-import javax.websocket.RemoteEndpoint;
-import javax.websocket.SendHandler;
-import javax.websocket.SendResult;
-
-import websocket.drawboard.wsmessages.AbstractWebsocketMessage;
-import websocket.drawboard.wsmessages.BinaryWebsocketMessage;
-import websocket.drawboard.wsmessages.StringWebsocketMessage;
-
-/**
- * Represents a client with methods to send messages.
- */
-public class Client {
-
-    private final RemoteEndpoint.Async async;
-
-    /**
-     * Contains the messages wich are buffered until the previous
-     * send operation has finished.
-     */
-    private final LinkedList<AbstractWebsocketMessage> messagesToSend =
-            new LinkedList<>();
-    /**
-     * If this client is currently sending a messages asynchronously.
-     */
-    private volatile boolean isSendingMessage = false;
-
-    public Client(RemoteEndpoint.Async async) {
-        this.async = async;
-    }
-
-
-    /**
-     * Sends the given message asynchronously to the client.
-     * If there is already a async sending in progress, then the message
-     * will be buffered and sent when possible.<br><br>
-     * 
-     * This method can be called from multiple threads.
-     * @param msg
-     */
-    public void sendMessage(AbstractWebsocketMessage msg) {
-        synchronized (messagesToSend) {
-            if (isSendingMessage) {
-                // TODO: Check if the buffered messages exceed
-                // a specific amount - in that case, disconnect the client
-                // to prevent DoS.
-
-                // TODO: Check if the last message is a
-                // String message - in that case we should concatenate them
-                // to reduce TCP overhead (using ";" as separator).
-
-                messagesToSend.add(msg);
-            } else {
-                isSendingMessage = true;
-                internalSendMessageAsync(msg);
-            }
-
-
-        }
-    }
-
-    /**
-     * Internally sends the messages asynchronously.
-     * @param msg
-     */
-    private void internalSendMessageAsync(AbstractWebsocketMessage msg) {
-        try {
-            if (msg instanceof StringWebsocketMessage) {
-                StringWebsocketMessage sMsg = (StringWebsocketMessage) msg;
-                async.sendText(sMsg.getString(), sendHandler);
-
-            } else if (msg instanceof BinaryWebsocketMessage) {
-                BinaryWebsocketMessage bMsg = (BinaryWebsocketMessage) msg;
-                async.sendBinary(bMsg.getBytes(), sendHandler);
-            }
-        } catch (IllegalStateException ex) {
-            // Trying to write to the client when the session has
-            // already been closed.
-            // Ignore
-        }
-    }
-
-
-
-    /**
-     * SendHandler that will continue to send buffered messages.
-     */
-    private final SendHandler sendHandler = new SendHandler() {
-        @Override
-        public void onResult(SendResult result) {
-            synchronized (messagesToSend) {
-
-                if (!messagesToSend.isEmpty()) {
-                    AbstractWebsocketMessage msg = messagesToSend.remove();
-                    internalSendMessageAsync(msg);
-
-                } else {
-                    isSendingMessage = false;
-                }
-
-            }
-        }
-    };
-
-}
+/*
+ *  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 websocket.drawboard;
+
+import java.util.LinkedList;
+
+import javax.websocket.RemoteEndpoint;
+import javax.websocket.SendHandler;
+import javax.websocket.SendResult;
+
+import websocket.drawboard.wsmessages.AbstractWebsocketMessage;
+import websocket.drawboard.wsmessages.BinaryWebsocketMessage;
+import websocket.drawboard.wsmessages.StringWebsocketMessage;
+
+/**
+ * Represents a client with methods to send messages.
+ */
+public class Client {
+
+    private final RemoteEndpoint.Async async;
+
+    /**
+     * Contains the messages wich are buffered until the previous
+     * send operation has finished.
+     */
+    private final LinkedList<AbstractWebsocketMessage> messagesToSend =
+            new LinkedList<>();
+    /**
+     * If this client is currently sending a messages asynchronously.
+     */
+    private volatile boolean isSendingMessage = false;
+
+    public Client(RemoteEndpoint.Async async) {
+        this.async = async;
+    }
+
+
+    /**
+     * Sends the given message asynchronously to the client.
+     * If there is already a async sending in progress, then the message
+     * will be buffered and sent when possible.<br><br>
+     * 
+     * This method can be called from multiple threads.
+     * @param msg
+     */
+    public void sendMessage(AbstractWebsocketMessage msg) {
+        synchronized (messagesToSend) {
+            if (isSendingMessage) {
+                // TODO: Check if the buffered messages exceed
+                // a specific amount - in that case, disconnect the client
+                // to prevent DoS.
+
+                // TODO: Check if the last message is a
+                // String message - in that case we should concatenate them
+                // to reduce TCP overhead (using ";" as separator).
+
+                messagesToSend.add(msg);
+            } else {
+                isSendingMessage = true;
+                internalSendMessageAsync(msg);
+            }
+
+
+        }
+    }
+
+    /**
+     * Internally sends the messages asynchronously.
+     * @param msg
+     */
+    private void internalSendMessageAsync(AbstractWebsocketMessage msg) {
+        try {
+            if (msg instanceof StringWebsocketMessage) {
+                StringWebsocketMessage sMsg = (StringWebsocketMessage) msg;
+                async.sendText(sMsg.getString(), sendHandler);
+
+            } else if (msg instanceof BinaryWebsocketMessage) {
+                BinaryWebsocketMessage bMsg = (BinaryWebsocketMessage) msg;
+                async.sendBinary(bMsg.getBytes(), sendHandler);
+            }
+        } catch (IllegalStateException ex) {
+            // Trying to write to the client when the session has
+            // already been closed.
+            // Ignore
+        }
+    }
+
+
+
+    /**
+     * SendHandler that will continue to send buffered messages.
+     */
+    private final SendHandler sendHandler = new SendHandler() {
+        @Override
+        public void onResult(SendResult result) {
+            synchronized (messagesToSend) {
+
+                if (!messagesToSend.isEmpty()) {
+                    AbstractWebsocketMessage msg = messagesToSend.remove();
+                    internalSendMessageAsync(msg);
+
+                } else {
+                    isSendingMessage = false;
+                }
+
+            }
+        }
+    };
+
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java Tue Oct  8 14:46:53 2013
@@ -1,211 +1,211 @@
-/*
- *  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 websocket.drawboard;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Graphics2D;
-
-/**
- * A message that represents a drawing action.
- * Note that we use primitive types instead of Point, Color etc.
- * to reduce object allocation.<br><br>
- * 
- * TODO: But a Color objects needs to be created anyway for drawing this
- * onto a Graphics2D object, so this probably does not save much.
- */
-public final class DrawMessage {
-
-
-    private int type;
-    private byte colorR, colorG, colorB, colorA;
-    private double thickness;
-    private int x1, y1, x2, y2;
-
-    /**
-     * The type. 1: Line.
-     * @return
-     */
-    public int getType() {
-        return type;
-    }
-    public void setType(int type) {
-        this.type = type;
-    }
-
-    public double getThickness() {
-        return thickness;
-    }
-    public void setThickness(double thickness) {
-        this.thickness = thickness;
-    }
-
-    public byte getColorR() {
-        return colorR;
-    }
-    public void setColorR(byte colorR) {
-        this.colorR = colorR;
-    }
-    public byte getColorG() {
-        return colorG;
-    }
-    public void setColorG(byte colorG) {
-        this.colorG = colorG;
-    }
-    public byte getColorB() {
-        return colorB;
-    }
-    public void setColorB(byte colorB) {
-        this.colorB = colorB;
-    }
-    public byte getColorA() {
-        return colorA;
-    }
-    public void setColorA(byte colorA) {
-        this.colorA = colorA;
-    }
-
-    public long getX1() {
-        return x1;
-    }
-    public void setX1(int x1) {
-        this.x1 = x1;
-    }
-    public int getX2() {
-        return x2;
-    }
-    public void setX2(int x2) {
-        this.x2 = x2;
-    }
-    public int getY1() {
-        return y1;
-    }
-    public void setY1(int y1) {
-        this.y1 = y1;
-    }
-    public int getY2() {
-        return y2;
-    }
-    public void setY2(int y2) {
-        this.y2 = y2;
-    }
-
-
-
-    public DrawMessage(int type, byte colorR, byte colorG, byte colorB,
-            byte colorA, double thickness, int x1, int x2, int y1, int y2) {
-
-        this.type = type;
-        this.colorR = colorR;
-        this.colorG = colorG;
-        this.colorB = colorB;
-        this.colorA = colorA;
-        this.thickness = thickness;
-        this.x1 = x1;
-        this.x2 = x2;
-        this.y1 = y1;
-        this.y2 = y2;
-    }
-
-
-    /**
-     * Draws this DrawMessage onto the given Graphics2D.
-     * @param g
-     */
-    public void draw(Graphics2D g) {
-        switch (type) {
-        case 1:
-            // Draw a line.
-            g.setStroke(new BasicStroke((float) thickness,
-                    BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
-            g.setColor(new Color(colorR & 0xFF, colorG & 0xFF, colorB & 0xFF,
-                    colorA & 0xFF));
-            g.drawLine(x1, y1, x2, y2);
-            break;
-        }
-    }
-
-    /**
-     * Converts this message into a String representation that
-     * can be sent over WebSocket.<br>
-     * Since a DrawMessage consists only of numbers,
-     * we concatenate those numbers with a ",".
-     */
-    @Override
-    public String toString() {
-
-        return type + "," + (colorR & 0xFF) + "," + (colorG & 0xFF) + ","
-                + (colorB & 0xFF) + "," + (colorA & 0xFF) + "," + thickness
-                + "," + x1 + "," + y1 + "," + x2 + "," + y2;
-    }
-
-    public static DrawMessage parseFromString(String str)
-            throws ParseException {
-
-        int type; 
-        byte[] colors = new byte[4];
-        double thickness;
-        int[] coords = new int[4];
-
-        try {
-            String[] elements = str.split(",");
-
-            type = Integer.parseInt(elements[0]);
-            if (type != 1)
-                throw new ParseException("Invalid type: " + type);
-
-            for (int i = 0; i < colors.length; i++) {
-                colors[i] = (byte) Integer.parseInt(elements[1 + i]);
-            }
-
-            thickness = Double.parseDouble(elements[5]);
-            if (Double.isNaN(thickness) || thickness < 0 || thickness > 100)
-                throw new ParseException("Invalid thickness: " + thickness);
-
-            for (int i = 0; i < coords.length; i++) {
-                coords[i] = Integer.parseInt(elements[6 + i]);
-                if (coords[i] < -1000000L || coords[i] > 1000000L)
-                    throw new ParseException("Invalid coordinate: "
-                            + coords[i]);
-            }
-
-
-        } catch (RuntimeException ex) {
-            throw new ParseException(ex);
-        }
-
-        DrawMessage m = new DrawMessage(type, colors[0], colors[1],
-                colors[2], colors[3], thickness, coords[0], coords[2],
-                coords[1], coords[3]);
-
-        return m;
-    }
-
-    public static class ParseException extends Exception {
-        private static final long serialVersionUID = -6651972769789842960L;
-
-        public ParseException(Throwable root) {
-            super(root);
-        }
-
-        public ParseException(String message) {
-            super(message);
-        }
-    }
-
-
-}
+/*
+ *  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 websocket.drawboard;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+
+/**
+ * A message that represents a drawing action.
+ * Note that we use primitive types instead of Point, Color etc.
+ * to reduce object allocation.<br><br>
+ * 
+ * TODO: But a Color objects needs to be created anyway for drawing this
+ * onto a Graphics2D object, so this probably does not save much.
+ */
+public final class DrawMessage {
+
+
+    private int type;
+    private byte colorR, colorG, colorB, colorA;
+    private double thickness;
+    private int x1, y1, x2, y2;
+
+    /**
+     * The type. 1: Line.
+     * @return
+     */
+    public int getType() {
+        return type;
+    }
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public double getThickness() {
+        return thickness;
+    }
+    public void setThickness(double thickness) {
+        this.thickness = thickness;
+    }
+
+    public byte getColorR() {
+        return colorR;
+    }
+    public void setColorR(byte colorR) {
+        this.colorR = colorR;
+    }
+    public byte getColorG() {
+        return colorG;
+    }
+    public void setColorG(byte colorG) {
+        this.colorG = colorG;
+    }
+    public byte getColorB() {
+        return colorB;
+    }
+    public void setColorB(byte colorB) {
+        this.colorB = colorB;
+    }
+    public byte getColorA() {
+        return colorA;
+    }
+    public void setColorA(byte colorA) {
+        this.colorA = colorA;
+    }
+
+    public long getX1() {
+        return x1;
+    }
+    public void setX1(int x1) {
+        this.x1 = x1;
+    }
+    public int getX2() {
+        return x2;
+    }
+    public void setX2(int x2) {
+        this.x2 = x2;
+    }
+    public int getY1() {
+        return y1;
+    }
+    public void setY1(int y1) {
+        this.y1 = y1;
+    }
+    public int getY2() {
+        return y2;
+    }
+    public void setY2(int y2) {
+        this.y2 = y2;
+    }
+
+
+
+    public DrawMessage(int type, byte colorR, byte colorG, byte colorB,
+            byte colorA, double thickness, int x1, int x2, int y1, int y2) {
+
+        this.type = type;
+        this.colorR = colorR;
+        this.colorG = colorG;
+        this.colorB = colorB;
+        this.colorA = colorA;
+        this.thickness = thickness;
+        this.x1 = x1;
+        this.x2 = x2;
+        this.y1 = y1;
+        this.y2 = y2;
+    }
+
+
+    /**
+     * Draws this DrawMessage onto the given Graphics2D.
+     * @param g
+     */
+    public void draw(Graphics2D g) {
+        switch (type) {
+        case 1:
+            // Draw a line.
+            g.setStroke(new BasicStroke((float) thickness,
+                    BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
+            g.setColor(new Color(colorR & 0xFF, colorG & 0xFF, colorB & 0xFF,
+                    colorA & 0xFF));
+            g.drawLine(x1, y1, x2, y2);
+            break;
+        }
+    }
+
+    /**
+     * Converts this message into a String representation that
+     * can be sent over WebSocket.<br>
+     * Since a DrawMessage consists only of numbers,
+     * we concatenate those numbers with a ",".
+     */
+    @Override
+    public String toString() {
+
+        return type + "," + (colorR & 0xFF) + "," + (colorG & 0xFF) + ","
+                + (colorB & 0xFF) + "," + (colorA & 0xFF) + "," + thickness
+                + "," + x1 + "," + y1 + "," + x2 + "," + y2;
+    }
+
+    public static DrawMessage parseFromString(String str)
+            throws ParseException {
+
+        int type; 
+        byte[] colors = new byte[4];
+        double thickness;
+        int[] coords = new int[4];
+
+        try {
+            String[] elements = str.split(",");
+
+            type = Integer.parseInt(elements[0]);
+            if (type != 1)
+                throw new ParseException("Invalid type: " + type);
+
+            for (int i = 0; i < colors.length; i++) {
+                colors[i] = (byte) Integer.parseInt(elements[1 + i]);
+            }
+
+            thickness = Double.parseDouble(elements[5]);
+            if (Double.isNaN(thickness) || thickness < 0 || thickness > 100)
+                throw new ParseException("Invalid thickness: " + thickness);
+
+            for (int i = 0; i < coords.length; i++) {
+                coords[i] = Integer.parseInt(elements[6 + i]);
+                if (coords[i] < -1000000L || coords[i] > 1000000L)
+                    throw new ParseException("Invalid coordinate: "
+                            + coords[i]);
+            }
+
+
+        } catch (RuntimeException ex) {
+            throw new ParseException(ex);
+        }
+
+        DrawMessage m = new DrawMessage(type, colors[0], colors[1],
+                colors[2], colors[3], thickness, coords[0], coords[2],
+                coords[1], coords[3]);
+
+        return m;
+    }
+
+    public static class ParseException extends Exception {
+        private static final long serialVersionUID = -6651972769789842960L;
+
+        public ParseException(Throwable root) {
+            super(root);
+        }
+
+        public ParseException(String message) {
+            super(message);
+        }
+    }
+
+
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java Tue Oct  8 14:46:53 2013
@@ -1,210 +1,210 @@
-/*
- *  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 websocket.drawboard;
-
-import java.io.EOFException;
-
-import javax.websocket.CloseReason;
-import javax.websocket.Endpoint;
-import javax.websocket.EndpointConfig;
-import javax.websocket.MessageHandler;
-import javax.websocket.Session;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
-import websocket.drawboard.DrawMessage.ParseException;
-import websocket.drawboard.wsmessages.StringWebsocketMessage;
-
-
-public final class DrawboardEndpoint extends Endpoint {
-
-    private static final Log log =
-            LogFactory.getLog(DrawboardEndpoint.class);
-
-
-    /**
-     * Our room where players can join.
-     */
-    private static final Room room = new Room();
-
-    public static Room getRoom() {
-        return room;
-    }
-
-    /**
-     * The player that is associated with this Endpoint and the current room.
-     * Note that this variable is only accessed from the Room Thread.<br><br>
-     * 
-     * TODO: Currently, Tomcat uses an Endpoint instance once - however
-     * the java doc of endpoint says:
-     * "Each instance of a websocket endpoint is guaranteed not to be called by
-     * more than one thread at a time per active connection."
-     * This could mean that after calling onClose(), the instance
-     * could be reused for another connection so onOpen() will get called
-     * (possibly from another thread).<br>
-     * If this is the case, we would need a variable holder for the variables
-     * that are accessed by the Room thread, and read the reference to the holder
-     * at the beginning of onOpen, onMessage, onClose methods to ensure the room
-     * thread always gets the correct instance of the variable holder.
-     */
-    private Room.Player player;
-
-
-    @Override
-    public void onOpen(Session session, EndpointConfig config) {
-        // Set maximum messages size to 10.000 bytes.
-        session.setMaxTextMessageBufferSize(10000);
-        session.addMessageHandler(stringHandler);
-        final Client client = new Client(session.getAsyncRemote());
-
-        room.invoke(new Runnable() {
-            @Override
-            public void run() {
-                try {
-
-                    // Create a new Player and add it to the room.
-                    try {
-                        player = room.createAndAddPlayer(client);
-                    } catch (IllegalStateException ex) {
-                        // Probably the max. number of players has been
-                        // reached.
-                        client.sendMessage(new StringWebsocketMessage(
-                                "0" + ex.getLocalizedMessage()));
-                    }
-
-                } catch (RuntimeException ex) {
-                    log.error("Unexpected exception: " + ex.toString(), ex);
-                }
-            }
-        });
-
-    }
-
-
-    @Override
-    public void onClose(Session session, CloseReason closeReason) {
-        room.invoke(new Runnable() {
-            @Override
-            public void run() {
-                try {
-
-                    // Player can be null if it couldn't enter the room
-                    if (player != null) {
-                        // Remove this player from the room.
-                        player.removeFromRoom();
-                    }
-
-                } catch (RuntimeException ex) {
-                    log.error("Unexpected exception: " + ex.toString(), ex);
-                }
-            }
-        });
-
-    }
-
-
-
-    @Override
-    public void onError(Session session, Throwable t) {
-        // Most likely cause is a user closing their browser. Check to see if
-        // the root cause is EOF and if it is ignore it.
-        // Protect against infinite loops.
-        int count = 0;
-        Throwable root = t;
-        while (root.getCause() != null && count < 20) {
-            root = root.getCause();
-            count ++;
-        }
-        if (root instanceof EOFException) {
-            // Assume this is triggered by the user closing their browser and
-            // ignore it.
-        } else {
-            log.error("onError: " + t.toString(), t);
-        }
-    }
-
-
-
-    private final MessageHandler.Whole<String> stringHandler =
-            new MessageHandler.Whole<String>() {
-
-        @Override
-        public void onMessage(final String message) {
-            // Invoke handling of the message in the room.
-            room.invoke(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-
-                        // Currently, the only types of messages the client will send
-                        // are draw messages prefixed by a Message ID
-                        // (starting with char '1'), and pong messages (starting
-                        // with char '0').
-                        // Draw messages should look like this:
-                        // ID|type,colR,colB,colG,colA,thickness,x1,y1,x2,y2
-
-                        boolean dontSwallowException = false;
-                        try {
-                            char messageType = message.charAt(0);
-                            switch (messageType) {
-                            case '0':
-                                // Pong message.
-                                // Do nothing.
-                                break;
-
-                            case '1':
-                                // Draw message
-                                int indexOfChar = message.indexOf('|');
-                                long msgId = Long.parseLong(
-                                        message.substring(0, indexOfChar));
-
-                                DrawMessage msg = DrawMessage.parseFromString(
-                                        message.substring(indexOfChar + 1));
-
-                                // Don't ingore RuntimeExceptions thrown by
-                                // this method
-                                // TODO: Find a better solution than this variable
-                                dontSwallowException = true;
-                                if (player != null) {
-                                    player.handleDrawMessage(msg, msgId);
-                                }
-                                dontSwallowException = false;
-
-                                break;
-                            }
-
-                        } catch (RuntimeException|ParseException ex) {
-                            // Client sent invalid data.
-                            // Ignore, TODO: maybe close connection
-                            if (dontSwallowException 
-                                    && ex instanceof RuntimeException) {
-                                throw (RuntimeException) ex;
-                            }
-                        }
-
-                    } catch (RuntimeException ex) {
-                        log.error("Unexpected exception: " + ex.toString(), ex);
-                    }
-                }
-            });
-
-        }
-    };
-
-
-}
+/*
+ *  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 websocket.drawboard;
+
+import java.io.EOFException;
+
+import javax.websocket.CloseReason;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+import websocket.drawboard.DrawMessage.ParseException;
+import websocket.drawboard.wsmessages.StringWebsocketMessage;
+
+
+public final class DrawboardEndpoint extends Endpoint {
+
+    private static final Log log =
+            LogFactory.getLog(DrawboardEndpoint.class);
+
+
+    /**
+     * Our room where players can join.
+     */
+    private static final Room room = new Room();
+
+    public static Room getRoom() {
+        return room;
+    }
+
+    /**
+     * The player that is associated with this Endpoint and the current room.
+     * Note that this variable is only accessed from the Room Thread.<br><br>
+     * 
+     * TODO: Currently, Tomcat uses an Endpoint instance once - however
+     * the java doc of endpoint says:
+     * "Each instance of a websocket endpoint is guaranteed not to be called by
+     * more than one thread at a time per active connection."
+     * This could mean that after calling onClose(), the instance
+     * could be reused for another connection so onOpen() will get called
+     * (possibly from another thread).<br>
+     * If this is the case, we would need a variable holder for the variables
+     * that are accessed by the Room thread, and read the reference to the holder
+     * at the beginning of onOpen, onMessage, onClose methods to ensure the room
+     * thread always gets the correct instance of the variable holder.
+     */
+    private Room.Player player;
+
+
+    @Override
+    public void onOpen(Session session, EndpointConfig config) {
+        // Set maximum messages size to 10.000 bytes.
+        session.setMaxTextMessageBufferSize(10000);
+        session.addMessageHandler(stringHandler);
+        final Client client = new Client(session.getAsyncRemote());
+
+        room.invoke(new Runnable() {
+            @Override
+            public void run() {
+                try {
+
+                    // Create a new Player and add it to the room.
+                    try {
+                        player = room.createAndAddPlayer(client);
+                    } catch (IllegalStateException ex) {
+                        // Probably the max. number of players has been
+                        // reached.
+                        client.sendMessage(new StringWebsocketMessage(
+                                "0" + ex.getLocalizedMessage()));
+                    }
+
+                } catch (RuntimeException ex) {
+                    log.error("Unexpected exception: " + ex.toString(), ex);
+                }
+            }
+        });
+
+    }
+
+
+    @Override
+    public void onClose(Session session, CloseReason closeReason) {
+        room.invoke(new Runnable() {
+            @Override
+            public void run() {
+                try {
+
+                    // Player can be null if it couldn't enter the room
+                    if (player != null) {
+                        // Remove this player from the room.
+                        player.removeFromRoom();
+                    }
+
+                } catch (RuntimeException ex) {
+                    log.error("Unexpected exception: " + ex.toString(), ex);
+                }
+            }
+        });
+
+    }
+
+
+
+    @Override
+    public void onError(Session session, Throwable t) {
+        // Most likely cause is a user closing their browser. Check to see if
+        // the root cause is EOF and if it is ignore it.
+        // Protect against infinite loops.
+        int count = 0;
+        Throwable root = t;
+        while (root.getCause() != null && count < 20) {
+            root = root.getCause();
+            count ++;
+        }
+        if (root instanceof EOFException) {
+            // Assume this is triggered by the user closing their browser and
+            // ignore it.
+        } else {
+            log.error("onError: " + t.toString(), t);
+        }
+    }
+
+
+
+    private final MessageHandler.Whole<String> stringHandler =
+            new MessageHandler.Whole<String>() {
+
+        @Override
+        public void onMessage(final String message) {
+            // Invoke handling of the message in the room.
+            room.invoke(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+
+                        // Currently, the only types of messages the client will send
+                        // are draw messages prefixed by a Message ID
+                        // (starting with char '1'), and pong messages (starting
+                        // with char '0').
+                        // Draw messages should look like this:
+                        // ID|type,colR,colB,colG,colA,thickness,x1,y1,x2,y2
+
+                        boolean dontSwallowException = false;
+                        try {
+                            char messageType = message.charAt(0);
+                            switch (messageType) {
+                            case '0':
+                                // Pong message.
+                                // Do nothing.
+                                break;
+
+                            case '1':
+                                // Draw message
+                                int indexOfChar = message.indexOf('|');
+                                long msgId = Long.parseLong(
+                                        message.substring(0, indexOfChar));
+
+                                DrawMessage msg = DrawMessage.parseFromString(
+                                        message.substring(indexOfChar + 1));
+
+                                // Don't ingore RuntimeExceptions thrown by
+                                // this method
+                                // TODO: Find a better solution than this variable
+                                dontSwallowException = true;
+                                if (player != null) {
+                                    player.handleDrawMessage(msg, msgId);
+                                }
+                                dontSwallowException = false;
+
+                                break;
+                            }
+
+                        } catch (RuntimeException|ParseException ex) {
+                            // Client sent invalid data.
+                            // Ignore, TODO: maybe close connection
+                            if (dontSwallowException 
+                                    && ex instanceof RuntimeException) {
+                                throw (RuntimeException) ex;
+                            }
+                        }
+
+                    } catch (RuntimeException ex) {
+                        log.error("Unexpected exception: " + ex.toString(), ex);
+                    }
+                }
+            });
+
+        }
+    };
+
+
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java Tue Oct  8 14:46:53 2013
@@ -1,436 +1,436 @@
-/*
- *  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 websocket.drawboard;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import javax.imageio.ImageIO;
-
-import websocket.drawboard.wsmessages.BinaryWebsocketMessage;
-import websocket.drawboard.wsmessages.StringWebsocketMessage;
-
-/**
- * A Room represents a drawboard where a number of
- * users participate.<br><br>
- * 
- * Each Room has its own "Room Thread" which manages all the actions
- * to be done in this Room. Instance methods should only be invoked
- * from this Room's thread by calling {@link #invoke(Runnable)} or
- * {@link #invokeAndWait(Runnable)}.
- */
-public final class Room {
-
-    /**
-     * Specifies the type of a room message that is sent to a client.<br>
-     * Note: Currently we are sending simple string messages - for production
-     * apps, a JSON lib should be used for object-level messages.<br><br>
-     * 
-     * The number (single char) will be prefixed to the string when sending
-     * the message.
-     */
-    public static enum MessageType {
-        /**
-         * '0': Error: contains error message.
-         */
-        ERROR('0'),
-        /**
-         * '1': DrawMesssage: contains serialized DrawMessage(s) prefixed
-         *      with the current Player's {@link Player#lastReceivedMessageId}
-         *      and ",".<br>
-         *      Multiple draw messages are concatenated with "|" as separator.
-         */
-        DRAW_MESSAGE('1'),
-        /**
-         * '2': ImageMessage: Contains number of current players in this room.
-         *      After this message a Binary Websocket message will follow,
-         *      containing the current Room image as PNG.<br>
-         *      This is the first message that a Room sends to a new Player.
-         */
-        IMAGE_MESSAGE('2'),
-        /**
-         * '3': PlayerChanged: contains "+" or "-" which indicate a player
-         *      was added or removed to this Room.
-         */
-        PLAYER_CHANGED('3');
-
-        private final char flag;
-
-        private MessageType(char flag) {
-            this.flag = flag;
-        }
-
-    }
-
-
-
-    /**
-     * If <code>true</code>, outgoing DrawMessages will be buffered until the
-     * drawmessageBroadcastTimer ticks. Otherwise they will be sent
-     * immediately.
-     */
-    private static final boolean BUFFER_DRAW_MESSAGES = true; 
-
-    /**
-     * A single-threaded ExecutorService where tasks
-     * are scheduled that are to be run in the Room Thread.
-     */
-    private final ExecutorService roomExecutor =
-            Executors.newSingleThreadExecutor();
-
-    /**
-     * A timer which sends buffered drawmessages to the client at once
-     * at a regular interval, to avoid sending a lot of very small
-     * messages which would cause TCP overhead and high CPU usage.
-     */
-    private final Timer drawmessageBroadcastTimer = new Timer();
-
-
-    /**
-     * The current image of the room drawboard. DrawMessages that are
-     * received from Players will be drawn onto this image.
-     */
-    private final BufferedImage roomImage =
-            new BufferedImage(900, 600, BufferedImage.TYPE_INT_RGB);
-    private final Graphics2D roomGraphics = roomImage.createGraphics();
-
-
-    /**
-     * The maximum number of players that can join this room.
-     */
-    private static final int MAX_PLAYER_COUNT = 2;
-
-    /**
-     * List of all currently joined players.
-     */
-    private final List<Player> players = new ArrayList<>();
-
-
-
-    public Room() {
-        roomGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                RenderingHints.VALUE_ANTIALIAS_ON);
-
-        // Clear the image with white background.
-        roomGraphics.setBackground(Color.WHITE);
-        roomGraphics.clearRect(0, 0, roomImage.getWidth(),
-                roomImage.getHeight());
-
-        // Schedule a TimerTask that broadcasts draw messages.
-        drawmessageBroadcastTimer.schedule(new TimerTask() {
-            @Override
-            public void run() {
-                try {
-                    invokeAndWait(new Runnable() {
-                        @Override
-                        public void run() {
-                            broadcastTimerTick();
-                        }
-                    });
-                } catch (InterruptedException | ExecutionException e) {
-                    // TODO
-                }
-            }
-        }, 30, 30);
-    }
-
-    /**
-     * Creates a Player from the given Client and adds it to this room.
-     * @param c the client
-     * @return
-     */
-    public Player createAndAddPlayer(Client client) {
-        if (players.size() >= MAX_PLAYER_COUNT) {
-            throw new IllegalStateException("MAX_PLAYER_COUNT has been reached.");
-        }
-
-        Player p = new Player(this, client);
-
-        // Broadcast to the other players that one player joined.
-        broadcastRoomMessage(MessageType.PLAYER_CHANGED, "+");
-
-        // Add the new player to the list.
-        players.add(p);
-
-        // Send him the current number of players and the current room image.
-        String content = String.valueOf(players.size());
-        p.sendRoomMessage(MessageType.IMAGE_MESSAGE, content);
-
-        // Store image as PNG
-        ByteArrayOutputStream bout = new ByteArrayOutputStream();
-        try {
-            ImageIO.write(roomImage, "PNG", bout);
-        } catch (IOException e) { /* Should never happen */ }
-
-
-        // Send the image as binary message.
-        BinaryWebsocketMessage msg = new BinaryWebsocketMessage(
-                ByteBuffer.wrap(bout.toByteArray()));
-        p.getClient().sendMessage(msg);
-
-        return p;
-
-    }
-
-    /**
-     * @see Player#removeFromRoom()
-     * @param p
-     */
-    private void internalRemovePlayer(Player p) {
-        players.remove(p);
-
-        // Broadcast that one player is removed.
-        broadcastRoomMessage(MessageType.PLAYER_CHANGED, "-");
-    }
-
-    /**
-     * @see Player#handleDrawMessage(DrawMessage, long)
-     * @param p
-     * @param msg
-     * @param msgId
-     */
-    private void internalHandleDrawMessage(Player p, DrawMessage msg,
-            long msgId) {
-        p.setLastReceivedMessageId(msgId);
-
-        // Draw the RoomMessage onto our Room Image.
-        msg.draw(roomGraphics);
-
-        // Broadcast the Draw Message.
-        broadcastDrawMessage(msg);
-    }
-
-
-    /**
-     * Broadcasts the given drawboard message to all connected players.
-     * Note: For DrawMessages, please use
-     * {@link #broadcastDrawMessage(DrawMessage)}
-     * as this method will buffer them and prefix them with the correct
-     * last received Message ID.
-     * @param type
-     * @param content
-     */
-    private void broadcastRoomMessage(MessageType type, String content) {
-        for (Player p : players) {
-            p.sendRoomMessage(type, content);
-        }
-    }
-
-
-    /**
-     * Broadcast the given DrawMessage. This will buffer the message
-     * and the {@link #drawmessageBroadcastTimer} will broadcast them
-     * at a regular interval, prefixing them with the player's current
-     * {@link Player#lastReceivedMessageId}.
-     * @param msg
-     */
-    private void broadcastDrawMessage(DrawMessage msg) {
-        if (!BUFFER_DRAW_MESSAGES) {
-            String msgStr = msg.toString();
-
-            for (Player p : players) {
-                String s = String.valueOf(p.getLastReceivedMessageId())
-                        + "," + msgStr;
-                p.sendRoomMessage(MessageType.DRAW_MESSAGE, s);
-            }
-        } else {
-            for (Player p : players) {
-                p.getBufferedDrawMessages().add(msg);
-            }
-        }
-    }
-
-
-    /**
-     * Tick handler for the broadcastTimer.
-     */
-    private void broadcastTimerTick() {
-        // For each Player, send all per Player buffered
-        // DrawMessages, prefixing each DrawMessage with the player's
-        // lastReceuvedMessageId.
-        // Multiple messages are concatenated with "|".
-
-        for (Player p : players) {
-
-            StringBuilder sb = new StringBuilder();
-            List<DrawMessage> drawMessages = p.getBufferedDrawMessages();
-
-            if (drawMessages.size() > 0) {
-                for (int i = 0; i < drawMessages.size(); i++) {
-                    DrawMessage msg = drawMessages.get(i);
-
-                    String s = String.valueOf(p.getLastReceivedMessageId())
-                            + "," + msg.toString();
-                    if (i > 0)
-                        sb.append("|");
-
-                    sb.append(s);
-                }
-                drawMessages.clear();            
-
-                p.sendRoomMessage(MessageType.DRAW_MESSAGE, sb.toString());
-            }
-        }
-    }
-
-
-
-
-    /**
-     * Submits the given Runnable to the Room Executor.
-     * @param run
-     */
-    public void invoke(Runnable task) {
-        roomExecutor.submit(task);
-    }
-
-    /**
-     * Submits the given Runnable to the Room Executor and waits until it
-     * has been executed.
-     * @param task
-     * @throws InterruptedException if the current thread was interrupted
-     * while waiting
-     * @throws ExecutionException if the computation threw an exception 
-     */
-    public void invokeAndWait(Runnable task)
-            throws InterruptedException, ExecutionException {
-        Future<?> f = roomExecutor.submit(task);
-        f.get();
-    }
-
-    /**
-     * Shuts down the roomExecutor and the drawmessageBroadcastTimer.
-     */
-    public void shutdown() {
-        roomExecutor.shutdown();
-        drawmessageBroadcastTimer.cancel();
-    }
-
-
-
-    /**
-     * A Player participates in a Room. It is the interface between the
-     * {@link Room} and the {@link Client}.<br><br>
-     * 
-     * Note: This means a player object is actually a join between Room and
-     * Endpoint.
-     */
-    public final class Player {
-
-        /**
-         * The room to which this player belongs.
-         */
-        private Room room;
-
-        /**
-         * The room buffers the last draw message ID that was received from
-         * this player.
-         */
-        private long lastReceivedMessageId = 0;
-
-        private final Client client;
-
-        /**
-         * Buffered DrawMessages that will be sent by a Timer.
-         * TODO: This should be refactored to be in a Room-Player join class
-         * as this is room-specific.
-         */
-        private final List<DrawMessage> bufferedDrawMessages =
-                new ArrayList<>();
-
-        private List<DrawMessage> getBufferedDrawMessages() {
-            return bufferedDrawMessages;
-        }
-
-
-
-        private Player(Room room, Client client) {
-            this.room = room;
-            this.client = client;
-        }
-
-        public Room getRoom() {
-            return room;
-        }
-
-        public Client getClient() {
-            return client;
-        }
-
-        /**
-         * Removes this player from its room, e.g. when
-         * the client disconnects.
-         */
-        public void removeFromRoom() {
-            room.internalRemovePlayer(this);
-            room = null;
-        }
-
-
-        private long getLastReceivedMessageId() {
-            return lastReceivedMessageId;
-        }
-        private void setLastReceivedMessageId(long value) {
-            lastReceivedMessageId = value;
-        }
-
-
-        /**
-         * Handles the given DrawMessage by drawing it onto this Room's
-         * image and by broadcasting it to the connected players.
-         * @param sender
-         * @param msg
-         * @param msgId
-         */
-        public void handleDrawMessage(DrawMessage msg, long msgId) {
-            room.internalHandleDrawMessage(this, msg, msgId);
-        }
-
-
-        /**
-         * Sends the given room message.
-         * @param type
-         * @param content
-         */
-        private void sendRoomMessage(MessageType type, String content) {
-            if (content == null || type == null)
-                throw null;
-
-            String completeMsg = String.valueOf(type.flag) + content;
-
-            client.sendMessage(new StringWebsocketMessage(completeMsg));
-        }
-
-
-
-    }
-
-
-}
+/*
+ *  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 websocket.drawboard;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.imageio.ImageIO;
+
+import websocket.drawboard.wsmessages.BinaryWebsocketMessage;
+import websocket.drawboard.wsmessages.StringWebsocketMessage;
+
+/**
+ * A Room represents a drawboard where a number of
+ * users participate.<br><br>
+ * 
+ * Each Room has its own "Room Thread" which manages all the actions
+ * to be done in this Room. Instance methods should only be invoked
+ * from this Room's thread by calling {@link #invoke(Runnable)} or
+ * {@link #invokeAndWait(Runnable)}.
+ */
+public final class Room {
+
+    /**
+     * Specifies the type of a room message that is sent to a client.<br>
+     * Note: Currently we are sending simple string messages - for production
+     * apps, a JSON lib should be used for object-level messages.<br><br>
+     * 
+     * The number (single char) will be prefixed to the string when sending
+     * the message.
+     */
+    public static enum MessageType {
+        /**
+         * '0': Error: contains error message.
+         */
+        ERROR('0'),
+        /**
+         * '1': DrawMesssage: contains serialized DrawMessage(s) prefixed
+         *      with the current Player's {@link Player#lastReceivedMessageId}
+         *      and ",".<br>
+         *      Multiple draw messages are concatenated with "|" as separator.
+         */
+        DRAW_MESSAGE('1'),
+        /**
+         * '2': ImageMessage: Contains number of current players in this room.
+         *      After this message a Binary Websocket message will follow,
+         *      containing the current Room image as PNG.<br>
+         *      This is the first message that a Room sends to a new Player.
+         */
+        IMAGE_MESSAGE('2'),
+        /**
+         * '3': PlayerChanged: contains "+" or "-" which indicate a player
+         *      was added or removed to this Room.
+         */
+        PLAYER_CHANGED('3');
+
+        private final char flag;
+
+        private MessageType(char flag) {
+            this.flag = flag;
+        }
+
+    }
+
+
+
+    /**
+     * If <code>true</code>, outgoing DrawMessages will be buffered until the
+     * drawmessageBroadcastTimer ticks. Otherwise they will be sent
+     * immediately.
+     */
+    private static final boolean BUFFER_DRAW_MESSAGES = true; 
+
+    /**
+     * A single-threaded ExecutorService where tasks
+     * are scheduled that are to be run in the Room Thread.
+     */
+    private final ExecutorService roomExecutor =
+            Executors.newSingleThreadExecutor();
+
+    /**
+     * A timer which sends buffered drawmessages to the client at once
+     * at a regular interval, to avoid sending a lot of very small
+     * messages which would cause TCP overhead and high CPU usage.
+     */
+    private final Timer drawmessageBroadcastTimer = new Timer();
+
+
+    /**
+     * The current image of the room drawboard. DrawMessages that are
+     * received from Players will be drawn onto this image.
+     */
+    private final BufferedImage roomImage =
+            new BufferedImage(900, 600, BufferedImage.TYPE_INT_RGB);
+    private final Graphics2D roomGraphics = roomImage.createGraphics();
+
+
+    /**
+     * The maximum number of players that can join this room.
+     */
+    private static final int MAX_PLAYER_COUNT = 2;
+
+    /**
+     * List of all currently joined players.
+     */
+    private final List<Player> players = new ArrayList<>();
+
+
+
+    public Room() {
+        roomGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+
+        // Clear the image with white background.
+        roomGraphics.setBackground(Color.WHITE);
+        roomGraphics.clearRect(0, 0, roomImage.getWidth(),
+                roomImage.getHeight());
+
+        // Schedule a TimerTask that broadcasts draw messages.
+        drawmessageBroadcastTimer.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                try {
+                    invokeAndWait(new Runnable() {
+                        @Override
+                        public void run() {
+                            broadcastTimerTick();
+                        }
+                    });
+                } catch (InterruptedException | ExecutionException e) {
+                    // TODO
+                }
+            }
+        }, 30, 30);
+    }
+
+    /**
+     * Creates a Player from the given Client and adds it to this room.
+     * @param c the client
+     * @return
+     */
+    public Player createAndAddPlayer(Client client) {
+        if (players.size() >= MAX_PLAYER_COUNT) {
+            throw new IllegalStateException("MAX_PLAYER_COUNT has been reached.");
+        }
+
+        Player p = new Player(this, client);
+
+        // Broadcast to the other players that one player joined.
+        broadcastRoomMessage(MessageType.PLAYER_CHANGED, "+");
+
+        // Add the new player to the list.
+        players.add(p);
+
+        // Send him the current number of players and the current room image.
+        String content = String.valueOf(players.size());
+        p.sendRoomMessage(MessageType.IMAGE_MESSAGE, content);
+
+        // Store image as PNG
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        try {
+            ImageIO.write(roomImage, "PNG", bout);
+        } catch (IOException e) { /* Should never happen */ }
+
+
+        // Send the image as binary message.
+        BinaryWebsocketMessage msg = new BinaryWebsocketMessage(
+                ByteBuffer.wrap(bout.toByteArray()));
+        p.getClient().sendMessage(msg);
+
+        return p;
+
+    }
+
+    /**
+     * @see Player#removeFromRoom()
+     * @param p
+     */
+    private void internalRemovePlayer(Player p) {
+        players.remove(p);
+
+        // Broadcast that one player is removed.
+        broadcastRoomMessage(MessageType.PLAYER_CHANGED, "-");
+    }
+
+    /**
+     * @see Player#handleDrawMessage(DrawMessage, long)
+     * @param p
+     * @param msg
+     * @param msgId
+     */
+    private void internalHandleDrawMessage(Player p, DrawMessage msg,
+            long msgId) {
+        p.setLastReceivedMessageId(msgId);
+
+        // Draw the RoomMessage onto our Room Image.
+        msg.draw(roomGraphics);
+
+        // Broadcast the Draw Message.
+        broadcastDrawMessage(msg);
+    }
+
+
+    /**
+     * Broadcasts the given drawboard message to all connected players.
+     * Note: For DrawMessages, please use
+     * {@link #broadcastDrawMessage(DrawMessage)}
+     * as this method will buffer them and prefix them with the correct
+     * last received Message ID.
+     * @param type
+     * @param content
+     */
+    private void broadcastRoomMessage(MessageType type, String content) {
+        for (Player p : players) {
+            p.sendRoomMessage(type, content);
+        }
+    }
+
+
+    /**
+     * Broadcast the given DrawMessage. This will buffer the message
+     * and the {@link #drawmessageBroadcastTimer} will broadcast them
+     * at a regular interval, prefixing them with the player's current
+     * {@link Player#lastReceivedMessageId}.
+     * @param msg
+     */
+    private void broadcastDrawMessage(DrawMessage msg) {
+        if (!BUFFER_DRAW_MESSAGES) {
+            String msgStr = msg.toString();
+
+            for (Player p : players) {
+                String s = String.valueOf(p.getLastReceivedMessageId())
+                        + "," + msgStr;
+                p.sendRoomMessage(MessageType.DRAW_MESSAGE, s);
+            }
+        } else {
+            for (Player p : players) {
+                p.getBufferedDrawMessages().add(msg);
+            }
+        }
+    }
+
+
+    /**
+     * Tick handler for the broadcastTimer.
+     */
+    private void broadcastTimerTick() {
+        // For each Player, send all per Player buffered
+        // DrawMessages, prefixing each DrawMessage with the player's
+        // lastReceuvedMessageId.
+        // Multiple messages are concatenated with "|".
+
+        for (Player p : players) {
+
+            StringBuilder sb = new StringBuilder();
+            List<DrawMessage> drawMessages = p.getBufferedDrawMessages();
+
+            if (drawMessages.size() > 0) {
+                for (int i = 0; i < drawMessages.size(); i++) {
+                    DrawMessage msg = drawMessages.get(i);
+
+                    String s = String.valueOf(p.getLastReceivedMessageId())
+                            + "," + msg.toString();
+                    if (i > 0)
+                        sb.append("|");
+
+                    sb.append(s);
+                }
+                drawMessages.clear();            
+
+                p.sendRoomMessage(MessageType.DRAW_MESSAGE, sb.toString());
+            }
+        }
+    }
+
+
+
+
+    /**
+     * Submits the given Runnable to the Room Executor.
+     * @param run
+     */
+    public void invoke(Runnable task) {
+        roomExecutor.submit(task);
+    }
+
+    /**
+     * Submits the given Runnable to the Room Executor and waits until it
+     * has been executed.
+     * @param task
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     * @throws ExecutionException if the computation threw an exception 
+     */
+    public void invokeAndWait(Runnable task)
+            throws InterruptedException, ExecutionException {
+        Future<?> f = roomExecutor.submit(task);
+        f.get();
+    }
+
+    /**
+     * Shuts down the roomExecutor and the drawmessageBroadcastTimer.
+     */
+    public void shutdown() {
+        roomExecutor.shutdown();
+        drawmessageBroadcastTimer.cancel();
+    }
+
+
+
+    /**
+     * A Player participates in a Room. It is the interface between the
+     * {@link Room} and the {@link Client}.<br><br>
+     * 
+     * Note: This means a player object is actually a join between Room and
+     * Endpoint.
+     */
+    public final class Player {
+
+        /**
+         * The room to which this player belongs.
+         */
+        private Room room;
+
+        /**
+         * The room buffers the last draw message ID that was received from
+         * this player.
+         */
+        private long lastReceivedMessageId = 0;
+
+        private final Client client;
+
+        /**
+         * Buffered DrawMessages that will be sent by a Timer.
+         * TODO: This should be refactored to be in a Room-Player join class
+         * as this is room-specific.
+         */
+        private final List<DrawMessage> bufferedDrawMessages =
+                new ArrayList<>();
+
+        private List<DrawMessage> getBufferedDrawMessages() {
+            return bufferedDrawMessages;
+        }
+
+
+
+        private Player(Room room, Client client) {
+            this.room = room;
+            this.client = client;
+        }
+
+        public Room getRoom() {
+            return room;
+        }
+
+        public Client getClient() {
+            return client;
+        }
+
+        /**
+         * Removes this player from its room, e.g. when
+         * the client disconnects.
+         */
+        public void removeFromRoom() {
+            room.internalRemovePlayer(this);
+            room = null;
+        }
+
+
+        private long getLastReceivedMessageId() {
+            return lastReceivedMessageId;
+        }
+        private void setLastReceivedMessageId(long value) {
+            lastReceivedMessageId = value;
+        }
+
+
+        /**
+         * Handles the given DrawMessage by drawing it onto this Room's
+         * image and by broadcasting it to the connected players.
+         * @param sender
+         * @param msg
+         * @param msgId
+         */
+        public void handleDrawMessage(DrawMessage msg, long msgId) {
+            room.internalHandleDrawMessage(this, msg, msgId);
+        }
+
+
+        /**
+         * Sends the given room message.
+         * @param type
+         * @param content
+         */
+        private void sendRoomMessage(MessageType type, String content) {
+            if (content == null || type == null)
+                throw null;
+
+            String completeMsg = String.valueOf(type.flag) + content;
+
+            client.sendMessage(new StringWebsocketMessage(completeMsg));
+        }
+
+
+
+    }
+
+
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/WsConfigListener.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/WsConfigListener.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/WsConfigListener.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/WsConfigListener.java Tue Oct  8 14:46:53 2013
@@ -1,48 +1,48 @@
-/*
- *  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 websocket.drawboard;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-import javax.websocket.DeploymentException;
-import javax.websocket.server.ServerContainer;
-import javax.websocket.server.ServerEndpointConfig;
-
-@WebListener
-public final class WsConfigListener implements ServletContextListener {
-
-    @Override
-    public void contextInitialized(ServletContextEvent sce) {
-
-        ServerContainer sc =
-                (ServerContainer) sce.getServletContext().getAttribute(
-                        "javax.websocket.server.ServerContainer");
-        try {
-            sc.addEndpoint(ServerEndpointConfig.Builder.create(
-                    DrawboardEndpoint.class, "/websocket/drawboard").build());
-        } catch (DeploymentException e) {
-            throw new IllegalStateException(e);
-        }
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent sce) {
-        // Shutdown our room.
-        DrawboardEndpoint.getRoom().shutdown();
-    }
-}
+/*
+ *  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 websocket.drawboard;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+@WebListener
+public final class WsConfigListener implements ServletContextListener {
+
+    @Override
+    public void contextInitialized(ServletContextEvent sce) {
+
+        ServerContainer sc =
+                (ServerContainer) sce.getServletContext().getAttribute(
+                        "javax.websocket.server.ServerContainer");
+        try {
+            sc.addEndpoint(ServerEndpointConfig.Builder.create(
+                    DrawboardEndpoint.class, "/websocket/drawboard").build());
+        } catch (DeploymentException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce) {
+        // Shutdown our room.
+        DrawboardEndpoint.getRoom().shutdown();
+    }
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/WsConfigListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java Tue Oct  8 14:46:53 2013
@@ -1,25 +1,25 @@
-/*
- *  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 websocket.drawboard.wsmessages;
-
-/**
- * Abstract base class for Websocket Messages (binary or string)
- * that can be buffered.
- */
-public abstract class AbstractWebsocketMessage {
-
-}
+/*
+ *  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 websocket.drawboard.wsmessages;
+
+/**
+ * Abstract base class for Websocket Messages (binary or string)
+ * that can be buffered.
+ */
+public abstract class AbstractWebsocketMessage {
+
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java Tue Oct  8 14:46:53 2013
@@ -1,34 +1,34 @@
-/*
- *  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 websocket.drawboard.wsmessages;
-
-import java.nio.ByteBuffer;
-
-/**
- * Represents a binary websocket message.
- */
-public final class BinaryWebsocketMessage extends AbstractWebsocketMessage {
-    private final ByteBuffer bytes;
-
-    public BinaryWebsocketMessage(ByteBuffer bytes) {
-        this.bytes = bytes;
-    }
-
-    public ByteBuffer getBytes() {
-        return bytes;
-    }
-}
+/*
+ *  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 websocket.drawboard.wsmessages;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Represents a binary websocket message.
+ */
+public final class BinaryWebsocketMessage extends AbstractWebsocketMessage {
+    private final ByteBuffer bytes;
+
+    public BinaryWebsocketMessage(ByteBuffer bytes) {
+        this.bytes = bytes;
+    }
+
+    public ByteBuffer getBytes() {
+        return bytes;
+    }
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java?rev=1530298&r1=1530297&r2=1530298&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java Tue Oct  8 14:46:53 2013
@@ -1,34 +1,34 @@
-/*
- *  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 websocket.drawboard.wsmessages;
-
-/**
- * Represents a string websocket message.
- *
- */
-public final class StringWebsocketMessage extends AbstractWebsocketMessage {
-    private final String string;
-
-    public StringWebsocketMessage(String string) {
-        this.string = string;
-    }
-
-    public String getString() {
-        return string;
-    }
-
-}
+/*
+ *  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 websocket.drawboard.wsmessages;
+
+/**
+ * Represents a string websocket message.
+ *
+ */
+public final class StringWebsocketMessage extends AbstractWebsocketMessage {
+    private final String string;
+
+    public StringWebsocketMessage(String string) {
+        this.string = string;
+    }
+
+    public String getString() {
+        return string;
+    }
+
+}

Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message