升级Tomcat版本 apache-tomcat-7.0.77
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.class b/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.class
index bc8e321..5b481e7 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.java b/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.java
index 5d7d5ce..b3e1c09 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/CookieExample.java
@@ -15,10 +15,15 @@
* limitations under the License.
*/
-import java.io.*;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ResourceBundle;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import util.HTMLFilter;
@@ -30,29 +35,42 @@
public class CookieExample extends HttpServlet {
- ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
-
+ private static final long serialVersionUID = 1L;
+
+ private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings");
+
+ @Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
+
+ String cookieName = request.getParameter("cookiename");
+ String cookieValue = request.getParameter("cookievalue");
+ Cookie aCookie = null;
+ if (cookieName != null && cookieValue != null) {
+ aCookie = new Cookie(cookieName, cookieValue);
+ aCookie.setPath(request.getContextPath() + "/");
+ response.addCookie(aCookie);
+ }
+
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
- String title = rb.getString("cookies.title");
+ String title = RB.getString("cookies.title");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
- // relative links
+ // relative links
// XXX
// making these absolute till we work out the
- // addition of a PathInfo issue
-
+ // addition of a PathInfo issue
+
out.println("<a href=\"../cookies.html\">");
out.println("<img src=\"../images/code.gif\" height=24 " +
"width=24 align=right border=0 alt=\"view code\"></a>");
@@ -64,47 +82,44 @@
Cookie[] cookies = request.getCookies();
if ((cookies != null) && (cookies.length > 0)) {
- out.println(rb.getString("cookies.cookies") + "<br>");
+ out.println(RB.getString("cookies.cookies") + "<br>");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
out.print("Cookie Name: " + HTMLFilter.filter(cookie.getName())
+ "<br>");
- out.println(" Cookie Value: "
+ out.println(" Cookie Value: "
+ HTMLFilter.filter(cookie.getValue())
+ "<br><br>");
}
} else {
- out.println(rb.getString("cookies.no-cookies"));
+ out.println(RB.getString("cookies.no-cookies"));
}
- String cookieName = request.getParameter("cookiename");
- String cookieValue = request.getParameter("cookievalue");
- if (cookieName != null && cookieValue != null) {
- Cookie cookie = new Cookie(cookieName, cookieValue);
- response.addCookie(cookie);
+ if (aCookie != null) {
out.println("<P>");
- out.println(rb.getString("cookies.set") + "<br>");
- out.print(rb.getString("cookies.name") + " "
+ out.println(RB.getString("cookies.set") + "<br>");
+ out.print(RB.getString("cookies.name") + " "
+ HTMLFilter.filter(cookieName) + "<br>");
- out.print(rb.getString("cookies.value") + " "
+ out.print(RB.getString("cookies.value") + " "
+ HTMLFilter.filter(cookieValue));
}
-
+
out.println("<P>");
- out.println(rb.getString("cookies.make-cookie") + "<br>");
+ out.println(RB.getString("cookies.make-cookie") + "<br>");
out.print("<form action=\"");
out.println("CookieExample\" method=POST>");
- out.print(rb.getString("cookies.name") + " ");
+ out.print(RB.getString("cookies.name") + " ");
out.println("<input type=text length=20 name=cookiename><br>");
- out.print(rb.getString("cookies.value") + " ");
+ out.print(RB.getString("cookies.value") + " ");
out.println("<input type=text length=20 name=cookievalue><br>");
out.println("<input type=submit></form>");
-
-
+
+
out.println("</body>");
out.println("</html>");
}
+ @Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.class b/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.class
index 0d3c85e..41e3c40 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.java b/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.java
index 3702542..9902e3b 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/HelloWorldExample.java
@@ -14,11 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ResourceBundle;
-import java.io.*;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
/**
* The simplest possible servlet.
@@ -28,7 +31,9 @@
public class HelloWorldExample extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+ @Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
@@ -41,22 +46,22 @@
out.println("<html>");
out.println("<head>");
- String title = rb.getString("helloworld.title");
+ String title = rb.getString("helloworld.title");
- out.println("<title>" + title + "</title>");
+ out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
- // note that all links are created to be relative. this
- // ensures that we can move the web application that this
- // servlet belongs to to a different place in the url
- // tree and not have any harmful side effects.
+ // note that all links are created to be relative. this
+ // ensures that we can move the web application that this
+ // servlet belongs to to a different place in the url
+ // tree and not have any harmful side effects.
// XXX
// making these absolute till we work out the
// addition of a PathInfo issue
- out.println("<a href=\"../helloworld.html\">");
+ out.println("<a href=\"../helloworld.html\">");
out.println("<img src=\"../images/code.gif\" height=24 " +
"width=24 align=right border=0 alt=\"view code\"></a>");
out.println("<a href=\"../index.html\">");
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/LocalStrings_es.properties b/tomcat-cas/webapps/examples/WEB-INF/classes/LocalStrings_es.properties
index f5a1261..009e34d 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/LocalStrings_es.properties
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/LocalStrings_es.properties
@@ -12,40 +12,31 @@
# 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.
-
-# Default localized string information
-# Localized para Locale es_ES
-
-helloworld.title=Hola Mundo!
-
-requestinfo.title=Ejemplo de Informacion de Request
-requestinfo.label.method=Metodo:
-requestinfo.label.requesturi=Request URI:
-requestinfo.label.protocol=Protocolo:
-requestinfo.label.pathinfo=Path Info:
-requestinfo.label.remoteaddr=Direccion Remota:
-
-requestheader.title=Ejemplo de Cabecera de Request
-
-requestparams.title=Ejemplo de parametros de Request
-requestparams.params-in-req=Parametros en este Request:
-requestparams.no-params=No hay parametro. por favor usa alguno
-requestparams.firstname=Nombre:
-requestparams.lastname=Apellidos:
-
-cookies.title=Ejemplo de Cookies
-cookies.cookies=Tu navegador esta enviando los siguientes cookies:
-cookies.no-cookies=Tu navegador no esta enviando cookies
-cookies.make-cookie=Crea un cookie para enviarlo a tu navegador
-cookies.name=Nombre:
-cookies.value=Valor:
-cookies.set=Acabas de enviar a tu navegador estos cookies:
-
-sessions.title=ejemplo de Sesiones
-sessions.id=ID de Sesion:
-sessions.created=Creado:
-sessions.lastaccessed=Ultimo Acceso:
-sessions.data=Lo siguientes datos estan en tu sesion:
-sessions.adddata=A\u00f1ade datos a tu sesion:
-sessions.dataname=Nombre del atributo de sesion:
-sessions.datavalue=Valor del atributo de sesion:
+helloworld.title = Hola Mundo\!
+requestinfo.title = Ejemplo de Informacion de Requerimiento\:
+requestinfo.label.method = M\u00E9todo\:
+requestinfo.label.requesturi = URI de Requerimiento\:
+requestinfo.label.protocol = Protocolo\:
+requestinfo.label.pathinfo = Info de Ruta\:
+requestinfo.label.remoteaddr = Direccion Remota\:
+requestheader.title = Ejemplo de Cabecera de Requerimiento\:
+requestparams.title = Ejemplo de par\u00E1metros de Requerimiento\:
+requestparams.params-in-req = Par\u00E1metros en este Request\:
+requestparams.no-params = No hay p\u00E1rametro. Por favor, usa alguno
+requestparams.firstname = Nombre\:
+requestparams.lastname = Apellidos\:
+cookies.title = Ejemplo de Cookies
+cookies.cookies = Tu navegador est\u00E1 enviando los siguientes cookies\:
+cookies.no-cookies = Tu navegador no est\u00E1 enviando cookies
+cookies.make-cookie = Crea un cookie para enviarlo a tu navegador
+cookies.name = Nombre\:
+cookies.value = Valor\:
+cookies.set = Acabas de enviar a tu navegador estos cookies\:
+sessions.title = Ejemplo de Sesiones
+sessions.id = ID de Sesi\u00F3n\:
+sessions.created = Creado\:
+sessions.lastaccessed = Ultimo Acceso\:
+sessions.data = Lo siguientes datos est\u00E1n en tu sesi\u00F3n\:
+sessions.adddata = A\u00F1ade datos a tu sesi\u00F3n\:
+sessions.dataname = Nombre del atributo de sesi\u00F3n\:
+sessions.datavalue = Valor del atributo de sesi\u00F3n\:
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.class b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.class
index 8270f63..23151e8 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.java b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.java
index 2a550f2..2010767 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestHeaderExample.java
@@ -15,11 +15,19 @@
* limitations under the License.
*/
-import java.io.*;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import util.CookieFilter;
import util.HTMLFilter;
/**
@@ -30,8 +38,11 @@
public class RequestHeaderExample extends HttpServlet {
- ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
-
+ private static final long serialVersionUID = 1L;
+
+ private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings");
+
+ @Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
@@ -42,17 +53,17 @@
out.println("<html>");
out.println("<head>");
- String title = rb.getString("requestheader.title");
+ String title = RB.getString("requestheader.title");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
- // all links relative
+ // all links relative
// XXX
// making these absolute till we work out the
- // addition of a PathInfo issue
-
+ // addition of a PathInfo issue
+
out.println("<a href=\"../reqheaders.html\">");
out.println("<img src=\"../images/code.gif\" height=24 " +
"width=24 align=right border=0 alt=\"view code\"></a>");
@@ -62,19 +73,29 @@
out.println("<h3>" + title + "</h3>");
out.println("<table border=0>");
- Enumeration e = request.getHeaderNames();
+ Enumeration<String> e = request.getHeaderNames();
while (e.hasMoreElements()) {
- String headerName = (String)e.nextElement();
+ String headerName = e.nextElement();
String headerValue = request.getHeader(headerName);
out.println("<tr><td bgcolor=\"#CCCCCC\">");
out.println(HTMLFilter.filter(headerName));
out.println("</td><td>");
- out.println(HTMLFilter.filter(headerValue));
+ if (headerName.toLowerCase(Locale.ENGLISH).contains("cookie")) {
+ HttpSession session = request.getSession(false);
+ String sessionId = null;
+ if (session != null) {
+ sessionId = session.getId();
+ }
+ out.println(HTMLFilter.filter(CookieFilter.filter(headerValue, sessionId)));
+ } else {
+ out.println(HTMLFilter.filter(headerValue));
+ }
out.println("</td></tr>");
}
out.println("</table>");
}
+ @Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.class b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.class
index e93ed68..b060caf 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.java b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.java
index 86313e5..1f429e8 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestInfoExample.java
@@ -15,10 +15,14 @@
* limitations under the License.
*/
-import java.io.*;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ResourceBundle;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import util.HTMLFilter;
@@ -30,9 +34,11 @@
public class RequestInfoExample extends HttpServlet {
+ private static final long serialVersionUID = 1L;
- ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
+ private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings");
+ @Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
@@ -43,7 +49,7 @@
out.println("<html>");
out.println("<head>");
- String title = rb.getString("requestinfo.title");
+ String title = RB.getString("requestinfo.title");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
@@ -64,23 +70,23 @@
out.println("<h3>" + title + "</h3>");
out.println("<table border=0><tr><td>");
- out.println(rb.getString("requestinfo.label.method"));
+ out.println(RB.getString("requestinfo.label.method"));
out.println("</td><td>");
out.println(HTMLFilter.filter(request.getMethod()));
out.println("</td></tr><tr><td>");
- out.println(rb.getString("requestinfo.label.requesturi"));
+ out.println(RB.getString("requestinfo.label.requesturi"));
out.println("</td><td>");
out.println(HTMLFilter.filter(request.getRequestURI()));
out.println("</td></tr><tr><td>");
- out.println(rb.getString("requestinfo.label.protocol"));
+ out.println(RB.getString("requestinfo.label.protocol"));
out.println("</td><td>");
out.println(HTMLFilter.filter(request.getProtocol()));
out.println("</td></tr><tr><td>");
- out.println(rb.getString("requestinfo.label.pathinfo"));
+ out.println(RB.getString("requestinfo.label.pathinfo"));
out.println("</td><td>");
out.println(HTMLFilter.filter(request.getPathInfo()));
out.println("</td></tr><tr><td>");
- out.println(rb.getString("requestinfo.label.remoteaddr"));
+ out.println(RB.getString("requestinfo.label.remoteaddr"));
out.println("</td><td>");
out.println(HTMLFilter.filter(request.getRemoteAddr()));
out.println("</td></tr>");
@@ -98,6 +104,7 @@
out.println("</table>");
}
+ @Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.class b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.class
index dccd0ba..a0233b4 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.java b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.java
index 2b8b77c..a4c5c67 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/RequestParamExample.java
@@ -15,10 +15,14 @@
* limitations under the License.
*/
-import java.io.*;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ResourceBundle;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import util.HTMLFilter;
@@ -30,9 +34,11 @@
public class RequestParamExample extends HttpServlet {
+ private static final long serialVersionUID = 1L;
- ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
-
+ private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings");
+
+ @Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
@@ -43,19 +49,19 @@
out.println("<html>");
out.println("<head>");
- String title = rb.getString("requestparams.title");
+ String title = RB.getString("requestparams.title");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
// img stuff not req'd for source code html showing
- // all links relative
+ // all links relative
// XXX
// making these absolute till we work out the
- // addition of a PathInfo issue
-
+ // addition of a PathInfo issue
+
out.println("<a href=\"../reqparams.html\">");
out.println("<img src=\"../images/code.gif\" height=24 " +
"width=24 align=right border=0 alt=\"view code\"></a>");
@@ -66,23 +72,23 @@
out.println("<h3>" + title + "</h3>");
String firstName = request.getParameter("firstname");
String lastName = request.getParameter("lastname");
- out.println(rb.getString("requestparams.params-in-req") + "<br>");
+ out.println(RB.getString("requestparams.params-in-req") + "<br>");
if (firstName != null || lastName != null) {
- out.println(rb.getString("requestparams.firstname"));
+ out.println(RB.getString("requestparams.firstname"));
out.println(" = " + HTMLFilter.filter(firstName) + "<br>");
- out.println(rb.getString("requestparams.lastname"));
+ out.println(RB.getString("requestparams.lastname"));
out.println(" = " + HTMLFilter.filter(lastName));
} else {
- out.println(rb.getString("requestparams.no-params"));
+ out.println(RB.getString("requestparams.no-params"));
}
out.println("<P>");
out.print("<form action=\"");
out.print("RequestParamExample\" ");
out.println("method=POST>");
- out.println(rb.getString("requestparams.firstname"));
+ out.println(RB.getString("requestparams.firstname"));
out.println("<input type=text size=20 name=firstname>");
out.println("<br>");
- out.println(rb.getString("requestparams.lastname"));
+ out.println(RB.getString("requestparams.lastname"));
out.println("<input type=text size=20 name=lastname>");
out.println("<br>");
out.println("<input type=submit>");
@@ -92,6 +98,7 @@
out.println("</html>");
}
+ @Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.class b/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.class
index 372e463..232cc36 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.java b/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.java
index 33f4f8f..cca91e0 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/SessionExample.java
@@ -15,10 +15,17 @@
* limitations under the License.
*/
-import java.io.*;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
import util.HTMLFilter;
@@ -30,8 +37,11 @@
public class SessionExample extends HttpServlet {
- ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
-
+ private static final long serialVersionUID = 1L;
+
+ private static final ResourceBundle RB = ResourceBundle.getBundle("LocalStrings");
+
+ @Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
@@ -42,18 +52,18 @@
out.println("<html>");
out.println("<head>");
- String title = rb.getString("sessions.title");
+ String title = RB.getString("sessions.title");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
// img stuff not req'd for source code html showing
- // relative links everywhere!
+ // relative links everywhere!
// XXX
// making these absolute till we work out the
- // addition of a PathInfo issue
-
+ // addition of a PathInfo issue
+
out.println("<a href=\"../sessions.html\">");
out.println("<img src=\"../images/code.gif\" height=24 " +
"width=24 align=right border=0 alt=\"view code\"></a>");
@@ -64,11 +74,11 @@
out.println("<h3>" + title + "</h3>");
HttpSession session = request.getSession(true);
- out.println(rb.getString("sessions.id") + " " + session.getId());
+ out.println(RB.getString("sessions.id") + " " + session.getId());
out.println("<br>");
- out.println(rb.getString("sessions.created") + " ");
+ out.println(RB.getString("sessions.created") + " ");
out.println(new Date(session.getCreationTime()) + "<br>");
- out.println(rb.getString("sessions.lastaccessed") + " ");
+ out.println(RB.getString("sessions.lastaccessed") + " ");
out.println(new Date(session.getLastAccessedTime()));
String dataName = request.getParameter("dataname");
@@ -78,24 +88,24 @@
}
out.println("<P>");
- out.println(rb.getString("sessions.data") + "<br>");
- Enumeration names = session.getAttributeNames();
+ out.println(RB.getString("sessions.data") + "<br>");
+ Enumeration<String> names = session.getAttributeNames();
while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
+ String name = names.nextElement();
String value = session.getAttribute(name).toString();
- out.println(HTMLFilter.filter(name) + " = "
+ out.println(HTMLFilter.filter(name) + " = "
+ HTMLFilter.filter(value) + "<br>");
}
out.println("<P>");
out.print("<form action=\"");
- out.print(response.encodeURL("SessionExample"));
+ out.print(response.encodeURL("SessionExample"));
out.print("\" ");
out.println("method=POST>");
- out.println(rb.getString("sessions.dataname"));
+ out.println(RB.getString("sessions.dataname"));
out.println("<input type=text size=20 name=dataname>");
out.println("<br>");
- out.println(rb.getString("sessions.datavalue"));
+ out.println(RB.getString("sessions.datavalue"));
out.println("<input type=text size=20 name=datavalue>");
out.println("<br>");
out.println("<input type=submit>");
@@ -103,13 +113,13 @@
out.println("<P>GET based form:<br>");
out.print("<form action=\"");
- out.print(response.encodeURL("SessionExample"));
+ out.print(response.encodeURL("SessionExample"));
out.print("\" ");
out.println("method=GET>");
- out.println(rb.getString("sessions.dataname"));
+ out.println(RB.getString("sessions.dataname"));
out.println("<input type=text size=20 name=dataname>");
out.println("<br>");
- out.println(rb.getString("sessions.datavalue"));
+ out.println(RB.getString("sessions.datavalue"));
out.println("<input type=text size=20 name=datavalue>");
out.println("<br>");
out.println("<input type=submit>");
@@ -118,11 +128,12 @@
out.print("<p><a href=\"");
out.print(HTMLFilter.filter(response.encodeURL("SessionExample?dataname=foo&datavalue=bar")));
out.println("\" >URL encoded </a>");
-
+
out.println("</body>");
out.println("</html>");
}
+ @Override
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0$1.class
new file mode 100644
index 0000000..021733f
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0.class
new file mode 100644
index 0000000..16fde39
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0.java b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0.java
new file mode 100644
index 0000000..ea4df76
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async0.java
@@ -0,0 +1,67 @@
+/*
+* 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 async;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+public class Async0 extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Log log = LogFactory.getLog(Async0.class);
+
+ @Override
+ protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+ if (Boolean.TRUE.equals(req.getAttribute("dispatch"))) {
+ log.info("Received dispatch, completing on the worker thread.");
+ log.info("After complete called started:"+req.isAsyncStarted());
+ resp.getWriter().write("Async dispatch worked:+"+System.currentTimeMillis()+"\n");
+ } else {
+ resp.setContentType("text/plain");
+ final AsyncContext actx = req.startAsync();
+ actx.setTimeout(Long.MAX_VALUE);
+ Runnable run = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ req.setAttribute("dispatch", Boolean.TRUE);
+ Thread.currentThread().setName("Async0-Thread");
+ log.info("Putting AsyncThread to sleep");
+ Thread.sleep(2*1000);
+ log.info("Dispatching");
+ actx.dispatch();
+ }catch (InterruptedException x) {
+ log.error("Async1",x);
+ }catch (IllegalStateException x) {
+ log.error("Async1",x);
+ }
+ }
+ };
+ Thread t = new Thread(run);
+ t.start();
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1$1.class
new file mode 100644
index 0000000..531cadb
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1.class
new file mode 100644
index 0000000..eb85ea0
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1.java b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1.java
new file mode 100644
index 0000000..9403a3a
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async1.java
@@ -0,0 +1,62 @@
+/*
+* 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 async;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+public class Async1 extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Log log = LogFactory.getLog(Async1.class);
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ final AsyncContext actx = req.startAsync();
+ actx.setTimeout(30*1000);
+ Runnable run = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String path = "/jsp/async/async1.jsp";
+ Thread.currentThread().setName("Async1-Thread");
+ log.info("Putting AsyncThread to sleep");
+ Thread.sleep(2*1000);
+ log.info("Dispatching to "+path);
+ actx.dispatch(path);
+ }catch (InterruptedException x) {
+ log.error("Async1",x);
+ }catch (IllegalStateException x) {
+ log.error("Async1",x);
+ }
+ }
+ };
+ Thread t = new Thread(run);
+ t.start();
+ }
+
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2$1.class
new file mode 100644
index 0000000..10cfa14
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2.class
new file mode 100644
index 0000000..d79bb88
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2.java b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2.java
new file mode 100644
index 0000000..649afbc
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async2.java
@@ -0,0 +1,64 @@
+/*
+* 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 async;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+public class Async2 extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Log log = LogFactory.getLog(Async2.class);
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ final AsyncContext actx = req.startAsync();
+ actx.setTimeout(30*1000);
+ Runnable run = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.currentThread().setName("Async2-Thread");
+ log.info("Putting AsyncThread to sleep");
+ Thread.sleep(2*1000);
+ log.info("Writing data.");
+ actx.getResponse().getWriter().write("Output from background thread. Time:"+System.currentTimeMillis()+"\n");
+ actx.complete();
+ }catch (InterruptedException x) {
+ log.error("Async2",x);
+ }catch (IllegalStateException x) {
+ log.error("Async2",x);
+ }catch (IOException x) {
+ log.error("Async2",x);
+ }
+ }
+ };
+ Thread t = new Thread(run);
+ t.start();
+ }
+
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async3.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async3.class
new file mode 100644
index 0000000..bd90d90
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async3.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async3.java b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async3.java
new file mode 100644
index 0000000..39e0fe5
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Async3.java
@@ -0,0 +1,39 @@
+/*
+* 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 async;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class Async3 extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ final AsyncContext actx = req.startAsync();
+ actx.setTimeout(30*1000);
+ actx.dispatch("/jsp/async/async3.jsp");
+ }
+
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.class
new file mode 100644
index 0000000..117f084
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java b/tomcat-cas/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java
new file mode 100644
index 0000000..ad4c43e
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java
@@ -0,0 +1,131 @@
+/*
+ * 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 async;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import async.Stockticker.Stock;
+import async.Stockticker.TickListener;
+
+public class AsyncStockServlet extends HttpServlet implements TickListener, AsyncListener{
+
+ private static final long serialVersionUID = 1L;
+
+ public static final String POLL = "POLL";
+ public static final String LONG_POLL = "LONG-POLL";
+ public static final String STREAM = "STREAM";
+
+ static ArrayList<Stock> ticks = new ArrayList<Stock>();
+ static ConcurrentLinkedQueue<AsyncContext> clients = new ConcurrentLinkedQueue<AsyncContext>();
+ static AtomicInteger clientcount = new AtomicInteger(0);
+ static Stockticker ticker = new Stockticker();
+
+ public AsyncStockServlet() {
+ System.out.println("AsyncStockServlet created");
+ }
+
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ if (req.isAsyncStarted()) {
+ req.getAsyncContext().complete();
+ } else if (req.isAsyncSupported()) {
+ AsyncContext actx = req.startAsync();
+ actx.addListener(this);
+ resp.setContentType("text/plain");
+ clients.add(actx);
+ if (clientcount.incrementAndGet()==1) {
+ ticker.addTickListener(this);
+ }
+ } else {
+ new Exception("Async Not Supported").printStackTrace();
+ resp.sendError(400,"Async is not supported.");
+ }
+ }
+
+
+ @Override
+ public void tick(Stock stock) {
+ ticks.add((Stock)stock.clone());
+ Iterator<AsyncContext> it = clients.iterator();
+ while (it.hasNext()) {
+ AsyncContext actx = it.next();
+ try {
+ writeStock(actx, stock);
+ } catch (Exception e) {
+ // Ignore. The async error handling will deal with this.
+ }
+ }
+ }
+
+ public void writeStock(AsyncContext actx, Stock stock) {
+ HttpServletResponse response = (HttpServletResponse)actx.getResponse();
+ try {
+ PrintWriter writer = response.getWriter();
+ writer.write("STOCK#");//make client parsing easier
+ writer.write(stock.getSymbol());
+ writer.write("#");
+ writer.write(stock.getValueAsString());
+ writer.write("#");
+ writer.write(stock.getLastChangeAsString());
+ writer.write("#");
+ writer.write(String.valueOf(stock.getCnt()));
+ writer.write("\n");
+ writer.flush();
+ response.flushBuffer();
+ }catch (IOException x) {
+ try {actx.complete();}catch (Exception ignore){/* Ignore */}
+ }
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException {
+ if (clients.remove(event.getAsyncContext()) && clientcount.decrementAndGet()==0) {
+ ticker.removeTickListener(this);
+ }
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException {
+ event.getAsyncContext().complete();
+ }
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException {
+ event.getAsyncContext().complete();
+ }
+
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException {
+ // NOOP
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker$Stock.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker$Stock.class
new file mode 100644
index 0000000..bf771c3
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker$Stock.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker$TickListener.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker$TickListener.class
new file mode 100644
index 0000000..928b52f
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker$TickListener.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker.class b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker.class
new file mode 100644
index 0000000..7a99163
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker.java b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker.java
new file mode 100644
index 0000000..0bebf86
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/async/Stockticker.java
@@ -0,0 +1,188 @@
+/*
+ * 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 async;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Stockticker implements Runnable {
+ public volatile boolean run = true;
+ protected AtomicInteger counter = new AtomicInteger(0);
+ ArrayList<TickListener> listeners = new ArrayList<TickListener>();
+ protected volatile Thread ticker = null;
+ protected volatile int ticknr = 0;
+
+ public synchronized void start() {
+ run = true;
+ ticker = new Thread(this);
+ ticker.setName("Ticker Thread");
+ ticker.start();
+ }
+
+ public synchronized void stop() {
+ run = false;
+ try {
+ ticker.join();
+ }catch (InterruptedException x) {
+ Thread.interrupted();
+ }
+
+ ticker = null;
+ }
+
+ public void addTickListener(TickListener listener) {
+ if (listeners.add(listener)) {
+ if (counter.incrementAndGet()==1) start();
+ }
+
+ }
+
+ public void removeTickListener(TickListener listener) {
+ if (listeners.remove(listener)) {
+ if (counter.decrementAndGet()==0) stop();
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+
+ Stock[] stocks = new Stock[] { new Stock("GOOG", 435.43),
+ new Stock("YHOO", 27.88), new Stock("ASF", 1015.55), };
+ Random r = new Random(System.currentTimeMillis());
+ while (run) {
+ for (int j = 0; j < 1; j++) {
+ int i = r.nextInt() % 3;
+ if (i < 0)
+ i = i * (-1);
+ Stock stock = stocks[i];
+ double change = r.nextDouble();
+ boolean plus = r.nextBoolean();
+ if (plus) {
+ stock.setValue(stock.getValue() + change);
+ } else {
+ stock.setValue(stock.getValue() - change);
+ }
+ stock.setCnt(++ticknr);
+ for (TickListener l : listeners) {
+ l.tick(stock);
+ }
+
+ }
+ Thread.sleep(850);
+ }
+ } catch (InterruptedException ix) {
+ // Ignore
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+
+
+ public static interface TickListener {
+ public void tick(Stock stock);
+ }
+
+ public static final class Stock implements Cloneable {
+ protected static DecimalFormat df = new DecimalFormat("0.00");
+ protected String symbol = "";
+ protected double value = 0.0d;
+ protected double lastchange = 0.0d;
+ protected int cnt = 0;
+
+ public Stock(String symbol, double initvalue) {
+ this.symbol = symbol;
+ this.value = initvalue;
+ }
+
+ public void setCnt(int c) {
+ this.cnt = c;
+ }
+
+ public int getCnt() {
+ return cnt;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+
+ public double getValue() {
+ return value;
+ }
+
+ public void setValue(double value) {
+ double old = this.value;
+ this.value = value;
+ this.lastchange = value - old;
+ }
+
+ public String getValueAsString() {
+ return df.format(value);
+ }
+
+ public double getLastChange() {
+ return this.lastchange;
+ }
+
+ public void setLastChange(double lastchange) {
+ this.lastchange = lastchange;
+ }
+
+ public String getLastChangeAsString() {
+ return df.format(lastchange);
+ }
+
+ @Override
+ public int hashCode() {
+ return symbol.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Stock) {
+ return this.symbol.equals(((Stock) other).symbol);
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder("STOCK#");
+ buf.append(getSymbol());
+ buf.append("#");
+ buf.append(getValueAsString());
+ buf.append("#");
+ buf.append(getLastChangeAsString());
+ buf.append("#");
+ buf.append(String.valueOf(getCnt()));
+ return buf.toString();
+
+ }
+
+ @Override
+ public Object clone() {
+ Stock s = new Stock(this.getSymbol(), this.getValue());
+ s.setLastChange(this.getLastChange());
+ s.setCnt(this.cnt);
+ return s;
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.class b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.class
index ab44434..30bed2f 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.java b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.java
index ea0867b..443cd60 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entries.java
@@ -1,72 +1,60 @@
/*
-* 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.
-*/
+ * 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 cal;
import java.util.Hashtable;
-import javax.servlet.http.*;
+
+import javax.servlet.http.HttpServletRequest;
public class Entries {
- private Hashtable entries;
- private static final String[] time = {"8am", "9am", "10am", "11am", "12pm",
- "1pm", "2pm", "3pm", "4pm", "5pm", "6pm",
- "7pm", "8pm" };
- public static final int rows = 12;
+ private Hashtable<String, Entry> entries;
+ private static final String[] time = { "8am", "9am", "10am", "11am",
+ "12pm", "1pm", "2pm", "3pm", "4pm", "5pm", "6pm", "7pm", "8pm" };
+ public static final int rows = 12;
- public Entries () {
- entries = new Hashtable (rows);
- for (int i=0; i < rows; i++) {
- entries.put (time[i], new Entry(time[i]));
- }
- }
-
- public int getRows () {
- return rows;
- }
-
- public Entry getEntry (int index) {
- return (Entry)this.entries.get(time[index]);
- }
-
- public int getIndex (String tm) {
- for (int i=0; i<rows; i++)
- if(tm.equals(time[i])) return i;
- return -1;
- }
-
- public void processRequest (HttpServletRequest request, String tm) {
- int index = getIndex (tm);
- if (index >= 0) {
- String descr = request.getParameter ("description");
- ((Entry)entries.get(time[index])).setDescription (descr);
+ public Entries() {
+ entries = new Hashtable<String, Entry>(rows);
+ for (int i = 0; i < rows; i++) {
+ entries.put(time[i], new Entry(time[i]));
+ }
}
- }
+
+ public int getRows() {
+ return rows;
+ }
+
+ public Entry getEntry(int index) {
+ return this.entries.get(time[index]);
+ }
+
+ public int getIndex(String tm) {
+ for (int i = 0; i < rows; i++)
+ if (tm.equals(time[i]))
+ return i;
+ return -1;
+ }
+
+ public void processRequest(HttpServletRequest request, String tm) {
+ int index = getIndex(tm);
+ if (index >= 0) {
+ String descr = request.getParameter("description");
+ entries.get(time[index]).setDescription(descr);
+ }
+ }
}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.class b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.class
index b4619a6..44c493d 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.java b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.java
index d4596d9..e6403b2 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/Entry.java
@@ -1,55 +1,53 @@
/*
-* 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.
-*/
+ * 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 cal;
public class Entry {
- String hour;
- String description;
- String color;
+ String hour;
+ String description;
- public Entry (String hour) {
- this.hour = hour;
- this.description = "";
+ public Entry(String hour) {
+ this.hour = hour;
+ this.description = "";
- }
+ }
- public String getHour () {
- return this.hour;
- }
+ public String getHour() {
+ return this.hour;
+ }
- public String getColor () {
- if (description.equals("")) return "lightblue";
- else return "red";
- }
+ public String getColor() {
+ if (description.equals("")) {
+ return "lightblue";
+ }
+ return "red";
+ }
- public String getDescription () {
- if (description.equals("")) return "None";
- else return this.description;
- }
+ public String getDescription() {
+ if (description.equals("")) {
+ return "None";
+ }
+ return this.description;
+ }
- public void setDescription (String descr) {
- description = descr;
- }
-
+ public void setDescription(String descr) {
+ description = descr;
+ }
+
}
-
-
-
-
-
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.class b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.class
index dfd95e1..e1c6efa 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.java b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.java
index b2db6c0..dff319c 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/JspCalendar.java
@@ -17,138 +17,135 @@
package cal;
-import java.util.*;
+import java.util.Calendar;
+import java.util.Date;
public class JspCalendar {
Calendar calendar = null;
- Date currentDate;
public JspCalendar() {
- calendar = Calendar.getInstance();
- Date trialTime = new Date();
- calendar.setTime(trialTime);
+ calendar = Calendar.getInstance();
+ Date trialTime = new Date();
+ calendar.setTime(trialTime);
}
public int getYear() {
- return calendar.get(Calendar.YEAR);
+ return calendar.get(Calendar.YEAR);
}
-
+
public String getMonth() {
- int m = getMonthInt();
- String[] months = new String [] { "January", "February", "March",
- "April", "May", "June",
- "July", "August", "September",
- "October", "November", "December" };
- if (m > 12)
- return "Unknown to Man";
-
- return months[m - 1];
+ int m = getMonthInt();
+ String[] months = new String [] { "January", "February", "March",
+ "April", "May", "June",
+ "July", "August", "September",
+ "October", "November", "December" };
+ if (m > 12)
+ return "Unknown to Man";
+
+ return months[m - 1];
}
public String getDay() {
- int x = getDayOfWeek();
- String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday"};
+ int x = getDayOfWeek();
+ String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"};
- if (x > 7)
- return "Unknown to Man";
+ if (x > 7)
+ return "Unknown to Man";
- return days[x - 1];
+ return days[x - 1];
}
-
+
public int getMonthInt() {
- return 1 + calendar.get(Calendar.MONTH);
+ return 1 + calendar.get(Calendar.MONTH);
}
public String getDate() {
- return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
+ return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
}
public String getCurrentDate() {
Date dt = new Date ();
- calendar.setTime (dt);
- return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
+ calendar.setTime (dt);
+ return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
}
public String getNextDate() {
calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() + 1);
- return getDate ();
+ return getDate ();
}
public String getPrevDate() {
calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() - 1);
- return getDate ();
+ return getDate ();
}
public String getTime() {
- return getHour() + ":" + getMinute() + ":" + getSecond();
+ return getHour() + ":" + getMinute() + ":" + getSecond();
}
public int getDayOfMonth() {
- return calendar.get(Calendar.DAY_OF_MONTH);
+ return calendar.get(Calendar.DAY_OF_MONTH);
}
public int getDayOfYear() {
- return calendar.get(Calendar.DAY_OF_YEAR);
+ return calendar.get(Calendar.DAY_OF_YEAR);
}
public int getWeekOfYear() {
- return calendar.get(Calendar.WEEK_OF_YEAR);
+ return calendar.get(Calendar.WEEK_OF_YEAR);
}
public int getWeekOfMonth() {
- return calendar.get(Calendar.WEEK_OF_MONTH);
+ return calendar.get(Calendar.WEEK_OF_MONTH);
}
public int getDayOfWeek() {
- return calendar.get(Calendar.DAY_OF_WEEK);
+ return calendar.get(Calendar.DAY_OF_WEEK);
}
-
+
public int getHour() {
- return calendar.get(Calendar.HOUR_OF_DAY);
+ return calendar.get(Calendar.HOUR_OF_DAY);
}
-
+
public int getMinute() {
- return calendar.get(Calendar.MINUTE);
+ return calendar.get(Calendar.MINUTE);
}
public int getSecond() {
- return calendar.get(Calendar.SECOND);
+ return calendar.get(Calendar.SECOND);
}
-
+
public int getEra() {
- return calendar.get(Calendar.ERA);
+ return calendar.get(Calendar.ERA);
}
public String getUSTimeZone() {
- String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific",
- "Mountain", "Central", "Eastern"};
-
- return zones[10 + getZoneOffset()];
+ String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific",
+ "Mountain", "Central", "Eastern"};
+
+ return zones[10 + getZoneOffset()];
}
public int getZoneOffset() {
- return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000);
+ return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000);
}
public int getDSTOffset() {
- return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
+ return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
}
-
+
public int getAMPM() {
- return calendar.get(Calendar.AM_PM);
+ return calendar.get(Calendar.AM_PM);
}
}
-
-
-
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.class b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.class
index 8afd547..fdd37a8 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.java b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.java
index f55327c..1c32e68 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/cal/TableBean.java
@@ -1,100 +1,101 @@
/*
-* 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.
-*/
+ * 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 cal;
-import javax.servlet.http.*;
import java.util.Hashtable;
+import javax.servlet.http.HttpServletRequest;
+
public class TableBean {
- Hashtable table;
- JspCalendar JspCal;
- Entries entries;
- String date;
- String name = null;
- String email = null;
- boolean processError = false;
+ Hashtable<String, Entries> table;
+ JspCalendar JspCal;
+ Entries entries;
+ String date;
+ String name = null;
+ String email = null;
+ boolean processError = false;
- public TableBean () {
- this.table = new Hashtable (10);
- this.JspCal = new JspCalendar ();
- this.date = JspCal.getCurrentDate ();
- }
-
- public void setName (String nm) {
- this.name = nm;
- }
-
- public String getName () {
- return this.name;
- }
-
- public void setEmail (String mail) {
- this.email = mail;
- }
-
- public String getEmail () {
- return this.email;
- }
-
- public String getDate () {
- return this.date;
- }
-
- public Entries getEntries () {
- return this.entries;
- }
-
- public void processRequest (HttpServletRequest request) {
-
- // Get the name and e-mail.
- this.processError = false;
- if (name == null || name.equals("")) setName(request.getParameter ("name"));
- if (email == null || email.equals("")) setEmail(request.getParameter ("email"));
- if (name == null || email == null ||
- name.equals("") || email.equals("")) {
- this.processError = true;
- return;
+ public TableBean() {
+ this.table = new Hashtable<String, Entries>(10);
+ this.JspCal = new JspCalendar();
+ this.date = JspCal.getCurrentDate();
}
- // Get the date.
- String dateR = request.getParameter ("date");
- if (dateR == null) date = JspCal.getCurrentDate ();
- else if (dateR.equalsIgnoreCase("next")) date = JspCal.getNextDate ();
- else if (dateR.equalsIgnoreCase("prev")) date = JspCal.getPrevDate ();
-
- entries = (Entries) table.get (date);
- if (entries == null) {
- entries = new Entries ();
- table.put (date, entries);
+ public void setName(String nm) {
+ this.name = nm;
}
- // If time is provided add the event.
- String time = request.getParameter("time");
- if (time != null) entries.processRequest (request, time);
- }
+ public String getName() {
+ return this.name;
+ }
- public boolean getProcessError () {
- return this.processError;
- }
+ public void setEmail(String mail) {
+ this.email = mail;
+ }
+
+ public String getEmail() {
+ return this.email;
+ }
+
+ public String getDate() {
+ return this.date;
+ }
+
+ public Entries getEntries() {
+ return this.entries;
+ }
+
+ public void processRequest(HttpServletRequest request) {
+
+ // Get the name and e-mail.
+ this.processError = false;
+ if (name == null || name.equals(""))
+ setName(request.getParameter("name"));
+ if (email == null || email.equals(""))
+ setEmail(request.getParameter("email"));
+ if (name == null || email == null || name.equals("")
+ || email.equals("")) {
+ this.processError = true;
+ return;
+ }
+
+ // Get the date.
+ String dateR = request.getParameter("date");
+ if (dateR == null)
+ date = JspCal.getCurrentDate();
+ else if (dateR.equalsIgnoreCase("next"))
+ date = JspCal.getNextDate();
+ else if (dateR.equalsIgnoreCase("prev"))
+ date = JspCal.getPrevDate();
+
+ entries = table.get(date);
+ if (entries == null) {
+ entries = new Entries();
+ table.put(date, entries);
+ }
+
+ // If time is provided add the event.
+ String time = request.getParameter("time");
+ if (time != null)
+ entries.processRequest(request, time);
+ }
+
+ public boolean getProcessError() {
+ return this.processError;
+ }
}
-
-
-
-
-
-
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet$MessageSender.class b/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet$MessageSender.class
index 6712d68..c4be561 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet$MessageSender.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet$MessageSender.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.class b/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.class
index 752adba..ea047bd 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.java b/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.java
index 11d3757..d92092d 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/chat/ChatServlet.java
@@ -5,9 +5,9 @@
* 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.
@@ -24,14 +24,14 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import org.apache.catalina.CometEvent;
-import org.apache.catalina.CometProcessor;
-
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.comet.CometEvent;
+import org.apache.catalina.comet.CometProcessor;
+
/**
* Helper class to implement Comet functionality.
@@ -39,20 +39,24 @@
public class ChatServlet
extends HttpServlet implements CometProcessor {
+ private static final long serialVersionUID = 1L;
+
private static final String CHARSET = "UTF-8";
- protected ArrayList<HttpServletResponse> connections =
+ protected ArrayList<HttpServletResponse> connections =
new ArrayList<HttpServletResponse>();
- protected MessageSender messageSender = null;
-
+ protected transient MessageSender messageSender = null;
+
+ @Override
public void init() throws ServletException {
messageSender = new MessageSender();
- Thread messageSenderThread =
+ Thread messageSenderThread =
new Thread(messageSender, "MessageSender[" + getServletContext().getContextPath() + "]");
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}
+ @Override
public void destroy() {
connections.clear();
messageSender.stop();
@@ -61,11 +65,12 @@
/**
* Process the given Comet event.
- *
+ *
* @param event The Comet event that will be processed
* @throws IOException
* @throws ServletException
*/
+ @Override
public void event(CometEvent event)
throws IOException, ServletException {
@@ -73,7 +78,7 @@
// mixing Comet stuff with regular connection processing
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
-
+
if (event.getEventType() == CometEvent.EventType.BEGIN) {
String action = request.getParameter("action");
if (action != null) {
@@ -83,22 +88,20 @@
response.sendRedirect("index.jsp");
event.close();
return;
- } else {
- String nickname = (String) request.getSession(true).getAttribute("nickname");
- String message = request.getParameter("message");
- messageSender.send(nickname, message);
- response.sendRedirect("post.jsp");
- event.close();
- return;
}
- } else {
- if (request.getSession(true).getAttribute("nickname") == null) {
- // Redirect to "login"
- log("Redirect to login for session: " + request.getSession(true).getId());
- response.sendRedirect("login.jsp");
- event.close();
- return;
- }
+ String nickname = (String) request.getSession(true).getAttribute("nickname");
+ String message = request.getParameter("message");
+ messageSender.send(nickname, message);
+ response.sendRedirect("post.jsp");
+ event.close();
+ return;
+ }
+ if (request.getSession(true).getAttribute("nickname") == null) {
+ // Redirect to "login"
+ log("Redirect to login for session: " + request.getSession(true).getId());
+ response.sendRedirect("login.jsp");
+ event.close();
+ return;
}
begin(event, request, response);
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
@@ -110,8 +113,9 @@
}
}
- protected void begin(CometEvent event, HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
+ protected void begin(@SuppressWarnings("unused") CometEvent event,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
log("Begin for session: " + request.getSession(true).getId());
response.setContentType("text/html; charset=" + CHARSET);
@@ -128,38 +132,38 @@
messageSender.send("Tomcat", request.getSession(true).getAttribute("nickname") + " joined the chat.");
}
-
+
protected void end(CometEvent event, HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
+ throws IOException {
log("End for session: " + request.getSession(true).getId());
synchronized(connections) {
connections.remove(response);
}
-
+
PrintWriter writer = response.getWriter();
writer.println("</body></html>");
-
+
event.close();
}
-
+
protected void error(CometEvent event, HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
+ throws IOException {
log("Error for session: " + request.getSession(true).getId());
synchronized(connections) {
connections.remove(response);
}
event.close();
}
-
+
protected void read(CometEvent event, HttpServletRequest request, HttpServletResponse response)
- throws IOException, ServletException {
+ throws IOException {
InputStream is = request.getInputStream();
byte[] buf = new byte[512];
while (is.available() > 0) {
log("Available: " + is.available());
int n = is.read(buf);
if (n > 0) {
- log("Read " + n + " bytes: " + new String(buf, 0, n)
+ log("Read " + n + " bytes: " + new String(buf, 0, n)
+ " for session: " + request.getSession(true).getId());
} else if (n < 0) {
log("End of file: " + n);
@@ -169,6 +173,7 @@
}
}
+ @Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Compatibility method: equivalent method using the regular connection model
@@ -180,7 +185,7 @@
writer.println("Configure a connector that supports Comet and try again.");
writer.println("</body></html>");
}
-
+
/**
* Poller class.
@@ -189,10 +194,11 @@
protected boolean running = true;
protected ArrayList<String> messages = new ArrayList<String>();
-
+
public MessageSender() {
+ // Default contructor
}
-
+
public void stop() {
running = false;
synchronized (messages) {
@@ -200,14 +206,6 @@
}
}
- /**
- * Add specified socket and associated pool to the poller. The socket will
- * be added to a temporary array, and polled first after a maximum amount
- * of time equal to pollTime (in most cases, latency will be much lower,
- * however).
- *
- * @param socket to add to the poller
- */
public void send(String user, String message) {
synchronized (messages) {
messages.add("[" + user + "]: " + message);
@@ -219,6 +217,7 @@
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
+ @Override
public void run() {
// Loop until we receive a shutdown command
@@ -226,7 +225,7 @@
String[] pendingMessages;
synchronized (messages) {
try {
- if (messages.size() == 0) {
+ if (running && messages.size() == 0) {
messages.wait();
}
} catch (InterruptedException e) {
@@ -261,7 +260,7 @@
* in HTML.
*
* @param message The message string to be filtered
- * @author Copied from org.apache.catalina.util.RequestUtil#filter(String)
+ * @author Copied from org.apache.catalina.util.RequestUtil#filter(String)
*/
protected static String filter(String message) {
if (message == null)
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.class b/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.class
index 87011a7..e5fc31c 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.java b/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.java
index 70623e2..c25448b 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/checkbox/CheckTest.java
@@ -22,10 +22,10 @@
String b[] = new String[] { "1", "2", "3", "4" };
public String[] getFruit() {
- return b;
+ return b;
}
public void setFruit(String [] b) {
- this.b = b;
+ this.b = b;
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.class b/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.class
index 408dc45..bed4bf3 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.java b/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.java
index 5748217..6e2d741 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/colors/ColorGameBean.java
@@ -16,8 +16,6 @@
*/
package colors;
-import javax.servlet.http.*;
-
public class ColorGameBean {
private String background = "yellow";
@@ -26,90 +24,90 @@
private String color2 = background;
private String hint = "no";
private int attempts = 0;
- private int intval = 0;
+ private int intval = 0;
private boolean tookHints = false;
- public void processRequest(HttpServletRequest request) {
+ public void processRequest() {
- // background = "yellow";
- // foreground = "red";
+ // background = "yellow";
+ // foreground = "red";
- if (! color1.equals(foreground)) {
- if (color1.equalsIgnoreCase("black") ||
- color1.equalsIgnoreCase("cyan")) {
- background = color1;
- }
- }
+ if (! color1.equals(foreground)) {
+ if (color1.equalsIgnoreCase("black") ||
+ color1.equalsIgnoreCase("cyan")) {
+ background = color1;
+ }
+ }
- if (! color2.equals(background)) {
- if (color2.equalsIgnoreCase("black") ||
- color2.equalsIgnoreCase("cyan")) {
- foreground = color2;
- }
- }
+ if (! color2.equals(background)) {
+ if (color2.equalsIgnoreCase("black") ||
+ color2.equalsIgnoreCase("cyan")) {
+ foreground = color2;
+ }
+ }
- attempts++;
+ attempts++;
}
public void setColor2(String x) {
- color2 = x;
+ color2 = x;
}
public void setColor1(String x) {
- color1 = x;
+ color1 = x;
}
public void setAction(String x) {
- if (!tookHints)
- tookHints = x.equalsIgnoreCase("Hint");
- hint = x;
+ if (!tookHints)
+ tookHints = x.equalsIgnoreCase("Hint");
+ hint = x;
}
public String getColor2() {
- return background;
+ return background;
}
public String getColor1() {
- return foreground;
+ return foreground;
}
public int getAttempts() {
- return attempts;
+ return attempts;
}
public boolean getHint() {
- return hint.equalsIgnoreCase("Hint");
+ return hint.equalsIgnoreCase("Hint");
}
public boolean getSuccess() {
- if (background.equalsIgnoreCase("black") ||
- background.equalsIgnoreCase("cyan")) {
-
- if (foreground.equalsIgnoreCase("black") ||
- foreground.equalsIgnoreCase("cyan"))
- return true;
- else
- return false;
- }
+ if (background.equalsIgnoreCase("black") ||
+ background.equalsIgnoreCase("cyan")) {
- return false;
+ if (foreground.equalsIgnoreCase("black") ||
+ foreground.equalsIgnoreCase("cyan")) {
+ return true;
+ }
+ return false;
+ }
+
+ return false;
}
public boolean getHintTaken() {
- return tookHints;
+ return tookHints;
}
public void reset() {
- foreground = "red";
- background = "yellow";
+ foreground = "red";
+ background = "yellow";
}
public void setIntval(int value) {
- intval = value;
- }
+ intval = value;
+ }
public int getIntval() {
- return intval;
- }
+ return intval;
+ }
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.class b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.class
index 619a1a2..f81aba7 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
index fc298e2..350393a 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
@@ -14,11 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package compressionFilters;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.List;
+import java.util.StringTokenizer;
+
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@@ -28,7 +31,6 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
/**
* Implementation of <code>javax.servlet.Filter</code> used to compress
* the ServletResponse if it is bigger than a threshold.
@@ -36,7 +38,7 @@
* @author Amy Roh
* @author Dmitri Valdin
*/
-public class CompressionFilter implements Filter{
+public class CompressionFilter implements Filter {
/**
* The filter configuration object we are associated with. If this value
@@ -45,18 +47,32 @@
private FilterConfig config = null;
/**
- * Minimal reasonable threshold
+ * Minimal reasonable threshold.
*/
private int minThreshold = 128;
-
/**
- * The threshold number to compress
+ * The threshold number to compress.
*/
- protected int compressionThreshold;
+ protected int compressionThreshold = 0;
/**
- * Debug level for this filter
+ * Minimal reasonable buffer.
+ */
+ private int minBuffer = 8192; // 8KB is what tomcat would use by default anyway
+
+ /**
+ * The compression buffer size to avoid chunking.
+ */
+ protected int compressionBuffer = 0;
+
+ /**
+ * The mime types to compress.
+ */
+ protected String[] compressionMimeTypes = {"text/html", "text/xml", "text/plain"};
+
+ /**
+ * Debug level for this filter.
*/
private int debug = 0;
@@ -65,7 +81,7 @@
*
* @param filterConfig The filter configuration object
*/
-
+ @Override
public void init(FilterConfig filterConfig) {
config = filterConfig;
@@ -73,9 +89,8 @@
String value = filterConfig.getInitParameter("debug");
if (value!=null) {
debug = Integer.parseInt(value);
- } else {
- debug = 0;
}
+
String str = filterConfig.getInitParameter("compressionThreshold");
if (str!=null) {
compressionThreshold = Integer.parseInt(str);
@@ -86,12 +101,43 @@
}
compressionThreshold = minThreshold;
}
- } else {
- compressionThreshold = 0;
}
- } else {
- compressionThreshold = 0;
+ str = filterConfig.getInitParameter("compressionBuffer");
+ if (str!=null) {
+ compressionBuffer = Integer.parseInt(str);
+ if (compressionBuffer < minBuffer) {
+ if (debug > 0) {
+ System.out.println("compressionBuffer should be >= " + minBuffer);
+ System.out.println("compressionBuffer set to " + minBuffer);
+ }
+ compressionBuffer = minBuffer;
+ }
+ }
+
+ str = filterConfig.getInitParameter("compressionMimeTypes");
+ if (str!=null) {
+ List<String> values = new ArrayList<String>();
+ StringTokenizer st = new StringTokenizer(str, ",");
+
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken().trim();
+ if (token.length() > 0) {
+ values.add(token);
+ }
+ }
+
+ if (values.size() > 0) {
+ compressionMimeTypes = values.toArray(
+ new String[values.size()]);
+ } else {
+ compressionMimeTypes = null;
+ }
+
+ if (debug > 0) {
+ System.out.println("compressionMimeTypes set to " + compressionMimeTypes);
+ }
+ }
}
}
@@ -99,6 +145,7 @@
/**
* Take this filter out of service.
*/
+ @Override
public void destroy() {
this.config = null;
@@ -121,7 +168,7 @@
* It then invokes the next entity in the chain using the FilterChain object
* (<code>chain.doFilter()</code>), <br>
**/
-
+ @Override
public void doFilter ( ServletRequest request, ServletResponse response,
FilterChain chain ) throws IOException, ServletException {
@@ -131,7 +178,7 @@
if (compressionThreshold == 0) {
if (debug > 0) {
- System.out.println("doFilter gets called, but compressionTreshold is set to 0 - no compression");
+ System.out.println("doFilter got called, but compressionThreshold is set to 0 - no compression");
}
chain.doFilter(request, response);
return;
@@ -144,7 +191,7 @@
}
// Are we allowed to compress ?
- String s = (String) ((HttpServletRequest)request).getParameter("gzip");
+ String s = ((HttpServletRequest)request).getParameter("gzip");
if ("false".equals(s)) {
if (debug > 0) {
System.out.println("got parameter gzip=false --> don't compress, just chain filter");
@@ -153,10 +200,10 @@
return;
}
- Enumeration e =
+ Enumeration<String> e =
((HttpServletRequest)request).getHeaders("Accept-Encoding");
while (e.hasMoreElements()) {
- String name = (String)e.nextElement();
+ String name = e.nextElement();
if (name.indexOf("gzip") != -1) {
if (debug > 0) {
System.out.println("supports compression");
@@ -164,24 +211,20 @@
supportCompression = true;
} else {
if (debug > 0) {
- System.out.println("no support for compresion");
+ System.out.println("no support for compression");
}
}
}
}
- if (!supportCompression) {
- if (debug > 0) {
- System.out.println("doFilter gets called wo compression");
- }
- chain.doFilter(request, response);
- return;
- } else {
+ if (supportCompression) {
if (response instanceof HttpServletResponse) {
CompressionServletResponseWrapper wrappedResponse =
new CompressionServletResponseWrapper((HttpServletResponse)response);
wrappedResponse.setDebugLevel(debug);
wrappedResponse.setCompressionThreshold(compressionThreshold);
+ wrappedResponse.setCompressionBuffer(compressionBuffer);
+ wrappedResponse.setCompressionMimeTypes(compressionMimeTypes);
if (debug > 0) {
System.out.println("doFilter gets called with compression");
}
@@ -192,6 +235,12 @@
}
return;
}
+ } else {
+ if (debug > 0) {
+ System.out.println("doFilter gets called w/o compression");
+ }
+ chain.doFilter(request, response);
+ return;
}
}
@@ -206,12 +255,12 @@
}
/**
- * Return filter config
* Required by Weblogic 6.1
+ *
+ * @return the FilterConfig that was used to initialise this filter.
*/
public FilterConfig getFilterConfig() {
return config;
}
-
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.class b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.class
index a48332d..ce695cb 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
index 9f6090a..700cd1f 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
@@ -14,13 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package compressionFilters;
import java.io.IOException;
import java.util.Enumeration;
-import javax.servlet.*;
-import javax.servlet.http.*;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
/**
* Very Simple test servlet to test compression filter
@@ -28,15 +31,18 @@
*/
public class CompressionFilterTestServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ @Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletOutputStream out = response.getOutputStream();
response.setContentType("text/plain");
- Enumeration e = ((HttpServletRequest)request).getHeaders("Accept-Encoding");
+ Enumeration<String> e = request.getHeaders("Accept-Encoding");
while (e.hasMoreElements()) {
- String name = (String)e.nextElement();
+ String name = e.nextElement();
out.println(name);
if (name.indexOf("gzip") != -1) {
out.println("gzip supported -- able to compress");
@@ -48,6 +54,11 @@
out.println("Compression Filter Test Servlet");
+ out.println("Minimum content length for compression is 128 bytes");
+ out.println("********** 32 bytes **********");
+ out.println("********** 32 bytes **********");
+ out.println("********** 32 bytes **********");
+ out.println("********** 32 bytes **********");
out.close();
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.class b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.class
index a52f332..3d05f19 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
index 120b82a..a79027a 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
@@ -19,9 +19,8 @@
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletOutputStream;
/**
* Implementation of <b>ServletOutputStream</b> that works with
@@ -30,25 +29,24 @@
* @author Amy Roh
* @author Dmitri Valdin
*/
-public class CompressionResponseStream
- extends ServletOutputStream {
-
+public class CompressionResponseStream extends ServletOutputStream {
// ----------------------------------------------------------- Constructors
-
/**
* Construct a servlet output stream associated with the specified Response.
*
- * @param response The associated response
+ * @param responseWrapper The associated response wrapper
+ * @param originalOutput the output stream
*/
- public CompressionResponseStream(HttpServletResponse response) throws IOException{
+ public CompressionResponseStream(
+ CompressionServletResponseWrapper responseWrapper,
+ ServletOutputStream originalOutput) {
super();
closed = false;
- this.response = response;
- this.output = response.getOutputStream();
-
+ this.response = responseWrapper;
+ this.output = originalOutput;
}
@@ -62,6 +60,16 @@
protected int compressionThreshold = 0;
/**
+ * The compression buffer size to avoid chunking
+ */
+ protected int compressionBuffer = 0;
+
+ /**
+ * The mime types to compress
+ */
+ protected String[] compressionMimeTypes = {"text/html", "text/xml", "text/plain"};
+
+ /**
* Debug level
*/
private int debug = 0;
@@ -95,10 +103,10 @@
/**
* The response with which this servlet output stream is associated.
*/
- protected HttpServletResponse response = null;
+ protected CompressionServletResponseWrapper response = null;
/**
- * The underlying servket output stream to which we should write data.
+ * The underlying servlet output stream to which we should write data.
*/
protected ServletOutputStream output = null;
@@ -116,11 +124,31 @@
/**
* Set the compressionThreshold number and create buffer for this size
*/
- protected void setBuffer(int threshold) {
- compressionThreshold = threshold;
- buffer = new byte[compressionThreshold];
+ protected void setCompressionThreshold(int compressionThreshold) {
+ this.compressionThreshold = compressionThreshold;
+ buffer = new byte[this.compressionThreshold];
if (debug > 1) {
- System.out.println("buffer is set to "+compressionThreshold);
+ System.out.println("compressionThreshold is set to "+ this.compressionThreshold);
+ }
+ }
+
+ /**
+ * The compression buffer size to avoid chunking
+ */
+ protected void setCompressionBuffer(int compressionBuffer) {
+ this.compressionBuffer = compressionBuffer;
+ if (debug > 1) {
+ System.out.println("compressionBuffer is set to "+ this.compressionBuffer);
+ }
+ }
+
+ /**
+ * Set supported mime types
+ */
+ public void setCompressionMimeTypes(String[] compressionMimeTypes) {
+ this.compressionMimeTypes = compressionMimeTypes;
+ if (debug > 1) {
+ System.out.println("compressionMimeTypes is set to " + this.compressionMimeTypes);
}
}
@@ -128,6 +156,7 @@
* Close this output stream, causing any buffered data to be flushed and
* any further output data to throw an IOException.
*/
+ @Override
public void close() throws IOException {
if (debug > 1) {
@@ -162,6 +191,7 @@
* Flush any buffered data for this output stream, which also causes the
* response to be committed.
*/
+ @Override
public void flush() throws IOException {
if (debug > 1) {
@@ -199,6 +229,7 @@
*
* @exception IOException if an input/output error occurs
*/
+ @Override
public void write(int b) throws IOException {
if (debug > 1) {
@@ -224,6 +255,7 @@
*
* @exception IOException if an input/output error occurs
*/
+ @Override
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
@@ -241,6 +273,7 @@
*
* @exception IOException if an input/output error occurs
*/
+ @Override
public void write(byte b[], int off, int len) throws IOException {
if (debug > 1) {
@@ -293,12 +326,53 @@
if (debug > 1) {
System.out.println("new GZIPOutputStream");
}
+
+ boolean alreadyCompressed = false;
+ String contentEncoding = response.getHeader("Content-Encoding");
+ if (contentEncoding != null) {
+ if (contentEncoding.contains("gzip")) {
+ alreadyCompressed = true;
+ if (debug > 0) {
+ System.out.println("content is already compressed");
+ }
+ } else {
+ if (debug > 0) {
+ System.out.println("content is not compressed yet");
+ }
+ }
+ }
+
+ boolean compressibleMimeType = false;
+ // Check for compatible MIME-TYPE
+ if (compressionMimeTypes != null) {
+ if (startsWithStringArray(compressionMimeTypes, response.getContentType())) {
+ compressibleMimeType = true;
+ if (debug > 0) {
+ System.out.println("mime type " + response.getContentType() + " is compressible");
+ }
+ } else {
+ if (debug > 0) {
+ System.out.println("mime type " + response.getContentType() + " is not compressible");
+ }
+ }
+ }
+
if (response.isCommitted()) {
if (debug > 1)
System.out.print("Response already committed. Using original output stream");
gzipstream = output;
+ } else if (alreadyCompressed) {
+ if (debug > 1)
+ System.out.print("Response already compressed. Using original output stream");
+ gzipstream = output;
+ } else if (!compressibleMimeType) {
+ if (debug > 1)
+ System.out.print("Response mime type is not compressible. Using original output stream");
+ gzipstream = output;
} else {
response.addHeader("Content-Encoding", "gzip");
+ response.setContentLength(-1); // don't use any preset content-length as it will be wrong after gzipping
+ response.setBufferSize(compressionBuffer);
gzipstream = new GZIPOutputStream(output);
}
}
@@ -319,4 +393,20 @@
}
+ /**
+ * Checks if any entry in the string array starts with the specified value
+ *
+ * @param sArray the StringArray
+ * @param value string
+ */
+ private boolean startsWithStringArray(String sArray[], String value) {
+ if (value == null)
+ return false;
+ for (int i = 0; i < sArray.length; i++) {
+ if (value.startsWith(sArray[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.class b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.class
index 838e08c..1198e42 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
index e2cd66b..1e28d44 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
@@ -19,6 +19,9 @@
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
@@ -30,7 +33,8 @@
* @author Amy Roh
* @author Dmitri Valdin
*/
-public class CompressionServletResponseWrapper extends HttpServletResponseWrapper {
+public class CompressionServletResponseWrapper
+ extends HttpServletResponseWrapper {
// ----------------------------------------------------- Constructor
@@ -38,7 +42,6 @@
* Calls the parent constructor which creates a ServletResponse adaptor
* wrapping the given response object.
*/
-
public CompressionServletResponseWrapper(HttpServletResponse response) {
super(response);
origResponse = response;
@@ -80,43 +83,61 @@
/**
* The threshold number to compress
*/
- protected int threshold = 0;
+ protected int compressionThreshold = 0;
+
+ /**
+ * The compression buffer size
+ */
+ protected int compressionBuffer = 8192; // 8KB default
+
+ /**
+ * The mime types to compress
+ */
+ protected String[] compressionMimeTypes = {"text/html", "text/xml", "text/plain"};
/**
* Debug level
*/
- private int debug = 0;
+ protected int debug = 0;
/**
- * Content type
+ * keeps a copy of all headers set
*/
- protected String contentType = null;
+ private Map<String,String> headerCopies = new HashMap<String,String>();
+
// --------------------------------------------------------- Public Methods
/**
- * Set content type
- */
- public void setContentType(String contentType) {
- if (debug > 1) {
- System.out.println("setContentType to "+contentType);
- }
- this.contentType = contentType;
- origResponse.setContentType(contentType);
- }
-
-
- /**
* Set threshold number
*/
public void setCompressionThreshold(int threshold) {
if (debug > 1) {
System.out.println("setCompressionThreshold to " + threshold);
}
- this.threshold = threshold;
+ this.compressionThreshold = threshold;
}
+ /**
+ * Set compression buffer
+ */
+ public void setCompressionBuffer(int buffer) {
+ if (debug > 1) {
+ System.out.println("setCompressionBuffer to " + buffer);
+ }
+ this.compressionBuffer = buffer;
+ }
+
+ /**
+ * Set compressible mime types
+ */
+ public void setCompressionMimeTypes(String[] mimeTypes) {
+ if (debug > 1) {
+ System.out.println("setCompressionMimeTypes to " + mimeTypes);
+ }
+ this.compressionMimeTypes = mimeTypes;
+ }
/**
* Set debug level
@@ -137,12 +158,14 @@
System.out.println("createOutputStream gets called");
}
- CompressionResponseStream stream = new CompressionResponseStream(origResponse);
+ CompressionResponseStream stream = new CompressionResponseStream(
+ this, origResponse.getOutputStream());
stream.setDebugLevel(debug);
- stream.setBuffer(threshold);
+ stream.setCompressionThreshold(compressionThreshold);
+ stream.setCompressionBuffer(compressionBuffer);
+ stream.setCompressionMimeTypes(compressionMimeTypes);
return stream;
-
}
@@ -158,6 +181,7 @@
stream.close();
}
} catch (IOException e) {
+ // Ignore
}
}
@@ -170,9 +194,10 @@
*
* @exception IOException if an input/output error occurs
*/
+ @Override
public void flushBuffer() throws IOException {
if (debug > 1) {
- System.out.println("flush buffer @ CompressionServletResponseWrapper");
+ System.out.println("flush buffer @ GZipServletResponseWrapper");
}
((CompressionResponseStream)stream).flush();
@@ -185,6 +210,7 @@
* already been called for this response
* @exception IOException if an input/output error occurs
*/
+ @Override
public ServletOutputStream getOutputStream() throws IOException {
if (writer != null)
@@ -207,6 +233,7 @@
* already been called for this response
* @exception IOException if an input/output error occurs
*/
+ @Override
public PrintWriter getWriter() throws IOException {
if (writer != null)
@@ -219,7 +246,6 @@
if (debug > 1) {
System.out.println("stream is set to "+stream+" in getWriter");
}
- //String charset = getCharsetFromContentType(contentType);
String charEnc = origResponse.getCharacterEncoding();
if (debug > 1) {
System.out.println("character encoding is " + charEnc);
@@ -231,13 +257,29 @@
} else {
writer = new PrintWriter(stream);
}
-
+
return (writer);
+ }
+ @Override
+ public String getHeader(String name) {
+ return headerCopies.get(name);
+ }
+
+ @Override
+ public void addHeader(String name, String value) {
+ if (headerCopies.containsKey(name)) {
+ String existingValue = headerCopies.get(name);
+ if ((existingValue != null) && (existingValue.length() > 0)) headerCopies.put(name, existingValue + "," + value);
+ else headerCopies.put(name, value);
+ } else headerCopies.put(name, value);
+ super.addHeader(name, value);
}
- public void setContentLength(int length) {
+ @Override
+ public void setHeader(String name, String value) {
+ headerCopies.put(name, value);
+ super.setHeader(name, value);
}
-
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.class b/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.class
index 7ae66d3..56cd2b5 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.java b/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.java
index 22e1f86..9c90bbd 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/dates/JspCalendar.java
@@ -16,137 +16,138 @@
*/
package dates;
-import java.util.*;
+import java.util.Calendar;
+import java.util.Date;
public class JspCalendar {
Calendar calendar = null;
public JspCalendar() {
- calendar = Calendar.getInstance();
- Date trialTime = new Date();
- calendar.setTime(trialTime);
+ calendar = Calendar.getInstance();
+ Date trialTime = new Date();
+ calendar.setTime(trialTime);
}
public int getYear() {
- return calendar.get(Calendar.YEAR);
+ return calendar.get(Calendar.YEAR);
}
-
+
public String getMonth() {
- int m = getMonthInt();
- String[] months = new String [] { "January", "February", "March",
- "April", "May", "June",
- "July", "August", "September",
- "October", "November", "December" };
- if (m > 12)
- return "Unknown to Man";
-
- return months[m - 1];
+ int m = getMonthInt();
+ String[] months = new String [] { "January", "February", "March",
+ "April", "May", "June",
+ "July", "August", "September",
+ "October", "November", "December" };
+ if (m > 12)
+ return "Unknown to Man";
+
+ return months[m - 1];
}
public String getDay() {
- int x = getDayOfWeek();
- String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday"};
+ int x = getDayOfWeek();
+ String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"};
- if (x > 7)
- return "Unknown to Man";
+ if (x > 7)
+ return "Unknown to Man";
- return days[x - 1];
+ return days[x - 1];
}
-
+
public int getMonthInt() {
- return 1 + calendar.get(Calendar.MONTH);
+ return 1 + calendar.get(Calendar.MONTH);
}
public String getDate() {
- return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
+ return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
}
public String getTime() {
- return getHour() + ":" + getMinute() + ":" + getSecond();
+ return getHour() + ":" + getMinute() + ":" + getSecond();
}
public int getDayOfMonth() {
- return calendar.get(Calendar.DAY_OF_MONTH);
+ return calendar.get(Calendar.DAY_OF_MONTH);
}
public int getDayOfYear() {
- return calendar.get(Calendar.DAY_OF_YEAR);
+ return calendar.get(Calendar.DAY_OF_YEAR);
}
public int getWeekOfYear() {
- return calendar.get(Calendar.WEEK_OF_YEAR);
+ return calendar.get(Calendar.WEEK_OF_YEAR);
}
public int getWeekOfMonth() {
- return calendar.get(Calendar.WEEK_OF_MONTH);
+ return calendar.get(Calendar.WEEK_OF_MONTH);
}
public int getDayOfWeek() {
- return calendar.get(Calendar.DAY_OF_WEEK);
+ return calendar.get(Calendar.DAY_OF_WEEK);
}
-
+
public int getHour() {
- return calendar.get(Calendar.HOUR_OF_DAY);
+ return calendar.get(Calendar.HOUR_OF_DAY);
}
-
+
public int getMinute() {
- return calendar.get(Calendar.MINUTE);
+ return calendar.get(Calendar.MINUTE);
}
public int getSecond() {
- return calendar.get(Calendar.SECOND);
+ return calendar.get(Calendar.SECOND);
}
public static void main(String args[]) {
- JspCalendar db = new JspCalendar();
- p("date: " + db.getDayOfMonth());
- p("year: " + db.getYear());
- p("month: " + db.getMonth());
- p("time: " + db.getTime());
- p("date: " + db.getDate());
- p("Day: " + db.getDay());
- p("DayOfYear: " + db.getDayOfYear());
- p("WeekOfYear: " + db.getWeekOfYear());
- p("era: " + db.getEra());
- p("ampm: " + db.getAMPM());
- p("DST: " + db.getDSTOffset());
- p("ZONE Offset: " + db.getZoneOffset());
- p("TIMEZONE: " + db.getUSTimeZone());
+ JspCalendar db = new JspCalendar();
+ p("date: " + db.getDayOfMonth());
+ p("year: " + db.getYear());
+ p("month: " + db.getMonth());
+ p("time: " + db.getTime());
+ p("date: " + db.getDate());
+ p("Day: " + db.getDay());
+ p("DayOfYear: " + db.getDayOfYear());
+ p("WeekOfYear: " + db.getWeekOfYear());
+ p("era: " + db.getEra());
+ p("ampm: " + db.getAMPM());
+ p("DST: " + db.getDSTOffset());
+ p("ZONE Offset: " + db.getZoneOffset());
+ p("TIMEZONE: " + db.getUSTimeZone());
}
private static void p(String x) {
- System.out.println(x);
+ System.out.println(x);
}
public int getEra() {
- return calendar.get(Calendar.ERA);
+ return calendar.get(Calendar.ERA);
}
public String getUSTimeZone() {
- String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific",
- "Mountain", "Central", "Eastern"};
-
- return zones[10 + getZoneOffset()];
+ String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific",
+ "Mountain", "Central", "Eastern"};
+
+ return zones[10 + getZoneOffset()];
}
public int getZoneOffset() {
- return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000);
+ return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000);
}
public int getDSTOffset() {
- return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
+ return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
}
-
+
public int getAMPM() {
- return calendar.get(Calendar.AM_PM);
+ return calendar.get(Calendar.AM_PM);
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.class b/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.class
index 5445742..fd96ee2 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.java b/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.java
index 3af3a38..67aff03 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/error/Smart.java
@@ -1,32 +1,30 @@
/*
-* 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.
-*/
-
-
+ * 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 error;
public class Smart {
- String name = "JSP";
+ String name = "JSP";
- public String getName () {
- return name;
- }
+ public String getName() {
+ return name;
+ }
- public void setName (String name) {
- this.name = name;
- }
+ public void setName(String name) {
+ this.name = name;
+ }
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.class b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.class
index 35edd28..4ac9330 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.java b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.java
index 13bcd16..d339adb 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ExampleTagBase.java
@@ -16,52 +16,59 @@
*/
package examples;
-import javax.servlet.jsp.*;
-import javax.servlet.jsp.tagext.*;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.BodyContent;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
public abstract class ExampleTagBase extends BodyTagSupport {
+ private static final long serialVersionUID = 1L;
+
+ @Override
public void setParent(Tag parent) {
this.parent = parent;
}
+ @Override
public void setBodyContent(BodyContent bodyOut) {
this.bodyOut = bodyOut;
}
- public void setPageContext(PageContext pageContext) {
- this.pageContext = pageContext;
- }
-
+ @Override
public Tag getParent() {
return this.parent;
}
-
+
+ @Override
public int doStartTag() throws JspException {
return SKIP_BODY;
}
+ @Override
public int doEndTag() throws JspException {
return EVAL_PAGE;
}
-
- // Default implementations for BodyTag methods as well
- // just in case a tag decides to implement BodyTag.
+
+ @Override
public void doInitBody() throws JspException {
+ // Default implementations for BodyTag methods as well
+ // just in case a tag decides to implement BodyTag.
}
+ @Override
public int doAfterBody() throws JspException {
return SKIP_BODY;
}
+ @Override
public void release() {
bodyOut = null;
pageContext = null;
parent = null;
}
-
+
protected BodyContent bodyOut;
- protected PageContext pageContext;
protected Tag parent;
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.class
index d60a6bd..3d6d760 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.java
index 4e11f30..c8fdb0a 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTag.java
@@ -16,9 +16,11 @@
*/
package examples;
-import javax.servlet.jsp.*;
import java.io.IOException;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+
/**
* Example1: the simplest tag
* Collect attributes and call into some actions
@@ -26,20 +28,21 @@
* <foo att1="..." att2="...." att3="...." />
*/
-public class FooTag
- extends ExampleTagBase
-{
+public class FooTag extends ExampleTagBase {
+
+ private static final long serialVersionUID = 1L;
+
private String atts[] = new String[3];
int i = 0;
-
+
private final void setAtt(int index, String value) {
atts[index] = value;
}
-
+
public void setAtt1(String value) {
setAtt(0, value);
}
-
+
public void setAtt2(String value) {
setAtt(1, value);
}
@@ -47,29 +50,33 @@
public void setAtt3(String value) {
setAtt(2, value);
}
-
+
/**
* Process start tag
*
* @return EVAL_BODY_INCLUDE
*/
+ @Override
public int doStartTag() throws JspException {
i = 0;
- return EVAL_BODY_BUFFERED;
+ return EVAL_BODY_BUFFERED;
}
+ @Override
public void doInitBody() throws JspException {
pageContext.setAttribute("member", atts[i]);
i++;
}
-
+
+ @Override
public int doAfterBody() throws JspException {
try {
if (i == 3) {
bodyOut.writeOut(bodyOut.getEnclosingWriter());
return SKIP_BODY;
- } else
- pageContext.setAttribute("member", atts[i]);
+ }
+
+ pageContext.setAttribute("member", atts[i]);
i++;
return EVAL_BODY_BUFFERED;
} catch (IOException ex) {
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.class b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.class
index 5ca9cfb..ead843e 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.java b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.java
index 99e5dfb..1ae0492 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/FooTagExtraInfo.java
@@ -16,11 +16,14 @@
*/
package examples;
-import javax.servlet.jsp.tagext.*;
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+import javax.servlet.jsp.tagext.VariableInfo;
public class FooTagExtraInfo extends TagExtraInfo {
+ @Override
public VariableInfo[] getVariableInfo(TagData data) {
- return new VariableInfo[]
+ return new VariableInfo[]
{
new VariableInfo("member",
"String",
@@ -30,4 +33,4 @@
}
}
-
+
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.class
index 92abeab..7b62ca8 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.java
index 961cfc8..32584fd 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/LogTag.java
@@ -16,19 +16,20 @@
*/
package examples;
-
-import javax.servlet.jsp.*;
-
import java.io.IOException;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+
/**
- * Log the contents of the body. Could be used to handle errors etc.
+ * Log the contents of the body. Could be used to handle errors etc.
*/
-public class LogTag
- extends ExampleTagBase
-{
+public class LogTag extends ExampleTagBase {
+
+ private static final long serialVersionUID = 1L;
+
boolean toBrowser = false;
-
+
public void setToBrowser(String value) {
if (value == null)
toBrowser = false;
@@ -38,10 +39,12 @@
toBrowser = false;
}
+ @Override
public int doStartTag() throws JspException {
return EVAL_BODY_BUFFERED;
}
-
+
+ @Override
public int doAfterBody() throws JspException {
try {
String s = bodyOut.getString();
@@ -55,6 +58,4 @@
}
}
-
-
-
+
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.class b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.class
index c02b3ff..5e4fba6 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.java b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.java
index 8afbf09..195e32d 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ShowSource.java
@@ -16,43 +16,45 @@
*/
package examples;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
-import javax.servlet.jsp.*;
-import javax.servlet.jsp.tagext.*;
-
-import java.io.*;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.tagext.TagSupport;
/**
* Display the sources of the JSP file.
*/
-public class ShowSource
- extends TagSupport
-{
+public class ShowSource extends TagSupport {
+
+ private static final long serialVersionUID = 1L;
+
String jspFile;
-
+
public void setJspFile(String jspFile) {
this.jspFile = jspFile;
}
+ @Override
public int doEndTag() throws JspException {
- if ((jspFile.indexOf( ".." ) >= 0) ||
- (jspFile.toUpperCase().indexOf("/WEB-INF/") != 0) ||
- (jspFile.toUpperCase().indexOf("/META-INF/") != 0))
- throw new JspTagException("Invalid JSP file " + jspFile);
+ if ((jspFile.indexOf( ".." ) >= 0) ||
+ (jspFile.toUpperCase(Locale.ENGLISH).indexOf("/WEB-INF/") != 0) ||
+ (jspFile.toUpperCase(Locale.ENGLISH).indexOf("/META-INF/") != 0))
+ throw new JspTagException("Invalid JSP file " + jspFile);
- InputStream in
- = pageContext.getServletContext().getResourceAsStream(jspFile);
-
+ InputStream in = pageContext.getServletContext().getResourceAsStream(
+ jspFile);
if (in == null)
- throw new JspTagException("Unable to find JSP file: "+jspFile);
-
- JspWriter out = pageContext.getOut();
-
+ throw new JspTagException("Unable to find JSP file: " + jspFile);
try {
+ JspWriter out = pageContext.getOut();
out.println("<body>");
out.println("<pre>");
- for(int ch = in.read(); ch != -1; ch = in.read())
+ for (int ch = in.read(); ch != -1; ch = in.read())
if (ch == '<')
out.print("<");
else
@@ -60,12 +62,16 @@
out.println("</pre>");
out.println("</body>");
} catch (IOException ex) {
- throw new JspTagException("IOException: "+ex.toString());
+ throw new JspTagException("IOException: " + ex.toString());
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ throw new JspTagException("Can't close inputstream: ", e);
+ }
}
return super.doEndTag();
}
}
-
-
-
+
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ValuesTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ValuesTag.class
new file mode 100644
index 0000000..cc4d3ff
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ValuesTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ValuesTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ValuesTag.java
new file mode 100644
index 0000000..20468dc
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/examples/ValuesTag.java
@@ -0,0 +1,79 @@
+/*
+ * 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 examples;
+
+import java.io.IOException;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.tagext.TagSupport;
+
+/**
+ * Accept and display a value.
+ */
+public class ValuesTag extends TagSupport {
+
+ private static final long serialVersionUID = 1L;
+
+ // Using "-1" as the default value,
+ // in the assumption that it won't be used as the value.
+ // Cannot use null here, because null is an important case
+ // that should be present in the tests.
+ private Object objectValue = "-1";
+ private String stringValue = "-1";
+ private long longValue = -1;
+ private double doubleValue = -1;
+
+ public void setObject(Object objectValue) {
+ this.objectValue = objectValue;
+ }
+
+ public void setString(String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ public void setLong(long longValue) {
+ this.longValue = longValue;
+ }
+
+ public void setDouble(double doubleValue) {
+ this.doubleValue = doubleValue;
+ }
+
+ @Override
+ public int doEndTag() throws JspException {
+ JspWriter out = pageContext.getOut();
+
+ try {
+ if (!"-1".equals(objectValue)) {
+ out.print(objectValue);
+ } else if (!"-1".equals(stringValue)) {
+ out.print(stringValue);
+ } else if (longValue != -1) {
+ out.print(longValue);
+ } else if (doubleValue != -1) {
+ out.print(doubleValue);
+ } else {
+ out.print("-1");
+ }
+ } catch (IOException ex) {
+ throw new JspTagException("IOException: " + ex.toString(), ex);
+ }
+ return super.doEndTag();
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.class b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.class
index 10a6710..12e41d8 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.java b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.java
index 0601b87..59764ef 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/ExampleFilter.java
@@ -19,6 +19,7 @@
import java.io.IOException;
+
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
@@ -67,6 +68,7 @@
/**
* Take this filter out of service.
*/
+ @Override
public void destroy() {
this.attribute = null;
@@ -80,27 +82,28 @@
* current filter stack, including the ultimately invoked servlet.
*
* @param request The servlet request we are processing
- * @param result The servlet response we are creating
+ * @param response The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
+ @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
- throws IOException, ServletException {
+ throws IOException, ServletException {
- // Store ourselves as a request attribute (if requested)
- if (attribute != null)
- request.setAttribute(attribute, this);
+ // Store ourselves as a request attribute (if requested)
+ if (attribute != null)
+ request.setAttribute(attribute, this);
- // Time and log the subsequent processing
- long startTime = System.currentTimeMillis();
+ // Time and log the subsequent processing
+ long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
- long stopTime = System.currentTimeMillis();
- filterConfig.getServletContext().log
- (this.toString() + ": " + (stopTime - startTime) +
- " milliseconds");
+ long stopTime = System.currentTimeMillis();
+ filterConfig.getServletContext().log
+ (this.toString() + ": " + (stopTime - startTime) +
+ " milliseconds");
}
@@ -108,12 +111,13 @@
/**
* Place this filter into service.
*
- * @param filterConfig The filter configuration object
+ * @param fConfig The filter configuration object
*/
- public void init(FilterConfig filterConfig) throws ServletException {
+ @Override
+ public void init(FilterConfig fConfig) throws ServletException {
- this.filterConfig = filterConfig;
- this.attribute = filterConfig.getInitParameter("attribute");
+ this.filterConfig = fConfig;
+ this.attribute = fConfig.getInitParameter("attribute");
}
@@ -121,14 +125,15 @@
/**
* Return a String representation of this object.
*/
+ @Override
public String toString() {
- if (filterConfig == null)
- return ("InvokerFilter()");
- StringBuffer sb = new StringBuffer("InvokerFilter(");
- sb.append(filterConfig);
- sb.append(")");
- return (sb.toString());
+ if (filterConfig == null)
+ return ("TimingFilter()");
+ StringBuilder sb = new StringBuilder("TimingFilter(");
+ sb.append(filterConfig);
+ sb.append(")");
+ return (sb.toString());
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.class b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.class
deleted file mode 100644
index 5b244bf..0000000
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.class
+++ /dev/null
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.java b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.java
deleted file mode 100644
index 7c45a40..0000000
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/RequestDumperFilter.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-* 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 filters;
-
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.sql.Timestamp;
-import java.util.Enumeration;
-import java.util.Locale;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-
-
-/**
- * Example filter that dumps interesting state information about a request
- * to the associated servlet context log file, before allowing the servlet
- * to process the request in the usual way. This can be installed as needed
- * to assist in debugging problems.
- *
- * @author Craig McClanahan
- */
-public final class RequestDumperFilter implements Filter {
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- /**
- * The filter configuration object we are associated with. If this value
- * is null, this filter instance is not currently configured.
- */
- private FilterConfig filterConfig = null;
-
-
- // --------------------------------------------------------- Public Methods
-
-
- /**
- * Take this filter out of service.
- */
- public void destroy() {
-
- this.filterConfig = null;
-
- }
-
-
- /**
- * Time the processing that is performed by all subsequent filters in the
- * current filter stack, including the ultimately invoked servlet.
- *
- * @param request The servlet request we are processing
- * @param result The servlet response we are creating
- * @param chain The filter chain we are processing
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet error occurs
- */
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain)
- throws IOException, ServletException {
-
- if (filterConfig == null)
- return;
-
- // Render the generic servlet request properties
- StringWriter sw = new StringWriter();
- PrintWriter writer = new PrintWriter(sw);
- writer.println("Request Received at " +
- (new Timestamp(System.currentTimeMillis())));
- writer.println(" characterEncoding=" + request.getCharacterEncoding());
- writer.println(" contentLength=" + request.getContentLength());
- writer.println(" contentType=" + request.getContentType());
- writer.println(" locale=" + request.getLocale());
- writer.print(" locales=");
- Enumeration locales = request.getLocales();
- boolean first = true;
- while (locales.hasMoreElements()) {
- Locale locale = (Locale) locales.nextElement();
- if (first)
- first = false;
- else
- writer.print(", ");
- writer.print(locale.toString());
- }
- writer.println();
- Enumeration names = request.getParameterNames();
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- writer.print(" parameter=" + name + "=");
- String values[] = request.getParameterValues(name);
- for (int i = 0; i < values.length; i++) {
- if (i > 0)
- writer.print(", ");
- writer.print(values[i]);
- }
- writer.println();
- }
- writer.println(" protocol=" + request.getProtocol());
- writer.println(" remoteAddr=" + request.getRemoteAddr());
- writer.println(" remoteHost=" + request.getRemoteHost());
- writer.println(" scheme=" + request.getScheme());
- writer.println(" serverName=" + request.getServerName());
- writer.println(" serverPort=" + request.getServerPort());
- writer.println(" isSecure=" + request.isSecure());
-
- // Render the HTTP servlet request properties
- if (request instanceof HttpServletRequest) {
- writer.println("---------------------------------------------");
- HttpServletRequest hrequest = (HttpServletRequest) request;
- writer.println(" contextPath=" + hrequest.getContextPath());
- Cookie cookies[] = hrequest.getCookies();
- if (cookies == null)
- cookies = new Cookie[0];
- for (int i = 0; i < cookies.length; i++) {
- writer.println(" cookie=" + cookies[i].getName() +
- "=" + cookies[i].getValue());
- }
- names = hrequest.getHeaderNames();
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- String value = hrequest.getHeader(name);
- writer.println(" header=" + name + "=" + value);
- }
- writer.println(" method=" + hrequest.getMethod());
- writer.println(" pathInfo=" + hrequest.getPathInfo());
- writer.println(" queryString=" + hrequest.getQueryString());
- writer.println(" remoteUser=" + hrequest.getRemoteUser());
- writer.println("requestedSessionId=" +
- hrequest.getRequestedSessionId());
- writer.println(" requestURI=" + hrequest.getRequestURI());
- writer.println(" servletPath=" + hrequest.getServletPath());
- }
- writer.println("=============================================");
-
- // Log the resulting string
- writer.flush();
- filterConfig.getServletContext().log(sw.getBuffer().toString());
-
- // Pass control on to the next filter
- chain.doFilter(request, response);
-
- }
-
-
- /**
- * Place this filter into service.
- *
- * @param filterConfig The filter configuration object
- */
- public void init(FilterConfig filterConfig) throws ServletException {
-
- this.filterConfig = filterConfig;
-
- }
-
-
- /**
- * Return a String representation of this object.
- */
- public String toString() {
-
- if (filterConfig == null)
- return ("RequestDumperFilter()");
- StringBuffer sb = new StringBuffer("RequestDumperFilter(");
- sb.append(filterConfig);
- sb.append(")");
- return (sb.toString());
-
- }
-
-
-}
-
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.class b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.class
deleted file mode 100644
index 94be00b..0000000
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.class
+++ /dev/null
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java b/tomcat-cas/webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java
deleted file mode 100644
index 9373222..0000000
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
-* 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 filters;
-
-
-import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-
-/**
- * <p>Example filter that sets the character encoding to be used in parsing the
- * incoming request, either unconditionally or only if the client did not
- * specify a character encoding. Configuration of this filter is based on
- * the following initialization parameters:</p>
- * <ul>
- * <li><strong>encoding</strong> - The character encoding to be configured
- * for this request, either conditionally or unconditionally based on
- * the <code>ignore</code> initialization parameter. This parameter
- * is required, so there is no default.</li>
- * <li><strong>ignore</strong> - If set to "true", any character encoding
- * specified by the client is ignored, and the value returned by the
- * <code>selectEncoding()</code> method is set. If set to "false,
- * <code>selectEncoding()</code> is called <strong>only</strong> if the
- * client has not already specified an encoding. By default, this
- * parameter is set to "true".</li>
- * </ul>
- *
- * <p>Although this filter can be used unchanged, it is also easy to
- * subclass it and make the <code>selectEncoding()</code> method more
- * intelligent about what encoding to choose, based on characteristics of
- * the incoming request (such as the values of the <code>Accept-Language</code>
- * and <code>User-Agent</code> headers, or a value stashed in the current
- * user's session.</p>
- *
- * @author Craig McClanahan
- */
-public class SetCharacterEncodingFilter implements Filter {
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- /**
- * The default character encoding to set for requests that pass through
- * this filter.
- */
- protected String encoding = null;
-
-
- /**
- * The filter configuration object we are associated with. If this value
- * is null, this filter instance is not currently configured.
- */
- protected FilterConfig filterConfig = null;
-
-
- /**
- * Should a character encoding specified by the client be ignored?
- */
- protected boolean ignore = true;
-
-
- // --------------------------------------------------------- Public Methods
-
-
- /**
- * Take this filter out of service.
- */
- public void destroy() {
-
- this.encoding = null;
- this.filterConfig = null;
-
- }
-
-
- /**
- * Select and set (if specified) the character encoding to be used to
- * interpret request parameters for this request.
- *
- * @param request The servlet request we are processing
- * @param result The servlet response we are creating
- * @param chain The filter chain we are processing
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet error occurs
- */
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain)
- throws IOException, ServletException {
-
- // Conditionally select and set the character encoding to be used
- if (ignore || (request.getCharacterEncoding() == null)) {
- String encoding = selectEncoding(request);
- if (encoding != null)
- request.setCharacterEncoding(encoding);
- }
-
- // Pass control on to the next filter
- chain.doFilter(request, response);
-
- }
-
-
- /**
- * Place this filter into service.
- *
- * @param filterConfig The filter configuration object
- */
- public void init(FilterConfig filterConfig) throws ServletException {
-
- this.filterConfig = filterConfig;
- this.encoding = filterConfig.getInitParameter("encoding");
- String value = filterConfig.getInitParameter("ignore");
- if (value == null)
- this.ignore = true;
- else if (value.equalsIgnoreCase("true"))
- this.ignore = true;
- else if (value.equalsIgnoreCase("yes"))
- this.ignore = true;
- else
- this.ignore = false;
-
- }
-
-
- // ------------------------------------------------------ Protected Methods
-
-
- /**
- * Select an appropriate character encoding to be used, based on the
- * characteristics of the current request and/or filter initialization
- * parameters. If no character encoding should be set, return
- * <code>null</code>.
- * <p>
- * The default implementation unconditionally returns the value configured
- * by the <strong>encoding</strong> initialization parameter for this
- * filter.
- *
- * @param request The servlet request we are processing
- */
- protected String selectEncoding(ServletRequest request) {
-
- return (this.encoding);
-
- }
-
-
-}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.class
index 98b8c31..e817362 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.java
index 5e5dec4..cc7e805 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.java
@@ -22,7 +22,7 @@
private String title;
private String author;
private String isbn;
-
+
public BookBean( String title, String author, String isbn ) {
this.title = title;
this.author = author;
@@ -32,13 +32,13 @@
public String getTitle() {
return this.title;
}
-
+
public String getAuthor() {
return this.author;
}
-
+
public String getIsbn() {
return this.isbn;
}
-
+
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.class
index 6605d19..f624400 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.java
index c7f4d39..057a581 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.java
@@ -20,17 +20,17 @@
public class FooBean {
private String bar;
-
+
public FooBean() {
bar = "Initial value";
}
-
+
public String getBar() {
return this.bar;
}
-
+
public void setBar(String bar) {
this.bar = bar;
}
-
+
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.class
new file mode 100644
index 0000000..1ae6315
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.java
new file mode 100644
index 0000000..b7ff056
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/ValuesBean.java
@@ -0,0 +1,52 @@
+/*
+* 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 jsp2.examples;
+
+/**
+ * Accept and display a value.
+ */
+public class ValuesBean {
+ private String string;
+ private double doubleValue;
+ private long longValue;
+
+ public String getStringValue() {
+ return this.string;
+ }
+
+ public void setStringValue(String string) {
+ this.string = string;
+ }
+
+ public double getDoubleValue() {
+ return doubleValue;
+ }
+
+ public void setDoubleValue(double doubleValue) {
+ this.doubleValue = doubleValue;
+ }
+
+ public long getLongValue() {
+ return longValue;
+ }
+
+ public void setLongValue(long longValue) {
+ this.longValue = longValue;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.class
index e0a869c..54f11ef 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.java
index c42c0f7..cc15bf3 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/el/Functions.java
@@ -16,28 +16,30 @@
*/
package jsp2.examples.el;
+import java.util.Locale;
+
/**
* Defines the functions for the jsp2 example tag library.
- *
+ *
* <p>Each function is defined as a static method.</p>
*/
public class Functions {
public static String reverse( String text ) {
- return new StringBuffer( text ).reverse().toString();
+ return new StringBuilder( text ).reverse().toString();
}
public static int numVowels( String text ) {
String vowels = "aeiouAEIOU";
- int result = 0;
+ int result = 0;
for( int i = 0; i < text.length(); i++ ) {
- if( vowels.indexOf( text.charAt( i ) ) != -1 ) {
- result++;
- }
- }
- return result;
+ if( vowels.indexOf( text.charAt( i ) ) != -1 ) {
+ result++;
+ }
+ }
+ return result;
}
public static String caps( String text ) {
- return text.toUpperCase();
+ return text.toUpperCase(Locale.ENGLISH);
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.class
index 5cf67e4..f1ca8cd 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java
index c1a5f92..4dd5322 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java
@@ -18,37 +18,40 @@
package jsp2.examples.simpletag;
+import java.io.IOException;
+import java.util.ArrayList;
+
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
-import javax.servlet.jsp.tagext.SimpleTagSupport;
import javax.servlet.jsp.tagext.DynamicAttributes;
-import java.util.ArrayList;
-import java.io.IOException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
/**
- * SimpleTag handler that echoes all its attributes
+ * SimpleTag handler that echoes all its attributes
*/
-public class EchoAttributesTag
+public class EchoAttributesTag
extends SimpleTagSupport
implements DynamicAttributes
{
- private ArrayList keys = new ArrayList();
- private ArrayList values = new ArrayList();
+ private ArrayList<String> keys = new ArrayList<String>();
+ private ArrayList<Object> values = new ArrayList<Object>();
+ @Override
public void doTag() throws JspException, IOException {
- JspWriter out = getJspContext().getOut();
- for( int i = 0; i < keys.size(); i++ ) {
- String key = (String)keys.get( i );
- Object value = values.get( i );
- out.println( "<li>" + key + " = " + value + "</li>" );
+ JspWriter out = getJspContext().getOut();
+ for( int i = 0; i < keys.size(); i++ ) {
+ String key = keys.get( i );
+ Object value = values.get( i );
+ out.println( "<li>" + key + " = " + value + "</li>" );
}
}
- public void setDynamicAttribute( String uri, String localName,
- Object value )
- throws JspException
+ @Override
+ public void setDynamicAttribute( String uri, String localName,
+ Object value )
+ throws JspException
{
- keys.add( localName );
- values.add( value );
+ keys.add( localName );
+ values.add( value );
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.class
index dd95ddb..4b3a691 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java
index 3d4357d..7554558 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java
@@ -20,6 +20,7 @@
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
+
import jsp2.examples.BookBean;
/**
@@ -28,17 +29,18 @@
*/
public class FindBookSimpleTag extends SimpleTagSupport {
private String var;
-
+
private static final String BOOK_TITLE = "The Lord of the Rings";
private static final String BOOK_AUTHOR = "J. R. R. Tolkein";
private static final String BOOK_ISBN = "0618002251";
+ @Override
public void doTag() throws JspException {
BookBean book = new BookBean( BOOK_TITLE, BOOK_AUTHOR, BOOK_ISBN );
getJspContext().setAttribute( this.var, book );
}
public void setVar( String var ) {
- this.var = var;
+ this.var = var;
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.class
index ff44a1d..21450f5 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java
index 3085739..e068b65 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java
@@ -18,15 +18,17 @@
package jsp2.examples.simpletag;
+import java.io.IOException;
+
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
-import java.io.IOException;
/**
* SimpleTag handler that prints "Hello, world!"
*/
public class HelloWorldSimpleTag extends SimpleTagSupport {
+ @Override
public void doTag() throws JspException, IOException {
- getJspContext().getOut().write( "Hello, world!" );
+ getJspContext().getOut().write( "Hello, world!" );
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.class
index 55e4835..6307468 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java
index 9903a21..a9dda90 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java
@@ -18,25 +18,27 @@
package jsp2.examples.simpletag;
-import javax.servlet.jsp.JspException;
-import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+
/**
- * SimpleTag handler that accepts a num attribute and
+ * SimpleTag handler that accepts a num attribute and
* invokes its body 'num' times.
*/
public class RepeatSimpleTag extends SimpleTagSupport {
private int num;
+ @Override
public void doTag() throws JspException, IOException {
for (int i=0; i<num; i++) {
getJspContext().setAttribute("count", String.valueOf( i + 1 ) );
- getJspBody().invoke(null);
+ getJspBody().invoke(null);
}
}
public void setNum(int num) {
- this.num = num;
+ this.num = num;
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.class
index 759c5ac..3ba23ed 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java
index 64c5b72..e796af2 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java
@@ -18,22 +18,28 @@
package jsp2.examples.simpletag;
+import java.io.IOException;
+import java.util.Random;
+
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
-import java.io.IOException;
/**
* SimpleTag handler that accepts takes three attributes of type
* JspFragment and invokes then in a random order.
*/
public class ShuffleSimpleTag extends SimpleTagSupport {
+ // No need for this to use SecureRandom
+ private static Random random = new Random();
+
private JspFragment fragment1;
private JspFragment fragment2;
private JspFragment fragment3;
+ @Override
public void doTag() throws JspException, IOException {
- switch( (int)(Math.random() * 6) ) {
+ switch(random.nextInt(6)) {
case 0:
fragment1.invoke( null );
fragment2.invoke( null );
@@ -70,11 +76,11 @@
public void setFragment1( JspFragment fragment1 ) {
this.fragment1 = fragment1;
}
-
+
public void setFragment2( JspFragment fragment2 ) {
this.fragment2 = fragment2;
}
-
+
public void setFragment3( JspFragment fragment3 ) {
this.fragment3 = fragment3;
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.class b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.class
index c33cccc..d2162fe 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java
index 4f37e48..b95cc31 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java
@@ -18,9 +18,10 @@
package jsp2.examples.simpletag;
+import java.io.IOException;
+
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
-import java.io.IOException;
/**
* Displays a tile as a single cell in a table.
@@ -29,17 +30,18 @@
private String color;
private String label;
+ @Override
public void doTag() throws JspException, IOException {
- getJspContext().getOut().write(
- "<td width=\"32\" height=\"32\" bgcolor=\"" + this.color +
- "\"><font color=\"#ffffff\"><center>" + this.label +
+ getJspContext().getOut().write(
+ "<td width=\"32\" height=\"32\" bgcolor=\"" + this.color +
+ "\"><font color=\"#ffffff\"><center>" + this.label +
"</center></font></td>" );
}
public void setColor( String color ) {
this.color = color;
}
-
+
public void setLabel( String label ) {
this.label = label;
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.class b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.class
index 43f66ff..26619b0 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.java b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.java
index 4702546..7fd012f 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/ContextListener.java
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package listeners;
@@ -54,10 +53,11 @@
*
* @param event The servlet context attribute event
*/
+ @Override
public void attributeAdded(ServletContextAttributeEvent event) {
- log("attributeAdded('" + event.getName() + "', '" +
- event.getValue() + "')");
+ log("attributeAdded('" + event.getName() + "', '" +
+ event.getValue() + "')");
}
@@ -67,10 +67,11 @@
*
* @param event The servlet context attribute event
*/
+ @Override
public void attributeRemoved(ServletContextAttributeEvent event) {
- log("attributeRemoved('" + event.getName() + "', '" +
- event.getValue() + "')");
+ log("attributeRemoved('" + event.getName() + "', '" +
+ event.getValue() + "')");
}
@@ -80,10 +81,11 @@
*
* @param event The servlet context attribute event
*/
+ @Override
public void attributeReplaced(ServletContextAttributeEvent event) {
- log("attributeReplaced('" + event.getName() + "', '" +
- event.getValue() + "')");
+ log("attributeReplaced('" + event.getName() + "', '" +
+ event.getValue() + "')");
}
@@ -93,10 +95,11 @@
*
* @param event The servlet context event
*/
+ @Override
public void contextDestroyed(ServletContextEvent event) {
- log("contextDestroyed()");
- this.context = null;
+ log("contextDestroyed()");
+ this.context = null;
}
@@ -106,10 +109,11 @@
*
* @param event The servlet context event
*/
+ @Override
public void contextInitialized(ServletContextEvent event) {
- this.context = event.getServletContext();
- log("contextInitialized()");
+ this.context = event.getServletContext();
+ log("contextInitialized()");
}
@@ -124,10 +128,10 @@
*/
private void log(String message) {
- if (context != null)
- context.log("ContextListener: " + message);
- else
- System.out.println("ContextListener: " + message);
+ if (context != null)
+ context.log("ContextListener: " + message);
+ else
+ System.out.println("ContextListener: " + message);
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.class b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.class
index 8afca5e..22c53ea 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.java b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.java
index efac784..06a2aa8 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/listeners/SessionListener.java
@@ -1,23 +1,21 @@
/*
-* 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.
-*/
-
+ * 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 listeners;
-
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@@ -26,135 +24,136 @@
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
-
/**
* Example listener for context-related application events, which were
- * introduced in the 2.3 version of the Servlet API. This listener
- * merely documents the occurrence of such events in the application log
- * associated with our servlet context.
+ * introduced in the 2.3 version of the Servlet API. This listener merely
+ * documents the occurrence of such events in the application log associated
+ * with our servlet context.
*
* @author Craig R. McClanahan
*/
-public final class SessionListener
- implements ServletContextListener,
- HttpSessionAttributeListener, HttpSessionListener {
-
+public final class SessionListener implements ServletContextListener,
+ HttpSessionAttributeListener, HttpSessionListener {
// ----------------------------------------------------- Instance Variables
-
/**
* The servlet context with which we are associated.
*/
private ServletContext context = null;
-
// --------------------------------------------------------- Public Methods
-
/**
* Record the fact that a servlet context attribute was added.
*
- * @param event The session attribute event
+ * @param event
+ * The session attribute event
*/
+ @Override
public void attributeAdded(HttpSessionBindingEvent event) {
- log("attributeAdded('" + event.getSession().getId() + "', '" +
- event.getName() + "', '" + event.getValue() + "')");
+ log("attributeAdded('" + event.getSession().getId() + "', '"
+ + event.getName() + "', '" + event.getValue() + "')");
}
-
/**
* Record the fact that a servlet context attribute was removed.
*
- * @param event The session attribute event
+ * @param event
+ * The session attribute event
*/
+ @Override
public void attributeRemoved(HttpSessionBindingEvent event) {
- log("attributeRemoved('" + event.getSession().getId() + "', '" +
- event.getName() + "', '" + event.getValue() + "')");
+ log("attributeRemoved('" + event.getSession().getId() + "', '"
+ + event.getName() + "', '" + event.getValue() + "')");
}
-
/**
* Record the fact that a servlet context attribute was replaced.
*
- * @param event The session attribute event
+ * @param event
+ * The session attribute event
*/
+ @Override
public void attributeReplaced(HttpSessionBindingEvent event) {
- log("attributeReplaced('" + event.getSession().getId() + "', '" +
- event.getName() + "', '" + event.getValue() + "')");
+ log("attributeReplaced('" + event.getSession().getId() + "', '"
+ + event.getName() + "', '" + event.getValue() + "')");
}
-
/**
* Record the fact that this web application has been destroyed.
*
- * @param event The servlet context event
+ * @param event
+ * The servlet context event
*/
+ @Override
public void contextDestroyed(ServletContextEvent event) {
- log("contextDestroyed()");
- this.context = null;
+ log("contextDestroyed()");
+ this.context = null;
}
-
/**
* Record the fact that this web application has been initialized.
*
- * @param event The servlet context event
+ * @param event
+ * The servlet context event
*/
+ @Override
public void contextInitialized(ServletContextEvent event) {
- this.context = event.getServletContext();
- log("contextInitialized()");
+ this.context = event.getServletContext();
+ log("contextInitialized()");
}
-
/**
* Record the fact that a session has been created.
*
- * @param event The session event
+ * @param event
+ * The session event
*/
+ @Override
public void sessionCreated(HttpSessionEvent event) {
- log("sessionCreated('" + event.getSession().getId() + "')");
+ log("sessionCreated('" + event.getSession().getId() + "')");
}
-
/**
* Record the fact that a session has been destroyed.
*
- * @param event The session event
+ * @param event
+ * The session event
*/
+ @Override
public void sessionDestroyed(HttpSessionEvent event) {
- log("sessionDestroyed('" + event.getSession().getId() + "')");
+ log("sessionDestroyed('" + event.getSession().getId() + "')");
}
-
// -------------------------------------------------------- Private Methods
-
/**
* Log a message to the servlet context application log.
*
- * @param message Message to be logged
+ * @param message
+ * Message to be logged
*/
private void log(String message) {
- if (context != null)
- context.log("SessionListener: " + message);
- else
- System.out.println("SessionListener: " + message);
+ if (context != null)
+ context.log("SessionListener: " + message);
+ else
+ System.out.println("SessionListener: " + message);
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.class b/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.class
index 51e5b62..e2051e9 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.java b/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.java
index 7eed08e..a619edb 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/num/NumberGuessBean.java
@@ -1,19 +1,19 @@
/*
-* 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.
-*/
+ * 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.
+ */
/*
* Originally written by Jason Hunter, http://www.servlets.com.
@@ -21,59 +21,79 @@
package num;
-import java.util.*;
+import java.io.Serializable;
+import java.util.Random;
-public class NumberGuessBean {
+public class NumberGuessBean implements Serializable {
- int answer;
- boolean success;
- String hint;
- int numGuesses;
+ private static final long serialVersionUID = 1L;
- public NumberGuessBean() {
- reset();
- }
+ private int answer;
+ private String hint;
+ private int numGuesses;
+ private boolean success;
+ private Random random = new Random();
- public void setGuess(String guess) {
- numGuesses++;
-
- int g;
- try {
- g = Integer.parseInt(guess);
- }
- catch (NumberFormatException e) {
- g = -1;
+ public NumberGuessBean() {
+ reset();
}
- if (g == answer) {
- success = true;
+ public int getAnswer() {
+ return answer;
}
- else if (g == -1) {
- hint = "a number next time";
+
+ public void setAnswer(int answer) {
+ this.answer = answer;
}
- else if (g < answer) {
- hint = "higher";
+
+ public String getHint() {
+ return "" + hint;
}
- else if (g > answer) {
- hint = "lower";
+
+ public void setHint(String hint) {
+ this.hint = hint;
}
- }
- public boolean getSuccess() {
- return success;
- }
+ public void setNumGuesses(int numGuesses) {
+ this.numGuesses = numGuesses;
+ }
- public String getHint() {
- return "" + hint;
- }
+ public int getNumGuesses() {
+ return numGuesses;
+ }
- public int getNumGuesses() {
- return numGuesses;
- }
+ public boolean getSuccess() {
+ return success;
+ }
- public void reset() {
- answer = Math.abs(new Random().nextInt() % 100) + 1;
- success = false;
- numGuesses = 0;
- }
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public void setGuess(String guess) {
+ numGuesses++;
+
+ int g;
+ try {
+ g = Integer.parseInt(guess);
+ } catch (NumberFormatException e) {
+ g = -1;
+ }
+
+ if (g == answer) {
+ success = true;
+ } else if (g == -1) {
+ hint = "a number next time";
+ } else if (g < answer) {
+ hint = "higher";
+ } else if (g > answer) {
+ hint = "lower";
+ }
+ }
+
+ public void reset() {
+ answer = Math.abs(random.nextInt() % 100) + 1;
+ success = false;
+ numGuesses = 0;
+ }
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.class b/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.class
index c95143b..4432239 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.java b/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.java
index cfd198e..f5cd80a 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/servletToJsp.java
@@ -14,19 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import javax.servlet.http.*;
-public class servletToJsp extends HttpServlet {
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+public class ServletToJsp extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
public void doGet (HttpServletRequest request,
- HttpServletResponse response) {
+ HttpServletResponse response) {
- try {
- // Set the attribute and Forward to hello.jsp
- request.setAttribute ("servletName", "servletToJsp");
- getServletConfig().getServletContext().getRequestDispatcher("/jsp/jsptoserv/hello.jsp").forward(request, response);
- } catch (Exception ex) {
- ex.printStackTrace ();
- }
+ try {
+ // Set the attribute and Forward to hello.jsp
+ request.setAttribute ("servletName", "servletToJsp");
+ getServletConfig().getServletContext().getRequestDispatcher(
+ "/jsp/jsptoserv/hello.jsp").forward(request, response);
+ } catch (Exception ex) {
+ ex.printStackTrace ();
+ }
}
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.class b/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.class
index 5518952..2ad60c0 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.java b/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.java
index f0597e7..01480a0 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/sessions/DummyCart.java
@@ -22,7 +22,7 @@
Vector<String> v = new Vector<String>();
String submit = null;
String item = null;
-
+
private void addItem(String name) {
v.addElement(name);
}
@@ -34,7 +34,7 @@
public void setItem(String name) {
item = name;
}
-
+
public void setSubmit(String s) {
submit = s;
}
@@ -44,15 +44,15 @@
v.copyInto(s);
return s;
}
-
+
public void processRequest() {
- // null value for submit - user hit enter instead of clicking on
+ // null value for submit - user hit enter instead of clicking on
// "add" or "remove"
if (submit == null || submit.equals("add"))
addItem(item);
- else if (submit.equals("remove"))
+ else if (submit.equals("remove"))
removeItem(item);
-
+
// reset at the end of the request
reset();
}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/util/CookieFilter.class b/tomcat-cas/webapps/examples/WEB-INF/classes/util/CookieFilter.class
new file mode 100644
index 0000000..429bbac
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/util/CookieFilter.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/util/CookieFilter.java b/tomcat-cas/webapps/examples/WEB-INF/classes/util/CookieFilter.java
new file mode 100644
index 0000000..005222f
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/util/CookieFilter.java
@@ -0,0 +1,81 @@
+/*
+ * 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 util;
+
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+/**
+ * Processes a cookie header and attempts to obfuscate any cookie values that
+ * represent session IDs from other web applications. Since session cookie names
+ * are configurable, as are session ID lengths, this filter is not expected to
+ * be 100% effective.
+ *
+ * It is required that the examples web application is removed in security
+ * conscious environments as documented in the Security How-To. This filter is
+ * intended to reduce the impact of failing to follow that advice. A failure by
+ * this filter to obfuscate a session ID or similar value is not a security
+ * vulnerability. In such instances the vulnerability is the failure to remove
+ * the examples web application.
+ */
+public class CookieFilter {
+
+ private static final String OBFUSCATED = "[obfuscated]";
+
+ private CookieFilter() {
+ // Hide default constructor
+ }
+
+ public static String filter(String input, String sessionId) {
+
+ StringBuilder sb = new StringBuilder(input.length());
+
+ // Cookie name value pairs are ';' separated.
+ // Session IDs don't use ; in the value so don't worry about quoted
+ // values that contain ;
+ StringTokenizer st = new StringTokenizer(input, ";");
+
+ boolean first = true;
+ while (st.hasMoreTokens()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(';');
+ }
+ sb.append(filterNameValuePair(st.nextToken(), sessionId));
+ }
+
+
+ return sb.toString();
+ }
+
+ private static String filterNameValuePair(String input, String sessionId) {
+ int i = input.indexOf('=');
+ if (i == -1) {
+ return input;
+ }
+ String name = input.substring(0, i);
+ String value = input.substring(i + 1, input.length());
+
+ if (name.toLowerCase(Locale.ENGLISH).contains("jsessionid") &&
+ (sessionId == null || !value.contains(sessionId))) {
+ value = OBFUSCATED;
+ }
+
+ return name + "=" + value;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.class b/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.class
index 7555aa0..1ed1273 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.java b/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.java
index 3d85e81..ec66a89 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/util/HTMLFilter.java
@@ -39,7 +39,7 @@
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
- StringBuffer result = new StringBuffer(content.length + 50);
+ StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.class b/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.class
index 90b65ce..4a9fb4c 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.class
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.java b/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.java
index 1ddffc4..d5accba 100644
--- a/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.java
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/validators/DebugValidator.java
@@ -19,8 +19,9 @@
package validators;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
+
import javax.servlet.jsp.tagext.PageData;
import javax.servlet.jsp.tagext.TagLibraryValidator;
import javax.servlet.jsp.tagext.ValidationMessage;
@@ -55,6 +56,7 @@
* @param uri The value of the URI argument in this directive
* @param page The page data for this page
*/
+ @Override
public ValidationMessage[] validate(String prefix, String uri,
PageData page) {
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.class
new file mode 100644
index 0000000..188802e
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.java
new file mode 100644
index 0000000..38ba838
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/ExamplesConfig.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.websocket.Endpoint;
+import javax.websocket.server.ServerApplicationConfig;
+import javax.websocket.server.ServerEndpointConfig;
+
+import websocket.drawboard.DrawboardEndpoint;
+import websocket.echo.EchoEndpoint;
+
+public class ExamplesConfig implements ServerApplicationConfig {
+
+ @Override
+ public Set<ServerEndpointConfig> getEndpointConfigs(
+ Set<Class<? extends Endpoint>> scanned) {
+
+ Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();
+
+ if (scanned.contains(EchoEndpoint.class)) {
+ result.add(ServerEndpointConfig.Builder.create(
+ EchoEndpoint.class,
+ "/websocket/echoProgrammatic").build());
+ }
+
+ if (scanned.contains(DrawboardEndpoint.class)) {
+ result.add(ServerEndpointConfig.Builder.create(
+ DrawboardEndpoint.class,
+ "/websocket/drawboard").build());
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
+ // Deploy all WebSocket endpoints defined by annotations in the examples
+ // web application. Filter out all others to avoid issues when running
+ // tests on Gump
+ Set<Class<?>> results = new HashSet<Class<?>>();
+ for (Class<?> clazz : scanned) {
+ if (clazz.getPackage().getName().startsWith("websocket.")) {
+ results.add(clazz);
+ }
+ }
+ return results;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.class
new file mode 100644
index 0000000..154bd54
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java
new file mode 100644
index 0000000..d585d98
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/chat/ChatAnnotation.java
@@ -0,0 +1,109 @@
+/*
+ * 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.chat;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+import util.HTMLFilter;
+
+@ServerEndpoint(value = "/websocket/chat")
+public class ChatAnnotation {
+
+ private static final Log log = LogFactory.getLog(ChatAnnotation.class);
+
+ private static final String GUEST_PREFIX = "Guest";
+ private static final AtomicInteger connectionIds = new AtomicInteger(0);
+ private static final Set<ChatAnnotation> connections =
+ new CopyOnWriteArraySet<ChatAnnotation>();
+
+ private final String nickname;
+ private Session session;
+
+ public ChatAnnotation() {
+ nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
+ }
+
+
+ @OnOpen
+ public void start(Session session) {
+ this.session = session;
+ connections.add(this);
+ String message = String.format("* %s %s", nickname, "has joined.");
+ broadcast(message);
+ }
+
+
+ @OnClose
+ public void end() {
+ connections.remove(this);
+ String message = String.format("* %s %s",
+ nickname, "has disconnected.");
+ broadcast(message);
+ }
+
+
+ @OnMessage
+ public void incoming(String message) {
+ // Never trust the client
+ String filteredMessage = String.format("%s: %s",
+ nickname, HTMLFilter.filter(message.toString()));
+ broadcast(filteredMessage);
+ }
+
+
+
+
+ @OnError
+ public void onError(Throwable t) throws Throwable {
+ log.error("Chat Error: " + t.toString(), t);
+ }
+
+
+ private static void broadcast(String msg) {
+ for (ChatAnnotation client : connections) {
+ try {
+ synchronized (client) {
+ client.session.getBasicRemote().sendText(msg);
+ }
+ } catch (IOException e) {
+ log.debug("Chat Error: Failed to send message to client", e);
+ connections.remove(client);
+ try {
+ client.session.close();
+ } catch (IOException e1) {
+ // Ignore
+ }
+ String message = String.format("* %s %s",
+ client.nickname, "has been disconnected.");
+ broadcast(message);
+ }
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client$1.class
new file mode 100644
index 0000000..c152c6b
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.class
new file mode 100644
index 0000000..53bb52a
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java
new file mode 100644
index 0000000..71e47c9
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java
@@ -0,0 +1,233 @@
+/*
+ * 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.IOException;
+import java.util.LinkedList;
+
+import javax.websocket.CloseReason;
+import javax.websocket.CloseReason.CloseCodes;
+import javax.websocket.RemoteEndpoint.Async;
+import javax.websocket.SendHandler;
+import javax.websocket.SendResult;
+import javax.websocket.Session;
+
+import websocket.drawboard.wsmessages.AbstractWebsocketMessage;
+import websocket.drawboard.wsmessages.BinaryWebsocketMessage;
+import websocket.drawboard.wsmessages.CloseWebsocketMessage;
+import websocket.drawboard.wsmessages.StringWebsocketMessage;
+
+/**
+ * Represents a client with methods to send messages asynchronously.
+ */
+public class Client {
+
+ private final Session session;
+ private final Async async;
+
+ /**
+ * Contains the messages wich are buffered until the previous
+ * send operation has finished.
+ */
+ private final LinkedList<AbstractWebsocketMessage> messagesToSend =
+ new LinkedList<AbstractWebsocketMessage>();
+ /**
+ * If this client is currently sending a messages asynchronously.
+ */
+ private volatile boolean isSendingMessage = false;
+ /**
+ * If this client is closing. If <code>true</code>, new messages to
+ * send will be ignored.
+ */
+ private volatile boolean isClosing = false;
+ /**
+ * The length of all current buffered messages, to avoid iterating
+ * over a linked list.
+ */
+ private volatile long messagesToSendLength = 0;
+
+ public Client(Session session) {
+ this.session = session;
+ this.async = session.getAsyncRemote();
+ }
+
+ /**
+ * Asynchronously closes the Websocket session. This will wait until all
+ * remaining messages have been sent to the Client and then close
+ * the Websocket session.
+ */
+ public void close() {
+ sendMessage(new CloseWebsocketMessage());
+ }
+
+ /**
+ * 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 (!isClosing) {
+ // Check if we have a Close message
+ if (msg instanceof CloseWebsocketMessage) {
+ isClosing = true;
+ }
+
+ if (isSendingMessage) {
+ // Check if the buffered messages exceed
+ // a specific amount - in that case, disconnect the client
+ // to prevent DoS.
+ // In this case we check if there are >= 1000 messages
+ // or length(of all messages) >= 1000000 bytes.
+ if (messagesToSend.size() >= 1000
+ || messagesToSendLength >= 1000000) {
+ isClosing = true;
+
+ // Discard the new message and close the session immediately.
+ CloseReason cr = new CloseReason(
+ CloseCodes.VIOLATED_POLICY,
+ "Send Buffer exceeded");
+ try {
+ // TODO: close() may block if the remote endpoint doesn't read the data
+ // (eventually there will be a TimeoutException). However, this method
+ // (sendMessage) is intended to run asynchronous code and shouldn't
+ // block. Otherwise it would temporarily stop processing of messages
+ // from other clients.
+ // Maybe call this method on another thread.
+ // Note that when this method is called, the RemoteEndpoint.Async
+ // is still in the process of sending data, so there probably should
+ // be another way to abort the Websocket connection.
+ // Ideally, there should be some abort() method that cancels the
+ // connection immediately...
+ session.close(cr);
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ } else {
+
+ // Check if the last message and the new message are
+ // String messages - in that case we concatenate them
+ // to reduce TCP overhead (using ";" as separator).
+ if (msg instanceof StringWebsocketMessage
+ && !messagesToSend.isEmpty()
+ && messagesToSend.getLast()
+ instanceof StringWebsocketMessage) {
+
+ StringWebsocketMessage ms =
+ (StringWebsocketMessage) messagesToSend.removeLast();
+ messagesToSendLength -= calculateMessageLength(ms);
+
+ String concatenated = ms.getString() + ";" +
+ ((StringWebsocketMessage) msg).getString();
+ msg = new StringWebsocketMessage(concatenated);
+ }
+
+ messagesToSend.add(msg);
+ messagesToSendLength += calculateMessageLength(msg);
+ }
+ } else {
+ isSendingMessage = true;
+ internalSendMessageAsync(msg);
+ }
+ }
+
+ }
+ }
+
+ private long calculateMessageLength(AbstractWebsocketMessage msg) {
+ if (msg instanceof BinaryWebsocketMessage) {
+ return ((BinaryWebsocketMessage) msg).getBytes().capacity();
+ } else if (msg instanceof StringWebsocketMessage) {
+ return ((StringWebsocketMessage) msg).getString().length() * 2;
+ }
+
+ return 0;
+ }
+
+ /**
+ * 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);
+
+ } else if (msg instanceof CloseWebsocketMessage) {
+ // Close the session.
+ session.close();
+ }
+ } catch (IllegalStateException ex) {
+ // Trying to write to the client when the session has
+ // already been closed.
+ // Ignore
+ } catch (IOException 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) {
+ if (!result.isOK()) {
+ // Message could not be sent. In this case, we don't
+ // set isSendingMessage to false because we must assume the connection
+ // broke (and onClose will be called), so we don't try to send
+ // other messages.
+ // As a precaution, we close the session (e.g. if a send timeout occured).
+ // TODO: session.close() blocks, while this handler shouldn't block.
+ // Ideally, there should be some abort() method that cancels the
+ // connection immediately...
+ try {
+ session.close();
+ } catch (IOException ex) {
+ // Ignore
+ }
+ }
+ synchronized (messagesToSend) {
+
+ if (!messagesToSend.isEmpty()) {
+ AbstractWebsocketMessage msg = messagesToSend.remove();
+ messagesToSendLength -= calculateMessageLength(msg);
+
+ internalSendMessageAsync(msg);
+
+ } else {
+ isSendingMessage = false;
+ }
+
+ }
+ }
+ };
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage$ParseException.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage$ParseException.class
new file mode 100644
index 0000000..51943a6
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage$ParseException.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.class
new file mode 100644
index 0000000..f37e237
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java
new file mode 100644
index 0000000..c218cc8
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawMessage.java
@@ -0,0 +1,270 @@
+/*
+ * 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;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * 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 double x1, y1, x2, y2;
+ private boolean lastInChain;
+
+ /**
+ * The type.<br>
+ * 1: Brush<br>
+ * 2: Line<br>
+ * 3: Rectangle<br>
+ * 4: Ellipse
+ */
+ 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 double getX1() {
+ return x1;
+ }
+ public void setX1(double x1) {
+ this.x1 = x1;
+ }
+ public double getX2() {
+ return x2;
+ }
+ public void setX2(double x2) {
+ this.x2 = x2;
+ }
+ public double getY1() {
+ return y1;
+ }
+ public void setY1(double y1) {
+ this.y1 = y1;
+ }
+ public double getY2() {
+ return y2;
+ }
+ public void setY2(double y2) {
+ this.y2 = y2;
+ }
+
+ /**
+ * Specifies if this DrawMessage is the last one in a chain
+ * (e.g. a chain of brush paths).<br>
+ * Currently it is unused.
+ */
+ public boolean isLastInChain() {
+ return lastInChain;
+ }
+ public void setLastInChain(boolean lastInChain) {
+ this.lastInChain = lastInChain;
+ }
+
+
+
+ public DrawMessage(int type, byte colorR, byte colorG, byte colorB,
+ byte colorA, double thickness, double x1, double x2, double y1,
+ double y2, boolean lastInChain) {
+
+ 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;
+ this.lastInChain = lastInChain;
+ }
+
+
+ /**
+ * Draws this DrawMessage onto the given Graphics2D.
+ * @param g
+ */
+ public void draw(Graphics2D g) {
+
+ g.setStroke(new BasicStroke((float) thickness,
+ BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
+ g.setColor(new Color(colorR & 0xFF, colorG & 0xFF, colorB & 0xFF,
+ colorA & 0xFF));
+
+ if (x1 == x2 && y1 == y2) {
+ // Always draw as arc to meet the behavior in the HTML5 Canvas.
+ Arc2D arc = new Arc2D.Double(x1, y1, 0, 0,
+ 0d, 360d, Arc2D.OPEN);
+ g.draw(arc);
+
+ } else if (type == 1 || type == 2) {
+ // Draw a line.
+ Line2D line = new Line2D.Double(x1, y1, x2, y2);
+ g.draw(line);
+
+ } else if (type == 3 || type == 4) {
+ double x1 = this.x1, x2 = this.x2,
+ y1 = this.y1, y2 = this.y2;
+ if (x1 > x2) {
+ x1 = this.x2;
+ x2 = this.x1;
+ }
+ if (y1 > y2) {
+ y1 = this.y2;
+ y2 = this.y1;
+ }
+
+ // TODO: If (x1 == x2 || y1 == y2) draw as line.
+
+ if (type == 3) {
+ // Draw a rectangle.
+ Rectangle2D rect = new Rectangle2D.Double(x1, y1,
+ x2 - x1, y2 - y1);
+ g.draw(rect);
+
+ } else if (type == 4) {
+ // Draw an ellipse.
+ Arc2D arc = new Arc2D.Double(x1, y1, x2 - x1, y2 - y1,
+ 0d, 360d, Arc2D.OPEN);
+ g.draw(arc);
+
+ }
+ }
+ }
+
+ /**
+ * 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 + ","
+ + (lastInChain ? "1" : "0");
+ }
+
+ public static DrawMessage parseFromString(String str)
+ throws ParseException {
+
+ int type;
+ byte[] colors = new byte[4];
+ double thickness;
+ double[] coords = new double[4];
+ boolean last;
+
+ try {
+ String[] elements = str.split(",");
+
+ type = Integer.parseInt(elements[0]);
+ if (!(type >= 1 && type <= 4))
+ 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] = Double.parseDouble(elements[6 + i]);
+ if (Double.isNaN(coords[i]))
+ throw new ParseException("Invalid coordinate: "
+ + coords[i]);
+ }
+
+ last = !"0".equals(elements[10]);
+
+ } 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], last);
+
+ 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);
+ }
+ }
+
+
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.class
new file mode 100644
index 0000000..f6724e6
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.java
new file mode 100644
index 0000000..4ba2b38
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardContextListener.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+public final class DrawboardContextListener implements ServletContextListener {
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ // NO-OP
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ // Shutdown our room.
+ Room room = DrawboardEndpoint.getRoom(false);
+ if (room != null) {
+ room.shutdown();
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$1.class
new file mode 100644
index 0000000..3add6a1
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$2.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$2.class
new file mode 100644
index 0000000..ee2f923
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$2.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$3$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$3$1.class
new file mode 100644
index 0000000..86ff72e
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$3$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$3.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$3.class
new file mode 100644
index 0000000..9a9499e
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint$3.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.class
new file mode 100644
index 0000000..5f35890
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java
new file mode 100644
index 0000000..75d86f3
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java
@@ -0,0 +1,236 @@
+/*
+ * 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 java.io.IOException;
+
+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 volatile Room room = null;
+ private static final Object roomLock = new Object();
+
+ public static Room getRoom(boolean create) {
+ if (create) {
+ if (room == null) {
+ synchronized (roomLock) {
+ if (room == null) {
+ room = new Room();
+ }
+ }
+ }
+ return room;
+ } else {
+ 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);
+
+ final Room room = getRoom(true);
+ room.invokeAndWait(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()));
+ // Close the connection.
+ client.close();
+ }
+
+ } catch (RuntimeException ex) {
+ log.error("Unexpected exception: " + ex.toString(), ex);
+ }
+ }
+ });
+
+ }
+
+
+ @Override
+ public void onClose(Session session, CloseReason closeReason) {
+ Room room = getRoom(false);
+ if (room != null) {
+ room.invokeAndWait(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();
+
+ // Set player to null to prevent NPEs when onMessage events
+ // are processed (from other threads) after onClose has been
+ // called from different thread which closed the Websocket session.
+ player = null;
+ }
+ } 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 if (!session.isOpen() && root instanceof IOException) {
+ // IOException after close. Assume this is a variation of the user
+ // closing their browser (or refreshing very quickly) 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.invokeAndWait(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,lastInChain
+
+ boolean dontSwallowException = false;
+ try {
+ char messageType = message.charAt(0);
+ String messageContent = message.substring(1);
+ switch (messageType) {
+ case '0':
+ // Pong message.
+ // Do nothing.
+ break;
+
+ case '1':
+ // Draw message
+ int indexOfChar = messageContent.indexOf('|');
+ long msgId = Long.parseLong(
+ messageContent.substring(0, indexOfChar));
+
+ DrawMessage msg = DrawMessage.parseFromString(
+ messageContent.substring(indexOfChar + 1));
+
+ // Don't ignore 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 ex) {
+ // Client sent invalid data.
+ // Ignore, TODO: maybe close connection
+ if (dontSwallowException) {
+ throw ex;
+ }
+ } catch (ParseException ex) {
+ // Client sent invalid data.
+ // Ignore, TODO: maybe close connection
+ }
+ } catch (RuntimeException ex) {
+ log.error("Unexpected exception: " + ex.toString(), ex);
+ }
+ }
+ });
+
+ }
+ };
+
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$1$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$1$1.class
new file mode 100644
index 0000000..604acea
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$1$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$1.class
new file mode 100644
index 0000000..ba034ac
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$2.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$2.class
new file mode 100644
index 0000000..6ef92d7
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$2.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$MessageType.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$MessageType.class
new file mode 100644
index 0000000..1e5b6bc
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$MessageType.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$Player.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$Player.class
new file mode 100644
index 0000000..bf50834
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room$Player.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.class
new file mode 100644
index 0000000..7c9e605
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java
new file mode 100644
index 0000000..9e3b361
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java
@@ -0,0 +1,490 @@
+/*
+ * 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.locks.ReentrantLock;
+
+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>
+ *
+ * Note: Instance methods should only be invoked by calling
+ * {@link #invokeAndWait(Runnable)} to ensure access is correctly synchronized.
+ */
+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': DrawMessage: 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;
+ }
+
+ }
+
+
+ /**
+ * The lock used to synchronize access to this Room.
+ */
+ private final ReentrantLock roomLock = new ReentrantLock();
+
+ /**
+ * Indicates if this room has already been shutdown.
+ */
+ private volatile boolean closed = false;
+
+ /**
+ * 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 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();
+
+ private static final int TIMER_DELAY = 30;
+
+ /**
+ * The current active broadcast timer task. If null, then no Broadcast task is scheduled.
+ * The Task will be scheduled if the first player enters the Room, and
+ * cancelled if the last player exits the Room, to avoid unnecessary timer executions.
+ */
+ private TimerTask activeBroadcastTimerTask;
+
+
+ /**
+ * 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 = 100;
+
+ /**
+ * List of all currently joined players.
+ */
+ private final List<Player> players = new ArrayList<Player>();
+
+
+
+ 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());
+ }
+
+ private TimerTask createBroadcastTimerTask() {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ broadcastTimerTick();
+ }
+ });
+ }
+ };
+ }
+
+ /**
+ * Creates a Player from the given Client and adds it to this room.
+ * @param client the client
+ */
+ public Player createAndAddPlayer(Client client) {
+ if (players.size() >= MAX_PLAYER_COUNT) {
+ throw new IllegalStateException("Maximum player count ("
+ + 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);
+
+ // If currently no Broadcast Timer Task is scheduled, then we need to create one.
+ if (activeBroadcastTimerTask == null) {
+ activeBroadcastTimerTask = createBroadcastTimerTask();
+ drawmessageBroadcastTimer.schedule(activeBroadcastTimerTask,
+ TIMER_DELAY, TIMER_DELAY);
+ }
+
+ // 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) {
+ boolean removed = players.remove(p);
+ assert removed;
+
+ // If the last player left the Room, we need to cancel the Broadcast Timer Task.
+ if (players.size() == 0) {
+ // Cancel the task.
+ // Note that it can happen that the TimerTask is just about to execute (from
+ // the Timer thread) but waits until all players are gone (or even until a new
+ // player is added to the list), and then executes. This is OK. To prevent it,
+ // a TimerTask subclass would need to have some boolean "cancel" instance variable and
+ // query it in the invocation of Room#invokeAndWait.
+ activeBroadcastTimerTask.cancel();
+ activeBroadcastTimerTask = null;
+ }
+
+ // 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.<br>
+ * 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
+ // lastReceivedMessageId.
+ // 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());
+ }
+ }
+ }
+
+ /**
+ * A list of cached {@link Runnable}s to prevent recursive invocation of Runnables
+ * by one thread. This variable is only used by one thread at a time and then
+ * set to <code>null</code>.
+ */
+ private List<Runnable> cachedRunnables = null;
+
+ /**
+ * Submits the given Runnable to the Room Executor and waits until it
+ * has been executed. Currently, this simply means that the Runnable
+ * will be run directly inside of a synchronized() block.<br>
+ * Note that if a runnable recursively calls invokeAndWait() with another
+ * runnable on this Room, it will not be executed recursively, but instead
+ * cached until the original runnable is finished, to keep the behavior of
+ * using a Executor.
+ * @param task
+ */
+ public void invokeAndWait(Runnable task) {
+
+ // Check if the current thread already holds a lock on this room.
+ // If yes, then we must not directly execute the Runnable but instead
+ // cache it until the original invokeAndWait() has finished.
+ if (roomLock.isHeldByCurrentThread()) {
+
+ if (cachedRunnables == null) {
+ cachedRunnables = new ArrayList<Runnable>();
+ }
+ cachedRunnables.add(task);
+
+ } else {
+
+ roomLock.lock();
+ try {
+ // Explicitly overwrite value to ensure data consistency in
+ // current thread
+ cachedRunnables = null;
+
+ if (!closed) {
+ task.run();
+ }
+
+ // Run the cached runnables.
+ if (cachedRunnables != null) {
+ for (int i = 0; i < cachedRunnables.size(); i++) {
+ if (!closed) {
+ cachedRunnables.get(i).run();
+ }
+ }
+ cachedRunnables = null;
+ }
+
+ } finally {
+ roomLock.unlock();
+ }
+
+ }
+
+ }
+
+ /**
+ * Shuts down the roomExecutor and the drawmessageBroadcastTimer.
+ */
+ public void shutdown() {
+ invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ closed = true;
+ drawmessageBroadcastTimer.cancel();
+ roomGraphics.dispose();
+ }
+ });
+ }
+
+
+ /**
+ * 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
+ * Client.
+ */
+ 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.
+ */
+ private final List<DrawMessage> bufferedDrawMessages =
+ new ArrayList<DrawMessage>();
+
+ 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() {
+ if (room != null) {
+ 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 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 new NullPointerException();
+
+ String completeMsg = String.valueOf(type.flag) + content;
+
+ client.sendMessage(new StringWebsocketMessage(completeMsg));
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.class
new file mode 100644
index 0000000..3f4846b
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java
new file mode 100644
index 0000000..b1945fc
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/AbstractWebsocketMessage.java
@@ -0,0 +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 {
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.class
new file mode 100644
index 0000000..fe5a3f4
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java
new file mode 100644
index 0000000..0a28f64
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/BinaryWebsocketMessage.java
@@ -0,0 +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;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.class
new file mode 100644
index 0000000..bad57e0
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.java
new file mode 100644
index 0000000..898117f
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/CloseWebsocketMessage.java
@@ -0,0 +1,24 @@
+/*
+ * 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 "close" message that closes the session.
+ */
+public class CloseWebsocketMessage extends AbstractWebsocketMessage {
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.class
new file mode 100644
index 0000000..acf3928
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java
new file mode 100644
index 0000000..8646ea7
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/drawboard/wsmessages/StringWebsocketMessage.java
@@ -0,0 +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;
+ }
+
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.class
new file mode 100644
index 0000000..8c03f33
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java
new file mode 100644
index 0000000..b592153
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java
@@ -0,0 +1,70 @@
+/*
+ * 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.echo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import javax.websocket.OnMessage;
+import javax.websocket.PongMessage;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint("/websocket/echoAnnotation")
+public class EchoAnnotation {
+
+ @OnMessage
+ public void echoTextMessage(Session session, String msg, boolean last) {
+ try {
+ if (session.isOpen()) {
+ session.getBasicRemote().sendText(msg, last);
+ }
+ } catch (IOException e) {
+ try {
+ session.close();
+ } catch (IOException e1) {
+ // Ignore
+ }
+ }
+ }
+
+ @OnMessage
+ public void echoBinaryMessage(Session session, ByteBuffer bb,
+ boolean last) {
+ try {
+ if (session.isOpen()) {
+ session.getBasicRemote().sendBinary(bb, last);
+ }
+ } catch (IOException e) {
+ try {
+ session.close();
+ } catch (IOException e1) {
+ // Ignore
+ }
+ }
+ }
+
+ /**
+ * Process a received pong. This is a NO-OP.
+ *
+ * @param pm Ignored.
+ */
+ @OnMessage
+ public void echoPongMessage(PongMessage pm) {
+ // NO-OP
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$1.class
new file mode 100644
index 0000000..18684e5
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$EchoMessageHandlerBinary.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$EchoMessageHandlerBinary.class
new file mode 100644
index 0000000..62bf22d
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$EchoMessageHandlerBinary.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$EchoMessageHandlerText.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$EchoMessageHandlerText.class
new file mode 100644
index 0000000..c7ca81c
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint$EchoMessageHandlerText.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.class
new file mode 100644
index 0000000..4a304db
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java
new file mode 100644
index 0000000..d503994
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/echo/EchoEndpoint.java
@@ -0,0 +1,80 @@
+/*
+ * 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.echo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.RemoteEndpoint;
+import javax.websocket.Session;
+
+public class EchoEndpoint extends Endpoint {
+
+ @Override
+ public void onOpen(Session session, EndpointConfig endpointConfig) {
+ RemoteEndpoint.Basic remoteEndpointBasic = session.getBasicRemote();
+ session.addMessageHandler(new EchoMessageHandlerText(remoteEndpointBasic));
+ session.addMessageHandler(new EchoMessageHandlerBinary(remoteEndpointBasic));
+ }
+
+ private static class EchoMessageHandlerText
+ implements MessageHandler.Partial<String> {
+
+ private final RemoteEndpoint.Basic remoteEndpointBasic;
+
+ private EchoMessageHandlerText(RemoteEndpoint.Basic remoteEndpointBasic) {
+ this.remoteEndpointBasic = remoteEndpointBasic;
+ }
+
+ @Override
+ public void onMessage(String message, boolean last) {
+ try {
+ if (remoteEndpointBasic != null) {
+ remoteEndpointBasic.sendText(message, last);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static class EchoMessageHandlerBinary
+ implements MessageHandler.Partial<ByteBuffer> {
+
+ private final RemoteEndpoint.Basic remoteEndpointBasic;
+
+ private EchoMessageHandlerBinary(RemoteEndpoint.Basic remoteEndpointBasic) {
+ this.remoteEndpointBasic = remoteEndpointBasic;
+ }
+
+ @Override
+ public void onMessage(ByteBuffer message, boolean last) {
+ try {
+ if (remoteEndpointBasic != null) {
+ remoteEndpointBasic.sendBinary(message, last);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Direction.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Direction.class
new file mode 100644
index 0000000..b6f4494
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Direction.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Direction.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Direction.java
new file mode 100644
index 0000000..b36c7a2
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Direction.java
@@ -0,0 +1,21 @@
+/*
+ * 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.snake;
+
+public enum Direction {
+ NONE, NORTH, SOUTH, EAST, WEST
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location$1.class
new file mode 100644
index 0000000..2b42186
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location.class
new file mode 100644
index 0000000..e9db638
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location.java
new file mode 100644
index 0000000..d5c0007
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Location.java
@@ -0,0 +1,65 @@
+/*
+ * 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.snake;
+
+public class Location {
+
+ public int x;
+ public int y;
+
+ public Location(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Location getAdjacentLocation(Direction direction) {
+ switch (direction) {
+ case NORTH:
+ return new Location(x, y - SnakeAnnotation.GRID_SIZE);
+ case SOUTH:
+ return new Location(x, y + SnakeAnnotation.GRID_SIZE);
+ case EAST:
+ return new Location(x + SnakeAnnotation.GRID_SIZE, y);
+ case WEST:
+ return new Location(x - SnakeAnnotation.GRID_SIZE, y);
+ case NONE:
+ // fall through
+ default:
+ return this;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Location location = (Location) o;
+
+ if (x != location.x) return false;
+ if (y != location.y) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = x;
+ result = 31 * result + y;
+ return result;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Snake.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Snake.class
new file mode 100644
index 0000000..1449f3c
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Snake.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Snake.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Snake.java
new file mode 100644
index 0000000..f2c9c4c
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/Snake.java
@@ -0,0 +1,150 @@
+/*
+ * 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.snake;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+
+import javax.websocket.CloseReason;
+import javax.websocket.CloseReason.CloseCodes;
+import javax.websocket.Session;
+
+public class Snake {
+
+ private static final int DEFAULT_LENGTH = 5;
+
+ private final int id;
+ private final Session session;
+
+ private Direction direction;
+ private int length = DEFAULT_LENGTH;
+ private Location head;
+ private final Deque<Location> tail = new ArrayDeque<Location>();
+ private final String hexColor;
+
+ public Snake(int id, Session session) {
+ this.id = id;
+ this.session = session;
+ this.hexColor = SnakeAnnotation.getRandomHexColor();
+ resetState();
+ }
+
+ private void resetState() {
+ this.direction = Direction.NONE;
+ this.head = SnakeAnnotation.getRandomLocation();
+ this.tail.clear();
+ this.length = DEFAULT_LENGTH;
+ }
+
+ private synchronized void kill() {
+ resetState();
+ sendMessage("{'type': 'dead'}");
+ }
+
+ private synchronized void reward() {
+ length++;
+ sendMessage("{'type': 'kill'}");
+ }
+
+
+ protected void sendMessage(String msg) {
+ try {
+ session.getBasicRemote().sendText(msg);
+ } catch (IOException ioe) {
+ CloseReason cr =
+ new CloseReason(CloseCodes.CLOSED_ABNORMALLY, ioe.getMessage());
+ try {
+ session.close(cr);
+ } catch (IOException ioe2) {
+ // Ignore
+ }
+ }
+ }
+
+ public synchronized void update(Collection<Snake> snakes) {
+ Location nextLocation = head.getAdjacentLocation(direction);
+ if (nextLocation.x >= SnakeAnnotation.PLAYFIELD_WIDTH) {
+ nextLocation.x = 0;
+ }
+ if (nextLocation.y >= SnakeAnnotation.PLAYFIELD_HEIGHT) {
+ nextLocation.y = 0;
+ }
+ if (nextLocation.x < 0) {
+ nextLocation.x = SnakeAnnotation.PLAYFIELD_WIDTH;
+ }
+ if (nextLocation.y < 0) {
+ nextLocation.y = SnakeAnnotation.PLAYFIELD_HEIGHT;
+ }
+ if (direction != Direction.NONE) {
+ tail.addFirst(head);
+ if (tail.size() > length) {
+ tail.removeLast();
+ }
+ head = nextLocation;
+ }
+
+ handleCollisions(snakes);
+ }
+
+ private void handleCollisions(Collection<Snake> snakes) {
+ for (Snake snake : snakes) {
+ boolean headCollision = id != snake.id && snake.getHead().equals(head);
+ boolean tailCollision = snake.getTail().contains(head);
+ if (headCollision || tailCollision) {
+ kill();
+ if (id != snake.id) {
+ snake.reward();
+ }
+ }
+ }
+ }
+
+ public synchronized Location getHead() {
+ return head;
+ }
+
+ public synchronized Collection<Location> getTail() {
+ return tail;
+ }
+
+ public synchronized void setDirection(Direction direction) {
+ this.direction = direction;
+ }
+
+ public synchronized String getLocationsJson() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("{x: %d, y: %d}",
+ Integer.valueOf(head.x), Integer.valueOf(head.y)));
+ for (Location location : tail) {
+ sb.append(',');
+ sb.append(String.format("{x: %d, y: %d}",
+ Integer.valueOf(location.x), Integer.valueOf(location.y)));
+ }
+ return String.format("{'id':%d,'body':[%s]}",
+ Integer.valueOf(id), sb.toString());
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getHexColor() {
+ return hexColor;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.class
new file mode 100644
index 0000000..57b9447
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.java
new file mode 100644
index 0000000..519a304
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeAnnotation.java
@@ -0,0 +1,135 @@
+/*
+ * 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.snake;
+
+import java.awt.Color;
+import java.io.EOFException;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint(value = "/websocket/snake")
+public class SnakeAnnotation {
+
+ public static final int PLAYFIELD_WIDTH = 640;
+ public static final int PLAYFIELD_HEIGHT = 480;
+ public static final int GRID_SIZE = 10;
+
+ private static final AtomicInteger snakeIds = new AtomicInteger(0);
+ private static final Random random = new Random();
+
+
+ private final int id;
+ private Snake snake;
+
+ public static String getRandomHexColor() {
+ float hue = random.nextFloat();
+ // sat between 0.1 and 0.3
+ float saturation = (random.nextInt(2000) + 1000) / 10000f;
+ float luminance = 0.9f;
+ Color color = Color.getHSBColor(hue, saturation, luminance);
+ return '#' + Integer.toHexString(
+ (color.getRGB() & 0xffffff) | 0x1000000).substring(1);
+ }
+
+
+ public static Location getRandomLocation() {
+ int x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH));
+ int y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT));
+ return new Location(x, y);
+ }
+
+
+ private static int roundByGridSize(int value) {
+ value = value + (GRID_SIZE / 2);
+ value = value / GRID_SIZE;
+ value = value * GRID_SIZE;
+ return value;
+ }
+
+ public SnakeAnnotation() {
+ this.id = snakeIds.getAndIncrement();
+ }
+
+
+ @OnOpen
+ public void onOpen(Session session) {
+ this.snake = new Snake(id, session);
+ SnakeTimer.addSnake(snake);
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator();
+ iterator.hasNext();) {
+ Snake snake = iterator.next();
+ sb.append(String.format("{id: %d, color: '%s'}",
+ Integer.valueOf(snake.getId()), snake.getHexColor()));
+ if (iterator.hasNext()) {
+ sb.append(',');
+ }
+ }
+ SnakeTimer.broadcast(String.format("{'type': 'join','data':[%s]}",
+ sb.toString()));
+ }
+
+
+ @OnMessage
+ public void onTextMessage(String message) {
+ if ("west".equals(message)) {
+ snake.setDirection(Direction.WEST);
+ } else if ("north".equals(message)) {
+ snake.setDirection(Direction.NORTH);
+ } else if ("east".equals(message)) {
+ snake.setDirection(Direction.EAST);
+ } else if ("south".equals(message)) {
+ snake.setDirection(Direction.SOUTH);
+ }
+ }
+
+
+ @OnClose
+ public void onClose() {
+ SnakeTimer.removeSnake(snake);
+ SnakeTimer.broadcast(String.format("{'type': 'leave', 'id': %d}",
+ Integer.valueOf(id)));
+ }
+
+
+ @OnError
+ public void onError(Throwable t) throws Throwable {
+ // 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 {
+ throw t;
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer$1.class
new file mode 100644
index 0000000..1fb6005
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.class
new file mode 100644
index 0000000..14693fc
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.java
new file mode 100644
index 0000000..abc4991
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.java
@@ -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 websocket.snake;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Sets up the timer for the multi-player snake game WebSocket example.
+ */
+public class SnakeTimer {
+
+ private static final Log log =
+ LogFactory.getLog(SnakeTimer.class);
+
+ private static Timer gameTimer = null;
+
+ private static final long TICK_DELAY = 100;
+
+ private static final ConcurrentHashMap<Integer, Snake> snakes =
+ new ConcurrentHashMap<Integer, Snake>();
+
+ protected static synchronized void addSnake(Snake snake) {
+ if (snakes.size() == 0) {
+ startTimer();
+ }
+ snakes.put(Integer.valueOf(snake.getId()), snake);
+ }
+
+
+ protected static Collection<Snake> getSnakes() {
+ return Collections.unmodifiableCollection(snakes.values());
+ }
+
+
+ protected static synchronized void removeSnake(Snake snake) {
+ snakes.remove(Integer.valueOf(snake.getId()));
+ if (snakes.size() == 0) {
+ stopTimer();
+ }
+ }
+
+
+ protected static void tick() {
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator();
+ iterator.hasNext();) {
+ Snake snake = iterator.next();
+ snake.update(SnakeTimer.getSnakes());
+ sb.append(snake.getLocationsJson());
+ if (iterator.hasNext()) {
+ sb.append(',');
+ }
+ }
+ broadcast(String.format("{'type': 'update', 'data' : [%s]}",
+ sb.toString()));
+ }
+
+ protected static void broadcast(String message) {
+ for (Snake snake : SnakeTimer.getSnakes()) {
+ try {
+ snake.sendMessage(message);
+ } catch (IllegalStateException ise) {
+ // An ISE can occur if an attempt is made to write to a
+ // WebSocket connection after it has been closed. The
+ // alternative to catching this exception is to synchronise
+ // the writes to the clients along with the addSnake() and
+ // removeSnake() methods that are already synchronised.
+ }
+ }
+ }
+
+
+ public static void startTimer() {
+ gameTimer = new Timer(SnakeTimer.class.getSimpleName() + " Timer");
+ gameTimer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ tick();
+ } catch (RuntimeException e) {
+ log.error("Caught to prevent timer from shutting down", e);
+ }
+ }
+ }, TICK_DELAY, TICK_DELAY);
+ }
+
+
+ public static void stopTimer() {
+ if (gameTimer != null) {
+ gameTimer.cancel();
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet$1.class
new file mode 100644
index 0000000..9bbb179
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet$ChatMessageInbound.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet$ChatMessageInbound.class
new file mode 100644
index 0000000..3eecb9e
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet$ChatMessageInbound.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.class
new file mode 100644
index 0000000..edf666f
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.java
new file mode 100644
index 0000000..12d5419
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/chat/ChatWebSocketServlet.java
@@ -0,0 +1,105 @@
+/*
+ * 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.tc7.chat;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.catalina.websocket.MessageInbound;
+import org.apache.catalina.websocket.StreamInbound;
+import org.apache.catalina.websocket.WebSocketServlet;
+import org.apache.catalina.websocket.WsOutbound;
+
+import util.HTMLFilter;
+
+/**
+ * Example web socket servlet for chat.
+ * @deprecated See {@link websocket.chat.ChatAnnotation}
+ */
+@Deprecated
+public class ChatWebSocketServlet extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final String GUEST_PREFIX = "Guest";
+
+ private final AtomicInteger connectionIds = new AtomicInteger(0);
+ private final Set<ChatMessageInbound> connections =
+ new CopyOnWriteArraySet<ChatMessageInbound>();
+
+ @Override
+ protected StreamInbound createWebSocketInbound(String subProtocol,
+ HttpServletRequest request) {
+ return new ChatMessageInbound(connectionIds.incrementAndGet());
+ }
+
+ private final class ChatMessageInbound extends MessageInbound {
+
+ private final String nickname;
+
+ private ChatMessageInbound(int id) {
+ this.nickname = GUEST_PREFIX + id;
+ }
+
+ @Override
+ protected void onOpen(WsOutbound outbound) {
+ connections.add(this);
+ String message = String.format("* %s %s",
+ nickname, "has joined.");
+ broadcast(message);
+ }
+
+ @Override
+ protected void onClose(int status) {
+ connections.remove(this);
+ String message = String.format("* %s %s",
+ nickname, "has disconnected.");
+ broadcast(message);
+ }
+
+ @Override
+ protected void onBinaryMessage(ByteBuffer message) throws IOException {
+ throw new UnsupportedOperationException(
+ "Binary message not supported.");
+ }
+
+ @Override
+ protected void onTextMessage(CharBuffer message) throws IOException {
+ // Never trust the client
+ String filteredMessage = String.format("%s: %s",
+ nickname, HTMLFilter.filter(message.toString()));
+ broadcast(filteredMessage);
+ }
+
+ private void broadcast(String message) {
+ for (ChatMessageInbound connection : connections) {
+ try {
+ CharBuffer buffer = CharBuffer.wrap(message);
+ connection.getWsOutbound().writeTextMessage(buffer);
+ } catch (IOException ignore) {
+ // Ignore
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage$EchoMessageInbound.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage$EchoMessageInbound.class
new file mode 100644
index 0000000..ddb9dc4
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage$EchoMessageInbound.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.class
new file mode 100644
index 0000000..d600882
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.java
new file mode 100644
index 0000000..4073306
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoMessage.java
@@ -0,0 +1,88 @@
+/*
+ * 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.tc7.echo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.catalina.websocket.MessageInbound;
+import org.apache.catalina.websocket.StreamInbound;
+import org.apache.catalina.websocket.WebSocketServlet;
+/**
+ * @deprecated See {@link websocket.echo.EchoAnnotation}
+ */
+@Deprecated
+public class EchoMessage extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1L;
+ private volatile int byteBufSize;
+ private volatile int charBufSize;
+
+ @Override
+ public void init() throws ServletException {
+ super.init();
+ byteBufSize = getInitParameterIntValue("byteBufferMaxSize", 2097152);
+ charBufSize = getInitParameterIntValue("charBufferMaxSize", 2097152);
+ }
+
+ public int getInitParameterIntValue(String name, int defaultValue) {
+ String val = this.getInitParameter(name);
+ int result;
+ if(null != val) {
+ try {
+ result = Integer.parseInt(val);
+ }catch (Exception x) {
+ result = defaultValue;
+ }
+ } else {
+ result = defaultValue;
+ }
+
+ return result;
+ }
+
+
+
+ @Override
+ protected StreamInbound createWebSocketInbound(String subProtocol,
+ HttpServletRequest request) {
+ return new EchoMessageInbound(byteBufSize,charBufSize);
+ }
+
+ private static final class EchoMessageInbound extends MessageInbound {
+
+ public EchoMessageInbound(int byteBufferMaxSize, int charBufferMaxSize) {
+ super();
+ setByteBufferMaxSize(byteBufferMaxSize);
+ setCharBufferMaxSize(charBufferMaxSize);
+ }
+
+ @Override
+ protected void onBinaryMessage(ByteBuffer message) throws IOException {
+ getWsOutbound().writeBinaryMessage(message);
+ }
+
+ @Override
+ protected void onTextMessage(CharBuffer message) throws IOException {
+ getWsOutbound().writeTextMessage(message);
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream$1.class
new file mode 100644
index 0000000..b770d79
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream$EchoStreamInbound.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream$EchoStreamInbound.class
new file mode 100644
index 0000000..478607d
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream$EchoStreamInbound.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.class
new file mode 100644
index 0000000..f3d819d
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.java
new file mode 100644
index 0000000..9b34302
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/echo/EchoStream.java
@@ -0,0 +1,73 @@
+/*
+ * 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.tc7.echo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.catalina.websocket.StreamInbound;
+import org.apache.catalina.websocket.WebSocketServlet;
+import org.apache.catalina.websocket.WsOutbound;
+
+/**
+ * @deprecated See {@link websocket.echo.EchoAnnotation}
+ */
+@Deprecated
+public class EchoStream extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected StreamInbound createWebSocketInbound(String subProtocol,
+ HttpServletRequest request) {
+ return new EchoStreamInbound();
+ }
+
+ private static final class EchoStreamInbound extends StreamInbound {
+
+ @Override
+ protected void onBinaryData(InputStream is) throws IOException {
+ // Simply echo the data to back to the client.
+ WsOutbound outbound = getWsOutbound();
+
+ int i = is.read();
+ while (i != -1) {
+ outbound.writeBinaryData(i);
+ i = is.read();
+ }
+
+ outbound.flush();
+ }
+
+ @Override
+ protected void onTextData(Reader r) throws IOException {
+ // Simply echo the data to back to the client.
+ WsOutbound outbound = getWsOutbound();
+
+ int c = r.read();
+ while (c != -1) {
+ outbound.writeTextData((char) c);
+ c = r.read();
+ }
+
+ outbound.flush();
+ }
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.class
new file mode 100644
index 0000000..7db9c55
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.java
new file mode 100644
index 0000000..4e375e7
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Direction.java
@@ -0,0 +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.tc7.snake;
+
+/**
+ * @deprecated See {@link websocket.snake.Direction}
+ */
+@Deprecated
+public enum Direction {
+ NONE, NORTH, SOUTH, EAST, WEST
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location$1.class
new file mode 100644
index 0000000..7e71c10
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.class
new file mode 100644
index 0000000..b052a15
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.java
new file mode 100644
index 0000000..257752e
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Location.java
@@ -0,0 +1,69 @@
+/*
+ * 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.tc7.snake;
+
+/**
+ * @deprecated See {@link websocket.snake.Location}
+ */
+@Deprecated
+public class Location {
+
+ public int x;
+ public int y;
+
+ public Location(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Location getAdjacentLocation(Direction direction) {
+ switch (direction) {
+ case NORTH:
+ return new Location(x, y - SnakeWebSocketServlet.GRID_SIZE);
+ case SOUTH:
+ return new Location(x, y + SnakeWebSocketServlet.GRID_SIZE);
+ case EAST:
+ return new Location(x + SnakeWebSocketServlet.GRID_SIZE, y);
+ case WEST:
+ return new Location(x - SnakeWebSocketServlet.GRID_SIZE, y);
+ case NONE:
+ // fall through
+ default:
+ return this;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Location location = (Location) o;
+
+ if (x != location.x) return false;
+ if (y != location.y) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = x;
+ result = 31 * result + y;
+ return result;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.class
new file mode 100644
index 0000000..336a9c3
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.java
new file mode 100644
index 0000000..df36332
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/Snake.java
@@ -0,0 +1,148 @@
+/*
+ * 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.tc7.snake;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+
+import org.apache.catalina.websocket.WsOutbound;
+
+/**
+ * @deprecated See {@link websocket.snake.Snake}
+ */
+@Deprecated
+public class Snake {
+
+ private static final int DEFAULT_LENGTH = 5;
+
+ private final int id;
+ private final WsOutbound outbound;
+
+ private Direction direction;
+ private int length = DEFAULT_LENGTH;
+ private Location head;
+ private Deque<Location> tail = new ArrayDeque<Location>();
+ private String hexColor;
+
+ public Snake(int id, WsOutbound outbound) {
+ this.id = id;
+ this.outbound = outbound;
+ this.hexColor = SnakeWebSocketServlet.getRandomHexColor();
+ resetState();
+ }
+
+ private void resetState() {
+ this.direction = Direction.NONE;
+ this.head = SnakeWebSocketServlet.getRandomLocation();
+ this.tail.clear();
+ this.length = DEFAULT_LENGTH;
+ }
+
+ private synchronized void kill() {
+ resetState();
+ try {
+ CharBuffer response = CharBuffer.wrap("{'type': 'dead'}");
+ outbound.writeTextMessage(response);
+ } catch (IOException ioe) {
+ // Ignore
+ }
+ }
+
+ private synchronized void reward() {
+ length++;
+ try {
+ CharBuffer response = CharBuffer.wrap("{'type': 'kill'}");
+ outbound.writeTextMessage(response);
+ } catch (IOException ioe) {
+ // Ignore
+ }
+ }
+
+ public synchronized void update(Collection<Snake> snakes) {
+ Location nextLocation = head.getAdjacentLocation(direction);
+ if (nextLocation.x >= SnakeWebSocketServlet.PLAYFIELD_WIDTH) {
+ nextLocation.x = 0;
+ }
+ if (nextLocation.y >= SnakeWebSocketServlet.PLAYFIELD_HEIGHT) {
+ nextLocation.y = 0;
+ }
+ if (nextLocation.x < 0) {
+ nextLocation.x = SnakeWebSocketServlet.PLAYFIELD_WIDTH;
+ }
+ if (nextLocation.y < 0) {
+ nextLocation.y = SnakeWebSocketServlet.PLAYFIELD_HEIGHT;
+ }
+ if (direction != Direction.NONE) {
+ tail.addFirst(head);
+ if (tail.size() > length) {
+ tail.removeLast();
+ }
+ head = nextLocation;
+ }
+
+ handleCollisions(snakes);
+ }
+
+ private void handleCollisions(Collection<Snake> snakes) {
+ for (Snake snake : snakes) {
+ boolean headCollision = id != snake.id && snake.getHead().equals(head);
+ boolean tailCollision = snake.getTail().contains(head);
+ if (headCollision || tailCollision) {
+ kill();
+ if (id != snake.id) {
+ snake.reward();
+ }
+ }
+ }
+ }
+
+ public synchronized Location getHead() {
+ return head;
+ }
+
+ public synchronized Collection<Location> getTail() {
+ return tail;
+ }
+
+ public synchronized void setDirection(Direction direction) {
+ this.direction = direction;
+ }
+
+ public synchronized String getLocationsJson() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("{x: %d, y: %d}",
+ Integer.valueOf(head.x), Integer.valueOf(head.y)));
+ for (Location location : tail) {
+ sb.append(',');
+ sb.append(String.format("{x: %d, y: %d}",
+ Integer.valueOf(location.x), Integer.valueOf(location.y)));
+ }
+ return String.format("{'id':%d,'body':[%s]}",
+ Integer.valueOf(id), sb.toString());
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getHexColor() {
+ return hexColor;
+ }
+}
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet$1.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet$1.class
new file mode 100644
index 0000000..2707bb7
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet$1.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet$SnakeMessageInbound.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet$SnakeMessageInbound.class
new file mode 100644
index 0000000..2649169
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet$SnakeMessageInbound.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.class b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.class
new file mode 100644
index 0000000..f174143
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.class
Binary files differ
diff --git a/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.java b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.java
new file mode 100644
index 0000000..0a8c353
--- /dev/null
+++ b/tomcat-cas/webapps/examples/WEB-INF/classes/websocket/tc7/snake/SnakeWebSocketServlet.java
@@ -0,0 +1,215 @@
+/*
+ * 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.tc7.snake;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.catalina.websocket.MessageInbound;
+import org.apache.catalina.websocket.StreamInbound;
+import org.apache.catalina.websocket.WebSocketServlet;
+import org.apache.catalina.websocket.WsOutbound;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Example web socket servlet for simple multi-player snake.
+ * @deprecated See {@link websocket.snake.SnakeAnnotation}
+ */
+@Deprecated
+public class SnakeWebSocketServlet extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Log log =
+ LogFactory.getLog(SnakeWebSocketServlet.class);
+
+ public static final int PLAYFIELD_WIDTH = 640;
+ public static final int PLAYFIELD_HEIGHT = 480;
+ public static final int GRID_SIZE = 10;
+
+ private static final long TICK_DELAY = 100;
+
+ private static final Random random = new Random();
+
+ private final Timer gameTimer =
+ new Timer(SnakeWebSocketServlet.class.getSimpleName() + " Timer");
+
+ private final AtomicInteger connectionIds = new AtomicInteger(0);
+ private final ConcurrentHashMap<Integer, Snake> snakes =
+ new ConcurrentHashMap<Integer, Snake>();
+ private final ConcurrentHashMap<Integer, SnakeMessageInbound> connections =
+ new ConcurrentHashMap<Integer, SnakeMessageInbound>();
+
+ @Override
+ public void init() throws ServletException {
+ super.init();
+ gameTimer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ tick();
+ } catch (RuntimeException e) {
+ log.error("Caught to prevent timer from shutting down", e);
+ }
+ }
+ }, TICK_DELAY, TICK_DELAY);
+ }
+
+ private void tick() {
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<Snake> iterator = getSnakes().iterator();
+ iterator.hasNext();) {
+ Snake snake = iterator.next();
+ snake.update(getSnakes());
+ sb.append(snake.getLocationsJson());
+ if (iterator.hasNext()) {
+ sb.append(',');
+ }
+ }
+ broadcast(String.format("{'type': 'update', 'data' : [%s]}",
+ sb.toString()));
+ }
+
+ private void broadcast(String message) {
+ for (SnakeMessageInbound connection : getConnections()) {
+ try {
+ CharBuffer buffer = CharBuffer.wrap(message);
+ connection.getWsOutbound().writeTextMessage(buffer);
+ } catch (IOException ignore) {
+ // Ignore
+ }
+ }
+ }
+
+ private Collection<SnakeMessageInbound> getConnections() {
+ return Collections.unmodifiableCollection(connections.values());
+ }
+
+ private Collection<Snake> getSnakes() {
+ return Collections.unmodifiableCollection(snakes.values());
+ }
+
+ public static String getRandomHexColor() {
+ float hue = random.nextFloat();
+ // sat between 0.1 and 0.3
+ float saturation = (random.nextInt(2000) + 1000) / 10000f;
+ float luminance = 0.9f;
+ Color color = Color.getHSBColor(hue, saturation, luminance);
+ return '#' + Integer.toHexString(
+ (color.getRGB() & 0xffffff) | 0x1000000).substring(1);
+ }
+
+ public static Location getRandomLocation() {
+ int x = roundByGridSize(
+ random.nextInt(SnakeWebSocketServlet.PLAYFIELD_WIDTH));
+ int y = roundByGridSize(
+ random.nextInt(SnakeWebSocketServlet.PLAYFIELD_HEIGHT));
+ return new Location(x, y);
+ }
+
+ private static int roundByGridSize(int value) {
+ value = value + (SnakeWebSocketServlet.GRID_SIZE / 2);
+ value = value / SnakeWebSocketServlet.GRID_SIZE;
+ value = value * SnakeWebSocketServlet.GRID_SIZE;
+ return value;
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ if (gameTimer != null) {
+ gameTimer.cancel();
+ }
+ }
+
+ @Override
+ protected StreamInbound createWebSocketInbound(String subProtocol,
+ HttpServletRequest request) {
+ return new SnakeMessageInbound(connectionIds.incrementAndGet());
+ }
+
+ private final class SnakeMessageInbound extends MessageInbound {
+
+ private final int id;
+ private Snake snake;
+
+ private SnakeMessageInbound(int id) {
+ this.id = id;
+ }
+
+ @Override
+ protected void onOpen(WsOutbound outbound) {
+ this.snake = new Snake(id, outbound);
+ snakes.put(Integer.valueOf(id), snake);
+ connections.put(Integer.valueOf(id), this);
+ StringBuilder sb = new StringBuilder();
+ for (Iterator<Snake> iterator = getSnakes().iterator();
+ iterator.hasNext();) {
+ Snake snake = iterator.next();
+ sb.append(String.format("{id: %d, color: '%s'}",
+ Integer.valueOf(snake.getId()), snake.getHexColor()));
+ if (iterator.hasNext()) {
+ sb.append(',');
+ }
+ }
+ broadcast(String.format("{'type': 'join','data':[%s]}",
+ sb.toString()));
+ }
+
+ @Override
+ protected void onClose(int status) {
+ connections.remove(Integer.valueOf(id));
+ snakes.remove(Integer.valueOf(id));
+ broadcast(String.format("{'type': 'leave', 'id': %d}",
+ Integer.valueOf(id)));
+ }
+
+ @Override
+ protected void onBinaryMessage(ByteBuffer message) throws IOException {
+ throw new UnsupportedOperationException(
+ "Binary message not supported.");
+ }
+
+ @Override
+ protected void onTextMessage(CharBuffer charBuffer) throws IOException {
+ String message = charBuffer.toString();
+ if ("west".equals(message)) {
+ snake.setDirection(Direction.WEST);
+ } else if ("north".equals(message)) {
+ snake.setDirection(Direction.NORTH);
+ } else if ("east".equals(message)) {
+ snake.setDirection(Direction.EAST);
+ } else if ("south".equals(message)) {
+ snake.setDirection(Direction.SOUTH);
+ }
+ }
+ }
+}