Проблема сериализации Wicket с WebApplication

#serialization #websocket #wicket

#сериализация #websocket #wicket

Вопрос:

Я продолжаю вести журнал, используя WebSocketBehavior. В настоящее время он записывает правильные данные в консоль, но также выдает ужасную ошибку сериализации. Это потому, что я предоставляю само приложение Wicket в качестве аргумента конструктора для поведения. Я пытался передать ему свой объект сеанса и использовать его для получения WebApplication, но он постоянно возвращает null. Для правильной работы объекта broadcaster требуется приложение. Мой вопрос в том, как я могу предоставить WebApplication для поведения, избегая при этом неприятной ошибки сериализации?? Вот мой класс поведения:

     public class LogWebSocketBehavior extends WebSocketBehavior implements Serializable {

private static final long serialVersionUID = 1L;

private Console console;
private Handler logHandler;
private Model<LogRecord> model = new Model<>();
private WebApplication application;

public LogWebSocketBehavior(Console console, WebApplication application) {
    super();
    configureLogger();
    this.console = console;
    this.application = application;


}

private void configureLogger() {

    Enumeration<String> list = LogManager.getLogManager().getLoggerNames();

    list.hasMoreElements();

    Logger l = Logger.getLogger(AppUtils.loggerName);
    l.addHandler(getLoggerHandler());

}

@Override
protected synchronized void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {
    LogRecord r = model.getObject();
    sendRecordToConsole(handler, r);
}

private Handler getLoggerHandler() {
    return new LogHandler() {

        private static final long serialVersionUID = 1L;

        @Override
        public void publish(LogRecord record) {
            model.setObject(record);

            sendToAllConnectedClients("data");
        }
    };
}

private synchronized void sendToAllConnectedClients(String message) {

        IWebSocketConnectionRegistry registry = new SimpleWebSocketConnectionRegistry();
        WebSocketPushBroadcaster b = new WebSocketPushBroadcaster(registry);


        b.broadcastAll(application, new Message());

}

private void sendRecordToConsole(WebSocketRequestHandler handler, LogRecord r) {

    Level level = r.getLevel();

    if (level.equals(Level.INFO)) {
        console.info(handler, new SimpleFormatter().formatMessage(r));
    } else {
        console.error(handler, new SimpleFormatter().formatMessage(r));
    }
}

class Message implements IWebSocketPushMessage {

    public Message() {

    }

}

}
 

Вот панель, которая используется для отображения сообщений:

 public class FooterPanel extends Panel {

private static final long serialVersionUID = 1L;

private Form form;
private Console console;

public FooterPanel(String id) {
    super(id);
}

@Override
public void onInitialize() {
    super.onInitialize();
    form = new Form("form");
    form.add(console = getConsole("feedback_console"));
    console.setOutputMarkupId(true);
    form.setOutputMarkupId(true);
    add(form);

    add(getLoggingBehavior());

}

private Console getConsole(String id) {
    return new Console(id) {

        private static final long serialVersionUID = 1L;

    };
}

private WebSocketBehavior getLoggingBehavior() {

    return new LogWebSocketBehavior(console, this.getWebApplication());

}

}
 

Я обновил свое поведение следующим образом:

     public class LogWebSocketBehavior extends WebSocketBehavior implements Serializable {

private static final long serialVersionUID = 1L;

private Console console;
private Handler logHandler;
private Model<LogRecord> model = new Model<>();

public LogWebSocketBehavior(Console console) {
    super();
    configureLogger();
    this.console = console;

}

private void configureLogger() {

    Enumeration<String> list = LogManager.getLogManager().getLoggerNames();

    list.hasMoreElements();

    Logger l = Logger.getLogger(AppUtils.loggerName);
    l.addHandler(getLoggerHandler());

}

@Override
protected synchronized void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {
    LogRecord r = model.getObject();
    sendRecordToConsole(handler, r);
}

private Handler getLoggerHandler() {
    return new LogHandler() {

        private static final long serialVersionUID = 1L;

        @Override
        public void publish(LogRecord record) {
            model.setObject(record);

            sendToAllConnectedClients("data");
        }
    };
}

private synchronized void sendToAllConnectedClients(String message) {

    WebApplication application = WebApplication.get();
    IWebSocketConnectionRegistry registry = new SimpleWebSocketConnectionRegistry();
    WebSocketPushBroadcaster b = new WebSocketPushBroadcaster(registry);

    b.broadcastAll(application, new Message());

}

private void sendRecordToConsole(WebSocketRequestHandler handler, LogRecord r) {

    Level level = r.getLevel();
    String message = AppUtils.consoleDateTimeFormat.format(LocalDateTime.now())   " - "   AppUtils.LogFormatter.formatMessage(r);
    if (level.equals(Level.INFO)) {
        console.info(handler, message);
    } else {
        console.error(handler, message);
    }
}

class Message implements IWebSocketPushMessage {

    public Message() {

    }

}

}
 

И я возвращаюсь к исходным проблемам, с которых я начал, а именно к следующей ошибке:

ОШИБКА — ErrorLogger — Job (report.DB5E002E046235586592E7E984338DEE3 : 653 вызвал исключение. org.quartz.Исключение SchedulerException:

Задание выдало необработанное исключение. [См. Вложенное исключение: org.apache.калитка.Исключение WicketRuntimeException: нет приложения, подключенного к текущему потоку DefaultQuartzScheduler_Worker-1] в org.quartz.core.JobRunShell.run(JobRunShell.java:213)

 at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
 

Вызвано: org.apache.калитка.Исключение WicketRuntimeException: нет приложения, подключенного к текущему потоку DefaultQuartzScheduler_Worker-1
в org.apache.калитка.Application.get(Application.java: 236)

 at org.apache.wicket.protocol.http.WebApplication.get(WebApplication.java:160)

at eb.wicket.behaviors.LogWebSocketBehavior.sendToAllConnectedClients(LogWebSocketBehavior.java:77)

at eb.wicket.behaviors.LogWebSocketBehavior.access$100(LogWebSocketBehavior.java:29)

at eb.wicket.behaviors.LogWebSocketBehavior$1.publish(LogWebSocketBehavior.java:70)
 

Наконец-то работает по желанию.. Вот класс поведения:

 public class LogWebSocketBehavior extends WebSocketBehavior implements Serializable {

private static final long serialVersionUID = 1L;

private Console console;
private Model<LogRecord> model = new Model<>();

public LogWebSocketBehavior(Console console) {
    super();
    configureLogger();
    this.console = console;

}

private void configureLogger() {

    Enumeration<String> list = LogManager.getLogManager().getLoggerNames();

    list.hasMoreElements();

    Logger l = Logger.getLogger(AppUtils.loggerName);
    l.addHandler(getLoggerHandler());

}

@Override
protected synchronized void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {
    LogRecord r = model.getObject();
    sendRecordToConsole(handler, r);
}

private Handler getLoggerHandler() {
    return new LogHandler() {

        private static final long serialVersionUID = 1L;

        @Override
        public void publish(LogRecord record) {
            model.setObject(record);

            sendToAllConnectedClients("data");
        }
    };
}

private synchronized void sendToAllConnectedClients(String message) {

    IWebSocketConnectionRegistry registry = new SimpleWebSocketConnectionRegistry();
    WebSocketPushBroadcaster b = new WebSocketPushBroadcaster(registry);
    b.broadcastAll(Application.get("eb.wicket.MyWicketFilter"), new Message());

}

private void sendRecordToConsole(WebSocketRequestHandler handler, LogRecord r) {

    Level level = r.getLevel();
    String message = AppUtils.consoleDateTimeFormat.format(LocalDateTime.now())   " - "   AppUtils.LogFormatter.formatMessage(r);
    if (level.equals(Level.INFO)) {
        console.info(handler, message);
    } else {
        console.error(handler, message);
    }
}

class Message implements IWebSocketPushMessage {

    public Message() {

    }

}

}
 

Ответ №1:

Вместо того, чтобы сохранять ссылку на приложение, просто найдите его, когда это необходимо : Application.get() .

После обновления вашего вопроса мы видим:

  Caused by: org.apache.wicket.WicketRuntimeException: 
 There is no application attached to current thread DefaultQuartzScheduler_Worker-1
 

Это объясняет это — это поток, запущенный Quartz, это не http-поток.

Единственный способ преодолеть это — использовать Application.get(String) . Значением должно быть имя приложения (Application#getName()), указанное в качестве значения для <filter-name> в вашем web.xml .

Таким образом, вы можете получить экземпляр приложения, но нет способа сделать то же самое для Session и / или RequestCycle на случай, если они вам тоже понадобятся.

Комментарии:

1. Я попробовал это, и я продолжаю получать null. Я нашел этот ответ на другой вопрос и понимаю, как он должен работать. Я бы подумал, что это вернет приложение, но последовательно возвращает значение null..

2. Пожалуйста, смотрите выше.

3. Потрясающе, большое вам спасибо!!! Теперь он работает так, как хотелось бы. Я опубликовал рабочий код в исходном сообщении…