Bisakah server Tyrus menggunakan titik akhir kelas dalam?

Saya mengalami masalah dalam membuat server websocket Tyrus mandiri yang sangat sederhana berfungsi. Saya membuat ini berfungsi dalam keadaan yang sangat spesifik yang tidak masuk akal bagi saya.

Kasus yang berfungsi dengan benar adalah saat saya mendefinisikan kelas titik akhir server tingkat atas (dalam filenya sendiri) dan membubuhi keterangan dengan @ServerEndpoint. Kelas ini mencakup metode yang dianotasi dengan @OnOpen, @OnMessage, dan @OnClose, semuanya umum. Saya meneruskan kelas ini ke konstruktor Server. Klien sederhana saya dapat terhubung ke server ini, dan berhasil mengirimkan pesan yang diterima oleh server.

Masalahnya terjadi ketika saya mengubah kelas titik akhir server tingkat atas menjadi kelas dalam dari kelas yang menginisialisasi server (ini adalah SATU-SATUNYA perubahan yang saya buat). Dalam hal ini klien saya dapat terhubung dan metode @OnOpen klien dipanggil. Namun server tidak membuat instance titik akhir server dan, akibatnya, metode @OnOpen tidak pernah dipanggil. Jelas, penerimaan pesan server tidak terjadi.

Apakah ada persyaratan di Tyrus bahwa kelas titik akhir server yang dianotasi tidak boleh menjadi kelas dalam? Jika tidak, apakah ada izin khusus pada kelas titik akhir server (semuanya telah dipublikasikan untuk mencoba membuatnya berfungsi tetapi tidak berhasil)? Saya menggunakan Tyrus 1.9 dengan JDK 1.7 di Mac, OSX 1.9.5.

Server sederhana (termasuk dan dikonfigurasi untuk menggunakan titik akhir server dalam yang gagal):

package tyrus.example;

import java.util.concurrent.TimeUnit;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.glassfish.tyrus.server.Server;

public class SimpleServer
{
    private static final String HOST_ADDR = "localhost";
    private static final int HOST_PORT = 8025;

    public static void main(String[] args) {
        Server websocketServer = new Server(HOST_ADDR, HOST_PORT, "/ws", null, InnerSimpleServerEndpoint.class);

        try {
            websocketServer.start();
            Thread.sleep(TimeUnit.MINUTES.toMillis(5));
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        websocketServer.stop();

        System.out.println("Done.");
    }

    @ServerEndpoint("/myapp")
    public class InnerSimpleServerEndpoint {
        @OnOpen
        public void onOpen(Session session) {
            System.out.println("Connection received for "+session.getRequestURI());
        }

        @OnMessage
        public void onMessage(String message, Session session) {
            System.out.println("Message received: "+message);
        }

        @OnClose
        public void onClose(Session session, CloseReason closeReason) {
            System.out.println("Session closed, reason: "+closeReason);
        }
    }
}

Klien sederhana:

package tyrus.example;

import java.io.IOException;
import java.net.URI;

import javax.websocket.ClientEndpointConfig;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;

import org.glassfish.tyrus.client.ClientManager;

public class SimpleClient
{
    private static final String DEF_WS_URL = "ws://localhost:8025/ws/myapp";

    public static void main(String[] args) {
        ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
        ClientManager client = ClientManager.createClient();

        try {
            client.connectToServer(new ClientEndpoint(), cec, new URI(DEF_WS_URL));
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("Done.");
    }

    private static class ClientEndpoint extends Endpoint {
        @Override
        public void onOpen(Session session, EndpointConfig config) {
            System.out.println("ClientEndpoint: server session opened: "+session);

            session.addMessageHandler(new MessageHandler.Whole<String>() {
                @Override
                public void onMessage(String message) {
                    System.out.println("ClientEndpoint: received message: "+message);
                }
            });

            try {
                session.getBasicRemote().sendText("Hello server!");
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Dan terakhir titik akhir server kelas non-dalam yang berfungsi saat server menggunakannya:

package tyrus.example;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/myapp")
public class SimpleServerEndpoint {
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connection received for "+session.getRequestURI());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Message received: "+message);
    }

    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println("Session closed, reason: "+closeReason);
    }
}

person Bill Balloni    schedule 09.03.2015    source sumber


Jawaban (3)


Di server, titik akhir dapat berupa kelas dalam, namun juga harus statis. Meskipun kodenya berjalan dan berfungsi, karena alasan tertentu, saya hanya dapat membuatnya berfungsi jika titik akhir server juga statis. Yaitu: Ubah untuk menambahkan statis dalam kode server:

@ServerEndpoint("/myapp") public static class InnerSimpleServerEndpoint { }

Anda mungkin juga ingin menambahkan

@OnError public void onError(Session session, Throwable throwable) { //... }

person jazeee    schedule 09.04.2016
comment
Terima kasih, saya mendapat masalah yang sama. kelas harus bersifat publik dan statis. - person Samuel; 29.08.2017

Titik akhir dapat berupa kelas dalam, TETAPI harus dapat dipakai - kelas ClientEndpoint dalam contoh Anda yang gagal adalah private, sehingga Tyrus tidak dapat membuat instance darinya.

Ubah ke publik dan itu akan berfungsi seperti yang diharapkan.

person Pavel Bucek    schedule 09.03.2015
comment
Pavel masalahnya ada pada server, bukan klien. Karena kode klien saya melakukan instantiasi titik akhir, klien berfungsi dengan baik. Namun server, seperti yang ditunjukkan di atas, menggunakan titik akhir server kelas dalam InnerSimpleServerEndpoint , yang sepenuhnya bersifat publik termasuk konstruktor, dan gagal. Namun ketika menggunakan kelas mandiri SimpleServerEndpoint (juga ditunjukkan di atas) semuanya berfungsi. Ada apa dengan titik akhir server kelas dalam yang menyebabkan kegagalan? Apakah saya melakukan sesuatu yang salah atau ini bug di Tyrus? - person Bill Balloni; 09.03.2015
comment
Ah, oke, saya terlalu cepat menilai masalah ini. Bagaimanapun, dalam kasus ini, Tyrus tidak melakukan apa pun - pemindaian paket didelegasikan ke wadah Servlet - lihat anotasi @HandlesTypes javadoc. Saya tidak melihat adanya pengecualian kelas dalam, jadi ini mungkin menjadi masalah dalam impl Servlet (atau saya tidak membaca spesifikasi dengan benar). Bagaimanapun, Anda dapat mengatasinya dengan menggunakan kelas ServerApplicationConfig dari javax.websocket.server API. - person Pavel Bucek; 09.03.2015
comment
Terima kasih Pavel. Apakah ada contoh kode untuk menggunakan ServerApplicationConfig dalam aplikasi mandiri? Saya memang bermain-main dengan ini dan mendapatkan pengecualian penunjuk nol (TyrusServerConfiguration.java:191, tyrus versi 1.10). Jika Anda memiliki tautan ke sesuatu, silakan sebarkan. - person Bill Balloni; 09.03.2015
comment
tentu, misalnya di sini: github.com/tyrus-project/tyrus/blob/ - person Pavel Bucek; 10.03.2015

Kelas dalam harus statis, jika tidak maka tidak dapat dipakai tanpa turunan dari kelas luar. Lihat ini: https://www.javatpoint.com/why-we-use-static-class-in-java Jadi, jika kelas yang dianotasi dengan @ServerEndpoint tidak statis, maka kelas tersebut tidak dapat dipakai.

person omid    schedule 22.07.2021