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 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 /**
072 * Reads the receiver's template and figures out which elements wrap which other elements.
073 */
074
075 private void readTemplate(IRequestCycle cycle, IPageLoader loader)
076 {
077 loader.loadTemplateForComponent(cycle, this);
078 }
079
080 /**
081 * Renders the top level components contained by the receiver.
082 *
083 * @since 2.0.3
084 */
085
086 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
087 {
088 if (LOG.isDebugEnabled())
089 LOG.debug("Begin render " + getExtendedId());
090
091 for (int i = 0; i < _outerCount; i++)
092 _outer[i].render(writer, cycle);
093
094 if (LOG.isDebugEnabled())
095 LOG.debug("End render " + getExtendedId());
096 }
097
098 /**
099 * Loads the template for the component, then invokes
100 * {@link AbstractComponent#finishLoad(IRequestCycle, IPageLoader, IComponentSpecification)}.
101 * Subclasses must invoke this method first, before adding any additional behavior, though its
102 * usually simpler to override {@link #finishLoad()}instead.
103 */
104
105 public void finishLoad(IRequestCycle cycle, IPageLoader loader, IComponentSpecification specification)
106 {
107 readTemplate(cycle, loader);
108
109 super.finishLoad(cycle, loader, specification);
110 }
111 }