Hot questions for Using GlassFish in javascript

Question:

This is quite common problem, but I cannot find a solution to my specific case. I'm using Glassfish 4.1.1 and my application implements Websockets.

On a client side I'm connecting to WS-server simply by:

var serviceLocation = "ws://" + window.location.host + window.location.pathname + "dialog/";
var wsocket = new WebSocket(serviceLocation + token_var);

On a server side websockets are implemented via @ServerEndpoint functionality and looks very common:

@ServerEndpoint(value = "/dialog/{token}", decoders = DialogMessageDecoder.class)
public class DialogWebsoketEndpoint {

    @OnOpen
    public void open(final Session session, @PathParam("token") final String token) { ... }
etc.
}

Everything works fine up to the moment when customer tries to connect behind proxy. Using this test: http://websocketstest.com/ I've found that computer of the customer works behind http-proxy 1.1. He cannot connect to websockets, onopen simply do not fire at all. wsoscket.readyState never become 1.

How can I tune my ServerEndpoint to make this code work even when customer is connecting behind proxy?

Thank you in advance!

UPDATE: I would provide a screenshot with websocketstest at that computer:

On my computer it seems similarly except one thing: HTTP Proxy: NO.


Answer:

Much as the comments to the questions state, it seems the Proxy doesn't support Websockets properly.

This is a common issue (some cell-phone companies have proxies that disrupt websocket connections) and the solution is to use TLS/SSL connections.

The issue comes up mainly because some proxies "correct" (read: corrupt) the Websocket request headers.

However, when using TLS/SSL, the proxies can't read the header data (which is encrypted), causing data "pass-through" on most proxies.

This means the headers will arrive safely at the other end and the proxy will (mostly) ignore the connection... this might still cause an issue where connection timeouts are concerned, but it usually resolves the issue.

EDIT

Notice that the browsers will protect the client from mixing non-encrypted content with encrypted content. Make sure the script initiates the ws connections using the wss variant when TLS/SSL connections are used.

Question:

I have created Java websocket application using NetBeans IDE. And it is running on GlassFish server well. But when I change the server to Apache Tomcat then it is not runnig well. I can't create connection with client. Here is my client code (JavaScript)

                if(webSocket !== undefined && webSocket.readyState !== WebSocket.CLOSED){
                   writeResponse("WebSocket is already opened.");
                   return;
                }
                webSocket = new WebSocket("ws://localhost:8080/Sl2World/slworldendpoint");

                webSocket.onopen = function(event){
                    if(event.data === undefined)
                        return; 
                    writeResponse(event.data);
                };

                webSocket.onmessage = function(event){

                    writeResponse(event.data);                    
                }; 
                webSocket.onclose = function(event){
                    writeResponse("Connection closed");
                }; 


function writeResponse(text){
       alert(text);  
}

this is my websocket endpoint code (java)

@OnOpen
public void onOpen(Session session){   
    try {
        session.getBasicRemote().sendText("Connection Established");
    } catch (IOException ex) {
        ex.printStackTrace();
    }
} 
@OnMessage
public void onMessage(String message, Session session){
    System.out.println("Message from " + session.getId() + ": " + message);        
    try {            
        sess.getBasicRemote().sendText("message send");
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
} 
@OnClose
public void onClose(Session session){
    System.out.println("Session " +session.getId()+" has ended");

}

When I run on Tomcat server my output was 'Connection closed' but when I run on GlassFish server my output was 'Connection Established'.

I want to run my application on tomcat server. Help?


Answer:

Tomcat 6 did not have Websocket support. Upgrade to a higher version (at least Tomcat 7 with JDK 7).

Question:

I'm new to Websockets and I want to make a multiplayer-Pong-game. I got it working using Javascript with websockets on the client side and a WebsocketEndpoint (Glassfish-Server) on the server side, but I was wondering if this is a good soldution. As far as I found out, it is very hard to push data to clients while using this combination. After some search I found out about the Netty Framework which is said to be a good solution for this kind of application. The thing is: During my research, I have never seen any JavaScript client to such a Netty Application. Is this possible?

In short: What I want to achieve is: - Using Javascript with websockets on client side - Using Java on server side

Does anybody have experience with it?

Thanks in advance.


Answer:

The generally described architecture sounds fine to me, namely a websocket server and a javascript websocket client. If you're happy with Glassfish, I would run with it.

You can also use Netty to implement the same thing, as it has excellent support for WebSockets and barring anything out of the oridinary with your Glassfish implementation, the same JavaScript client should work with a Netty WebSocket server.

If you decide to pursue the Netty server angle, take a look at the Netty WebSocket example. That example is for Netty 3 (which I am still on) but Netty 4 is the most widely used, and Netty 5 is the latest and greatest. The example supplies a basic javascript client, but as I said, if you have already written one, I would assume it will work seamlessly.

Question:

I use websockets and Glassfish. I call start() funcion on load page. When start function contains alert it sends the message to the server but when I don't put the alert it doesn't work. I can't figure out why.

java script

function start() {
   alert('a'); //this alert
   webSocket.send('start_server');
}

function onMessage(event) {
    document.getElementById('messages').innerHTML
    += event.data;
}

server side

@OnMessage
public void onMessage(String message, Session session) 
    throws IOException, InterruptedException {

    System.out.println("Message recieved");
    session.getBasicRemote().sendText(message);

}   

@OnOpen
public void onOpen() {
    System.out.println("Client connected");
}

Answer:

Where do you initialize the web-socket on the client side? The alert suspends execution until you click ok - so i guess your order of execution is wrong (initialize the websocket before webSocket.send)

You may send data after the WebSocket#open event happend.

var connection = new WebSocket(...) connection.onopen = function () { connection.send('Ping'); };

Source: html5rocks

Question:

This is my web service's declaration

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json")
public DeviceDbUploadResponse upload(@FormDataParam("file1") InputStream file1, 
@FormDataParam("file2") InputStream file2,
@FormDataParam("name1") String filename1,
@FormDataParam("name2") String filename2,
@FormDataParam("ID") String ID)

My web service call

var fd=new FormData();
fd.append("ID",ID);
/* lines of code here */

$.ajax({
         url: 'http://localhost:8080/linterm2m/webapi/m2m/upload',
         data: fd,
         processData: false,
         contentType: false,
         type: 'POST'
       });

Everything works well so far. Now it is required to receive all the data (filename and ID) through an Request Object, something like:

public class Request{
    String ID;
    String filename1;
    String filename2;
}

But I doubt it can be fulfilled because of the multipart-form-data consuming type. I need some enlightenment and a solution.


Answer:

Composing multipart/form-data with a different Content-Type on each parts with Javascript (or Angular)

I try following the answer in this question and it works.

fd.append('whole', new Blob([JSON.stringify({
        ID: ID,
        name1:file1.name,
        name2:file2.name,
    })], {
        type: "application/json"
    }));

The Request class is just as I mentioned. The name1,name2 part is not needed but I just want to test with an Object with various attributes. Much appreciation for Naman's help about FormDataContentDisposition.

Question:

I made an Alternate Document Root for Glassfish in glassfish-web.xml:

<glassfish-web-app>
    <property name="alternatedocroot_1" value="from=/Database/* dir=c:/GetSome" />
</glassfish-web-app>

JS uploads the file and if it succeeds, then it loads jsp with the uploaded file:

function Changed_inputFileLogo()
{
    /*console.log("function Changed_inputFileLogo");*/
    current = event.target;
    var data = new FormData();

    $.each(current.files, function(key, value)
    {
        data.append(key, value);
    });
    data.append("idOrganization", _Organization.id);
    data.append("requestPage", true);

            $.ajax({
            type: 'POST',
            async: false,
            url: 'UploadLogo',
            data: data,
            processData: false,
            contentType: false,
            success: function(response)
            {
                _Organization.logo = 1;
                $.ajax({
                type: 'POST',
                async: false,
                url: 'PhotoExist.jsp',
                data: "path=" + "Database/LogoOrganization/"+_Organization.id+".jpg",
                success: function(response)
                {
                    $("#divLogo").html(response);
                },
                error: function(xhr, textStatus, errorThrown) 
                {
                    LogConsole_ajaxError(xhr, textStatus, errorThrown);
                }
                });
            },
            error: function(xhr, textStatus, errorThrown) 
            {
                LogConsole_ajaxError(xhr, textStatus, errorThrown);
            }
        });
}

Here is PhotoExist.jsp file:

...
<%  String path  = request.getParameter("path");%>
...
        <div class="divPhotoWrapper HavePhoto" onmouseover="ShowPhotoButton()" onmouseout="HidePhotoButton()">
            <div class="divDeletePhoto displayNone">
                <button class="buttonDeletePhoto" onclick="DeletePhoto()"></button>
            </div>
            <a id="aLogo">
                <img id="imgLogo" src="<%=path + "?time=" +System.currentTimeMillis()%>" width="100" height="100">
            </a>
        </div>
...

Here is servlet, that copies the uploaded file to Alternate Document Root folder:

...
try
{
    filePart = request.getPart("0"); 
    String fullName = Common._FolderDatabase_LogoOrganization + File.separator + idOrganization + ".jpg";
    File FileTemp = new File(fullName);

    out = new FileOutputStream(FileTemp);
    filecontent = filePart.getInputStream();

    int read = 0;
    final byte[] bytes = new byte[1024];

    while ((read = filecontent.read(bytes)) != -1) 
    {
        out.write(bytes, 0, read);
    }
}
catch(IOException exception)
{
    Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Unable to copy file." + " Exception: ", exception);
    response.sendError(HttpServletResponse.SC_ACCEPTED, "Unable to copy file.");
    return;
}
finally 
{
    if (out != null) 
        out.close();
    if (filecontent != null) 
        filecontent.close();
}
...

It works fine, but sometimes (one in ten attempts) the browser can't download the image source, and gives this error:GET http://localhost:8080/GetSome/Database/LogoOrganization/85.jpg?time=1407933088377 404 (Not Found). I've tried to check in the servlet if file is available like this:

File FileTemp = new File(fullName);
while(!FileTemp.canWrite())
{
    Thread.sleep(1000);
}

and like this:

in = new FileInputStream(FileTemp);
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = in.read(bytes)) != -1) 
{
}

In both cases the file is available, but it doesn't help. I guess that Glassfish does not have time to get access to the file after it is uploaded to a folder.


Answer:

I solved the problem by checking the availability of the Glassfish resource

URL url = getServletContext().getResource(requestUri);
if (url != null) { 
    try
    {
        Thread.sleep(100);
    } 
    catch (InterruptedException ex)
    {
        Logger.getLogger(UploadLogo.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Thanks to this answer.