    001    // Copyright 2006, 2007, 2008, 2010, 2011 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.internal.services;
    016
    017    import org.apache.tapestry5.ComponentResources;
    018    import org.apache.tapestry5.MarkupWriter;
    019    import org.apache.tapestry5.TapestryMarkers;
    020    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    021    import org.apache.tapestry5.ioc.util.Stack;
    022    import org.apache.tapestry5.runtime.RenderCommand;
    023    import org.apache.tapestry5.runtime.RenderQueue;
    024    import org.slf4j.Logger;
    025
    026    public class RenderQueueImpl implements RenderQueue
    027    {
    028        private static final int INITIAL_QUEUE_DEPTH = 200;
    029
    030        private final Stack<RenderCommand> queue = CollectionFactory.newStack(INITIAL_QUEUE_DEPTH);
    031
    032        private final Stack<ComponentResources> renderingComponents = CollectionFactory.newStack();
    033
    034        private final Logger logger;
    035
    036        public RenderQueueImpl(Logger logger)
    037        {
    038            this.logger = logger;
    039        }
    040
    041        public void push(RenderCommand command)
    042        {
    043            assert command != null;
    044            queue.push(command);
    045        }
    046
    047        public void run(MarkupWriter writer)
    048        {
    049            RenderCommand command = null;
    050
    051            boolean traceEnabled = logger.isTraceEnabled(TapestryMarkers.RENDER_COMMANDS);
    052
    053            long startNanos = System.nanoTime();
    054            int commandCount = 0;
    055            int maxDepth = 0;
    056
    057            // Seems to make sense to use one try/finally around the whole processInbound, rather than
    058            // around each call to render() since the end result (in a failure scenario) is the same.
    059
    060            try
    061            {
    062                while (!queue.isEmpty())
    063                {
    064                    maxDepth = Math.max(maxDepth, queue.getDepth());
    065
    066                    command = queue.pop();
    067
    068                    commandCount++;
    069
    070                    if (traceEnabled) logger.trace(TapestryMarkers.RENDER_COMMANDS, "Executing: {}", command);
    071
    072                    command.render(writer, this);
    073                }
    074            }
    075            catch (RuntimeException ex)
    076            {
    077                String message = ServicesMessages.renderQueueError(command, ex);
    078
    079                logger.error(message, ex);
    080
    081                throw new RenderQueueException(message, renderingComponents.getSnapshot(), ex);
    082            }
    083
    084            long endNanos = System.nanoTime();
    085
    086            long elapsedNanos = endNanos - startNanos;
    087            double elapsedSeconds = ((double) elapsedNanos) / 1000000000d;
    088
    089            logger.debug(TapestryMarkers.RENDER_COMMANDS,
    090                         String.format("Executed %,d rendering commands (max queue depth: %,d) in %.3f seconds",
    091                                       commandCount,
    092                                       maxDepth,
    093                                       elapsedSeconds));
    094        }
    095
    096        public void startComponent(ComponentResources resources)
    097        {
    098            assert resources != null;
    099            renderingComponents.push(resources);
    100        }
    101
    102        public void endComponent()
    103        {
    104            renderingComponents.pop();
    105        }
    106    }