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 }