Java servlet session not working properly with NGinx, how to fix? - java
I have a site running Java servlet, using tomcat8.5, it's working fine : http://69.197.177.154:8080/GATE_Web/index.jsp
But the guy at the ISP is concerned about security, so he suggested we use NGinx to make it safer, therefore the same app is doing a NGinx Proxy pass through, and is running at : http://gatecybertech.net/
It is not running properly, when I clicked on the buttons, the cursor at the bottom is not moving, and I've notice the "User Count : " at the upper right of the page is increasing quickly, even when there is only one user [ me ] testing the app. I use Java session to keep track of new user sessions, it's working fine in the 1st site, but when working with NGinx, it's not behaving correctly.
Since the app is complicated, in order to quickly figure out why it's not working properly with NGinx, I simplified the app and created another servlet called Test_Servlet : http://69.197.177.154:8080/GATE_Web/Test_Servlet
As you can see, when you click on different buttons, the cursor with follow and point to the clicked button.
The same Test_Servlet running with NGinx is at : http://gatecybertech.net/Test_Servlet
With this one, the cursor won't follow the button you click on.
I suspect the config for the NGinx is not properly set, what do you think is wrong with it ?
And here is the simplified servlet.
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import Utility.*;
public class Test_Servlet extends HttpServlet
{
private boolean Debug=false;
String App_Id="Test_Servlet",GATE_Title,User_Id=null,Profile="Profile",requestMethod,
Spaces_Text=" ",Line_Breaks="<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n<P><Br>\n";
public Test_Servlet()
{
super();
GATE_Title="<Table Border=0 Cellpadding=0 Cellspacing=8>\n"+
" <Tr><Td Align=Center><Font Color=#3636CC Size=2>Server : [Server_Info] "+Spaces_Text+" User Count : [User_Count]</Font></Td></Tr>\n"+
"</Table>\n";
}
/** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* #param request servlet request
* #param response servlet response
*/
private void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException
{
HttpSession session=request.getSession(true);
Session_Counter counter=(Session_Counter)session.getAttribute(Session_Counter.COUNTER);
int User_Count=counter.getActiveSessionNumber();
String title="Test_Servlet",Server_Info=getServletContext().getServerInfo(),Action,Current_Id_Button,responseText,
responseString="<!DOCTYPE html>\n"+
"<Html>\n"+
"<Head>\n"+
" <Title>"+title+"</Title>\n"+
Get_jQuery()+
" <Link rel=\"stylesheet\" type=\"text/css\" href=\"GATE_Style.css\">\n"+
"</Head>\n\n"+
"<Body BgColor=#C6DAFA>\n\n"+
"<Center>\n"+
"<P><Br><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P><Br><P>\n"+
GATE_Title.replace("[Server_Info]",Server_Info).replace("[User_Count]",User_Count+"")+"<P><P>\n";
LinkedHashMap<String,String> params=getQueryParameterMap(request);
int Font_Size=20,Current_Id;
requestMethod=request.getMethod()+"()";
response.setContentType("text/html");
response.setHeader("Content-Type","text/html;charset=utf-8");
PrintWriter out=response.getWriter();
try
{
User_Id=Decode_String(params.get("User_Id"));
Action=Decode_String(params.get("Action"));
Current_Id_Button=Decode_String(params.get("Current_Id_Button"));
Debug=(params.get("Debug")==null?Debug:params.get("Debug").toLowerCase().equals("true"));
if (session.getAttribute("Current_Id")==null)
{
Current_Id=1;
session.setAttribute("Current_Id",Current_Id+"");
}
else Current_Id=Integer.parseInt((String)session.getAttribute("Current_Id"));
if (Action!=null && Action.equals("Get_Pointer_Table")) // Everytime after Current_Id change, adjust pointer table
{
out.print(Get_Pointer_Table(Current_Id));
// Out(Get_Pointer_Table(Current_Id));
}
else if (Current_Id_Button!=null && Current_Id_Button.startsWith("Current_")) // Current_Id Button is clicked, set Current_Id to it
{
Current_Id=Integer.parseInt(Current_Id_Button.substring(8));
session.setAttribute("Current_Id",Current_Id+"");
}
else if (Action!=null && Action.equals("Current_Id")) // Everytime a symbols/token is clicked, increase Current_Id by one
{
responseText=Current_Id+"";
if (Current_Id<6) Current_Id++;
else Current_Id=1;
session.setAttribute("Current_Id",Current_Id+"");
out.println(responseText);
// Out(" Current_Id = "+Current_Id);
}
else
{
responseString+=Get_Parameters(params)+"<P>\n";
// Object does not exist or is not a file: reject with 404 error.
// responseString+="404 (Not Found)\n";
responseString+="<Br><P><Br><P><Br><P>\n";
Current_Id=1;
session.setAttribute("Current_Id",Current_Id+"");
responseString+="<Table Border=0 Cellpadding=0 Cellspacing=0>\n"+
" <Tr>\n"+
" <Td>\n"+
" <Table Border=0 Cellpadding=0 Cellspacing=3>\n"+
" <Tr>\n"+
" <Td>"+Get_Html_Button("Current_1","1",82,82,Font_Size)+"</Td>\n"+
" <Td>"+Get_Html_Button("Current_2","2",82,82,Font_Size)+"</Td>\n"+
" <Td>"+Get_Html_Button("Current_3","3",82,82,Font_Size)+"</Td>\n"+
" <Td>"+Get_Html_Button("Current_4","4",82,82,Font_Size)+"</Td>\n"+
" <Td>"+Get_Html_Button("Current_5","5",82,82,Font_Size)+"</Td>\n"+
" <Td>"+Get_Html_Button("Current_6","6",82,82,Font_Size)+"</Td>\n"+
" </Tr>\n"+
" </Table>\n"+
" </Td>\n"+
" </Tr>\n"+
" <Tr>\n"+
" <Td>\n"+
Get_Pointer_Table(Current_Id)+
" </Td>\n"+
" </Tr>\n"+
"</Table>\n";
responseString+="</div>\n";
out.println(responseString);
// Out(responseString);
}
}
catch (Exception e)
{
if (!e.toString().equals("java.io.IOException: Broken pipe")) // When user closes a window while half way writing, gets a "Broken pipe"
{
responseString+="<P><Pre>"+e.toString()+"\n"+Tool_Lib_Thin.Get_Stack_Trace(e)+"</Pre>\n";
e.printStackTrace();
}
}
finally
{
try
{
// responseBody.close();
// if (User_Id!=null && User_Id.equals("Stop_Server")) server.stop(0);
}
catch (Exception ex)
{
if (!ex.toString().equals("java.io.IOException: Broken pipe")) // When user closes a window while half way writing, gets a "Broken pipe"
{
ex.printStackTrace();
}
}
}
}
public static String Decode_String(String Input) // Fix this problem : // Error : java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "</"
{
if (Input==null) return null; // Replace "+" with "<plus>", and replace "%" with "<percentage>" won't work. Because characters that get encoded have % and + signs in them,
// so although this helps with % and + characters in a string, yet it doesn't decode things like %20 (space) because you are taking out the percent before decoding.
String Output=""; // Stack overflow solution : https://stackoverflow.com/questions/6067673/urldecoder-illegal-hex-characters-in-escape-pattern-for-input-string
try // A solution is to replace %2B (+) and %25 (%) instead.
{
Output=Input.replaceAll("%(?![0-9a-fA-F]{2})","%25"); // The first replaceAll is the regex that replaces any percent sign that isn't another encoded character with the percent encoded value. The question
Output=Output.replaceAll("\\+","%2B"); // mark makes the proceeding optional, the [0-9a-fA-F] looks for those ranges of characters/numbers and the {2} looks for exactly 2 characters/numbers.
Output=Output.replaceAll("&","&"); // The second replaceAll just replaces the + sign with its encoded value.
Output=URLDecoder.decode(Output,"utf-8");
}
catch (Exception e) { e.printStackTrace(); }
return Output;
}
public LinkedHashMap<String,String> getQueryParameterMap(HttpServletRequest request)
{
LinkedHashMap<String,String> queryParameterMap=new LinkedHashMap();
Map params=request.getParameterMap();
Iterator i=params.keySet().iterator();
while (i.hasNext())
{
String key=(String)i.next();
String value=((String[])params.get(key))[0];
queryParameterMap.put(key,value);
}
return queryParameterMap;
}
String Get_jQuery()
{
return "<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js\"></script>\n"+
"<script>\n"+
"$(document).ready(function()\n"+
"{\n"+
" $('button').not('#Save').not('#Login').click($.now(),function(event)\n"+ // 100% Firefox , IE & Chrome [ OK when click on side if var Clicked_Button=event.target ]
" {\n"+
" if($(this).attr('id').indexOf('Current_')==0) // Clicked on Current_Id_Button \n"+
" {\n"+
" $.get('Test_Servlet?Current_Id_Button='+this.id+'&now='+$.now(),function()\n"+ // use now=$.now() to avoid IE cashing
" {\n"+
" $.get('Test_Servlet?Action=Get_Pointer_Table&now='+$.now(),function(data)\n"+ // data holds new Pointer_Table html, use now=$.now() to avoid IE cashing
" {\n"+ // Get_Pointer_Table must be done here after Current_Id_Button to avoid out of sync
" var Current_Pointer_Table=data;\n"+
" $(\"div.Table\").replaceWith(Current_Pointer_Table);\n"+
" });\n"+
" });\n"+
" }\n"+
// " alert(data);\n"+
" });\n"+
"});\n"+
"</script>\n";
}
String Get_Pointer_Table(int Id)
{
String Pointer_Text="<Font size=4 Color=blue>\u2191</Font><Br><Font size=2 Color=blue>Current</Font>";
return " <div class=\"inner Table\">\n"+
" <Table border=0>\n"+
" <Tr>\n"+
" <Td Align=Center Width=82>"+(Id==1?Pointer_Text:"")+"</Td>\n"+
" <Td Align=Center Width=82>"+(Id==2?Pointer_Text:"")+"</Td>\n"+
" <Td Align=Center Width=82>"+(Id==3?Pointer_Text:"")+"</Td>\n"+
" <Td Align=Center Width=82>"+(Id==4?Pointer_Text:"")+"</Td>\n"+
" <Td Align=Center Width=82>"+(Id==5?Pointer_Text:"")+"</Td>\n"+
" <Td Align=Center Width=82>"+(Id==6?Pointer_Text:"")+"</Td>\n"+
" <Td Width=56> </Td>\n"+
" </Tr>\n"+
" </Table>\n"+
" </div>\n";
}
String Get_Html_Button(String Id,String Text,int W,int H,int Font_Size)
{
return "<button id="+Id+" type=button style=\""+(W<50?"padding: .01em;":"")+"width:"+W+"px;height:"+H+"px;font-size: "+Font_Size+"px\">"+Text+"</button>";
}
String Get_Parameters(Map<String,String> params)
{
String title="Reading All Request Parameters",paramName,paramValue="";
String Parameters_Table="<Table Border=1 Align=Center Cellpadding=5 Cellspacing=2>\n <Tr Bgcolor=#0088FF Colspan=2><Th><Font Color=White>"+title+"</Font></Th></Tr>\n</Table>\n<P>\n"+
"<Font Color=blue>This is class [ "+this.getClass().getName()+" ] using the "+requestMethod+" method [ "+new Date()+" ]</Font><P>\n\n"+
"<Table Border=1 Align=Center Cellpadding=2 Cellspacing=2>\n <Tr Bgcolor=#99CCFF><Th>Parameter Name</Th><Th>Parameter Value(s)</Th></Tr>\n";
for (Map.Entry<String,String> entry : params.entrySet())
{
paramName=entry.getKey().replace("+"," ");
Parameters_Table+=" <Tr><Td Align=Right>"+(paramName.trim().length()<1?" ":paramName)+"</Td>";
try { paramValue=URLDecoder.decode(entry.getValue(),"utf-8"); }
catch (Exception e) { e.printStackTrace(); }
// Out(paramName+" : "+paramValue);
Parameters_Table+="<Td>"+(paramValue.trim().length()<1?" ":paramValue)+"</Td></Tr>\n";
}
Parameters_Table+="</Table>\n";
return Debug?Parameters_Table:"";
}
public LinkedHashMap<String,String> queryToMap(String query) // http://localhost:6600/Resume_App?Id=Edit&File_Name=AT&T.txt
{
// Out("query = "+query);
LinkedHashMap<String,String> result=new LinkedHashMap();
for (String param : query.split("&"))
{
String pair[]=param.split("=");
if (pair.length>1) result.put(pair[0],pair[1]);
else result.put(pair[0],"");
}
return result;
}
private static void out(String message)
{
System.out.print(message);
try { System.out.print(message); }
catch (Exception e) { }
// GATE_App.Log_TextArea.append(message);
}
private static void Out(String message)
{
System.out.println(message);
try { System.out.println(message); }
catch (Exception e) { }
// GATE_App.Log_TextArea.append(message+"\n");
}
/** Handles the HTTP <code>GET</code> method. This method is called when a form has its tag value method equals to get.
* #param request servlet request
* #param response servlet response
*/
public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { processRequest(request,response); }
/** Handles the HTTP <code>POST</code> method. This method is called when a form has its tag value method equals to post.
* #param request servlet request
* #param response servlet response
*/
public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException { processRequest(request,response); }
/** This method is called when a HTTP put request is received.
*
* #param request the request send by the client to the server
* #param response the response send by the server to the client
*/
public void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException
{
// Put your code here
}
/** This method is called when a HTTP delete request is received.
*
* #param request the request send by the client to the server
* #param response the response send by the server to the client
*/
public void doDelete(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException
{
// Put your code here
}
public void destroy() { super.destroy(); }
/**
* Returns information about the servlet, such as
* author, version, and copyright.
*
* #return String information about this servlet
*/
public String getServletInfo() { return "This is servlet : [ "+this.getClass().getName()+" ]"; }
/**
* Initialization of the servlet. <br>
*
* #throws ServletException if an error occurs
*/
public void init() throws ServletException
{
// Put your code here
}
}
=========================================================
package Utility;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.ArrayList;
public class Session_Counter implements HttpSessionListener
{
private List<String> sessions=new ArrayList<>();
public static final String COUNTER="session-counter";
GATE_4_App_Lib GATE_4_app_lib=new GATE_4_App_Lib();
public void sessionCreated(HttpSessionEvent event)
{
System.out.println("Session_Counter.sessionCreated");
HttpSession session=event.getSession();
sessions.add(session.getId());
session.setAttribute(Session_Counter.COUNTER,this);
}
public void sessionDestroyed(HttpSessionEvent event)
{
System.out.println("Session_Counter.sessionDestroyed");
HttpSession session=event.getSession();
sessions.remove(session.getId());
session.setAttribute(Session_Counter.COUNTER,this);
GATE_4_app_lib.Save_To_GATE_Web_Log("[-] Client_IP = "+session.getAttribute("Client_IP")+", Client_Browser = "+session.getAttribute("Client_Browser"));
}
public int getActiveSessionNumber() { return sessions.size(); }
}
Yes, it seems that nginx configuration is not correct
curl -vvv http://gatecybertech.net/Test_Servlet
<skip>
Set-Cookie: JSESSIONID=E3551B683A0FD1A8A17829022A070AE2;path=/GATE_Web;HttpOnly
Your site sets cookie with path /GATE_Web while from the point of a browser the URL is not under this path, so the browser will not send the cookie on subsequent requests, and HTTP session will be started over.
One suggestion is to map to /GATE_Web in nginx as well and use http://gatecybertech.net/GATE_Web/Test_Servlet instead of http://gatecybertech.net/Test_Servlet
Alright, I've solved the problem. By doing the following :
In /opt/tomcat85/conf/context.xml, change "<Context>" to :
<Context sessionCookiePath="/">
...
</Context>
Related
Java - OpenID (Login with Steam)
I have recently had to some trouble trying to get OpenID to work in Java (servlet). I'm trying to make a user able to login to my website using their Steam account. I've tried mutliple libraries but some of them are outdated and for others is almost no documentation available so the library I'm trying right now is JOpenID. It works as expected until I need to verify the information sent back by Steam (http://steamcommunity.com/openid). This is my Servlet: #WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private OpenIdManager manager; static final long ONE_HOUR = 3600000L; static final long TWO_HOUR = ONE_HOUR * 2L; static final String ATTR_MAC = "openid_mac"; static final String ATTR_ALIAS = "openid_alias"; public LoginServlet() { super(); } #Override public void init() throws ServletException { super.init(); manager = new OpenIdManager(); manager.setRealm("http://localhost:8080/TestServletProject/LoginServlet"); manager.setReturnTo("http://localhost:8080/TestServletProject/LoginServlet?login=verify"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); String login = request.getParameter("login"); if(login != null){ if(login.equals("steam")){ out.print("<h2>Redirecting</h2>"); Endpoint endpoint = manager.lookupEndpoint("http://steamcommunity.com/openid"); Association association = manager.lookupAssociation(endpoint); request.getSession().setAttribute(ATTR_MAC, association.getRawMacKey()); request.getSession().setAttribute(ATTR_ALIAS, endpoint.getAlias()); String url = manager.getAuthenticationUrl(endpoint, association); response.sendRedirect(url); }else if(login.equals("verify")){ checkNonce(request.getParameter("openid.response_nonce")); byte[] mac_key = (byte[]) request.getSession().getAttribute(ATTR_MAC); String alias = (String) request.getSession().getAttribute(ATTR_ALIAS); Authentication authentication = manager.getAuthentication(request, mac_key, alias); response.setContentType("text/html; charset=UTF-8"); showAuthentication(response.getWriter(), authentication); return; }else if(login.equals("logout")){ out.print("<h2>Loggin out</h2>"); } return; } String id = (String) request.getSession().getAttribute("steamid"); if (id != null) { out.print("<h2>Welcome "); out.print(id); out.print("</h2>"); out.print("Logout"); } else { out.print("Login"); } } void showAuthentication(PrintWriter pw, Authentication auth) { pw.print("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><title>Test JOpenID</title></head><body><h1>You have successfully signed on!</h1>"); pw.print("<p>Identity: " + auth.getIdentity() + "</p>"); pw.print("<p>Email: " + auth.getEmail() + "</p>"); pw.print("<p>Full name: " + auth.getFullname() + "</p>"); pw.print("<p>First name: " + auth.getFirstname() + "</p>"); pw.print("<p>Last name: " + auth.getLastname() + "</p>"); pw.print("<p>Gender: " + auth.getGender() + "</p>"); pw.print("<p>Language: " + auth.getLanguage() + "</p>"); pw.print("</body></html>"); pw.flush(); } void checkNonce(String nonce) { // check response_nonce to prevent replay-attack: if (nonce==null || nonce.length()<20) throw new OpenIdException("Verify failed."); // make sure the time of server is correct: long nonceTime = getNonceTime(nonce); long diff = Math.abs(System.currentTimeMillis() - nonceTime); if (diff > ONE_HOUR) throw new OpenIdException("Bad nonce time."); if (isNonceExist(nonce)) throw new OpenIdException("Verify nonce failed."); storeNonce(nonce, nonceTime + TWO_HOUR); } private Set<String> nonceDb = new HashSet<String>(); // check if nonce is exist in database: boolean isNonceExist(String nonce) { return nonceDb.contains(nonce); } // store nonce in database: void storeNonce(String nonce, long expires) { nonceDb.add(nonce); } long getNonceTime(String nonce) { try { return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") .parse(nonce.substring(0, 19) + "+0000") .getTime(); } catch(ParseException e) { throw new OpenIdException("Bad nonce time."); } } } I'm getting a org.expressme.openid.OpenIdException: Invalidate handle on line 65: Authentication authentication = manager.getAuthentication(request, mac_key, alias); While doing some research I found out that this had to do with the Assosiaction sent to steam being expired. This is the JOpenID class that causes the OpenIdException: https://github.com/michaelliao/jopenid/blob/master/src/main/java/org/expressme/openid/OpenIdManager.java Does anybody know how I can get this to work, or alternatively, know a better library to use. I'm quite new to this and I'm not sure if I'm using the right library or if there's better ways to do this.
So for anyone still wondering: I looked into the JOpenID code and it seems like the code in the getAuthentication() method that goes before the code that throws the exception is enough to retrieve the Steam ID (which is what I tried to get from Steam). So instead of Authentication authentication = manager.getAuthentication(request, mac_key, alias); I now just put String identity = request.getParameter("openid.identity");. This returns http://steamcommunity.com/openid/id/76561198206376959, last part being the Steam ID.
how to run java on website and to get values to html
i know the question may sound easy to most of you but I am stuck with it. First of all i like to define what i am trying to achieve. on eclipse i am running a piece of code that sends some data over specific port, and via html and javascript i am getting those that it's sent and print them on screen. I have an account from one of free hosting websites. I want to run my code on that website e.g mywebsite.blahblah.com/... and from html file on my computer i want to access that website, get those values produced by java code and print them on screen. I have no idea where to start. the codes are java and html import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Collection; import org.java_websocket.WebSocket; import org.java_websocket.WebSocketImpl; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; public class GPSServer extends WebSocketServer { static int port = 9876; public GPSServer(int port) throws UnknownHostException { super(new InetSocketAddress(port)); } public GPSServer(InetSocketAddress address) { super(address); } public void sendData(String s) { Collection<WebSocket> con = connections(); synchronized (con) { for (WebSocket c : con) { c.send(s); } } } #Override public void onOpen(WebSocket arg0, ClientHandshake arg1) { System.out.println(arg0.getRemoteSocketAddress().getAddress() .getHostAddress() + " connected to the server!"); } #Override public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) { System.out.println(arg0 + " disconnected!"); } #Override public void onError(WebSocket arg0, Exception arg1) { arg1.printStackTrace(); if (arg0 != null) { } } #Override public void onMessage(WebSocket arg0, String arg1) { System.out.println(arg0 + ": " + arg1); } public static Runnable sendData() { Runnable r = new Runnable() { #Override public void run() { WebSocketImpl.DEBUG = true; GPSServer server; try { server = new GPSServer(GPSServer.port); server.start(); System.out.println("GPS server started at port: " + server.getPort()); double longitude = 39.55; double latitude = 22.16; String lng = Double.toString(longitude); String ltd = Double.toString(latitude); String all = lng + "-" + ltd; while (true) { server.sendData(all); /* * server.sendData(Double.toString(longitude)); * System.out.println("longitude sent..."); * server.sendData(Double.toString(latitude)); * System.out.println("latitude sent..."); */ Thread.sleep(5000); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; return r; } public static void main(String[] args) throws UnknownHostException { Thread thread = new Thread(GPSServer.sendData()); thread.start(); } } -- <!DOCTYPE HTML> <html> <head> <script type="text/javascript"> function WebSocketTest() { var lat; var lng; if ("WebSocket" in window) { alert("WebSocket is supported by your Browser!"); console.log("WebSocket is supported by your Browser!"); // Let us open a web socket var ws = new WebSocket("ws://localhost:9876/echo"); ws.onopen = function() { ws.send("Message to send"); alert("Message is sent..."); }; ws.onmessage = function (evt) { var partsArray = evt.data.split('-'); lng=partsArray[0]; lat=partsArray[1]; alert(lat); alert(lng); }; ws.onclose = function() { alert("Connection is closed..."); console.log("Connection is closed..."); }; } else { alert("WebSocket NOT supported by your Browser!"); } } </script> </head> <body> <div id="sse"> Run WebSocket </div> <div> <p id="para"> BASIC HTML!</p> </div> </body> </html> Thanks!
I'm assuming you're very new to all this web development. I haven't studied your code fully but the basic idea is you need a server side scripting language like JSP(of course JSP because you're using Java Code). I hope you know Javascript's basic idea is to use resources on the client's end, or to load data dynamically. So if you're only concerned with displaying some values from server to the client, you can simple make a servlet which will print your data. Following MVC pattern, Controller== Make a servlet which will handle the request made by user(i.e. the link which will show data,basically). Set your Model in this controller once you receive a request(you can decide what to do on GET/POST separately too). Model== Make an abstract representation(class of Java) holding all your data that is to be displayed. View== Here you'll receive the model. In other words, this will be your HTML. You can use JSP helpers to customize the view, the basic idea is to control HOW DATA WILL BE SHOWN TO THE USER(hence the name View). HTML will be automatically generated at run-time and passed to the user. Again, I say I'm assuming you're very new to web development. Please let me know if I haven't understood your question well. Enjoy coding.
Servlet 3: Async - cant PUSH partial response
I am using Tomcat 7. When my asynchronous servlet tries to PUSH partial response to client at different intervals, it does not work.. The response gets flushed only after the whole response is ready. How to PUSH partial response? Here is my code #WebServlet(urlPatterns={"/home"} , name="asynch", asyncSupported=true) public class CometServlet extends HttpServlet { public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { final AsyncContext ac = request.startAsync(); new MyThread(ac).start(); } } What MyThread does is it will write numbers from 1 to 10 to the reponse object at regular intervals. class MyThread extends Thread { AsyncContext ac; public MyThread( AsyncContext ac ) { this.ac = ac; } public void run() { int i =2 ; while( i < 10 ) { try { ac.getResponse().getWriter().print(i + "\n" ); ac.getResponse().getWriter().flush(); ac.getResponse().flushBuffer(); Thread.sleep(1000); } catch (Exception e) { System.out.println("ccttt " + e); } i++; } ac.complete(); } } And the page that requests the servlet <script type="text/javascript"> function show() { var xml = new XMLHttpRequest(); xml.open("GET", "http://localhost:8080/Comet/home", true ); xml.onreadystatechange=function() { if (xml.readyState== 3|| xml.readyState == 4 ) { document.getElementById("dynamicContent").innerHTML=xml.responseText; } } xml.send(null); } </script> <input type="button" value="show" onclick="show()"/> <div id="dynamicContent"> </div> After about 10 seconds I see the complete response on the browser. But I want to see the partial outputs every second. All i want to learn is how to PUSH partial response with Servlet 3 API. Can someone answer this question?
Please see my answer for this exact same problem mentioned in another question. If you still face this problem after following the instructions in that answer, do let me know.
Unable to set the value for running the java file
I'm working in Google gcm application,and here I'm authenticating the app user by correct Id & password.Authentication is working properly. My I'm running this page by Run as -> Run on Server(Homeservlet.java),even for the correct employee and password,it's not showing the written jsp code(which is written in the if condition) and going to the else-part. In the eclipse console : I can see the employee name and it's password.But my question is how to set the values sothat when I will run this page it'll show that jsp page inside. I'm using set parameter to set the value,but whenever I'm running this page in Tomcat server,it's showing IllegalArgumentException.I found it's quiet relevant because when I'm running the value's are not set. Actually I want ,for the correct employee and corresponding password,...it'll show that jsp page; otherwise(i mean in else-part,it'll not) public class HomeServlet extends BaseServlet { static final String ATTRIBUTE_STATUS = "status"; private static final int HTTP_STATUS = 200; // private static final String HTTP = "OK"; protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws IOException { PreparedStatement stmt = null; String employee=req.getParameter("employeeid"); //getting the value from app User String password=req.getParameter("password"); //corresponding password req.setAttribute(employee, employee); req.setAttribute(password, password); try { String url="jdbc:mysql://localhost/apps"; Class.forName("com.mysql.jdbc.Driver"); Connection con=DriverManager.getConnection(url,"root","root"); stmt = con.prepareStatement("select * from regid where emp_id=? and password=?"); stmt.setString(1, employee); stmt.setString(2, password); ResultSet rs = stmt.executeQuery(); if(rs.next()) { System.out.println("2> Employee Id : "+employee+" && Password : "+password); System.out.println("3> This employee "+employee+" exsists in the database and will be there"); resp.setContentType("text/html"); PrintWriter out = resp.getWriter(); out.print("<html>"); //1> want to run this portion from here out.print("<head>"); out.print("<title>Policy Page</title>"); out.print("<link rel='icon' href='../images/favicon.png'/>"); out.print("</head>"); out.print("<body>"); String status = (String) req.getAttribute(ATTRIBUTE_STATUS); if (status != null) { out.print("Status : "+status); } List<String> devices = Datastore.getDevices(); if (devices.isEmpty()) { out.print("<h2>No devices registered!</h2>"); } else { out.print("<h2>" + devices.size() + " device(s) registered!</h2>"); out.print("<form name='form' method='POST' action='sendAll'>"); out.print("<input type='text' name='policy'>"); resp.setStatus(HttpServletResponse.SC_OK); out.print("<input type='submit' value='Apply Policy'>"); out.print("</form>"); // getServletContext().getRequestDispatcher("/home").forward(req, resp); } out.print("</body></html>"); //2> to here resp.setStatus(HttpServletResponse.SC_OK); } else { //else-part resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); System.out.println(HttpServletResponse.SC_BAD_REQUEST); System.out.println("4> This employee "+employee+" does not exsist in the database"); } } catch(Exception e) { e.printStackTrace(); } finally { try { stmt.close(); } catch(Exception x) {} } } #Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { doGet(req, resp); } } When the app user giving the id-password,the output in the console is: 2> Employee Id : P1 && Password : ppp 3> This employee P1 exsists in the database and will be there but I'm running the page(run as->run on server-tomcat-6),it is showing this(instead of showing the jsp page) HTTP Status 500 java.lang.IllegalArgumentException: Cannot call setAttribute with a null name at org.apache.catalina.connector.Request.setAttribute(Request.java:1431) at org.apache.catalina.connector.RequestFacade.setAttribute(RequestFacade.java:50 any idea....... where I'm going wrong.
2 things observed. 1) Use req.setParameter("employee", employee); req.setParameter("password", password); instead req.setAttribute(employee, employee); req.setAttribute(password, password); 2) The next page you are showing is not a JSP. It is plain html created in servlet. The set content type is html. If you want to display employee in html, you can write code like this, out.print("<body>"); out.print("Welcome to this site Mr."+ employee); If you still want to use the employee as a variable on that html, you have to embed Javascript in this page.
Is there a useDirtyFlag option for Tomcat 6 cluster configuration?
In Tomcat 5.0.x you had the ability to set useDirtyFlag="false" to force replication of the session after every request rather than checking for set/removeAttribute calls. <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster" managerClassName="org.apache.catalina.cluster.session.SimpleTcpReplicationManager" expireSessionsOnShutdown="false" **useDirtyFlag="false"** doClusterLog="true" clusterLogName="clusterLog"> ... The comments in the server.xml stated this may be used to make the following work: <% HashMap map = (HashMap)session.getAttribute("map"); map.put("key","value"); %> i.e. change the state of an object that has already been put in the session and you can be sure that this object still be replicated to the other nodes in the cluster. According to the Tomcat 6 documentation you only have two "Manager" options - DeltaManager & BackupManager ... neither of these seem to allow this option or anything like it. In my testing the default setup: <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> where you get the DeltaManager by default, it's definitely behaving as useDirtyFlag="true" (as I'd expect). So my question is - is there an equivalent in Tomcat 6? Looking at the source I can see a manager implementation "org.apache.catalina.ha.session.SimpleTcpReplicationManager" which does have the useDirtyFlag but the javadoc comments in this state it's "Tomcat Session Replication for Tomcat 4.0" ... I don't know if this is ok to use - I'm guessing not as it's not mentioned in the main cluster configuration documentation.
I posted essentially the same question on the tomcat-users mailing list and the responses to this along with some information in the tomcat bugzilla ([43866]) led me to the following conclusions: There is no equivalent to the useDirtyFlag, if you're putting mutable (ie changing) objects in the session you need a custom coded solution. A Tomcat ClusterValve seems to be an effecting place for this solution - plug into the cluster mechanism, manipulate attributes to make it appear to the DeltaManager that all attributes in the session have changed. This forces replication of the entire session. Step 1: Write the ForceReplicationValve (extends ValveBase implements ClusterValve) I won't include the whole class but the key bit of logic (taking out the logging and instanceof checking): #Override public void invoke(Request request, Response response) throws IOException, ServletException { getNext().invoke(request, response); Session session = request.getSessionInternal(); HttpSession deltaSession = (HttpSession) session; for (Enumeration<String> names = deltaSession.getAttributeNames(); names.hasMoreElements(); ) { String name = names.nextElement(); deltaSession.setAttribute(name, deltaSession.getAttribute(name)); } } Step 2: Alter the cluster config (in conf/server.xml) <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8"> <Valve className="org.apache.catalina.ha.tcp.ForceReplicationValve"/> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*\.gif;.*\.jpg;.*\.png;.*\.js;.*\.htm;.*\.html;.*\.txt;.*\.css;"/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster> Replication of the session to all cluster nodes will now happen after every request. Aside: Note the channelSendOptions setting. This replaces the replicationMode=asynchronous/synchronous/pooled from Tomcat 5.0.x. See the cluster documentation for the possible int values. Appendix: Full Valve source as requested package org.apache.catalina.ha.tcp; import java.io.IOException; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpSession; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Session; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterValve; import org.apache.catalina.ha.session.ReplicatedSession; import org.apache.catalina.ha.session.SimpleTcpReplicationManager; import org.apache.catalina.util.LifecycleSupport; //import org.apache.catalina.util.StringManager; import org.apache.catalina.valves.ValveBase; /** * <p>With the {#link SimpleTcpReplicationManager} effectively deprecated, this allows * mutable objects to be replicated in the cluster by forcing the "dirty" status on * every request.</p> * * #author Jon Brisbin (via post on tomcat-users http://markmail.org/thread/rdo3drcir75dzzrq) * #author Kevin Jansz */ public class ForceReplicationValve extends ValveBase implements Lifecycle, ClusterValve { private static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( ForceReplicationValve.class ); #SuppressWarnings("hiding") protected static final String info = "org.apache.catalina.ha.tcp.ForceReplicationValve/1.0"; // this could be used if ForceReplicationValve messages were setup // in org/apache/catalina/ha/tcp/LocalStrings.properties // // /** // * The StringManager for this package. // */ // #SuppressWarnings("hiding") // protected static StringManager sm = // StringManager.getManager(Constants.Package); /** * Not actually required but this must implement {#link ClusterValve} to * be allowed to be added to the Cluster. */ private CatalinaCluster cluster = null ; /** * Also not really required, implementing {#link Lifecycle} to allow * initialisation and shutdown to be logged. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * Default constructor */ public ForceReplicationValve() { super(); if (log.isInfoEnabled()) { log.info(getInfo() + ": created"); } } #Override public String getInfo() { return info; } #Override public void invoke(Request request, Response response) throws IOException, ServletException { getNext().invoke(request, response); Session session = null; try { session = request.getSessionInternal(); } catch (Throwable e) { log.error(getInfo() + ": Unable to perform replication request.", e); } String context = request.getContext().getName(); String task = request.getPathInfo(); if(task == null) { task = request.getRequestURI(); } if (session != null) { if (log.isDebugEnabled()) { log.debug(getInfo() + ": [session=" + session.getId() + ", instanceof=" + session.getClass().getName() + ", context=" + context + ", request=" + task + "]"); } if (session instanceof ReplicatedSession) { // it's a SimpleTcpReplicationManager - can just set to dirty ((ReplicatedSession) session).setIsDirty(true); if (log.isDebugEnabled()) { log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] maked DIRTY"); } } else { // for everything else - cycle all attributes List cycledNames = new LinkedList(); // in a cluster where the app is <distributable/> this should be // org.apache.catalina.ha.session.DeltaSession - implements HttpSession HttpSession deltaSession = (HttpSession) session; for (Enumeration<String> names = deltaSession.getAttributeNames(); names.hasMoreElements(); ) { String name = names.nextElement(); deltaSession.setAttribute(name, deltaSession.getAttribute(name)); cycledNames.add(name); } if (log.isDebugEnabled()) { log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] cycled atrributes=" + cycledNames + ""); } } } else { String id = request.getRequestedSessionId(); log.warn(getInfo() + ": [session=" + id + ", context=" + context + ", request=" + task + "] Session not available, unable to send session over cluster."); } } /* * ClusterValve methods - implemented to ensure this valve is not ignored by Cluster */ public CatalinaCluster getCluster() { return cluster; } public void setCluster(CatalinaCluster cluster) { this.cluster = cluster; } /* * Lifecycle methods - currently implemented just for logging startup */ /** * Add a lifecycle event listener to this component. * * #param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Get the lifecycle listeners associated with this lifecycle. If this * Lifecycle has no listeners registered, a zero-length array is returned. */ public LifecycleListener[] findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } /** * Remove a lifecycle event listener from this component. * * #param listener The listener to remove */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } public void start() throws LifecycleException { lifecycle.fireLifecycleEvent(START_EVENT, null); if (log.isInfoEnabled()) { log.info(getInfo() + ": started"); } } public void stop() throws LifecycleException { lifecycle.fireLifecycleEvent(STOP_EVENT, null); if (log.isInfoEnabled()) { log.info(getInfo() + ": stopped"); } } }
Many thanks to kevinjansz for providing the source for ForceReplicationValve. I adjusted it for Tomcat7, here it is if anyone needs it: package org.apache.catalina.ha.tcp; import java.io.IOException; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpSession; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Session; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.ha.CatalinaCluster; import org.apache.catalina.ha.ClusterValve; import org.apache.catalina.util.LifecycleSupport; import org.apache.catalina.valves.ValveBase; import org.apache.catalina.LifecycleState; // import org.apache.tomcat.util.res.StringManager; /** * <p>With the {#link SimpleTcpReplicationManager} effectively deprecated, this allows * mutable objects to be replicated in the cluster by forcing the "dirty" status on * every request.</p> * * #author Jon Brisbin (via post on tomcat-users http://markmail.org/thread/rdo3drcir75dzzrq) * #author Kevin Jansz */ public class ForceReplicationValve extends ValveBase implements Lifecycle, ClusterValve { private static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( ForceReplicationValve.class ); #SuppressWarnings("hiding") protected static final String info = "org.apache.catalina.ha.tcp.ForceReplicationValve/1.0"; // this could be used if ForceReplicationValve messages were setup // in org/apache/catalina/ha/tcp/LocalStrings.properties // // /** // * The StringManager for this package. // */ // #SuppressWarnings("hiding") // protected static StringManager sm = // StringManager.getManager(Constants.Package); /** * Not actually required but this must implement {#link ClusterValve} to * be allowed to be added to the Cluster. */ private CatalinaCluster cluster = null; /** * Also not really required, implementing {#link Lifecycle} to allow * initialisation and shutdown to be logged. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * Default constructor */ public ForceReplicationValve() { super(); if (log.isInfoEnabled()) { log.info(getInfo() + ": created"); } } #Override public String getInfo() { return info; } #Override public void invoke(Request request, Response response) throws IOException, ServletException { getNext().invoke(request, response); Session session = null; try { session = request.getSessionInternal(); } catch (Throwable e) { log.error(getInfo() + ": Unable to perform replication request.", e); } String context = request.getContext().getName(); String task = request.getPathInfo(); if(task == null) { task = request.getRequestURI(); } if (session != null) { if (log.isDebugEnabled()) { log.debug(getInfo() + ": [session=" + session.getId() + ", instanceof=" + session.getClass().getName() + ", context=" + context + ", request=" + task + "]"); } //cycle all attributes List<String> cycledNames = new LinkedList<String>(); // in a cluster where the app is <distributable/> this should be // org.apache.catalina.ha.session.DeltaSession - implements HttpSession HttpSession deltaSession = (HttpSession) session; for (Enumeration<String> names = deltaSession.getAttributeNames(); names.hasMoreElements(); ) { String name = names.nextElement(); deltaSession.setAttribute(name, deltaSession.getAttribute(name)); cycledNames.add(name); } if (log.isDebugEnabled()) { log.debug(getInfo() + ": [session=" + session.getId() + ", context=" + context + ", request=" + task + "] cycled atrributes=" + cycledNames + ""); } } else { String id = request.getRequestedSessionId(); log.warn(getInfo() + ": [session=" + id + ", context=" + context + ", request=" + task + "] Session not available, unable to send session over cluster."); } } /* * ClusterValve methods - implemented to ensure this valve is not ignored by Cluster */ public CatalinaCluster getCluster() { return cluster; } public void setCluster(CatalinaCluster cluster) { this.cluster = cluster; } /* * Lifecycle methods - currently implemented just for logging startup */ /** * Add a lifecycle event listener to this component. * * #param listener The listener to add */ public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Get the lifecycle listeners associated with this lifecycle. If this * Lifecycle has no listeners registered, a zero-length array is returned. */ public LifecycleListener[] findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } /** * Remove a lifecycle event listener from this component. * * #param listener The listener to remove */ public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } protected synchronized void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); if (log.isInfoEnabled()) { log.info(getInfo() + ": started"); } } protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); if (log.isInfoEnabled()) { log.info(getInfo() + ": stopped"); } } }