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    }