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 }