001 // Copyright 2004, 2005 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.tapestry;
016
017 import org.apache.commons.logging.Log;
018 import org.apache.commons.logging.LogFactory;
019 import org.apache.tapestry.engine.IPageLoader;
020 import org.apache.tapestry.spec.IComponentSpecification;
021
022 /**
023 * Base implementation for most components that use an HTML template.
024 *
025 * @author Howard Lewis Ship
026 */
027
028 public abstract class BaseComponent extends AbstractComponent implements ITemplateComponent
029 {
030 private static final Log LOG = LogFactory.getLog(BaseComponent.class);
031
032 private static final int OUTER_INIT_SIZE = 5;
033
034 private IRender[] _outer;
035
036 private int _outerCount = 0;
037
038 /**
039 * Adds an element as an outer element for the receiver. Outer elements are elements that should
040 * be directly rendered by the receiver's <code>render()</code> method. That is, they are
041 * top-level elements on the HTML template.
042 */
043
044 public void addOuter(IRender element)
045 {
046 if (_outer == null)
047 {
048 _outer = new IRender[OUTER_INIT_SIZE];
049 _outer[0] = element;
050
051 _outerCount = 1;
052 return;
053 }
054
055 // No more room? Make the array bigger.
056
057 if (_outerCount == _outer.length)
058 {
059 IRender[] newOuter;
060
061 newOuter = new IRender[_outer.length * 2];
062
063 System.arraycopy(_outer, 0, newOuter, 0, _outerCount);
064
065 _outer = newOuter;
066 }
067
068 _outer[_outerCount++] = element;
069 }
070
071 public IRender[] getContainedRenderers()
072 {
073 return _outer;
074 }
075
076 public IRender[] getInnerRenderers()
077 {
078 return _body;
079 }
080
081 /**
082 * Reads the receiver's template and figures out which elements wrap which other elements.
083 *
084 * @param cycle
085 * The current request.
086 * @param loader
087 * The service responsible for loading / resolving a page spec.
088 */
089
090 private void readTemplate(IRequestCycle cycle, IPageLoader loader)
091 {
092 loader.loadTemplateForComponent(cycle, this);
093 }
094
095 /**
096 * Renders the top level components contained by the receiver.
097 *
098 * @since 2.0.3
099 */
100
101 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
102 {
103 if (LOG.isDebugEnabled())
104 LOG.debug("Begin render " + getExtendedId());
105
106 for (int i = 0; i < _outerCount; i++)
107 cycle.getResponseBuilder().render(writer, _outer[i], cycle);
108
109 if (LOG.isDebugEnabled())
110 LOG.debug("End render " + getExtendedId());
111 }
112
113 /**
114 * Loads the template for the component, then invokes
115 * {@link AbstractComponent#finishLoad(IRequestCycle, IPageLoader, IComponentSpecification)}.
116 * Subclasses must invoke this method first, before adding any additional behavior, though its
117 * usually simpler to override {@link #finishLoad()}instead.
118 */
119
120 public void finishLoad(IRequestCycle cycle, IPageLoader loader, IComponentSpecification specification)
121 {
122 readTemplate(cycle, loader);
123
124 super.finishLoad(cycle, loader, specification);
125 }
126 }