Java tutorial
/* * Copyright (C) 2016 Singular Studios (a.k.a Atom Tecnologia) - www.opensingular.com * * Licensed 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 org.opensingular.internal.form.wicket.util; import com.google.common.base.Throwables; import org.apache.wicket.Application; import org.apache.wicket.Component; import org.apache.wicket.Page; import org.apache.wicket.application.IComponentOnAfterRenderListener; import org.apache.wicket.request.cycle.AbstractRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycle; import org.opensingular.form.SingularFormException; import org.opensingular.internal.lib.commons.util.SingularIOUtils; import org.opensingular.lib.commons.base.SingularException; import org.opensingular.lib.commons.base.SingularProperties; import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.ObjectInputStream; import java.util.logging.Logger; /** * Mtodo para apoio ao debug em tempo de desenvolvimento da correta capacidade de serializao das pginas Wicket. * <p>ATENO: ESSE DEBUG UMA OPERAO CUSTOSA. ATIVE-O APENAS EM DESENVOLVIMENTO.</p> * Deve ser usado da seguinte forma para ativar o uso dentro da classe que faz a configurao do application do wicket: * <pre> * WicketSerializationDebugUtil.configurePageSerializationDebug(wicketApplication, this.getClass()); * </pre> * Veja mais em {@link #configurePageSerializationDebug(Application, Class)} * * @author Daniel Bordin on 12/02/2017. */ public class WicketSerializationDebugUtil { private WicketSerializationDebugUtil() { } /** * Adiciona o verificado de pgina serializveis na aplicao se estiver no modo de desenvolvimento. Veja mais em * {@link #configurePageSerializationDebug(Application, Class)}. */ public static void configurePageSerializationDebugIfInDevelopmentMode(Application application, Class<?> targetClassLog) { if (SingularProperties.get().isTrue(SingularProperties.SINGULAR_DEV_MODE)) { configurePageSerializationDebug(application, targetClassLog); } } /** * Adiciona listener na aplicao para fazer o teste se ao final de cada renderizao de pgina, a pgina * serializvel. Passa a gera uma informao de tamanho e tempo da serializao no log da aplicao. Gera um log de * exception se a pgina no for serializvel. * * @param application A ser adicionada a verificao * @param targetClassLog Classe para o qual ser gerado os logs da verificao */ public static void configurePageSerializationDebug(Application application, Class<?> targetClassLog) { //Configura os listeners para verificao da serializao DebugSerializationListener debugger = new DebugSerializationListener(targetClassLog); application.getComponentOnAfterRenderListeners().add(debugger); application.getRequestCycleListeners().add(new DebugSerializationRequestCycleListeners(debugger)); //Ativa a pilha de serializao detalhada if (!"true".equals(System.getProperty("sun.io.serialization.extendedDebugInfo"))) { System.setProperty("sun.io.serialization.extendedDebugInfo", "true"); } } /** Apenas para implementao de JUnit. */ final static String getLastVerificationResult(Application application) { for (IComponentOnAfterRenderListener listener : application.getComponentOnAfterRenderListeners()) { if (listener instanceof DebugSerializationListener) { return ((DebugSerializationListener) listener).lastVerification; } } return null; } /** Listener da execuo do ciclo de vida da chamada para verifica necessidades de teste de serializao. */ private static class DebugSerializationRequestCycleListeners extends AbstractRequestCycleListener { private final DebugSerializationListener debugger; public DebugSerializationRequestCycleListeners(DebugSerializationListener debugger) { this.debugger = debugger; } @Override public void onBeginRequest(RequestCycle cycle) { super.onBeginRequest(cycle); debugger.clearCurrentThread(); } @Override public void onEndRequest(RequestCycle cycle) { debugger.runSerializationIfNecessary(); super.onEndRequest(cycle); } } /** Listener Wicket para executar a verificao da pgina como serializvel. */ private static class DebugSerializationListener implements IComponentOnAfterRenderListener { private final ThreadLocal<Component> componentThreadLocal = new ThreadLocal<>(); private final Logger logger; private String lastVerification; public DebugSerializationListener(Class<?> targetClassLog) { logger = Logger.getLogger(targetClassLog.getName()); } /** Limpa a requesio antes de comear um novo ciclo. */ public void clearCurrentThread() { componentThreadLocal.remove(); } /** * Mtodo chamado pelo listener da aplicao wicket para verificar se a pgina que acabou de ser redenderizada * serializvel. */ @Override public void onAfterRender(Component c) { Component current = componentThreadLocal.get(); if (c instanceof Page) { componentThreadLocal.set(c); tryComponentSerialization(c); return; } else if (current == null) { componentThreadLocal.set(c); return; } else if (current instanceof Page) { return; } for (Component parent = c.getParent(); parent != null; parent = parent.getParent()) { if (parent == current) { return; //The new component is inside of the current one } } componentThreadLocal.set(c); } /** Verifica se ficou alguma execuo de serializao pendente para testar. */ public void runSerializationIfNecessary() { Component c = componentThreadLocal.get(); if (c != null) { componentThreadLocal.remove(); if (!(c instanceof Page)) { //No foi chamada de pgina, mas uma chamada Ajax, ento chamara a serializao agora tryComponentSerialization(c); } } } private void tryComponentSerialization(Component c) { //Serialization long time = System.currentTimeMillis(); byte[] result = c.getApplication().getFrameworkSettings().getSerializer().serialize(c); time = System.currentTimeMillis() - time; String msg = "Serialization: target=" + c.getClass().getName() + " size=" + (result == null ? "EXCEPTION" : SingularIOUtils.humanReadableByteCount(result.length)) + " serialization=" + SingularIOUtils.humanReadableMiliSeconds(time); try { if (result == null) { throw new SingularFormException("Erro serializando a pgina " + c.getClass().getName() + ". Verifique o log para obter a pilha de erro da serializao."); } //Deserialization time = System.currentTimeMillis(); Object last = readAllObjects(result); time = System.currentTimeMillis() - time; msg += " deserialization=" + SingularIOUtils.humanReadableMiliSeconds(time); Class<?> classLast = (last == null ? null : last.getClass()); if (c.getClass() != classLast) { msg += " !!!! DESERIALIZATED CLASS NOT OF EXPECTED TYPE result=" + classLast; } } finally { lastVerification = msg; logger.info(msg); } } /** L todos os objetos serialziados, retornando o ltimo. */ private Object readAllObjects(byte[] content) { Object last = null; try { ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(content)); Object o; do { o = in.readObject(); if (o != null) { last = o; } } while (o != null); } catch (Exception e) { if (!(e instanceof EOFException)) { Throwables.throwIfUnchecked(e); throw SingularException.rethrow(e); } } return last; } } }