init
This commit is contained in:
141
webapps/examples/WEB-INF/classes/CookieExample.java
Normal file
141
webapps/examples/WEB-INF/classes/CookieExample.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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 javax.servlet.http.HttpSession;
|
||||
|
||||
import util.CookieFilter;
|
||||
import util.HTMLFilter;
|
||||
|
||||
/**
|
||||
* Example servlet showing request headers
|
||||
*
|
||||
* @author James Duncan Davidson <duncan@eng.sun.com>
|
||||
*/
|
||||
|
||||
public class CookieExample extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale());
|
||||
|
||||
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");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<!DOCTYPE html><html>");
|
||||
out.println("<head>");
|
||||
out.println("<meta charset=\"UTF-8\" />");
|
||||
|
||||
String title = rb.getString("cookies.title");
|
||||
out.println("<title>" + title + "</title>");
|
||||
out.println("</head>");
|
||||
out.println("<body bgcolor=\"white\">");
|
||||
|
||||
// relative links
|
||||
|
||||
// XXX
|
||||
// making these absolute till we work out the
|
||||
// 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>");
|
||||
out.println("<a href=\"../index.html\">");
|
||||
out.println("<img src=\"../images/return.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"return\"></a>");
|
||||
|
||||
out.println("<h3>" + title + "</h3>");
|
||||
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if ((cookies != null) && (cookies.length > 0)) {
|
||||
HttpSession session = request.getSession(false);
|
||||
String sessionId = null;
|
||||
if (session != null) {
|
||||
sessionId = session.getId();
|
||||
}
|
||||
out.println(rb.getString("cookies.cookies") + "<br>");
|
||||
for (int i = 0; i < cookies.length; i++) {
|
||||
Cookie cookie = cookies[i];
|
||||
String cName = cookie.getName();
|
||||
String cValue = cookie.getValue();
|
||||
out.print("Cookie Name: " + HTMLFilter.filter(cName) + "<br>");
|
||||
out.println(" Cookie Value: "
|
||||
+ HTMLFilter.filter(CookieFilter.filter(cName, cValue, sessionId))
|
||||
+ "<br><br>");
|
||||
}
|
||||
} else {
|
||||
out.println(rb.getString("cookies.no-cookies"));
|
||||
}
|
||||
|
||||
if (aCookie != null) {
|
||||
out.println("<P>");
|
||||
out.println(rb.getString("cookies.set") + "<br>");
|
||||
out.print(rb.getString("cookies.name") + " "
|
||||
+ HTMLFilter.filter(cookieName) + "<br>");
|
||||
out.print(rb.getString("cookies.value") + " "
|
||||
+ HTMLFilter.filter(cookieValue));
|
||||
}
|
||||
|
||||
out.println("<P>");
|
||||
out.println(rb.getString("cookies.make-cookie") + "<br>");
|
||||
out.print("<form action=\"");
|
||||
out.println("CookieExample\" method=POST>");
|
||||
out.print(rb.getString("cookies.name") + " ");
|
||||
out.println("<input type=text length=20 name=cookiename><br>");
|
||||
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
|
||||
{
|
||||
doGet(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
79
webapps/examples/WEB-INF/classes/HelloWorldExample.java
Normal file
79
webapps/examples/WEB-INF/classes/HelloWorldExample.java
Normal file
@@ -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.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* The simplest possible servlet.
|
||||
*
|
||||
* @author James Duncan Davidson
|
||||
*/
|
||||
|
||||
public class HelloWorldExample extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
ResourceBundle rb =
|
||||
ResourceBundle.getBundle("LocalStrings",request.getLocale());
|
||||
response.setContentType("text/html");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
out.println("<!DOCTYPE html><html>");
|
||||
out.println("<head>");
|
||||
out.println("<meta charset=\"UTF-8\" />");
|
||||
|
||||
String title = rb.getString("helloworld.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 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("<img src=\"../images/code.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"view code\"></a>");
|
||||
out.println("<a href=\"../index.html\">");
|
||||
out.println("<img src=\"../images/return.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"return\"></a>");
|
||||
out.println("<h1>" + title + "</h1>");
|
||||
out.println("</body>");
|
||||
out.println("</html>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
48
webapps/examples/WEB-INF/classes/LocalStrings.properties
Normal file
48
webapps/examples/WEB-INF/classes/LocalStrings.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cookies.cookies=Your browser is sending the following cookies:
|
||||
cookies.make-cookie=Create a cookie to send to your browser
|
||||
cookies.name=Name:
|
||||
cookies.no-cookies=Your browser isn't sending any cookies
|
||||
cookies.set=You just sent the following cookie to your browser:
|
||||
cookies.title=Cookies Example
|
||||
cookies.value=Value:
|
||||
|
||||
helloworld.title=Hello World!
|
||||
|
||||
requestheader.title=Request Header Example
|
||||
|
||||
requestinfo.label.method=Method:
|
||||
requestinfo.label.pathinfo=Path Info:
|
||||
requestinfo.label.protocol=Protocol:
|
||||
requestinfo.label.remoteaddr=Remote Address:
|
||||
requestinfo.label.requesturi=Request URI:
|
||||
requestinfo.title=Request Information Example
|
||||
|
||||
requestparams.firstname=First Name:
|
||||
requestparams.lastname=Last Name:
|
||||
requestparams.no-params=No Parameters, Please enter some
|
||||
requestparams.params-in-req=Parameters in this request:
|
||||
requestparams.title=Request Parameters Example
|
||||
|
||||
sessions.adddata=Add data to your session
|
||||
sessions.created=Created:
|
||||
sessions.data=The following data is in your session:
|
||||
sessions.dataname=Name of Session Attribute:
|
||||
sessions.datavalue=Value of Session Attribute:
|
||||
sessions.id=Session ID:
|
||||
sessions.lastaccessed=Last Accessed:
|
||||
sessions.title=Sessions Example
|
||||
28
webapps/examples/WEB-INF/classes/LocalStrings_de.properties
Normal file
28
webapps/examples/WEB-INF/classes/LocalStrings_de.properties
Normal file
@@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
cookies.make-cookie=Erzeuge ein Cookie um es an deinen Browser zu senden
|
||||
cookies.name=Name:
|
||||
|
||||
requestheader.title=Request-Header Beispiel
|
||||
|
||||
requestinfo.label.protocol=Protokoll:
|
||||
requestinfo.label.requesturi=Anfrage-URI:
|
||||
|
||||
requestparams.firstname=Vorname:
|
||||
requestparams.no-params=Keine Parameter, bitte geben Sie welche ein
|
||||
requestparams.title=Beispiel für Anfrageparameter
|
||||
|
||||
sessions.title=Sessions-Beispiel
|
||||
48
webapps/examples/WEB-INF/classes/LocalStrings_es.properties
Normal file
48
webapps/examples/WEB-INF/classes/LocalStrings_es.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cookies.cookies=Tu navegador está enviando los siguientes cookies:
|
||||
cookies.make-cookie=Crea un cookie para enviarlo a tu navegador
|
||||
cookies.name=Nombre:
|
||||
cookies.no-cookies=Tu navegador no está enviando cookies
|
||||
cookies.set=Acabas de enviar a tu navegador estos cookies:
|
||||
cookies.title=Ejemplo de Cookies
|
||||
cookies.value=Valor:
|
||||
|
||||
helloworld.title=Hola Mundo!
|
||||
|
||||
requestheader.title=Ejemplo de Cabecera de Requerimiento:
|
||||
|
||||
requestinfo.label.method=Método:
|
||||
requestinfo.label.pathinfo=Info de Ruta:
|
||||
requestinfo.label.protocol=Protocolo:
|
||||
requestinfo.label.remoteaddr=Direccion Remota:
|
||||
requestinfo.label.requesturi=URI de Requerimiento:
|
||||
requestinfo.title=Ejemplo de Informacion de Requerimiento:
|
||||
|
||||
requestparams.firstname=Nombre:
|
||||
requestparams.lastname=Apellidos:
|
||||
requestparams.no-params=No hay párametro. Por favor, usa alguno
|
||||
requestparams.params-in-req=Parámetros en este Request:
|
||||
requestparams.title=Ejemplo de solicitud con parámetros:
|
||||
|
||||
sessions.adddata=Añade datos a tu sesión:
|
||||
sessions.created=Creado:
|
||||
sessions.data=Lo siguientes datos están en tu sesión:
|
||||
sessions.dataname=Nombre del atributo de sesión:
|
||||
sessions.datavalue=Valor del atributo de sesión:
|
||||
sessions.id=ID de Sesión:
|
||||
sessions.lastaccessed=Ultimo Acceso:
|
||||
sessions.title=Ejemplo de Sesiones
|
||||
48
webapps/examples/WEB-INF/classes/LocalStrings_fr.properties
Normal file
48
webapps/examples/WEB-INF/classes/LocalStrings_fr.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cookies.cookies=Votre navigateur retourne les cookies suivant:
|
||||
cookies.make-cookie=Création d'un cookie à retourner à votre navigateur
|
||||
cookies.name=Nom:
|
||||
cookies.no-cookies=Votre navigateur ne retourne aucun cookie
|
||||
cookies.set=Vous venez d'envoyer le cookie suivant à votre navigateur:
|
||||
cookies.title=Exemple d'utilisation de Cookies
|
||||
cookies.value=Valeur:
|
||||
|
||||
helloworld.title=Salut le Monde!
|
||||
|
||||
requestheader.title=Exemple d'information sur les entêtes de requête
|
||||
|
||||
requestinfo.label.method=Méthode:
|
||||
requestinfo.label.pathinfo=Info de chemin:
|
||||
requestinfo.label.protocol=Protocole:
|
||||
requestinfo.label.remoteaddr=Adresse distante:
|
||||
requestinfo.label.requesturi=URI de requête:
|
||||
requestinfo.title=Exemple d'information sur la requête
|
||||
|
||||
requestparams.firstname=Prénom:
|
||||
requestparams.lastname=Nom:
|
||||
requestparams.no-params=Pas de paramêtre, merci d'en saisir quelques-uns
|
||||
requestparams.params-in-req=Paramêtres dans la requête:
|
||||
requestparams.title=Exemple de requête avec paramètres
|
||||
|
||||
sessions.adddata=Ajouter des données à votre session
|
||||
sessions.created=Crée le:
|
||||
sessions.data=Les données existantes dans votre session:
|
||||
sessions.dataname=Nom de l'Attribut de Session:
|
||||
sessions.datavalue=Valeur de l'Attribut de Session:
|
||||
sessions.id=ID de Session:
|
||||
sessions.lastaccessed=Dernier accès:
|
||||
sessions.title=Exemple de Sessions
|
||||
48
webapps/examples/WEB-INF/classes/LocalStrings_ja.properties
Normal file
48
webapps/examples/WEB-INF/classes/LocalStrings_ja.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cookies.cookies=あなたののブラウザから次のCookieが送信されています:
|
||||
cookies.make-cookie=ブラウザへ送信する cookie を作成します。
|
||||
cookies.name=Name:
|
||||
cookies.no-cookies=あなたのブラウザはクッキーを送信していません。
|
||||
cookies.set=ブラウザに cookie を送信しました。
|
||||
cookies.title=Cookie 例
|
||||
cookies.value=値:
|
||||
|
||||
helloworld.title=Hello World!
|
||||
|
||||
requestheader.title=リクエストヘッダ例
|
||||
|
||||
requestinfo.label.method=メソッド:
|
||||
requestinfo.label.pathinfo=パス情報:
|
||||
requestinfo.label.protocol=プロトコル:
|
||||
requestinfo.label.remoteaddr=リモートアドレス:
|
||||
requestinfo.label.requesturi=Request URI:
|
||||
requestinfo.title=リクエスト情報例
|
||||
|
||||
requestparams.firstname=First Name:
|
||||
requestparams.lastname=\ Last Name:
|
||||
requestparams.no-params=パラメータがありません。何か入力してください。
|
||||
requestparams.params-in-req=このリクエストのパラメータ:
|
||||
requestparams.title=リクエストパラメータ例
|
||||
|
||||
sessions.adddata=セッションにデータを追加します
|
||||
sessions.created=作成:
|
||||
sessions.data=あなたのセッションには次のデータがあります:
|
||||
sessions.dataname=セッション属性名:
|
||||
sessions.datavalue=セッション属性の値:
|
||||
sessions.id=セッションID
|
||||
sessions.lastaccessed=最終アクセス:
|
||||
sessions.title=セッション例
|
||||
48
webapps/examples/WEB-INF/classes/LocalStrings_ko.properties
Normal file
48
webapps/examples/WEB-INF/classes/LocalStrings_ko.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cookies.cookies=귀하의 브라우저가 다음 쿠키들을 보냅니다.
|
||||
cookies.make-cookie=귀하의 브라우저에 전송하기 위한 쿠키 생성
|
||||
cookies.name=이름:
|
||||
cookies.no-cookies=귀하의 브라우저는 어떤 쿠키도 전송하지 않습니다.
|
||||
cookies.set=귀하는 다음 쿠키를, 귀하의 브라우저에 전송했습니다.
|
||||
cookies.title=쿠키들의 예제
|
||||
cookies.value=값:
|
||||
|
||||
helloworld.title=안녕 세계여!
|
||||
|
||||
requestheader.title=요청의 헤더 예제
|
||||
|
||||
requestinfo.label.method=메소드:
|
||||
requestinfo.label.pathinfo=경로 정보:
|
||||
requestinfo.label.protocol=프로토콜:
|
||||
requestinfo.label.remoteaddr=원격 주소:
|
||||
requestinfo.label.requesturi=요청 URI:
|
||||
requestinfo.title=요청 정보 예제
|
||||
|
||||
requestparams.firstname=이름:
|
||||
requestparams.lastname=성
|
||||
requestparams.no-params=파라미터들이 없습니다. 파라미터들을 입력하십시오.
|
||||
requestparams.params-in-req=이 요청의 파라미터들:
|
||||
requestparams.title=요청 파라미터들의 예제
|
||||
|
||||
sessions.adddata=귀하의 세션에 데이터를 추가
|
||||
sessions.created=생성시간:
|
||||
sessions.data=귀하의 세션에 다음 데이터가 있습니다:
|
||||
sessions.dataname=세션 속성 이름:
|
||||
sessions.datavalue=세션 속성 값:
|
||||
sessions.id=세션 ID:
|
||||
sessions.lastaccessed=최종 접근 시간:
|
||||
sessions.title=세션들의 예제
|
||||
48
webapps/examples/WEB-INF/classes/LocalStrings_pt.properties
Normal file
48
webapps/examples/WEB-INF/classes/LocalStrings_pt.properties
Normal file
@@ -0,0 +1,48 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cookies.cookies=O se browser esta a enviar os seguintes cookies:
|
||||
cookies.make-cookie=Crie um cookie para enviar para o seu browser
|
||||
cookies.name=Nome:
|
||||
cookies.no-cookies=O seu browser nao esta a enviar nenhuns cookies
|
||||
cookies.set=Acabou de enviar o seguinte cookie para o seu browser:
|
||||
cookies.title=CExamplo de Cookies
|
||||
cookies.value=Valor:
|
||||
|
||||
helloworld.title=Ola Mundo!
|
||||
|
||||
requestheader.title=Exemplo da Cebeceira do Pedido
|
||||
|
||||
requestinfo.label.method=Metodo:
|
||||
requestinfo.label.pathinfo=Informacao do Caminho:
|
||||
requestinfo.label.protocol=Protocolo:
|
||||
requestinfo.label.remoteaddr=Endereco Remoto:
|
||||
requestinfo.label.requesturi=URI do Pedido:
|
||||
requestinfo.title=Exemplo da Informacao do Pedido
|
||||
|
||||
requestparams.firstname=Primeiro Nome:
|
||||
requestparams.lastname=Apelido:
|
||||
requestparams.no-params=Sem Parametros, Por favor entre alguns
|
||||
requestparams.params-in-req=Parametros neste pedido:
|
||||
requestparams.title=Examplo de Parametros do Pedido
|
||||
|
||||
sessions.adddata=Adicione data a sua sessao
|
||||
sessions.created=Criada:
|
||||
sessions.data=Os seguintes dados fazem parte da sua sessao:
|
||||
sessions.dataname=Nome do atributo da sessao:
|
||||
sessions.datavalue=Valor do atributo da Sessao:
|
||||
sessions.id=Identificador da Sessao:
|
||||
sessions.lastaccessed=Ultima vez acedida:
|
||||
sessions.title=Examplo de sessoes
|
||||
16
webapps/examples/WEB-INF/classes/LocalStrings_ru.properties
Normal file
16
webapps/examples/WEB-INF/classes/LocalStrings_ru.properties
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
requestparams.title=Пример параметров запроса
|
||||
@@ -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.
|
||||
|
||||
cookies.make-cookie=创建一个发送到你的浏览器的cookie
|
||||
cookies.name=名.称:
|
||||
cookies.no-cookies=你的浏览器未发送任何cookie
|
||||
cookies.set=你刚刚将以下cookie发送到你的浏览器:
|
||||
|
||||
helloworld.title=你好,世界.
|
||||
|
||||
requestheader.title=请求 Header 示例
|
||||
|
||||
requestinfo.label.method=方法:
|
||||
requestinfo.label.protocol=协议:
|
||||
requestinfo.label.remoteaddr=远程地址:
|
||||
requestinfo.label.requesturi=请求 URI (:
|
||||
requestinfo.title=请求信息范例
|
||||
|
||||
requestparams.firstname=姓:
|
||||
requestparams.no-params=没有参数,请输入一些
|
||||
requestparams.params-in-req=参数在请求中.
|
||||
requestparams.title=请求参数示例
|
||||
|
||||
sessions.adddata=将数据添加到你的会话中
|
||||
sessions.id=会话ID:
|
||||
sessions.lastaccessed=最后访问:
|
||||
sessions.title=会话.示例
|
||||
109
webapps/examples/WEB-INF/classes/RequestHeaderExample.java
Normal file
109
webapps/examples/WEB-INF/classes/RequestHeaderExample.java
Normal file
@@ -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.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Example servlet showing request headers
|
||||
*
|
||||
* @author James Duncan Davidson <duncan@eng.sun.com>
|
||||
*/
|
||||
|
||||
public class RequestHeaderExample extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale());
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<!DOCTYPE html><html>");
|
||||
out.println("<head>");
|
||||
out.println("<meta charset=\"UTF-8\" />");
|
||||
|
||||
String title = rb.getString("requestheader.title");
|
||||
out.println("<title>" + title + "</title>");
|
||||
out.println("</head>");
|
||||
out.println("<body bgcolor=\"white\">");
|
||||
|
||||
// all links relative
|
||||
|
||||
// XXX
|
||||
// making these absolute till we work out the
|
||||
// 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>");
|
||||
out.println("<a href=\"../index.html\">");
|
||||
out.println("<img src=\"../images/return.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"return\"></a>");
|
||||
|
||||
out.println("<h3>" + title + "</h3>");
|
||||
out.println("<table border=0>");
|
||||
Enumeration<String> e = request.getHeaderNames();
|
||||
while (e.hasMoreElements()) {
|
||||
String headerName = e.nextElement();
|
||||
String headerValue = request.getHeader(headerName);
|
||||
out.println("<tr><td bgcolor=\"#CCCCCC\">");
|
||||
out.println(HTMLFilter.filter(headerName));
|
||||
out.println("</td><td>");
|
||||
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
|
||||
{
|
||||
doGet(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
118
webapps/examples/WEB-INF/classes/RequestInfoExample.java
Normal file
118
webapps/examples/WEB-INF/classes/RequestInfoExample.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Example servlet showing request information.
|
||||
*
|
||||
* @author James Duncan Davidson <duncan@eng.sun.com>
|
||||
*/
|
||||
|
||||
public class RequestInfoExample extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale());
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<!DOCTYPE html><html>");
|
||||
out.println("<head>");
|
||||
out.println("<meta charset=\"UTF-8\" />");
|
||||
|
||||
String title = rb.getString("requestinfo.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!
|
||||
|
||||
// XXX
|
||||
// making these absolute till we work out the
|
||||
// addition of a PathInfo issue
|
||||
|
||||
out.println("<a href=\"../reqinfo.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\">");
|
||||
out.println("<img src=\"../images/return.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"return\"></a>");
|
||||
|
||||
out.println("<h3>" + title + "</h3>");
|
||||
out.println("<table border=0><tr><td>");
|
||||
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("</td><td>");
|
||||
out.println(HTMLFilter.filter(request.getRequestURI()));
|
||||
out.println("</td></tr><tr><td>");
|
||||
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("</td><td>");
|
||||
out.println(HTMLFilter.filter(request.getPathInfo()));
|
||||
out.println("</td></tr><tr><td>");
|
||||
out.println(rb.getString("requestinfo.label.remoteaddr"));
|
||||
out.println("</td><td>");
|
||||
out.println(HTMLFilter.filter(request.getRemoteAddr()));
|
||||
out.println("</td></tr>");
|
||||
|
||||
String cipherSuite=
|
||||
(String)request.getAttribute("javax.servlet.request.cipher_suite");
|
||||
if(cipherSuite!=null){
|
||||
out.println("<tr><td>");
|
||||
out.println("SSLCipherSuite:");
|
||||
out.println("</td><td>");
|
||||
out.println(HTMLFilter.filter(cipherSuite));
|
||||
out.println("</td></tr>");
|
||||
}
|
||||
|
||||
out.println("</table>");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
doGet(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
111
webapps/examples/WEB-INF/classes/RequestParamExample.java
Normal file
111
webapps/examples/WEB-INF/classes/RequestParamExample.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Example servlet showing request headers
|
||||
*
|
||||
* @author James Duncan Davidson <duncan@eng.sun.com>
|
||||
*/
|
||||
|
||||
public class RequestParamExample extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale());
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<!DOCTYPE html><html>");
|
||||
out.println("<head>");
|
||||
out.println("<meta charset=\"UTF-8\" />");
|
||||
|
||||
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
|
||||
|
||||
// XXX
|
||||
// making these absolute till we work out the
|
||||
// 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>");
|
||||
out.println("<a href=\"../index.html\">");
|
||||
out.println("<img src=\"../images/return.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"return\"></a>");
|
||||
|
||||
out.println("<h3>" + title + "</h3>");
|
||||
String firstName = request.getParameter("firstname");
|
||||
String lastName = request.getParameter("lastname");
|
||||
out.println(rb.getString("requestparams.params-in-req") + "<br>");
|
||||
if (firstName != null || lastName != null) {
|
||||
out.println(rb.getString("requestparams.firstname"));
|
||||
out.println(" = " + HTMLFilter.filter(firstName) + "<br>");
|
||||
out.println(rb.getString("requestparams.lastname"));
|
||||
out.println(" = " + HTMLFilter.filter(lastName));
|
||||
} else {
|
||||
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("<input type=text size=20 name=firstname>");
|
||||
out.println("<br>");
|
||||
out.println(rb.getString("requestparams.lastname"));
|
||||
out.println("<input type=text size=20 name=lastname>");
|
||||
out.println("<br>");
|
||||
out.println("<input type=submit>");
|
||||
out.println("</form>");
|
||||
|
||||
out.println("</body>");
|
||||
out.println("</html>");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
doGet(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
39
webapps/examples/WEB-INF/classes/ServletToJsp.java
Normal file
39
webapps/examples/WEB-INF/classes/ServletToJsp.java
Normal file
@@ -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.
|
||||
*/
|
||||
|
||||
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) {
|
||||
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
147
webapps/examples/WEB-INF/classes/SessionExample.java
Normal file
147
webapps/examples/WEB-INF/classes/SessionExample.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Example servlet showing request headers
|
||||
*
|
||||
* @author James Duncan Davidson <duncan@eng.sun.com>
|
||||
*/
|
||||
|
||||
public class SessionExample extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void doGet(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale());
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
PrintWriter out = response.getWriter();
|
||||
out.println("<!DOCTYPE html><html>");
|
||||
out.println("<head>");
|
||||
out.println("<meta charset=\"UTF-8\" />");
|
||||
|
||||
|
||||
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!
|
||||
|
||||
// XXX
|
||||
// making these absolute till we work out the
|
||||
// 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>");
|
||||
out.println("<a href=\"../index.html\">");
|
||||
out.println("<img src=\"../images/return.gif\" height=24 " +
|
||||
"width=24 align=right border=0 alt=\"return\"></a>");
|
||||
|
||||
out.println("<h3>" + title + "</h3>");
|
||||
|
||||
HttpSession session = request.getSession(true);
|
||||
out.println(rb.getString("sessions.id") + " " + session.getId());
|
||||
out.println("<br>");
|
||||
out.println(rb.getString("sessions.created") + " ");
|
||||
out.println(new Date(session.getCreationTime()) + "<br>");
|
||||
out.println(rb.getString("sessions.lastaccessed") + " ");
|
||||
out.println(new Date(session.getLastAccessedTime()));
|
||||
|
||||
String dataName = request.getParameter("dataname");
|
||||
String dataValue = request.getParameter("datavalue");
|
||||
if (dataName != null && dataValue != null) {
|
||||
session.setAttribute(dataName, dataValue);
|
||||
}
|
||||
|
||||
out.println("<P>");
|
||||
out.println(rb.getString("sessions.data") + "<br>");
|
||||
Enumeration<String> names = session.getAttributeNames();
|
||||
while (names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
String value = session.getAttribute(name).toString();
|
||||
out.println(HTMLFilter.filter(name) + " = "
|
||||
+ HTMLFilter.filter(value) + "<br>");
|
||||
}
|
||||
|
||||
out.println("<P>");
|
||||
out.print("<form action=\"");
|
||||
out.print(response.encodeURL("SessionExample"));
|
||||
out.print("\" ");
|
||||
out.println("method=POST>");
|
||||
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("<input type=text size=20 name=datavalue>");
|
||||
out.println("<br>");
|
||||
out.println("<input type=submit>");
|
||||
out.println("</form>");
|
||||
|
||||
out.println("<P>GET based form:<br>");
|
||||
out.print("<form action=\"");
|
||||
out.print(response.encodeURL("SessionExample"));
|
||||
out.print("\" ");
|
||||
out.println("method=GET>");
|
||||
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("<input type=text size=20 name=datavalue>");
|
||||
out.println("<br>");
|
||||
out.println("<input type=submit>");
|
||||
out.println("</form>");
|
||||
|
||||
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
|
||||
{
|
||||
doGet(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
71
webapps/examples/WEB-INF/classes/async/Async0.java
Normal file
71
webapps/examples/WEB-INF/classes/async/Async0.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
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());
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
resp.getWriter().write("Async dispatch worked: " + sdf.format(date) + "\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();
|
||||
}
|
||||
}
|
||||
}
|
||||
62
webapps/examples/WEB-INF/classes/async/Async1.java
Normal file
62
webapps/examples/WEB-INF/classes/async/Async1.java
Normal file
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
70
webapps/examples/WEB-INF/classes/async/Async2.java
Normal file
70
webapps/examples/WEB-INF/classes/async/Async2.java
Normal file
@@ -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 async;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
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.");
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
actx.getResponse().getWriter().write(
|
||||
"Output from background thread. Time: " + sdf.format(date) + "\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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
39
webapps/examples/WEB-INF/classes/async/Async3.java
Normal file
39
webapps/examples/WEB-INF/classes/async/Async3.java
Normal file
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
/*
|
||||
* Ensures the Stockticker is shut down cleanly when the context stops. This
|
||||
* also covers the case when the server shuts down.
|
||||
*/
|
||||
public class AsyncStockContextListener implements ServletContextListener {
|
||||
|
||||
public static final String STOCK_TICKER_KEY = "StockTicker";
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
Stockticker stockticker = new Stockticker();
|
||||
ServletContext sc = sce.getServletContext();
|
||||
sc.setAttribute(STOCK_TICKER_KEY, stockticker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
ServletContext sc = sce.getServletContext();
|
||||
Stockticker stockticker = (Stockticker) sc.getAttribute(STOCK_TICKER_KEY);
|
||||
stockticker.shutdown();
|
||||
}
|
||||
}
|
||||
149
webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java
Normal file
149
webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.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.ServletContext;
|
||||
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;
|
||||
|
||||
import async.Stockticker.Stock;
|
||||
import async.Stockticker.TickListener;
|
||||
|
||||
public class AsyncStockServlet extends HttpServlet implements TickListener, AsyncListener{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Log log = LogFactory.getLog(AsyncStockServlet.class);
|
||||
|
||||
private static final ConcurrentLinkedQueue<AsyncContext> clients =
|
||||
new ConcurrentLinkedQueue<>();
|
||||
private static final AtomicInteger clientcount = new AtomicInteger(0);
|
||||
|
||||
public AsyncStockServlet() {
|
||||
log.info("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) {
|
||||
Stockticker ticker = (Stockticker) req.getServletContext().getAttribute(
|
||||
AsyncStockContextListener.STOCK_TICKER_KEY);
|
||||
ticker.addTickListener(this);
|
||||
}
|
||||
} else {
|
||||
new Exception("Async Not Supported").printStackTrace();
|
||||
resp.sendError(400,"Async is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void tick(Stock stock) {
|
||||
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) throws IOException {
|
||||
HttpServletResponse response = (HttpServletResponse)actx.getResponse();
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
// The web application is shutting down. Complete any AsyncContexts
|
||||
// associated with an active client.
|
||||
Iterator<AsyncContext> it = clients.iterator();
|
||||
while (it.hasNext()) {
|
||||
AsyncContext actx = it.next();
|
||||
try {
|
||||
actx.complete();
|
||||
} catch (Exception e) {
|
||||
// Ignore. The async error handling will deal with this.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onComplete(AsyncEvent event) throws IOException {
|
||||
if (clients.remove(event.getAsyncContext()) && clientcount.decrementAndGet()==0) {
|
||||
ServletContext sc = event.getAsyncContext().getRequest().getServletContext();
|
||||
Stockticker ticker = (Stockticker) sc.getAttribute(
|
||||
AsyncStockContextListener.STOCK_TICKER_KEY);
|
||||
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
|
||||
}
|
||||
}
|
||||
207
webapps/examples/WEB-INF/classes/async/Stockticker.java
Normal file
207
webapps/examples/WEB-INF/classes/async/Stockticker.java
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Stockticker implements Runnable {
|
||||
public volatile boolean run = true;
|
||||
protected final AtomicInteger counter = new AtomicInteger(0);
|
||||
final List<TickListener> listeners = new CopyOnWriteArrayList<>();
|
||||
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() {
|
||||
// On context stop this can be called multiple times.
|
||||
// NO-OP is the ticker thread is not set
|
||||
// (i.e. stop() has already completed)
|
||||
if (ticker == null) {
|
||||
return;
|
||||
}
|
||||
run = false;
|
||||
try {
|
||||
ticker.join();
|
||||
}catch (InterruptedException x) {
|
||||
Thread.interrupted();
|
||||
}
|
||||
|
||||
ticker = null;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
// Notify each listener of the shutdown. This enables them to
|
||||
// trigger any necessary clean-up.
|
||||
for (TickListener l : listeners) {
|
||||
l.shutdown();
|
||||
}
|
||||
// Wait for the thread to stop. This prevents warnings in the logs
|
||||
// that the thread is still active when the context stops.
|
||||
stop();
|
||||
}
|
||||
|
||||
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 void shutdown();
|
||||
}
|
||||
|
||||
public static final class Stock implements Cloneable {
|
||||
protected static final DecimalFormat df = new DecimalFormat("0.00");
|
||||
protected final 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
webapps/examples/WEB-INF/classes/cal/Entries.java
Normal file
60
webapps/examples/WEB-INF/classes/cal/Entries.java
Normal file
@@ -0,0 +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.
|
||||
*/
|
||||
package cal;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class Entries {
|
||||
|
||||
private final 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
53
webapps/examples/WEB-INF/classes/cal/Entry.java
Normal file
53
webapps/examples/WEB-INF/classes/cal/Entry.java
Normal file
@@ -0,0 +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.
|
||||
*/
|
||||
|
||||
package cal;
|
||||
|
||||
public class Entry {
|
||||
|
||||
final String hour;
|
||||
String description;
|
||||
|
||||
public Entry(String hour) {
|
||||
this.hour = hour;
|
||||
this.description = "";
|
||||
|
||||
}
|
||||
|
||||
public String getHour() {
|
||||
return this.hour;
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
if (description.equals("")) {
|
||||
return "lightblue";
|
||||
}
|
||||
return "red";
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
if (description.equals("")) {
|
||||
return "None";
|
||||
}
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String descr) {
|
||||
description = descr;
|
||||
}
|
||||
|
||||
}
|
||||
151
webapps/examples/WEB-INF/classes/cal/JspCalendar.java
Normal file
151
webapps/examples/WEB-INF/classes/cal/JspCalendar.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
public class JspCalendar {
|
||||
final Calendar calendar;
|
||||
|
||||
public JspCalendar() {
|
||||
calendar = Calendar.getInstance();
|
||||
Date trialTime = new Date();
|
||||
calendar.setTime(trialTime);
|
||||
}
|
||||
|
||||
|
||||
public int getYear() {
|
||||
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];
|
||||
|
||||
}
|
||||
|
||||
public String getDay() {
|
||||
int x = getDayOfWeek();
|
||||
String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday"};
|
||||
|
||||
if (x > 7)
|
||||
return "Unknown to Man";
|
||||
|
||||
return days[x - 1];
|
||||
|
||||
}
|
||||
|
||||
public int getMonthInt() {
|
||||
return 1 + calendar.get(Calendar.MONTH);
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
|
||||
}
|
||||
|
||||
public String getCurrentDate() {
|
||||
Date dt = new Date ();
|
||||
calendar.setTime (dt);
|
||||
return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
|
||||
|
||||
}
|
||||
|
||||
public String getNextDate() {
|
||||
calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() + 1);
|
||||
return getDate ();
|
||||
}
|
||||
|
||||
public String getPrevDate() {
|
||||
calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() - 1);
|
||||
return getDate ();
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return getHour() + ":" + getMinute() + ":" + getSecond();
|
||||
}
|
||||
|
||||
public int getDayOfMonth() {
|
||||
return calendar.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
public int getDayOfYear() {
|
||||
return calendar.get(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
|
||||
public int getWeekOfYear() {
|
||||
return calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
}
|
||||
|
||||
public int getWeekOfMonth() {
|
||||
return calendar.get(Calendar.WEEK_OF_MONTH);
|
||||
}
|
||||
|
||||
public int getDayOfWeek() {
|
||||
return calendar.get(Calendar.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
public int getHour() {
|
||||
return calendar.get(Calendar.HOUR_OF_DAY);
|
||||
}
|
||||
|
||||
public int getMinute() {
|
||||
return calendar.get(Calendar.MINUTE);
|
||||
}
|
||||
|
||||
|
||||
public int getSecond() {
|
||||
return calendar.get(Calendar.SECOND);
|
||||
}
|
||||
|
||||
|
||||
public int getEra() {
|
||||
return calendar.get(Calendar.ERA);
|
||||
}
|
||||
|
||||
public String getUSTimeZone() {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public int getDSTOffset() {
|
||||
return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
|
||||
}
|
||||
|
||||
|
||||
public int getAMPM() {
|
||||
return calendar.get(Calendar.AM_PM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
101
webapps/examples/WEB-INF/classes/cal/TableBean.java
Normal file
101
webapps/examples/WEB-INF/classes/cal/TableBean.java
Normal file
@@ -0,0 +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.
|
||||
*/
|
||||
package cal;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class TableBean {
|
||||
|
||||
final Hashtable<String, Entries> table;
|
||||
final 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
31
webapps/examples/WEB-INF/classes/checkbox/CheckTest.java
Normal file
31
webapps/examples/WEB-INF/classes/checkbox/CheckTest.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 checkbox;
|
||||
|
||||
public class CheckTest {
|
||||
|
||||
String b[] = new String[] { "1", "2", "3", "4" };
|
||||
|
||||
public String[] getFruit() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setFruit(String [] b) {
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
113
webapps/examples/WEB-INF/classes/colors/ColorGameBean.java
Normal file
113
webapps/examples/WEB-INF/classes/colors/ColorGameBean.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 colors;
|
||||
|
||||
public class ColorGameBean {
|
||||
|
||||
private String background = "yellow";
|
||||
private String foreground = "red";
|
||||
private String color1 = foreground;
|
||||
private String color2 = background;
|
||||
private String hint = "no";
|
||||
private int attempts = 0;
|
||||
private int intval = 0;
|
||||
private boolean tookHints = false;
|
||||
|
||||
public void processRequest() {
|
||||
|
||||
// background = "yellow";
|
||||
// foreground = "red";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
attempts++;
|
||||
}
|
||||
|
||||
public void setColor2(String x) {
|
||||
color2 = x;
|
||||
}
|
||||
|
||||
public void setColor1(String x) {
|
||||
color1 = x;
|
||||
}
|
||||
|
||||
public void setAction(String x) {
|
||||
if (!tookHints)
|
||||
tookHints = x.equalsIgnoreCase("Hint");
|
||||
hint = x;
|
||||
}
|
||||
|
||||
public String getColor2() {
|
||||
return background;
|
||||
}
|
||||
|
||||
public String getColor1() {
|
||||
return foreground;
|
||||
}
|
||||
|
||||
public int getAttempts() {
|
||||
return attempts;
|
||||
}
|
||||
|
||||
public boolean getHint() {
|
||||
return hint.equalsIgnoreCase("Hint");
|
||||
}
|
||||
|
||||
public boolean getSuccess() {
|
||||
if (background.equalsIgnoreCase("black") ||
|
||||
background.equalsIgnoreCase("cyan")) {
|
||||
|
||||
if (foreground.equalsIgnoreCase("black") ||
|
||||
foreground.equalsIgnoreCase("cyan")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getHintTaken() {
|
||||
return tookHints;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
foreground = "red";
|
||||
background = "yellow";
|
||||
}
|
||||
|
||||
public void setIntval(int value) {
|
||||
intval = value;
|
||||
}
|
||||
|
||||
public int getIntval() {
|
||||
return intval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 compressionFilters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
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.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.
|
||||
*
|
||||
* @author Amy Roh
|
||||
* @author Dmitri Valdin
|
||||
*/
|
||||
public class CompressionFilter implements Filter {
|
||||
|
||||
/**
|
||||
* Minimal reasonable threshold.
|
||||
*/
|
||||
private static final int MIN_THRESHOLD = 128;
|
||||
|
||||
/**
|
||||
* Minimal reasonable buffer.
|
||||
*/
|
||||
// 8KB is what tomcat would use by default anyway
|
||||
private static final int MIN_BUFFER = 8192;
|
||||
|
||||
/**
|
||||
* The threshold number to compress.
|
||||
*/
|
||||
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 for this filter.
|
||||
*/
|
||||
private int debug = 0;
|
||||
|
||||
/**
|
||||
* Place this filter into service.
|
||||
*
|
||||
* @param filterConfig The filter configuration object
|
||||
*/
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
|
||||
if (filterConfig != null) {
|
||||
String value = filterConfig.getInitParameter("debug");
|
||||
if (value!=null) {
|
||||
debug = Integer.parseInt(value);
|
||||
}
|
||||
|
||||
String str = filterConfig.getInitParameter("compressionThreshold");
|
||||
if (str != null) {
|
||||
compressionThreshold = Integer.parseInt(str);
|
||||
if (compressionThreshold != 0 && compressionThreshold < MIN_THRESHOLD) {
|
||||
if (debug > 0) {
|
||||
System.out.println("compressionThreshold should be either 0 - no compression or >= " + MIN_THRESHOLD);
|
||||
System.out.println("compressionThreshold set to " + MIN_THRESHOLD);
|
||||
}
|
||||
compressionThreshold = MIN_THRESHOLD;
|
||||
}
|
||||
}
|
||||
|
||||
str = filterConfig.getInitParameter("compressionBuffer");
|
||||
if (str != null) {
|
||||
compressionBuffer = Integer.parseInt(str);
|
||||
if (compressionBuffer < MIN_BUFFER) {
|
||||
if (debug > 0) {
|
||||
System.out.println("compressionBuffer should be >= " + MIN_BUFFER);
|
||||
System.out.println("compressionBuffer set to " + MIN_BUFFER);
|
||||
}
|
||||
compressionBuffer = MIN_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
str = filterConfig.getInitParameter("compressionMimeTypes");
|
||||
if (str != null) {
|
||||
List<String> values = new ArrayList<>();
|
||||
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 " +
|
||||
Arrays.toString(compressionMimeTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Take this filter out of service.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>doFilter</code> method of the Filter is called by the container
|
||||
* each time a request/response pair is passed through the chain due
|
||||
* to a client request for a resource at the end of the chain.
|
||||
* The FilterChain passed into this method allows the Filter to pass on the
|
||||
* request and response to the next entity in the chain.<p>
|
||||
* This method first examines the request to check whether the client support
|
||||
* compression. <br>
|
||||
* It simply just pass the request and response if there is no support for
|
||||
* compression.<br>
|
||||
* If the compression support is available, it creates a
|
||||
* CompressionServletResponseWrapper object which compresses the content and
|
||||
* modifies the header if the content length is big enough.
|
||||
* 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 {
|
||||
|
||||
if (debug > 0) {
|
||||
System.out.println("@doFilter");
|
||||
}
|
||||
|
||||
if (compressionThreshold == 0) {
|
||||
if (debug > 0) {
|
||||
System.out.println("doFilter got called, but compressionThreshold is set to 0 - no compression");
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean supportCompression = false;
|
||||
if (request instanceof HttpServletRequest) {
|
||||
if (debug > 1) {
|
||||
System.out.println("requestURI = " + ((HttpServletRequest)request).getRequestURI());
|
||||
}
|
||||
|
||||
// Are we allowed to compress ?
|
||||
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");
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
Enumeration<String> e =
|
||||
((HttpServletRequest)request).getHeaders("Accept-Encoding");
|
||||
while (e.hasMoreElements()) {
|
||||
String name = e.nextElement();
|
||||
if (name.indexOf("gzip") != -1) {
|
||||
if (debug > 0) {
|
||||
System.out.println("supports compression");
|
||||
}
|
||||
supportCompression = true;
|
||||
} else {
|
||||
if (debug > 0) {
|
||||
System.out.println("no support for compression");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
try {
|
||||
chain.doFilter(request, wrappedResponse);
|
||||
} finally {
|
||||
wrappedResponse.finishResponse();
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (debug > 0) {
|
||||
System.out.println("doFilter gets called w/o compression");
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 compressionFilters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
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
|
||||
* @author Amy Roh
|
||||
*/
|
||||
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<String> e = request.getHeaders("Accept-Encoding");
|
||||
while (e.hasMoreElements()) {
|
||||
String name = e.nextElement();
|
||||
out.println(name);
|
||||
if (name.indexOf("gzip") != -1) {
|
||||
out.println("gzip supported -- able to compress");
|
||||
}
|
||||
else {
|
||||
out.println("gzip not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* 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 compressionFilters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
|
||||
/**
|
||||
* Implementation of <b>ServletOutputStream</b> that works with
|
||||
* the CompressionServletResponseWrapper implementation.
|
||||
*
|
||||
* @author Amy Roh
|
||||
* @author Dmitri Valdin
|
||||
*/
|
||||
public class CompressionResponseStream extends ServletOutputStream {
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
/**
|
||||
* Construct a servlet output stream associated with the specified Response.
|
||||
*
|
||||
* @param responseWrapper The associated response wrapper
|
||||
* @param originalOutput the output stream
|
||||
*/
|
||||
public CompressionResponseStream(
|
||||
CompressionServletResponseWrapper responseWrapper,
|
||||
ServletOutputStream originalOutput) {
|
||||
|
||||
super();
|
||||
closed = false;
|
||||
this.response = responseWrapper;
|
||||
this.output = originalOutput;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The threshold number which decides to compress or not.
|
||||
* Users can configure in web.xml to set it to fit their needs.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* The buffer through which all of our output bytes are passed.
|
||||
*/
|
||||
protected byte[] buffer = null;
|
||||
|
||||
/**
|
||||
* The number of data bytes currently in the buffer.
|
||||
*/
|
||||
protected int bufferCount = 0;
|
||||
|
||||
/**
|
||||
* The underlying gzip output stream to which we should write data.
|
||||
*/
|
||||
protected OutputStream gzipstream = null;
|
||||
|
||||
/**
|
||||
* Has this stream been closed?
|
||||
*/
|
||||
protected boolean closed = false;
|
||||
|
||||
/**
|
||||
* The response with which this servlet output stream is associated.
|
||||
*/
|
||||
protected final CompressionServletResponseWrapper response;
|
||||
|
||||
/**
|
||||
* The underlying servlet output stream to which we should write data.
|
||||
*/
|
||||
protected final ServletOutputStream output;
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Set debug level.
|
||||
*
|
||||
* @param debug The higher the number, the more detail shown. Currently the
|
||||
* range 0 (none) to 3 (everything) is used.
|
||||
*/
|
||||
public void setDebugLevel(int debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the compressionThreshold number and create buffer for this size
|
||||
*/
|
||||
protected void setCompressionThreshold(int compressionThreshold) {
|
||||
this.compressionThreshold = compressionThreshold;
|
||||
buffer = new byte[this.compressionThreshold];
|
||||
if (debug > 1) {
|
||||
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.
|
||||
*
|
||||
* @param compressionMimeTypes The mimetypes that will be compressed.
|
||||
*/
|
||||
public void setCompressionMimeTypes(String[] compressionMimeTypes) {
|
||||
this.compressionMimeTypes = compressionMimeTypes;
|
||||
if (debug > 1) {
|
||||
System.out.println("compressionMimeTypes is set to " +
|
||||
Arrays.toString(this.compressionMimeTypes));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
System.out.println("close() @ CompressionResponseStream");
|
||||
}
|
||||
if (closed)
|
||||
throw new IOException("This output stream has already been closed");
|
||||
|
||||
if (gzipstream != null) {
|
||||
flushToGZip();
|
||||
gzipstream.close();
|
||||
gzipstream = null;
|
||||
} else {
|
||||
if (bufferCount > 0) {
|
||||
if (debug > 2) {
|
||||
System.out.print("output.write(");
|
||||
System.out.write(buffer, 0, bufferCount);
|
||||
System.out.println(")");
|
||||
}
|
||||
output.write(buffer, 0, bufferCount);
|
||||
bufferCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
output.close();
|
||||
closed = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
System.out.println("flush() @ CompressionResponseStream");
|
||||
}
|
||||
if (closed) {
|
||||
throw new IOException("Cannot flush a closed output stream");
|
||||
}
|
||||
|
||||
if (gzipstream != null) {
|
||||
gzipstream.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void flushToGZip() throws IOException {
|
||||
|
||||
if (debug > 1) {
|
||||
System.out.println("flushToGZip() @ CompressionResponseStream");
|
||||
}
|
||||
if (bufferCount > 0) {
|
||||
if (debug > 1) {
|
||||
System.out.println("flushing out to GZipStream, bufferCount = " + bufferCount);
|
||||
}
|
||||
writeToGZip(buffer, 0, bufferCount);
|
||||
bufferCount = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the specified byte to our output stream.
|
||||
*
|
||||
* @param b The byte to be written
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
|
||||
if (debug > 1) {
|
||||
System.out.println("write "+b+" in CompressionResponseStream ");
|
||||
}
|
||||
if (closed)
|
||||
throw new IOException("Cannot write to a closed output stream");
|
||||
|
||||
if (bufferCount >= buffer.length) {
|
||||
flushToGZip();
|
||||
}
|
||||
|
||||
buffer[bufferCount++] = (byte) b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write <code>b.length</code> bytes from the specified byte array
|
||||
* to our output stream.
|
||||
*
|
||||
* @param b The byte array to be written
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(byte b[]) throws IOException {
|
||||
|
||||
write(b, 0, b.length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO SERVLET 3.1
|
||||
*/
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO SERVLET 3.1
|
||||
*/
|
||||
@Override
|
||||
public void setWriteListener(WriteListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write <code>len</code> bytes from the specified byte array, starting
|
||||
* at the specified offset, to our output stream.
|
||||
*
|
||||
* @param b The byte array containing the bytes to be written
|
||||
* @param off Zero-relative starting offset of the bytes to be written
|
||||
* @param len The number of bytes to be written
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
|
||||
if (debug > 1) {
|
||||
System.out.println("write, bufferCount = " + bufferCount + " len = " + len + " off = " + off);
|
||||
}
|
||||
if (debug > 2) {
|
||||
System.out.print("write(");
|
||||
System.out.write(b, off, len);
|
||||
System.out.println(")");
|
||||
}
|
||||
|
||||
if (closed)
|
||||
throw new IOException("Cannot write to a closed output stream");
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
// Can we write into buffer ?
|
||||
if (len <= (buffer.length - bufferCount)) {
|
||||
System.arraycopy(b, off, buffer, bufferCount, len);
|
||||
bufferCount += len;
|
||||
return;
|
||||
}
|
||||
|
||||
// There is not enough space in buffer. Flush it ...
|
||||
flushToGZip();
|
||||
|
||||
// ... and try again. Note, that bufferCount = 0 here !
|
||||
if (len <= (buffer.length - bufferCount)) {
|
||||
System.arraycopy(b, off, buffer, bufferCount, len);
|
||||
bufferCount += len;
|
||||
return;
|
||||
}
|
||||
|
||||
// write direct to gzip
|
||||
writeToGZip(b, off, len);
|
||||
}
|
||||
|
||||
public void writeToGZip(byte b[], int off, int len) throws IOException {
|
||||
|
||||
if (debug > 1) {
|
||||
System.out.println("writeToGZip, len = " + len);
|
||||
}
|
||||
if (debug > 2) {
|
||||
System.out.print("writeToGZip(");
|
||||
System.out.write(b, off, len);
|
||||
System.out.println(")");
|
||||
}
|
||||
if (gzipstream == null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
gzipstream.write(b, off, len);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Package Methods
|
||||
|
||||
/**
|
||||
* Has this response stream been closed?
|
||||
*
|
||||
* @return <code>true</code> if the stream has been closed, otherwise false.
|
||||
*/
|
||||
public boolean closed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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 compressionFilters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
/**
|
||||
* Implementation of <b>HttpServletResponseWrapper</b> that works with
|
||||
* the CompressionServletResponseStream implementation..
|
||||
*
|
||||
* @author Amy Roh
|
||||
* @author Dmitri Valdin
|
||||
*/
|
||||
public class CompressionServletResponseWrapper
|
||||
extends HttpServletResponseWrapper {
|
||||
|
||||
// ----------------------------------------------------- Constructor
|
||||
|
||||
/**
|
||||
* Calls the parent constructor which creates a ServletResponse adaptor
|
||||
* wrapping the given response object.
|
||||
*
|
||||
* @param response The response object to be wrapped.
|
||||
*/
|
||||
public CompressionServletResponseWrapper(HttpServletResponse response) {
|
||||
super(response);
|
||||
origResponse = response;
|
||||
if (debug > 1) {
|
||||
System.out.println("CompressionServletResponseWrapper constructor gets called");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* Original response
|
||||
*/
|
||||
protected final HttpServletResponse origResponse;
|
||||
|
||||
/**
|
||||
* The ServletOutputStream that has been returned by
|
||||
* <code>getOutputStream()</code>, if any.
|
||||
*/
|
||||
protected ServletOutputStream stream = null;
|
||||
|
||||
|
||||
/**
|
||||
* The PrintWriter that has been returned by
|
||||
* <code>getWriter()</code>, if any.
|
||||
*/
|
||||
protected PrintWriter writer = null;
|
||||
|
||||
/**
|
||||
* The threshold number to compress
|
||||
*/
|
||||
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
|
||||
*/
|
||||
protected int debug = 0;
|
||||
|
||||
/**
|
||||
* keeps a copy of all headers set
|
||||
*/
|
||||
private final Map<String,String> headerCopies = new HashMap<>();
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Set threshold number.
|
||||
*
|
||||
* @param threshold The new compression threshold
|
||||
*/
|
||||
public void setCompressionThreshold(int threshold) {
|
||||
if (debug > 1) {
|
||||
System.out.println("setCompressionThreshold to " + threshold);
|
||||
}
|
||||
this.compressionThreshold = threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set compression buffer.
|
||||
*
|
||||
* @param buffer New size of buffer to use for compressed output
|
||||
*/
|
||||
public void setCompressionBuffer(int buffer) {
|
||||
if (debug > 1) {
|
||||
System.out.println("setCompressionBuffer to " + buffer);
|
||||
}
|
||||
this.compressionBuffer = buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set compressible mime types.
|
||||
*
|
||||
* @param mimeTypes The new list of mime types that will be considered for
|
||||
* compression
|
||||
*/
|
||||
public void setCompressionMimeTypes(String[] mimeTypes) {
|
||||
if (debug > 1) {
|
||||
System.out.println("setCompressionMimeTypes to " +
|
||||
Arrays.toString(mimeTypes));
|
||||
}
|
||||
this.compressionMimeTypes = mimeTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug level.
|
||||
*
|
||||
* @param debug The new debug level
|
||||
*/
|
||||
public void setDebugLevel(int debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and return a ServletOutputStream to write the content
|
||||
* associated with this Response.
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*
|
||||
* @return A new servlet output stream that compressed any data written to
|
||||
* it
|
||||
*/
|
||||
protected ServletOutputStream createOutputStream() throws IOException {
|
||||
if (debug > 1) {
|
||||
System.out.println("createOutputStream gets called");
|
||||
}
|
||||
|
||||
CompressionResponseStream stream = new CompressionResponseStream(
|
||||
this, origResponse.getOutputStream());
|
||||
stream.setDebugLevel(debug);
|
||||
stream.setCompressionThreshold(compressionThreshold);
|
||||
stream.setCompressionBuffer(compressionBuffer);
|
||||
stream.setCompressionMimeTypes(compressionMimeTypes);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finish a response.
|
||||
*/
|
||||
public void finishResponse() {
|
||||
try {
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
} else {
|
||||
if (stream != null)
|
||||
stream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------ ServletResponse Methods
|
||||
|
||||
|
||||
/**
|
||||
* Flush the buffer and commit this response.
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public void flushBuffer() throws IOException {
|
||||
if (debug > 1) {
|
||||
System.out.println("flush buffer @ GZipServletResponseWrapper");
|
||||
}
|
||||
((CompressionResponseStream)stream).flush();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the servlet output stream associated with this Response.
|
||||
*
|
||||
* @exception IllegalStateException if <code>getWriter</code> has
|
||||
* already been called for this response
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
|
||||
if (writer != null)
|
||||
throw new IllegalStateException("getWriter() has already been called for this response");
|
||||
|
||||
if (stream == null)
|
||||
stream = createOutputStream();
|
||||
if (debug > 1) {
|
||||
System.out.println("stream is set to "+stream+" in getOutputStream");
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the writer associated with this Response.
|
||||
*
|
||||
* @exception IllegalStateException if <code>getOutputStream</code> has
|
||||
* already been called for this response
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
|
||||
if (writer != null)
|
||||
return writer;
|
||||
|
||||
if (stream != null)
|
||||
throw new IllegalStateException("getOutputStream() has already been called for this response");
|
||||
|
||||
stream = createOutputStream();
|
||||
if (debug > 1) {
|
||||
System.out.println("stream is set to "+stream+" in getWriter");
|
||||
}
|
||||
String charEnc = origResponse.getCharacterEncoding();
|
||||
if (debug > 1) {
|
||||
System.out.println("character encoding is " + charEnc);
|
||||
}
|
||||
writer = new PrintWriter(new OutputStreamWriter(stream, charEnc));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, String value) {
|
||||
headerCopies.put(name, value);
|
||||
super.setHeader(name, value);
|
||||
}
|
||||
}
|
||||
153
webapps/examples/WEB-INF/classes/dates/JspCalendar.java
Normal file
153
webapps/examples/WEB-INF/classes/dates/JspCalendar.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 dates;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
public class JspCalendar {
|
||||
final Calendar calendar;
|
||||
|
||||
public JspCalendar() {
|
||||
calendar = Calendar.getInstance();
|
||||
Date trialTime = new Date();
|
||||
calendar.setTime(trialTime);
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
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];
|
||||
|
||||
}
|
||||
|
||||
public String getDay() {
|
||||
int x = getDayOfWeek();
|
||||
String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday"};
|
||||
|
||||
if (x > 7)
|
||||
return "Unknown to Man";
|
||||
|
||||
return days[x - 1];
|
||||
|
||||
}
|
||||
|
||||
public int getMonthInt() {
|
||||
return 1 + calendar.get(Calendar.MONTH);
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return getMonthInt() + "/" + getDayOfMonth() + "/" + getYear();
|
||||
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return getHour() + ":" + getMinute() + ":" + getSecond();
|
||||
}
|
||||
|
||||
public int getDayOfMonth() {
|
||||
return calendar.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
public int getDayOfYear() {
|
||||
return calendar.get(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
|
||||
public int getWeekOfYear() {
|
||||
return calendar.get(Calendar.WEEK_OF_YEAR);
|
||||
}
|
||||
|
||||
public int getWeekOfMonth() {
|
||||
return calendar.get(Calendar.WEEK_OF_MONTH);
|
||||
}
|
||||
|
||||
public int getDayOfWeek() {
|
||||
return calendar.get(Calendar.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
public int getHour() {
|
||||
return calendar.get(Calendar.HOUR_OF_DAY);
|
||||
}
|
||||
|
||||
public int getMinute() {
|
||||
return calendar.get(Calendar.MINUTE);
|
||||
}
|
||||
|
||||
|
||||
public int getSecond() {
|
||||
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());
|
||||
}
|
||||
|
||||
private static void p(String x) {
|
||||
System.out.println(x);
|
||||
}
|
||||
|
||||
|
||||
public int getEra() {
|
||||
return calendar.get(Calendar.ERA);
|
||||
}
|
||||
|
||||
public String getUSTimeZone() {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public int getDSTOffset() {
|
||||
return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
|
||||
}
|
||||
|
||||
|
||||
public int getAMPM() {
|
||||
return calendar.get(Calendar.AM_PM);
|
||||
}
|
||||
}
|
||||
|
||||
30
webapps/examples/WEB-INF/classes/error/Smart.java
Normal file
30
webapps/examples/WEB-INF/classes/error/Smart.java
Normal file
@@ -0,0 +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.
|
||||
*/
|
||||
package error;
|
||||
|
||||
public class Smart {
|
||||
|
||||
String name = "JSP";
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
@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 Tag parent;
|
||||
}
|
||||
87
webapps/examples/WEB-INF/classes/examples/FooTag.java
Normal file
87
webapps/examples/WEB-INF/classes/examples/FooTag.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Example1: the simplest tag
|
||||
* Collect attributes and call into some actions
|
||||
*
|
||||
* <foo att1="..." att2="...." att3="...." />
|
||||
*/
|
||||
|
||||
public class FooTag extends ExampleTagBase {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
pageContext.setAttribute("member", atts[i]);
|
||||
i++;
|
||||
return EVAL_BODY_BUFFERED;
|
||||
} catch (IOException ex) {
|
||||
throw new JspTagException(ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 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[]
|
||||
{
|
||||
new VariableInfo("member",
|
||||
"String",
|
||||
true,
|
||||
VariableInfo.NESTED)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
61
webapps/examples/WEB-INF/classes/examples/LogTag.java
Normal file
61
webapps/examples/WEB-INF/classes/examples/LogTag.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Log the contents of the body. Could be used to handle errors etc.
|
||||
*/
|
||||
public class LogTag extends ExampleTagBase {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
boolean toBrowser = false;
|
||||
|
||||
public void setToBrowser(String value) {
|
||||
if (value == null)
|
||||
toBrowser = false;
|
||||
else if (value.equalsIgnoreCase("true"))
|
||||
toBrowser = true;
|
||||
else
|
||||
toBrowser = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doStartTag() throws JspException {
|
||||
return EVAL_BODY_BUFFERED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int doAfterBody() throws JspException {
|
||||
try {
|
||||
String s = bodyOut.getString();
|
||||
System.err.println(s);
|
||||
if (toBrowser)
|
||||
bodyOut.writeOut(bodyOut.getEnclosingWriter());
|
||||
return SKIP_BODY;
|
||||
} catch (IOException ex) {
|
||||
throw new JspTagException(ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
79
webapps/examples/WEB-INF/classes/examples/ValuesTag.java
Normal file
79
webapps/examples/WEB-INF/classes/examples/ValuesTag.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
137
webapps/examples/WEB-INF/classes/filters/ExampleFilter.java
Normal file
137
webapps/examples/WEB-INF/classes/filters/ExampleFilter.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* Example filter that can be attached to either an individual servlet
|
||||
* or to a URL pattern. This filter performs the following functions:
|
||||
* <ul>
|
||||
* <li>Attaches itself as a request attribute, under the attribute name
|
||||
* defined by the value of the <code>attribute</code> initialization
|
||||
* parameter.</li>
|
||||
* <li>Calculates the number of milliseconds required to perform the
|
||||
* servlet processing required by this request, including any
|
||||
* subsequently defined filters, and logs the result to the servlet
|
||||
* context log for this application.
|
||||
* </ul>
|
||||
*
|
||||
* @author Craig McClanahan
|
||||
*/
|
||||
public final class ExampleFilter implements Filter {
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The request attribute name under which we store a reference to ourself.
|
||||
*/
|
||||
private String attribute = null;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
this.attribute = null;
|
||||
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 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 {
|
||||
|
||||
// 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();
|
||||
chain.doFilter(request, response);
|
||||
long stopTime = System.currentTimeMillis();
|
||||
filterConfig.getServletContext().log
|
||||
(this.toString() + ": " + (stopTime - startTime) +
|
||||
" milliseconds");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Place this filter into service.
|
||||
*
|
||||
* @param fConfig The filter configuration object
|
||||
*/
|
||||
@Override
|
||||
public void init(FilterConfig fConfig) throws ServletException {
|
||||
|
||||
this.filterConfig = fConfig;
|
||||
this.attribute = fConfig.getInitParameter("attribute");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a String representation of this object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
if (filterConfig == null)
|
||||
return ("TimingFilter()");
|
||||
StringBuilder sb = new StringBuilder("TimingFilter(");
|
||||
sb.append(filterConfig);
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
44
webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.java
Normal file
44
webapps/examples/WEB-INF/classes/jsp2/examples/BookBean.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class BookBean {
|
||||
private final String title;
|
||||
private final String author;
|
||||
private final String isbn;
|
||||
|
||||
public BookBean( String title, String author, String isbn ) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.isbn = isbn;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return this.author;
|
||||
}
|
||||
|
||||
public String getIsbn() {
|
||||
return this.isbn;
|
||||
}
|
||||
|
||||
}
|
||||
36
webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.java
Normal file
36
webapps/examples/WEB-INF/classes/jsp2/examples/FooBean.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.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 StringBuilder( text ).reverse().toString();
|
||||
}
|
||||
|
||||
public static int numVowels( String text ) {
|
||||
String vowels = "aeiouAEIOU";
|
||||
int result = 0;
|
||||
for( int i = 0; i < text.length(); i++ ) {
|
||||
if( vowels.indexOf( text.charAt( i ) ) != -1 ) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String caps( String text ) {
|
||||
return text.toUpperCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.simpletag;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import javax.servlet.jsp.tagext.DynamicAttributes;
|
||||
import javax.servlet.jsp.tagext.SimpleTagSupport;
|
||||
|
||||
/**
|
||||
* SimpleTag handler that echoes all its attributes
|
||||
*/
|
||||
public class EchoAttributesTag
|
||||
extends SimpleTagSupport
|
||||
implements DynamicAttributes
|
||||
{
|
||||
private final List<String> keys = new ArrayList<>();
|
||||
private final List<Object> values = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void doTag() throws JspException, IOException {
|
||||
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>" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDynamicAttribute( String uri, String localName,
|
||||
Object value )
|
||||
throws JspException
|
||||
{
|
||||
keys.add( localName );
|
||||
values.add( value );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.simpletag;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.SimpleTagSupport;
|
||||
|
||||
import jsp2.examples.BookBean;
|
||||
|
||||
/**
|
||||
* SimpleTag handler that pretends to search for a book, and stores
|
||||
* the result in a scoped variable.
|
||||
*/
|
||||
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. Tolkien";
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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 jsp2.examples.simpletag;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.SimpleTagSupport;
|
||||
|
||||
/**
|
||||
* SimpleTag handler that prints "Hello, world!"
|
||||
*/
|
||||
public class HelloWorldSimpleTag extends SimpleTagSupport {
|
||||
@Override
|
||||
public void doTag() throws JspException, IOException {
|
||||
getJspContext().getOut().write( "Hello, world!" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.simpletag;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.SimpleTagSupport;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
public void setNum(int num) {
|
||||
this.num = num;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* 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 final Random random = new Random();
|
||||
|
||||
private JspFragment fragment1;
|
||||
private JspFragment fragment2;
|
||||
private JspFragment fragment3;
|
||||
|
||||
@Override
|
||||
public void doTag() throws JspException, IOException {
|
||||
switch(random.nextInt(6)) {
|
||||
case 0:
|
||||
fragment1.invoke( null );
|
||||
fragment2.invoke( null );
|
||||
fragment3.invoke( null );
|
||||
break;
|
||||
case 1:
|
||||
fragment1.invoke( null );
|
||||
fragment3.invoke( null );
|
||||
fragment2.invoke( null );
|
||||
break;
|
||||
case 2:
|
||||
fragment2.invoke( null );
|
||||
fragment1.invoke( null );
|
||||
fragment3.invoke( null );
|
||||
break;
|
||||
case 3:
|
||||
fragment2.invoke( null );
|
||||
fragment3.invoke( null );
|
||||
fragment1.invoke( null );
|
||||
break;
|
||||
case 4:
|
||||
fragment3.invoke( null );
|
||||
fragment1.invoke( null );
|
||||
fragment2.invoke( null );
|
||||
break;
|
||||
case 5:
|
||||
fragment3.invoke( null );
|
||||
fragment2.invoke( null );
|
||||
fragment1.invoke( null );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFragment1( JspFragment fragment1 ) {
|
||||
this.fragment1 = fragment1;
|
||||
}
|
||||
|
||||
public void setFragment2( JspFragment fragment2 ) {
|
||||
this.fragment2 = fragment2;
|
||||
}
|
||||
|
||||
public void setFragment3( JspFragment fragment3 ) {
|
||||
this.fragment3 = fragment3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package jsp2.examples.simpletag;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.tagext.SimpleTagSupport;
|
||||
|
||||
/**
|
||||
* Displays a tile as a single cell in a table.
|
||||
*/
|
||||
public class TileSimpleTag extends SimpleTagSupport {
|
||||
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 +
|
||||
"</center></font></td>" );
|
||||
}
|
||||
|
||||
public void setColor( String color ) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public void setLabel( String label ) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
138
webapps/examples/WEB-INF/classes/listeners/ContextListener.java
Normal file
138
webapps/examples/WEB-INF/classes/listeners/ContextListener.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.ServletContextAttributeEvent;
|
||||
import javax.servlet.ServletContextAttributeListener;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public final class ContextListener
|
||||
implements ServletContextAttributeListener, ServletContextListener {
|
||||
|
||||
|
||||
// ----------------------------------------------------- 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 servlet context attribute event
|
||||
*/
|
||||
@Override
|
||||
public void attributeAdded(ServletContextAttributeEvent event) {
|
||||
|
||||
log("attributeAdded('" + event.getName() + "', '" +
|
||||
event.getValue() + "')");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the fact that a servlet context attribute was removed.
|
||||
*
|
||||
* @param event The servlet context attribute event
|
||||
*/
|
||||
@Override
|
||||
public void attributeRemoved(ServletContextAttributeEvent event) {
|
||||
|
||||
log("attributeRemoved('" + event.getName() + "', '" +
|
||||
event.getValue() + "')");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the fact that a servlet context attribute was replaced.
|
||||
*
|
||||
* @param event The servlet context attribute event
|
||||
*/
|
||||
@Override
|
||||
public void attributeReplaced(ServletContextAttributeEvent event) {
|
||||
|
||||
log("attributeReplaced('" + event.getName() + "', '" +
|
||||
event.getValue() + "')");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the fact that this web application has been destroyed.
|
||||
*
|
||||
* @param event The servlet context event
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
|
||||
log("contextDestroyed()");
|
||||
this.context = null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record the fact that this web application has been initialized.
|
||||
*
|
||||
* @param event The servlet context event
|
||||
*/
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
|
||||
this.context = event.getServletContext();
|
||||
log("contextInitialized()");
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context application log.
|
||||
*
|
||||
* @param message Message to be logged
|
||||
*/
|
||||
private void log(String message) {
|
||||
|
||||
if (context != null)
|
||||
context.log("ContextListener: " + message);
|
||||
else
|
||||
System.out.println("ContextListener: " + message);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
160
webapps/examples/WEB-INF/classes/listeners/SessionListener.java
Normal file
160
webapps/examples/WEB-INF/classes/listeners/SessionListener.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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;
|
||||
import javax.servlet.http.HttpSessionAttributeListener;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
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.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public void attributeAdded(HttpSessionBindingEvent event) {
|
||||
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public void attributeRemoved(HttpSessionBindingEvent event) {
|
||||
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public void attributeReplaced(HttpSessionBindingEvent event) {
|
||||
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
|
||||
log("contextDestroyed()");
|
||||
this.context = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the fact that this web application has been initialized.
|
||||
*
|
||||
* @param event
|
||||
* The servlet context event
|
||||
*/
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
|
||||
this.context = event.getServletContext();
|
||||
log("contextInitialized()");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the fact that a session has been created.
|
||||
*
|
||||
* @param event
|
||||
* The session event
|
||||
*/
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent event) {
|
||||
|
||||
log("sessionCreated('" + event.getSession().getId() + "')");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the fact that a session has been destroyed.
|
||||
*
|
||||
* @param event
|
||||
* The session event
|
||||
*/
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent event) {
|
||||
|
||||
log("sessionDestroyed('" + event.getSession().getId() + "')");
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
/**
|
||||
* Log a message to the servlet context application log.
|
||||
*
|
||||
* @param message
|
||||
* Message to be logged
|
||||
*/
|
||||
private void log(String message) {
|
||||
|
||||
if (context != null)
|
||||
context.log("SessionListener: " + message);
|
||||
else
|
||||
System.out.println("SessionListener: " + message);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
142
webapps/examples/WEB-INF/classes/nonblocking/ByteCounter.java
Normal file
142
webapps/examples/WEB-INF/classes/nonblocking/ByteCounter.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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 nonblocking;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* This doesn't do anything particularly useful - it just counts the total
|
||||
* number of bytes in a request body while demonstrating how to perform
|
||||
* non-blocking reads.
|
||||
*/
|
||||
public class ByteCounter extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
|
||||
resp.getWriter().println("Try again using a POST request.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
|
||||
// Non-blocking IO requires async
|
||||
AsyncContext ac = req.startAsync();
|
||||
|
||||
// Use a single listener for read and write. Listeners often need to
|
||||
// share state to coordinate reads and writes and this is much easier as
|
||||
// a single object.
|
||||
@SuppressWarnings("unused")
|
||||
CounterListener listener = new CounterListener(
|
||||
ac, req.getInputStream(), resp.getOutputStream());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Keep in mind that each call may well be on a different thread to the
|
||||
* previous call. Ensure that changes in values will be visible across
|
||||
* threads. There should only ever be one container thread at a time calling
|
||||
* the listener.
|
||||
*/
|
||||
private static class CounterListener implements ReadListener, WriteListener {
|
||||
|
||||
private final AsyncContext ac;
|
||||
private final ServletInputStream sis;
|
||||
private final ServletOutputStream sos;
|
||||
|
||||
private volatile boolean readFinished = false;
|
||||
private volatile long totalBytesRead = 0;
|
||||
private byte[] buffer = new byte[8192];
|
||||
|
||||
private CounterListener(AsyncContext ac, ServletInputStream sis,
|
||||
ServletOutputStream sos) {
|
||||
this.ac = ac;
|
||||
this.sis = sis;
|
||||
this.sos = sos;
|
||||
|
||||
// In Tomcat, the order the listeners are set controls the order
|
||||
// that the first calls are made. In this case, the read listener
|
||||
// will be called before the write listener.
|
||||
sis.setReadListener(this);
|
||||
sos.setWriteListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataAvailable() throws IOException {
|
||||
int read = 0;
|
||||
// Loop as long as there is data to read. If isReady() returns false
|
||||
// the socket will be added to the poller and onDataAvailable() will
|
||||
// be called again as soon as there is more data to read.
|
||||
while (sis.isReady() && read > -1) {
|
||||
read = sis.read(buffer);
|
||||
if (read > 0) {
|
||||
totalBytesRead += read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllDataRead() throws IOException {
|
||||
readFinished = true;
|
||||
|
||||
// If sos is not ready to write data, the call to isReady() will
|
||||
// register the socket with the poller which will trigger a call to
|
||||
// onWritePossible() when the socket is ready to have data written
|
||||
// to it.
|
||||
if (sos.isReady()) {
|
||||
onWritePossible();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWritePossible() throws IOException {
|
||||
if (readFinished) {
|
||||
// Must be ready to write data if onWritePossible was called
|
||||
String msg = "Total bytes written = [" + totalBytesRead + "]";
|
||||
sos.write(msg.getBytes(StandardCharsets.UTF_8));
|
||||
ac.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
// Should probably log the throwable
|
||||
ac.complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
148
webapps/examples/WEB-INF/classes/nonblocking/NumberWriter.java
Normal file
148
webapps/examples/WEB-INF/classes/nonblocking/NumberWriter.java
Normal file
@@ -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 nonblocking;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* This doesn't do anything particularly useful - it just writes a series of
|
||||
* numbers to the response body while demonstrating how to perform non-blocking
|
||||
* writes.
|
||||
*/
|
||||
public class NumberWriter extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
|
||||
// Non-blocking IO requires async
|
||||
AsyncContext ac = req.startAsync();
|
||||
|
||||
// Use a single listener for read and write. Listeners often need to
|
||||
// share state to coordinate reads and writes and this is much easier as
|
||||
// a single object.
|
||||
@SuppressWarnings("unused")
|
||||
NumberWriterListener listener = new NumberWriterListener(
|
||||
ac, req.getInputStream(), resp.getOutputStream());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Keep in mind that each call may well be on a different thread to the
|
||||
* previous call. Ensure that changes in values will be visible across
|
||||
* threads. There should only ever be one container thread at a time calling
|
||||
* the listener.
|
||||
*/
|
||||
private static class NumberWriterListener implements ReadListener,
|
||||
WriteListener {
|
||||
|
||||
private static final int LIMIT = 10000;
|
||||
|
||||
private final AsyncContext ac;
|
||||
private final ServletInputStream sis;
|
||||
private final ServletOutputStream sos;
|
||||
private final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
private volatile boolean readFinished = false;
|
||||
private byte[] buffer = new byte[8192];
|
||||
|
||||
private NumberWriterListener(AsyncContext ac, ServletInputStream sis,
|
||||
ServletOutputStream sos) {
|
||||
this.ac = ac;
|
||||
this.sis = sis;
|
||||
this.sos = sos;
|
||||
|
||||
// In Tomcat, the order the listeners are set controls the order
|
||||
// that the first calls are made. In this case, the read listener
|
||||
// will be called before the write listener.
|
||||
sis.setReadListener(this);
|
||||
sos.setWriteListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataAvailable() throws IOException {
|
||||
|
||||
// There should be no data to read
|
||||
|
||||
int read = 0;
|
||||
// Loop as long as there is data to read. If isReady() returns false
|
||||
// the socket will be added to the poller and onDataAvailable() will
|
||||
// be called again as soon as there is more data to read.
|
||||
while (sis.isReady() && read > -1) {
|
||||
read = sis.read(buffer);
|
||||
if (read > 0) {
|
||||
throw new IOException("Data was present in input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllDataRead() throws IOException {
|
||||
readFinished = true;
|
||||
|
||||
// If sos is not ready to write data, the call to isReady() will
|
||||
// register the socket with the poller which will trigger a call to
|
||||
// onWritePossible() when the socket is ready to have data written
|
||||
// to it.
|
||||
if (sos.isReady()) {
|
||||
onWritePossible();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWritePossible() throws IOException {
|
||||
if (readFinished) {
|
||||
int i = counter.get();
|
||||
boolean ready = true;
|
||||
while (i < LIMIT && ready) {
|
||||
i = counter.incrementAndGet();
|
||||
String msg = String.format("%1$020d\n", Integer.valueOf(i));
|
||||
sos.write(msg.getBytes(StandardCharsets.UTF_8));
|
||||
ready = sos.isReady();
|
||||
}
|
||||
|
||||
if (i == LIMIT) {
|
||||
ac.complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
// Should probably log the throwable
|
||||
ac.complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
99
webapps/examples/WEB-INF/classes/num/NumberGuessBean.java
Normal file
99
webapps/examples/WEB-INF/classes/num/NumberGuessBean.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package num;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Random;
|
||||
|
||||
public class NumberGuessBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int answer;
|
||||
private String hint;
|
||||
private int numGuesses;
|
||||
private boolean success;
|
||||
private final Random random = new Random();
|
||||
|
||||
public NumberGuessBean() {
|
||||
reset();
|
||||
}
|
||||
|
||||
public int getAnswer() {
|
||||
return answer;
|
||||
}
|
||||
|
||||
public void setAnswer(int answer) {
|
||||
this.answer = answer;
|
||||
}
|
||||
|
||||
public String getHint() {
|
||||
return "" + hint;
|
||||
}
|
||||
|
||||
public void setHint(String hint) {
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
public void setNumGuesses(int numGuesses) {
|
||||
this.numGuesses = numGuesses;
|
||||
}
|
||||
|
||||
public int getNumGuesses() {
|
||||
return numGuesses;
|
||||
}
|
||||
|
||||
public boolean getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
65
webapps/examples/WEB-INF/classes/sessions/DummyCart.java
Normal file
65
webapps/examples/WEB-INF/classes/sessions/DummyCart.java
Normal file
@@ -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 sessions;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
public class DummyCart {
|
||||
final Vector<String> v = new Vector<>();
|
||||
String submit = null;
|
||||
String item = null;
|
||||
|
||||
private void addItem(String name) {
|
||||
v.addElement(name);
|
||||
}
|
||||
|
||||
private void removeItem(String name) {
|
||||
v.removeElement(name);
|
||||
}
|
||||
|
||||
public void setItem(String name) {
|
||||
item = name;
|
||||
}
|
||||
|
||||
public void setSubmit(String s) {
|
||||
submit = s;
|
||||
}
|
||||
|
||||
public String[] getItems() {
|
||||
String[] s = new String[v.size()];
|
||||
v.copyInto(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public void processRequest() {
|
||||
// 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"))
|
||||
removeItem(item);
|
||||
|
||||
// reset at the end of the request
|
||||
reset();
|
||||
}
|
||||
|
||||
// reset
|
||||
private void reset() {
|
||||
submit = null;
|
||||
item = null;
|
||||
}
|
||||
}
|
||||
85
webapps/examples/WEB-INF/classes/util/CookieFilter.java
Normal file
85
webapps/examples/WEB-INF/classes/util/CookieFilter.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 cookieHeader, String sessionId) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(cookieHeader.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(cookieHeader, ";");
|
||||
|
||||
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());
|
||||
|
||||
return name + "=" + filter(name, value, sessionId);
|
||||
}
|
||||
|
||||
public static String filter(String cookieName, String cookieValue, String sessionId) {
|
||||
if (cookieName.toLowerCase(Locale.ENGLISH).contains("jsessionid") &&
|
||||
(sessionId == null || !cookieValue.contains(sessionId))) {
|
||||
cookieValue = OBFUSCATED;
|
||||
}
|
||||
|
||||
return cookieValue;
|
||||
}
|
||||
}
|
||||
68
webapps/examples/WEB-INF/classes/util/HTMLFilter.java
Normal file
68
webapps/examples/WEB-INF/classes/util/HTMLFilter.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* HTML filter utility.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Tim Tye
|
||||
*/
|
||||
public final class HTMLFilter {
|
||||
|
||||
|
||||
/**
|
||||
* Filter the specified message string for characters that are sensitive
|
||||
* in HTML. This avoids potential attacks caused by including JavaScript
|
||||
* codes in the request URL that is often reported in error messages.
|
||||
*
|
||||
* @param message The message string to be filtered
|
||||
*
|
||||
* @return the filtered version of the message
|
||||
*/
|
||||
public static String filter(String message) {
|
||||
|
||||
if (message == null)
|
||||
return null;
|
||||
|
||||
char content[] = new char[message.length()];
|
||||
message.getChars(0, message.length(), content, 0);
|
||||
StringBuilder result = new StringBuilder(content.length + 50);
|
||||
for (int i = 0; i < content.length; i++) {
|
||||
switch (content[i]) {
|
||||
case '<':
|
||||
result.append("<");
|
||||
break;
|
||||
case '>':
|
||||
result.append(">");
|
||||
break;
|
||||
case '&':
|
||||
result.append("&");
|
||||
break;
|
||||
case '"':
|
||||
result.append(""");
|
||||
break;
|
||||
default:
|
||||
result.append(content[i]);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 validators;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Example tag library validator that simply dumps the XML version of each
|
||||
* page to standard output (which will typically be sent to the file
|
||||
* <code>$CATALINA_HOME/logs/catalina.out</code>). To utilize it, simply
|
||||
* include a <code>taglib</code> directive for this tag library at the top
|
||||
* of your JSP page.
|
||||
*
|
||||
* @author Craig McClanahan
|
||||
*/
|
||||
public class DebugValidator extends TagLibraryValidator {
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Validate a JSP page. This will get invoked once per directive in the
|
||||
* JSP page. This method will return <code>null</code> if the page is
|
||||
* valid; otherwise the method should return an array of
|
||||
* <code>ValidationMessage</code> objects. An array of length zero is
|
||||
* also interpreted as no errors.
|
||||
*
|
||||
* @param prefix The value of the prefix argument in this directive
|
||||
* @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) {
|
||||
|
||||
System.out.println("---------- Prefix=" + prefix + " URI=" + uri +
|
||||
"----------");
|
||||
|
||||
InputStream is = page.getInputStream();
|
||||
while (true) {
|
||||
try {
|
||||
int ch = is.read();
|
||||
if (ch < 0)
|
||||
break;
|
||||
System.out.print((char) ch);
|
||||
} catch (IOException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println("-----------------------------------------------");
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<>();
|
||||
|
||||
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<>();
|
||||
for (Class<?> clazz : scanned) {
|
||||
if (clazz.getPackage().getName().startsWith("websocket.")) {
|
||||
results.add(clazz);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@@ -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<>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
230
webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java
Normal file
230
webapps/examples/WEB-INF/classes/websocket/drawboard/Client.java
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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 which are buffered until the previous
|
||||
* send operation has finished.
|
||||
*/
|
||||
private final LinkedList<AbstractWebsocketMessage> messagesToSend =
|
||||
new LinkedList<>();
|
||||
/**
|
||||
* If this client is currently sending a messages asynchronously.
|
||||
*/
|
||||
private volatile boolean isSendingMessage = false;
|
||||
/**
|
||||
* 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 The message to send
|
||||
*/
|
||||
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|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 occurred).
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The type.
|
||||
*
|
||||
* @return 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;
|
||||
}
|
||||
|
||||
|
||||
public DrawMessage(int type, byte colorR, byte colorG, byte colorB,
|
||||
byte colorA, double thickness, double x1, double x2, double y1,
|
||||
double y2) {
|
||||
|
||||
this.type = type;
|
||||
this.colorR = colorR;
|
||||
this.colorG = colorG;
|
||||
this.colorB = colorB;
|
||||
this.colorA = colorA;
|
||||
this.thickness = thickness;
|
||||
this.x1 = x1;
|
||||
this.x2 = x2;
|
||||
this.y1 = y1;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draws this DrawMessage onto the given Graphics2D.
|
||||
*
|
||||
* @param g The target for the DrawMessage
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public static DrawMessage parseFromString(String str)
|
||||
throws ParseException {
|
||||
|
||||
int type;
|
||||
byte[] colors = new byte[4];
|
||||
double thickness;
|
||||
double[] coords = new double[4];
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
throw new ParseException(ex);
|
||||
}
|
||||
|
||||
DrawMessage m = new DrawMessage(type, colors[0], colors[1],
|
||||
colors[2], colors[3], thickness, coords[0], coords[2],
|
||||
coords[1], coords[3]);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public static class ParseException extends Exception {
|
||||
private static final long serialVersionUID = -6651972769789842960L;
|
||||
|
||||
public ParseException(Throwable root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
public ParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 (ParseException e) {
|
||||
// Client sent invalid data
|
||||
// Ignore, TODO: maybe close connection
|
||||
} catch (RuntimeException e) {
|
||||
// Client sent invalid data.
|
||||
// Ignore, TODO: maybe close connection
|
||||
if (dontSwallowException) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
log.error("Unexpected exception: " + ex.toString(), ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
496
webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java
Normal file
496
webapps/examples/WEB-INF/classes/websocket/drawboard/Room.java
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* 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.Objects;
|
||||
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 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<>();
|
||||
|
||||
|
||||
|
||||
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
|
||||
*
|
||||
* @return The newly created player
|
||||
*/
|
||||
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 The task to be executed
|
||||
*/
|
||||
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<>();
|
||||
}
|
||||
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 static 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<>();
|
||||
|
||||
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 The draw message received
|
||||
* @param msgId The ID for the draw message received
|
||||
*/
|
||||
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) {
|
||||
Objects.requireNonNull(content);
|
||||
Objects.requireNonNull(type);
|
||||
|
||||
String completeMsg = String.valueOf(type.flag) + content;
|
||||
|
||||
client.sendMessage(new StringWebsocketMessage(completeMsg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The three annotated echo endpoints can be used to test with Autobahn and
|
||||
* the following command "wstest -m fuzzingclient -s servers.json". See the
|
||||
* Autobahn documentation for setup and general information.
|
||||
*/
|
||||
@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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.PongMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
/**
|
||||
* The three annotated echo endpoints can be used to test with Autobahn and
|
||||
* the following command "wstest -m fuzzingclient -s servers.json". See the
|
||||
* Autobahn documentation for setup and general information.
|
||||
*
|
||||
* Note: This one is disabled by default since it allocates memory, and needs
|
||||
* to be enabled back.
|
||||
*/
|
||||
//@javax.websocket.server.ServerEndpoint("/websocket/echoAsyncAnnotation")
|
||||
public class EchoAsyncAnnotation {
|
||||
|
||||
private static final Future<Void> COMPLETED = new CompletedFuture();
|
||||
|
||||
Future<Void> f = COMPLETED;
|
||||
StringBuilder sb = null;
|
||||
ByteArrayOutputStream bytes = null;
|
||||
|
||||
@OnMessage
|
||||
public void echoTextMessage(Session session, String msg, boolean last) {
|
||||
if (sb == null) {
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
sb.append(msg);
|
||||
if (last) {
|
||||
// Before we send the next message, have to wait for the previous
|
||||
// message to complete
|
||||
try {
|
||||
f.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
// Let the container deal with it
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
f = session.getAsyncRemote().sendText(sb.toString());
|
||||
sb = null;
|
||||
}
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void echoBinaryMessage(byte[] msg, Session session, boolean last)
|
||||
throws IOException {
|
||||
if (bytes == null) {
|
||||
bytes = new ByteArrayOutputStream();
|
||||
}
|
||||
bytes.write(msg);
|
||||
if (last) {
|
||||
// Before we send the next message, have to wait for the previous
|
||||
// message to complete
|
||||
try {
|
||||
f.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
// Let the container deal with it
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
f = session.getAsyncRemote().sendBinary(ByteBuffer.wrap(bytes.toByteArray()));
|
||||
bytes = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a received pong. This is a NO-OP.
|
||||
*
|
||||
* @param pm Ignored.
|
||||
*/
|
||||
@OnMessage
|
||||
public void echoPongMessage(PongMessage pm) {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
private static class CompletedFuture implements Future<Void> {
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException,
|
||||
TimeoutException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.PongMessage;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
/**
|
||||
* The three annotated echo endpoints can be used to test with Autobahn and
|
||||
* the following command "wstest -m fuzzingclient -s servers.json". See the
|
||||
* Autobahn documentation for setup and general information.
|
||||
*/
|
||||
@ServerEndpoint("/websocket/echoStreamAnnotation")
|
||||
public class EchoStreamAnnotation {
|
||||
|
||||
Writer writer;
|
||||
OutputStream stream;
|
||||
|
||||
@OnMessage
|
||||
public void echoTextMessage(Session session, String msg, boolean last)
|
||||
throws IOException {
|
||||
if (writer == null) {
|
||||
writer = session.getBasicRemote().getSendWriter();
|
||||
}
|
||||
writer.write(msg);
|
||||
if (last) {
|
||||
writer.close();
|
||||
writer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void echoBinaryMessage(byte[] msg, Session session, boolean last)
|
||||
throws IOException {
|
||||
if (stream == null) {
|
||||
stream = session.getBasicRemote().getSendStream();
|
||||
}
|
||||
stream.write(msg);
|
||||
stream.flush();
|
||||
if (last) {
|
||||
stream.close();
|
||||
stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a received pong. This is a NO-OP.
|
||||
*
|
||||
* @param pm Ignored.
|
||||
*/
|
||||
@OnMessage
|
||||
public void echoPongMessage(PongMessage pm) {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
20
webapps/examples/WEB-INF/classes/websocket/echo/servers.json
Normal file
20
webapps/examples/WEB-INF/classes/websocket/echo/servers.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"options": {"failByDrop": false},
|
||||
"outdir": "./reports/servers",
|
||||
|
||||
"servers": [
|
||||
{"agent": "Basic",
|
||||
"url": "ws://localhost:8080/examples/websocket/echoAnnotation",
|
||||
"options": {"version": 18}},
|
||||
{"agent": "Stream",
|
||||
"url": "ws://localhost:8080/examples/websocket/echoStreamAnnotation",
|
||||
"options": {"version": 18}},
|
||||
{"agent": "Async",
|
||||
"url": "ws://localhost:8080/examples/websocket/echoAsyncAnnotation",
|
||||
"options": {"version": 18}}
|
||||
],
|
||||
|
||||
"cases": ["*"],
|
||||
"exclude-cases": [],
|
||||
"exclude-agent-cases": {}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
150
webapps/examples/WEB-INF/classes/websocket/snake/Snake.java
Normal file
150
webapps/examples/WEB-INF/classes/websocket/snake/Snake.java
Normal file
@@ -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<>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
115
webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.java
Normal file
115
webapps/examples/WEB-INF/classes/websocket/snake/SnakeTimer.java
Normal file
@@ -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<>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
230
webapps/examples/WEB-INF/jsp/applet/Clock2.java
Normal file
230
webapps/examples/WEB-INF/jsp/applet/Clock2.java
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Time!
|
||||
*
|
||||
* @author Rachel Gollub
|
||||
*/
|
||||
|
||||
public class Clock2 extends Applet implements Runnable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
Thread timer; // The thread that displays clock
|
||||
int lastxs, lastys, lastxm,
|
||||
lastym, lastxh, lastyh; // Dimensions used to draw hands
|
||||
SimpleDateFormat formatter; // Formats the date displayed
|
||||
String lastdate; // String to hold date displayed
|
||||
Font clockFaceFont; // Font for number display on clock
|
||||
Date currentDate; // Used to get date to display
|
||||
Color handColor; // Color of main hands and dial
|
||||
Color numberColor; // Color of second hand and numbers
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0;
|
||||
formatter = new SimpleDateFormat ("EEE MMM dd hh:mm:ss yyyy", Locale.getDefault());
|
||||
currentDate = new Date();
|
||||
lastdate = formatter.format(currentDate);
|
||||
clockFaceFont = new Font("Serif", Font.PLAIN, 14);
|
||||
handColor = Color.blue;
|
||||
numberColor = Color.darkGray;
|
||||
|
||||
try {
|
||||
setBackground(new Color(Integer.parseInt(getParameter("bgcolor"),16)));
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
try {
|
||||
handColor = new Color(Integer.parseInt(getParameter("fgcolor1"),16));
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
try {
|
||||
numberColor = new Color(Integer.parseInt(getParameter("fgcolor2"),16));
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
resize(300,300); // Set clock window size
|
||||
}
|
||||
|
||||
// Plotpoints allows calculation to only cover 45 degrees of the circle,
|
||||
// and then mirror
|
||||
public void plotpoints(int x0, int y0, int x, int y, Graphics g) {
|
||||
g.drawLine(x0+x,y0+y,x0+x,y0+y);
|
||||
g.drawLine(x0+y,y0+x,x0+y,y0+x);
|
||||
g.drawLine(x0+y,y0-x,x0+y,y0-x);
|
||||
g.drawLine(x0+x,y0-y,x0+x,y0-y);
|
||||
g.drawLine(x0-x,y0-y,x0-x,y0-y);
|
||||
g.drawLine(x0-y,y0-x,x0-y,y0-x);
|
||||
g.drawLine(x0-y,y0+x,x0-y,y0+x);
|
||||
g.drawLine(x0-x,y0+y,x0-x,y0+y);
|
||||
}
|
||||
|
||||
// Circle is just Bresenham's algorithm for a scan converted circle
|
||||
public void circle(int x0, int y0, int r, Graphics g) {
|
||||
int x,y;
|
||||
float d;
|
||||
x=0;
|
||||
y=r;
|
||||
d=5/4-r;
|
||||
plotpoints(x0,y0,x,y,g);
|
||||
|
||||
while (y>x){
|
||||
if (d<0) {
|
||||
d=d+2*x+3;
|
||||
x++;
|
||||
}
|
||||
else {
|
||||
d=d+2*(x-y)+5;
|
||||
x++;
|
||||
y--;
|
||||
}
|
||||
plotpoints(x0,y0,x,y,g);
|
||||
}
|
||||
}
|
||||
|
||||
// Paint is the main part of the program
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
int xh, yh, xm, ym, xs, ys, s = 0, m = 10, h = 10, xcenter, ycenter;
|
||||
String today;
|
||||
|
||||
currentDate = new Date();
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("s",Locale.getDefault());
|
||||
try {
|
||||
s = Integer.parseInt(formatter.format(currentDate));
|
||||
} catch (NumberFormatException n) {
|
||||
s = 0;
|
||||
}
|
||||
formatter.applyPattern("m");
|
||||
try {
|
||||
m = Integer.parseInt(formatter.format(currentDate));
|
||||
} catch (NumberFormatException n) {
|
||||
m = 10;
|
||||
}
|
||||
formatter.applyPattern("h");
|
||||
try {
|
||||
h = Integer.parseInt(formatter.format(currentDate));
|
||||
} catch (NumberFormatException n) {
|
||||
h = 10;
|
||||
}
|
||||
formatter.applyPattern("EEE MMM dd HH:mm:ss yyyy");
|
||||
today = formatter.format(currentDate);
|
||||
xcenter=80;
|
||||
ycenter=55;
|
||||
|
||||
// a= s* pi/2 - pi/2 (to switch 0,0 from 3:00 to 12:00)
|
||||
// x = r(cos a) + xcenter, y = r(sin a) + ycenter
|
||||
|
||||
xs = (int)(Math.cos(s * Math.PI/30 - Math.PI/2) * 45 + xcenter);
|
||||
ys = (int)(Math.sin(s * Math.PI/30 - Math.PI/2) * 45 + ycenter);
|
||||
xm = (int)(Math.cos(m * Math.PI/30 - Math.PI/2) * 40 + xcenter);
|
||||
ym = (int)(Math.sin(m * Math.PI/30 - Math.PI/2) * 40 + ycenter);
|
||||
xh = (int)(Math.cos((h*30 + m/2) * Math.PI/180 - Math.PI/2) * 30 + xcenter);
|
||||
yh = (int)(Math.sin((h*30 + m/2) * Math.PI/180 - Math.PI/2) * 30 + ycenter);
|
||||
|
||||
// Draw the circle and numbers
|
||||
|
||||
g.setFont(clockFaceFont);
|
||||
g.setColor(handColor);
|
||||
circle(xcenter,ycenter,50,g);
|
||||
g.setColor(numberColor);
|
||||
g.drawString("9",xcenter-45,ycenter+3);
|
||||
g.drawString("3",xcenter+40,ycenter+3);
|
||||
g.drawString("12",xcenter-5,ycenter-37);
|
||||
g.drawString("6",xcenter-3,ycenter+45);
|
||||
|
||||
// Erase if necessary, and redraw
|
||||
|
||||
g.setColor(getBackground());
|
||||
if (xs != lastxs || ys != lastys) {
|
||||
g.drawLine(xcenter, ycenter, lastxs, lastys);
|
||||
g.drawString(lastdate, 5, 125);
|
||||
}
|
||||
if (xm != lastxm || ym != lastym) {
|
||||
g.drawLine(xcenter, ycenter-1, lastxm, lastym);
|
||||
g.drawLine(xcenter-1, ycenter, lastxm, lastym); }
|
||||
if (xh != lastxh || yh != lastyh) {
|
||||
g.drawLine(xcenter, ycenter-1, lastxh, lastyh);
|
||||
g.drawLine(xcenter-1, ycenter, lastxh, lastyh); }
|
||||
g.setColor(numberColor);
|
||||
g.drawString("", 5, 125);
|
||||
g.drawString(today, 5, 125);
|
||||
g.drawLine(xcenter, ycenter, xs, ys);
|
||||
g.setColor(handColor);
|
||||
g.drawLine(xcenter, ycenter-1, xm, ym);
|
||||
g.drawLine(xcenter-1, ycenter, xm, ym);
|
||||
g.drawLine(xcenter, ycenter-1, xh, yh);
|
||||
g.drawLine(xcenter-1, ycenter, xh, yh);
|
||||
lastxs=xs; lastys=ys;
|
||||
lastxm=xm; lastym=ym;
|
||||
lastxh=xh; lastyh=yh;
|
||||
lastdate = today;
|
||||
currentDate=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
timer = new Thread(this);
|
||||
timer.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
timer = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Thread me = Thread.currentThread();
|
||||
while (timer == me) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Graphics g) {
|
||||
paint(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAppletInfo() {
|
||||
return "Title: A Clock \nAuthor: Rachel Gollub, 1995 \nAn analog clock.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[][] getParameterInfo() {
|
||||
String[][] info = {
|
||||
{"bgcolor", "hexadecimal RGB number", "The background color. Default is the color of your browser."},
|
||||
{"fgcolor1", "hexadecimal RGB number", "The color of the hands and dial. Default is blue."},
|
||||
{"fgcolor2", "hexadecimal RGB number", "The color of the seconds hand and numbers. Default is dark gray."}
|
||||
};
|
||||
return info;
|
||||
}
|
||||
}
|
||||
54
webapps/examples/WEB-INF/jsp/debug-taglib.tld
Normal file
54
webapps/examples/WEB-INF/jsp/debug-taglib.tld
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!DOCTYPE taglib
|
||||
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
|
||||
"http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
|
||||
|
||||
<!-- a tag library descriptor -->
|
||||
|
||||
<taglib>
|
||||
<tlib-version>1.0</tlib-version>
|
||||
<jsp-version>1.2</jsp-version>
|
||||
<short-name>debug</short-name>
|
||||
<uri>http://tomcat.apache.org/debug-taglib</uri>
|
||||
<description>
|
||||
This tag library defines no tags. Instead, its purpose is encapsulated
|
||||
in the TagLibraryValidator implementation that simply outputs the XML
|
||||
version of a JSP page to standard output, whenever this tag library is
|
||||
referenced in a "taglib" directive in a JSP page.
|
||||
</description>
|
||||
<validator>
|
||||
<validator-class>validators.DebugValidator</validator-class>
|
||||
</validator>
|
||||
|
||||
<!-- This is a dummy tag solely to satisfy DTD requirements -->
|
||||
<tag>
|
||||
<name>log</name>
|
||||
<tag-class>examples.LogTag</tag-class>
|
||||
<body-content>TAGDEPENDENT</body-content>
|
||||
<description>
|
||||
Perform a server side action; Log the message.
|
||||
</description>
|
||||
<attribute>
|
||||
<name>toBrowser</name>
|
||||
<required>false</required>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
|
||||
</taglib>
|
||||
107
webapps/examples/WEB-INF/jsp/example-taglib.tld
Normal file
107
webapps/examples/WEB-INF/jsp/example-taglib.tld
Normal file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!DOCTYPE taglib
|
||||
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
|
||||
"http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
|
||||
|
||||
<taglib>
|
||||
|
||||
<tlib-version>1.0</tlib-version>
|
||||
<jsp-version>1.2</jsp-version>
|
||||
<short-name>simple</short-name>
|
||||
<uri>http://tomcat.apache.org/example-taglib</uri>
|
||||
<description>
|
||||
A simple tab library for the examples
|
||||
</description>
|
||||
|
||||
<!-- A simple Tag -->
|
||||
<!-- foo tag -->
|
||||
<tag>
|
||||
<name>foo</name>
|
||||
<tag-class>examples.FooTag</tag-class>
|
||||
<tei-class>examples.FooTagExtraInfo</tei-class>
|
||||
<body-content>JSP</body-content>
|
||||
<description>
|
||||
Perform a server side action; uses 3 mandatory attributes
|
||||
</description>
|
||||
|
||||
<attribute>
|
||||
<name>att1</name>
|
||||
<required>true</required>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>att2</name>
|
||||
<required>true</required>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>att3</name>
|
||||
<required>true</required>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<!-- Another simple tag -->
|
||||
<!-- log tag -->
|
||||
<tag>
|
||||
<name>log</name>
|
||||
<tag-class>examples.LogTag</tag-class>
|
||||
<body-content>TAGDEPENDENT</body-content>
|
||||
<description>
|
||||
Perform a server side action; Log the message.
|
||||
</description>
|
||||
<attribute>
|
||||
<name>toBrowser</name>
|
||||
<required>false</required>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<!-- Another simple Tag -->
|
||||
<!-- values tag -->
|
||||
<tag>
|
||||
<name>values</name>
|
||||
<tag-class>examples.ValuesTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
<description>
|
||||
Accept and return values of different types. This tag is used
|
||||
to illustrate type coercions.
|
||||
</description>
|
||||
<attribute>
|
||||
<name>object</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<type>java.lang.Object</type>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>string</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<type>java.lang.String</type>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>long</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<type>long</type>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>double</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
<type>double</type>
|
||||
</attribute>
|
||||
</tag>
|
||||
</taglib>
|
||||
124
webapps/examples/WEB-INF/jsp2/jsp2-example-taglib.tld
Normal file
124
webapps/examples/WEB-INF/jsp2/jsp2-example-taglib.tld
Normal file
@@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
|
||||
version="2.0">
|
||||
<description>A tag library exercising SimpleTag handlers.</description>
|
||||
<tlib-version>1.0</tlib-version>
|
||||
<short-name>SimpleTagLibrary</short-name>
|
||||
<uri>http://tomcat.apache.org/jsp2-example-taglib</uri>
|
||||
<tag>
|
||||
<description>Outputs Hello, World</description>
|
||||
<name>helloWorld</name>
|
||||
<tag-class>jsp2.examples.simpletag.HelloWorldSimpleTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
</tag>
|
||||
<tag>
|
||||
<description>Repeats the body of the tag 'num' times</description>
|
||||
<name>repeat</name>
|
||||
<tag-class>jsp2.examples.simpletag.RepeatSimpleTag</tag-class>
|
||||
<body-content>scriptless</body-content>
|
||||
<variable>
|
||||
<description>Current invocation count (1 to num)</description>
|
||||
<name-given>count</name-given>
|
||||
</variable>
|
||||
<attribute>
|
||||
<name>num</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
<tag>
|
||||
<description>Populates the page context with a BookBean</description>
|
||||
<name>findBook</name>
|
||||
<tag-class>jsp2.examples.simpletag.FindBookSimpleTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
<attribute>
|
||||
<name>var</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
<tag>
|
||||
<description>
|
||||
Takes 3 fragments and invokes them in a random order
|
||||
</description>
|
||||
<name>shuffle</name>
|
||||
<tag-class>jsp2.examples.simpletag.ShuffleSimpleTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
<attribute>
|
||||
<name>fragment1</name>
|
||||
<required>true</required>
|
||||
<fragment>true</fragment>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>fragment2</name>
|
||||
<required>true</required>
|
||||
<fragment>true</fragment>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>fragment3</name>
|
||||
<required>true</required>
|
||||
<fragment>true</fragment>
|
||||
</attribute>
|
||||
</tag>
|
||||
<tag>
|
||||
<description>Outputs a colored tile</description>
|
||||
<name>tile</name>
|
||||
<tag-class>jsp2.examples.simpletag.TileSimpleTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
<attribute>
|
||||
<name>color</name>
|
||||
<required>true</required>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name>label</name>
|
||||
<required>true</required>
|
||||
</attribute>
|
||||
</tag>
|
||||
<tag>
|
||||
<description>
|
||||
Tag that echoes all its attributes and body content
|
||||
</description>
|
||||
<name>echoAttributes</name>
|
||||
<tag-class>jsp2.examples.simpletag.EchoAttributesTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
<dynamic-attributes>true</dynamic-attributes>
|
||||
</tag>
|
||||
<function>
|
||||
<description>Reverses the characters in the given String</description>
|
||||
<name>reverse</name>
|
||||
<function-class>jsp2.examples.el.Functions</function-class>
|
||||
<function-signature>java.lang.String reverse( java.lang.String )</function-signature>
|
||||
</function>
|
||||
<function>
|
||||
<description>Counts the number of vowels (a,e,i,o,u) in the given String</description>
|
||||
<name>countVowels</name>
|
||||
<function-class>jsp2.examples.el.Functions</function-class>
|
||||
<function-signature>java.lang.String numVowels( java.lang.String )</function-signature>
|
||||
</function>
|
||||
<function>
|
||||
<description>Converts the string to all caps</description>
|
||||
<name>caps</name>
|
||||
<function-class>jsp2.examples.el.Functions</function-class>
|
||||
<function-signature>java.lang.String caps( java.lang.String )</function-signature>
|
||||
</function>
|
||||
</taglib>
|
||||
|
||||
BIN
webapps/examples/WEB-INF/lib/taglibs-standard-impl-1.2.5.jar
Normal file
BIN
webapps/examples/WEB-INF/lib/taglibs-standard-impl-1.2.5.jar
Normal file
Binary file not shown.
BIN
webapps/examples/WEB-INF/lib/taglibs-standard-spec-1.2.5.jar
Normal file
BIN
webapps/examples/WEB-INF/lib/taglibs-standard-spec-1.2.5.jar
Normal file
Binary file not shown.
55
webapps/examples/WEB-INF/tags/displayProducts.tag
Normal file
55
webapps/examples/WEB-INF/tags/displayProducts.tag
Normal file
@@ -0,0 +1,55 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ attribute name="normalPrice" fragment="true" %>
|
||||
<%@ attribute name="onSale" fragment="true" %>
|
||||
<%@ variable name-given="name" %>
|
||||
<%@ variable name-given="price" %>
|
||||
<%@ variable name-given="origPrice" %>
|
||||
<%@ variable name-given="salePrice" %>
|
||||
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td>
|
||||
<c:set var="name" value="Hand-held Color PDA"/>
|
||||
<c:set var="price" value="$298.86"/>
|
||||
<jsp:invoke fragment="normalPrice"/>
|
||||
</td>
|
||||
<td>
|
||||
<c:set var="name" value="4-Pack 150 Watt Light Bulbs"/>
|
||||
<c:set var="origPrice" value="$2.98"/>
|
||||
<c:set var="salePrice" value="$2.32"/>
|
||||
<jsp:invoke fragment="onSale"/>
|
||||
</td>
|
||||
<td>
|
||||
<c:set var="name" value="Digital Cellular Phone"/>
|
||||
<c:set var="price" value="$68.74"/>
|
||||
<jsp:invoke fragment="normalPrice"/>
|
||||
</td>
|
||||
<td>
|
||||
<c:set var="name" value="Baby Grand Piano"/>
|
||||
<c:set var="price" value="$10,800.00"/>
|
||||
<jsp:invoke fragment="normalPrice"/>
|
||||
</td>
|
||||
<td>
|
||||
<c:set var="name" value="Luxury Car w/ Leather Seats"/>
|
||||
<c:set var="origPrice" value="$23,980.00"/>
|
||||
<c:set var="salePrice" value="$21,070.00"/>
|
||||
<jsp:invoke fragment="onSale"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
17
webapps/examples/WEB-INF/tags/helloWorld.tag
Normal file
17
webapps/examples/WEB-INF/tags/helloWorld.tag
Normal file
@@ -0,0 +1,17 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
Hello, world!
|
||||
29
webapps/examples/WEB-INF/tags/panel.tag
Normal file
29
webapps/examples/WEB-INF/tags/panel.tag
Normal file
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<%@ attribute name="color" %>
|
||||
<%@ attribute name="bgcolor" %>
|
||||
<%@ attribute name="title" %>
|
||||
<table border="1" bgcolor="${color}">
|
||||
<tr>
|
||||
<td><b>${title}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor="${bgcolor}">
|
||||
<jsp:doBody/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
399
webapps/examples/WEB-INF/web.xml
Normal file
399
webapps/examples/WEB-INF/web.xml
Normal file
@@ -0,0 +1,399 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1"
|
||||
metadata-complete="true">
|
||||
|
||||
<description>
|
||||
Servlet and JSP Examples.
|
||||
</description>
|
||||
<display-name>Servlet and JSP Examples</display-name>
|
||||
|
||||
<!-- Define example filters -->
|
||||
<filter>
|
||||
<filter-name>Timing Filter</filter-name>
|
||||
<filter-class>filters.ExampleFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>attribute</param-name>
|
||||
<param-value>filters.ExampleFilter</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<filter-name>Request Dumper Filter</filter-name>
|
||||
<filter-class>org.apache.catalina.filters.RequestDumperFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<!-- Example filter to set character encoding on each request -->
|
||||
<filter>
|
||||
<filter-name>Set Character Encoding</filter-name>
|
||||
<filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
<init-param>
|
||||
<param-name>encoding</param-name>
|
||||
<param-value>UTF-8</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>ignore</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<filter-name>Compression Filter</filter-name>
|
||||
<filter-class>compressionFilters.CompressionFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>compressionThreshold</param-name>
|
||||
<param-value>128</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>compressionBuffer</param-name>
|
||||
<param-value>8192</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>compressionMimeTypes</param-name>
|
||||
<param-value>text/html,text/plain,text/xml</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>debug</param-name>
|
||||
<param-value>0</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<!-- Define filter mappings for the timing filters -->
|
||||
<!--
|
||||
<filter-mapping>
|
||||
<filter-name>Timing Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
-->
|
||||
|
||||
<!-- Example filter mapping to apply the "Set Character Encoding" filter
|
||||
to *all* requests processed by this web application -->
|
||||
<filter-mapping>
|
||||
<filter-name>Set Character Encoding</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!--
|
||||
<filter-mapping>
|
||||
<filter-name>Compression Filter</filter-name>
|
||||
<url-pattern>/CompressionTest</url-pattern>
|
||||
</filter-mapping>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<filter-mapping>
|
||||
<filter-name>Request Dumper Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
-->
|
||||
|
||||
<!-- Define example application events listeners -->
|
||||
<listener>
|
||||
<listener-class>listeners.ContextListener</listener-class>
|
||||
</listener>
|
||||
<listener>
|
||||
<listener-class>listeners.SessionListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Define listeners required by examples -->
|
||||
<listener>
|
||||
<listener-class>async.AsyncStockContextListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Define servlets that are included in the example application -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>ServletToJsp</servlet-name>
|
||||
<servlet-class>ServletToJsp</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>CompressionFilterTestServlet</servlet-name>
|
||||
<servlet-class>compressionFilters.CompressionFilterTestServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>HelloWorldExample</servlet-name>
|
||||
<servlet-class>HelloWorldExample</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RequestInfoExample</servlet-name>
|
||||
<servlet-class>RequestInfoExample</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RequestHeaderExample</servlet-name>
|
||||
<servlet-class>RequestHeaderExample</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>RequestParamExample</servlet-name>
|
||||
<servlet-class>RequestParamExample</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>CookieExample</servlet-name>
|
||||
<servlet-class>CookieExample</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>SessionExample</servlet-name>
|
||||
<servlet-class>SessionExample</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>CompressionFilterTestServlet</servlet-name>
|
||||
<url-pattern>/CompressionTest</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>HelloWorldExample</servlet-name>
|
||||
<url-pattern>/servlets/servlet/HelloWorldExample</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RequestInfoExample</servlet-name>
|
||||
<url-pattern>/servlets/servlet/RequestInfoExample/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RequestHeaderExample</servlet-name>
|
||||
<url-pattern>/servlets/servlet/RequestHeaderExample</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>RequestParamExample</servlet-name>
|
||||
<url-pattern>/servlets/servlet/RequestParamExample</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>CookieExample</servlet-name>
|
||||
<url-pattern>/servlets/servlet/CookieExample</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>SessionExample</servlet-name>
|
||||
<url-pattern>/servlets/servlet/SessionExample</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ServletToJsp</servlet-name>
|
||||
<url-pattern>/servletToJsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<jsp-config>
|
||||
<taglib>
|
||||
<taglib-uri>
|
||||
http://tomcat.apache.org/debug-taglib
|
||||
</taglib-uri>
|
||||
<taglib-location>
|
||||
/WEB-INF/jsp/debug-taglib.tld
|
||||
</taglib-location>
|
||||
</taglib>
|
||||
|
||||
<taglib>
|
||||
<taglib-uri>
|
||||
http://tomcat.apache.org/example-taglib
|
||||
</taglib-uri>
|
||||
<taglib-location>
|
||||
/WEB-INF/jsp/example-taglib.tld
|
||||
</taglib-location>
|
||||
</taglib>
|
||||
|
||||
<taglib>
|
||||
<taglib-uri>
|
||||
http://tomcat.apache.org/jsp2-example-taglib
|
||||
</taglib-uri>
|
||||
<taglib-location>
|
||||
/WEB-INF/jsp2/jsp2-example-taglib.tld
|
||||
</taglib-location>
|
||||
</taglib>
|
||||
|
||||
<jsp-property-group>
|
||||
<description>
|
||||
Special property group for JSP Configuration JSP example.
|
||||
</description>
|
||||
<display-name>JSPConfiguration</display-name>
|
||||
<url-pattern>/jsp/jsp2/misc/config.jsp</url-pattern>
|
||||
<el-ignored>true</el-ignored>
|
||||
<page-encoding>ISO-8859-1</page-encoding>
|
||||
<scripting-invalid>true</scripting-invalid>
|
||||
<include-prelude>/jsp/jsp2/misc/prelude.jspf</include-prelude>
|
||||
<include-coda>/jsp/jsp2/misc/coda.jspf</include-coda>
|
||||
</jsp-property-group>
|
||||
</jsp-config>
|
||||
|
||||
<security-constraint>
|
||||
<display-name>Example Security Constraint - part 1</display-name>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Protected Area - Allow methods</web-resource-name>
|
||||
<!-- Define the context-relative URL(s) to be protected -->
|
||||
<url-pattern>/jsp/security/protected/*</url-pattern>
|
||||
<!-- If you list http methods, only those methods are protected so -->
|
||||
<!-- the constraint below ensures all other methods are denied -->
|
||||
<http-method>DELETE</http-method>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>POST</http-method>
|
||||
<http-method>PUT</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<!-- Anyone with one of the listed roles may access this area -->
|
||||
<role-name>tomcat</role-name>
|
||||
<role-name>role1</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<display-name>Example Security Constraint - part 2</display-name>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Protected Area - Deny methods</web-resource-name>
|
||||
<!-- Define the context-relative URL(s) to be protected -->
|
||||
<url-pattern>/jsp/security/protected/*</url-pattern>
|
||||
<http-method-omission>DELETE</http-method-omission>
|
||||
<http-method-omission>GET</http-method-omission>
|
||||
<http-method-omission>POST</http-method-omission>
|
||||
<http-method-omission>PUT</http-method-omission>
|
||||
</web-resource-collection>
|
||||
<!-- An empty auth constraint denies access -->
|
||||
<auth-constraint />
|
||||
</security-constraint>
|
||||
|
||||
<!-- Default login configuration uses form-based authentication -->
|
||||
<login-config>
|
||||
<auth-method>FORM</auth-method>
|
||||
<realm-name>Example Form-Based Authentication Area</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/jsp/security/protected/login.jsp</form-login-page>
|
||||
<form-error-page>/jsp/security/protected/error.jsp</form-error-page>
|
||||
</form-login-config>
|
||||
</login-config>
|
||||
|
||||
<!-- Security roles referenced by this web application -->
|
||||
<security-role>
|
||||
<role-name>role1</role-name>
|
||||
</security-role>
|
||||
<security-role>
|
||||
<role-name>tomcat</role-name>
|
||||
</security-role>
|
||||
|
||||
<!-- Environment entry examples -->
|
||||
<!--env-entry>
|
||||
<env-entry-description>
|
||||
The maximum number of tax exemptions allowed to be set.
|
||||
</env-entry-description>
|
||||
<env-entry-name>maxExemptions</env-entry-name>
|
||||
<env-entry-type>java.lang.Integer</env-entry-type>
|
||||
<env-entry-value>15</env-entry-value>
|
||||
</env-entry-->
|
||||
<env-entry>
|
||||
<env-entry-name>minExemptions</env-entry-name>
|
||||
<env-entry-type>java.lang.Integer</env-entry-type>
|
||||
<env-entry-value>1</env-entry-value>
|
||||
</env-entry>
|
||||
<env-entry>
|
||||
<env-entry-name>foo/name1</env-entry-name>
|
||||
<env-entry-type>java.lang.String</env-entry-type>
|
||||
<env-entry-value>value1</env-entry-value>
|
||||
</env-entry>
|
||||
<env-entry>
|
||||
<env-entry-name>foo/bar/name2</env-entry-name>
|
||||
<env-entry-type>java.lang.Boolean</env-entry-type>
|
||||
<env-entry-value>true</env-entry-value>
|
||||
</env-entry>
|
||||
<env-entry>
|
||||
<env-entry-name>name3</env-entry-name>
|
||||
<env-entry-type>java.lang.Integer</env-entry-type>
|
||||
<env-entry-value>1</env-entry-value>
|
||||
</env-entry>
|
||||
<env-entry>
|
||||
<env-entry-name>foo/name4</env-entry-name>
|
||||
<env-entry-type>java.lang.Integer</env-entry-type>
|
||||
<env-entry-value>10</env-entry-value>
|
||||
</env-entry>
|
||||
|
||||
<!-- Async examples -->
|
||||
<servlet>
|
||||
<servlet-name>async0</servlet-name>
|
||||
<servlet-class>async.Async0</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>async0</servlet-name>
|
||||
<url-pattern>/async/async0</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>async1</servlet-name>
|
||||
<servlet-class>async.Async1</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>async1</servlet-name>
|
||||
<url-pattern>/async/async1</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>async2</servlet-name>
|
||||
<servlet-class>async.Async2</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>async2</servlet-name>
|
||||
<url-pattern>/async/async2</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>async3</servlet-name>
|
||||
<servlet-class>async.Async3</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>async3</servlet-name>
|
||||
<url-pattern>/async/async3</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>stock</servlet-name>
|
||||
<servlet-class>async.AsyncStockServlet</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>stock</servlet-name>
|
||||
<url-pattern>/async/stockticker</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Non-blocking IO examples -->
|
||||
<servlet>
|
||||
<servlet-name>bytecounter</servlet-name>
|
||||
<servlet-class>nonblocking.ByteCounter</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>bytecounter</servlet-name>
|
||||
<url-pattern>/servlets/nonblocking/bytecounter</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet>
|
||||
<servlet-name>numberwriter</servlet-name>
|
||||
<servlet-class>nonblocking.NumberWriter</servlet-class>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>numberwriter</servlet-name>
|
||||
<url-pattern>/servlets/nonblocking/numberwriter</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.xhtml</welcome-file>
|
||||
<welcome-file>index.htm</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<!-- Websocket examples -->
|
||||
<listener>
|
||||
<listener-class>websocket.drawboard.DrawboardContextListener</listener-class>
|
||||
</listener>
|
||||
|
||||
</web-app>
|
||||
30
webapps/examples/index.html
Normal file
30
webapps/examples/index.html
Normal file
@@ -0,0 +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.
|
||||
-->
|
||||
<!DOCTYPE HTML><html lang="en"><head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Apache Tomcat Examples</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<h3>Apache Tomcat Examples</H3>
|
||||
<p></p>
|
||||
<ul>
|
||||
<li><a href="servlets">Servlets examples</a></li>
|
||||
<li><a href="jsp">JSP Examples</a></li>
|
||||
<li><a href="websocket/index.xhtml">WebSocket Examples</a></li>
|
||||
</ul>
|
||||
</body></html>
|
||||
28
webapps/examples/jsp/async/async1.jsp
Normal file
28
webapps/examples/jsp/async/async1.jsp
Normal file
@@ -0,0 +1,28 @@
|
||||
<%--
|
||||
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.
|
||||
--%>
|
||||
<%@page session="false" import="java.util.Date,java.text.SimpleDateFormat"%>
|
||||
Output from async1.jsp
|
||||
Type is <%=request.getDispatcherType()%>
|
||||
<%
|
||||
System.out.println("Inside Async 1");
|
||||
if (request.isAsyncStarted()) {
|
||||
request.getAsyncContext().complete();
|
||||
}
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
%>
|
||||
Completed async request at <%=sdf.format(date)%>
|
||||
25
webapps/examples/jsp/async/async3.jsp
Normal file
25
webapps/examples/jsp/async/async3.jsp
Normal file
@@ -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.
|
||||
--%>
|
||||
<%@page session="false" import="java.util.Date,java.text.SimpleDateFormat"%>
|
||||
Output from async3.jsp
|
||||
Type is <%=request.getDispatcherType()%>
|
||||
<%
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
%>
|
||||
|
||||
Completed async 3 request at <%=sdf.format(date)%>
|
||||
69
webapps/examples/jsp/async/index.jsp
Normal file
69
webapps/examples/jsp/async/index.jsp
Normal file
@@ -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.
|
||||
--%>
|
||||
<%@page session="false"%>
|
||||
|
||||
<pre>
|
||||
Use cases:
|
||||
|
||||
1. Simple dispatch
|
||||
- servlet does startAsync()
|
||||
- background thread calls ctx.dispatch()
|
||||
<a href="<%=response.encodeURL("/examples/async/async0")%>"> Async 0 </a>
|
||||
|
||||
2. Simple dispatch
|
||||
- servlet does startAsync()
|
||||
- background thread calls dispatch(/path/to/jsp)
|
||||
<a href="<%=response.encodeURL("/examples/async/async1")%>"> Async 1 </a>
|
||||
|
||||
3. Simple dispatch
|
||||
- servlet does startAsync()
|
||||
- background thread calls writes and calls complete()
|
||||
<a href="<%=response.encodeURL("/examples/async/async2")%>"> Async 2 </a>
|
||||
|
||||
4. Simple dispatch
|
||||
- servlet does a startAsync()
|
||||
- servlet calls dispatch(/path/to/jsp)
|
||||
- servlet calls complete()
|
||||
<a href="<%=response.encodeURL("/examples/async/async3")%>"> Async 3 </a>
|
||||
|
||||
3. Timeout s1
|
||||
- servlet does a startAsync()
|
||||
- servlet does a setAsyncTimeout
|
||||
- returns - waits for timeout to happen should return error page
|
||||
|
||||
4. Timeout s2
|
||||
- servlet does a startAsync()
|
||||
- servlet does a setAsyncTimeout
|
||||
- servlet does a addAsyncListener
|
||||
- returns - waits for timeout to happen and listener invoked
|
||||
|
||||
5. Dispatch to asyncSupported=false servlet
|
||||
- servlet1 does a startAsync()
|
||||
- servlet1 dispatches to dispatch(/servlet2)
|
||||
- the container calls complete() after servlet2 is complete
|
||||
- TODO
|
||||
|
||||
6. Chained dispatch
|
||||
- servlet1 does a startAsync
|
||||
- servlet1 does a dispatch to servlet2 (asyncsupported=true)
|
||||
- servlet2 does a dispatch to servlet3 (asyncsupported=true)
|
||||
- servlet3 does a dispatch to servlet4 (asyncsupported=false)
|
||||
|
||||
|
||||
7. Stock ticker
|
||||
<a href="<%=response.encodeURL("/examples/async/stockticker")%>"> StockTicker </a>
|
||||
</pre>
|
||||
94
webapps/examples/jsp/cal/cal1.jsp
Normal file
94
webapps/examples/jsp/cal/cal1.jsp
Normal file
@@ -0,0 +1,94 @@
|
||||
<%--
|
||||
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.
|
||||
--%>
|
||||
<%@page contentType="text/html; charset=UTF-8" %>
|
||||
<HTML>
|
||||
<HEAD><TITLE>
|
||||
Calendar: A JSP APPLICATION
|
||||
</TITLE></HEAD>
|
||||
|
||||
|
||||
<BODY BGCOLOR="white">
|
||||
|
||||
<%@ page language="java" import="cal.*" %>
|
||||
<jsp:useBean id="table" scope="session" class="cal.TableBean" />
|
||||
|
||||
<%
|
||||
table.processRequest(request);
|
||||
if (table.getProcessError() == false) {
|
||||
%>
|
||||
|
||||
<!-- html table goes here -->
|
||||
<CENTER>
|
||||
<TABLE WIDTH=60% BGCOLOR=yellow CELLPADDING=15>
|
||||
<TR>
|
||||
<TD ALIGN=CENTER> <A HREF=cal1.jsp?date=prev> prev </A>
|
||||
<TD ALIGN=CENTER> Calendar:<%= table.getDate() %></TD>
|
||||
<TD ALIGN=CENTER> <A HREF=cal1.jsp?date=next> next </A>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<!-- the main table -->
|
||||
<TABLE WIDTH=60% BGCOLOR=lightblue BORDER=1 CELLPADDING=10>
|
||||
<TR>
|
||||
<TH> Time </TH>
|
||||
<TH> Appointment </TH>
|
||||
</TR>
|
||||
<FORM METHOD=POST ACTION=cal1.jsp>
|
||||
<%
|
||||
for(int i=0; i<table.getEntries().getRows(); i++) {
|
||||
cal.Entry entr = table.getEntries().getEntry(i);
|
||||
%>
|
||||
<TR>
|
||||
<TD>
|
||||
<A HREF=cal2.jsp?time=<%= entr.getHour() %>>
|
||||
<%= entr.getHour() %> </A>
|
||||
</TD>
|
||||
<TD BGCOLOR=<%= entr.getColor() %>>
|
||||
<% out.print(util.HTMLFilter.filter(entr.getDescription())); %>
|
||||
</TD>
|
||||
</TR>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</FORM>
|
||||
</TABLE>
|
||||
<BR>
|
||||
|
||||
<!-- footer -->
|
||||
<TABLE WIDTH=60% BGCOLOR=yellow CELLPADDING=15>
|
||||
<TR>
|
||||
<TD ALIGN=CENTER> <% out.print(util.HTMLFilter.filter(table.getName())); %> :
|
||||
<% out.print(util.HTMLFilter.filter(table.getEmail())); %> </TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
<font size=5>
|
||||
You must enter your name and email address correctly.
|
||||
</font>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
|
||||
45
webapps/examples/jsp/cal/cal2.jsp
Normal file
45
webapps/examples/jsp/cal/cal2.jsp
Normal file
@@ -0,0 +1,45 @@
|
||||
<%--
|
||||
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.
|
||||
--%>
|
||||
<%@page contentType="text/html; charset=UTF-8" %>
|
||||
<HTML>
|
||||
<HEAD><TITLE>
|
||||
Calendar: A JSP APPLICATION
|
||||
</TITLE></HEAD>
|
||||
|
||||
|
||||
<BODY BGCOLOR="white">
|
||||
<jsp:useBean id="table" scope="session" class="cal.TableBean" />
|
||||
|
||||
<%
|
||||
String time = request.getParameter ("time");
|
||||
%>
|
||||
|
||||
<FONT SIZE=5> Please add the following event:
|
||||
<BR> <h3> Date <%= table.getDate() %>
|
||||
<BR> Time <%= util.HTMLFilter.filter(time) %> </h3>
|
||||
</FONT>
|
||||
<FORM METHOD=POST ACTION=cal1.jsp>
|
||||
<BR>
|
||||
<BR> <INPUT NAME="date" TYPE=HIDDEN VALUE="current">
|
||||
<BR> <INPUT NAME="time" TYPE=HIDDEN VALUE="<%= util.HTMLFilter.filter(time) %>">
|
||||
<BR> <h2> Description of the event <INPUT NAME="description" TYPE=TEXT SIZE=20> </h2>
|
||||
<BR> <INPUT TYPE=SUBMIT VALUE="submit">
|
||||
</FORM>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
43
webapps/examples/jsp/cal/calendar.html
Normal file
43
webapps/examples/jsp/cal/calendar.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<html>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<head>
|
||||
<title>Untitled Document</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
<p><font color="#0000FF"><a href="login.html"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
|
||||
|
||||
<h2> Source Code for Calendar Example. <br>
|
||||
<h3><a href="cal1.jsp.html">cal1.jsp<font color="#0000FF"></a>
|
||||
</font> </h3>
|
||||
<h3><a href="cal2.jsp.html">cal2.jsp<font color="#0000FF"></a>
|
||||
</font> </h3>
|
||||
|
||||
<br>
|
||||
<h2> Beans.
|
||||
<h3><a href="TableBean.java.html">TableBean<font color="#0000FF"></a>
|
||||
</font> </h3>
|
||||
<h3><a href="Entries.java.html">Entries<font color="#0000FF"></a>
|
||||
</font> </h3>
|
||||
<h3><a href="Entry.java.html">Entry<font color="#0000FF"></a>
|
||||
</font> </h3>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
47
webapps/examples/jsp/cal/login.html
Normal file
47
webapps/examples/jsp/cal/login.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<html>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<head>
|
||||
<title> Login page for the calendar. </title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="white">
|
||||
<center>
|
||||
|
||||
<font size=7 color="red"> Please Enter the following information: </font>
|
||||
|
||||
<br>
|
||||
<form method=GET action=cal1.jsp>
|
||||
|
||||
<font size=5> Name <input type=text name="name" size=20>
|
||||
</font>
|
||||
<br>
|
||||
<font size=5> Email <input type=text name="email" size=20>
|
||||
</font>
|
||||
<br>
|
||||
<input type=submit name=action value="Submit">
|
||||
|
||||
</form>
|
||||
<hr>
|
||||
<font size=3 color="red"> Note: This application does not implement the complete
|
||||
functionality of a typical calendar application. It demonstrates a way JSP can
|
||||
be used with html tables and forms.</font>
|
||||
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
56
webapps/examples/jsp/checkbox/CheckTest.html
Normal file
56
webapps/examples/jsp/checkbox/CheckTest.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<HTML>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<HEAD>
|
||||
<title>
|
||||
checkbox.CheckTest Bean Properties
|
||||
</title>
|
||||
<BODY BGCOLOR="white">
|
||||
<H2>
|
||||
checkbox.CheckTest Bean Properties
|
||||
</H2>
|
||||
<HR>
|
||||
<DL>
|
||||
<DT>public class <B>CheckTest</B><DT>extends Object</DL>
|
||||
|
||||
<P>
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
|
||||
<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0">
|
||||
<TR BGCOLOR="#EEEEFF">
|
||||
<TD COLSPAN=3><FONT SIZE="+2">
|
||||
<B>Properties Summary</B></FONT></TD>
|
||||
</TR>
|
||||
<TR BGCOLOR="white">
|
||||
<td align="right" valign="top" width="1%">
|
||||
<FONT SIZE="-1">
|
||||
String
|
||||
</FONT></TD>
|
||||
<TD><B>CheckTest:fruit</B>
|
||||
<BR>
|
||||
</TD>
|
||||
<td width="1%">
|
||||
<FONT SIZE="-1">
|
||||
Multi
|
||||
</FONT></TD>
|
||||
</TABLE>
|
||||
<HR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user