/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.wicket.devutils.inspector; import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; import org.apache.wicket.Page; import org.apache.wicket.application.IComponentInstantiationListener; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.devutils.debugbar.DebugBar; import org.apache.wicket.markup.html.debug.PageView; import org.apache.wicket.util.lang.Classes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A listener that adds a special {@link Behavior} that measures the time needed by a component to * render itself. {@link MarkupContainer}'s render includes the time for rendering its children so * the time accumulates. * <p> * To enable this listener use the following in YourApplication.init(): * * <pre> * getComponentInstantiationListeners().add(new RenderPerformanceListener()); * </pre> * * </p> */ public class RenderPerformanceListener implements IComponentInstantiationListener { private static final Logger log = LoggerFactory.getLogger(RenderPerformanceListener.class); @Override public void onInstantiation(final Component component) { if (accepts(component)) { component.add(new RenderMeasuringBehavior()); } } /** * Filters which components' render performance should be measured. * * @param component * the component that is instantiated * @return {@code true} if render time should be measured the for this component, {@code false} * - otherwise */ protected boolean accepts(final Component component) { return component.isAuto() == false; } /** * A {@link Behavior} that sets the current time in the meta data of the component before its * render starts and use it to calculate how long it took. The collected data is logged as debug * and also can be read from the meta data with key {@link PageView#RENDER_KEY}. * {@link DebugBar}'s inspector panel visualizes it. */ private static class RenderMeasuringBehavior extends Behavior { private static final long serialVersionUID = 1L; @Override public void beforeRender(final Component component) { super.beforeRender(component); if (component.isAuto() == false) { Long now = System.currentTimeMillis(); component.setMetaData(PageView.RENDER_KEY, now); } } @Override public void afterRender(final Component component) { super.afterRender(component); Long renderEnd = System.currentTimeMillis(); Long renderStart = component.getMetaData(PageView.RENDER_KEY); if (renderStart != null && component.isAuto() == false) { Long duration = renderEnd - renderStart; component.setMetaData(PageView.RENDER_KEY, duration); if (log.isDebugEnabled()) { String componentPath = (component instanceof Page) ? Classes.simpleName(component.getClass()) + " page" : component.getPageRelativePath(); log.debug("rendered '{}' for {}ms", componentPath, duration); } } } } }