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.link; 016 017 import org.apache.hivemind.ApplicationRuntimeException; 018 import org.apache.hivemind.HiveMind; 019 import org.apache.tapestry.IMarkupWriter; 020 import org.apache.tapestry.IRequestCycle; 021 import org.apache.tapestry.Tapestry; 022 import org.apache.tapestry.components.ILinkComponent; 023 import org.apache.tapestry.engine.ILink; 024 025 /** 026 * Default implementation of {@link org.apache.tapestry.link.ILinkRenderer}, which does nothing 027 * special. Can be used as a base class to provide additional handling. 028 * 029 * @author Howard Lewis Ship, David Solis 030 * @since 3.0 031 */ 032 033 public class DefaultLinkRenderer implements ILinkRenderer 034 { 035 /** 036 * A shared instance used as a default for any link that doesn't explicitly override. 037 */ 038 039 public static final ILinkRenderer SHARED_INSTANCE = new DefaultLinkRenderer(); 040 041 public void renderLink(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent linkComponent) 042 { 043 IMarkupWriter wrappedWriter = null; 044 045 if (cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME) != null) 046 throw new ApplicationRuntimeException(Tapestry 047 .getMessage("AbstractLinkComponent.no-nesting"), linkComponent, null, null); 048 049 cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME, linkComponent); 050 051 boolean hasBody = getHasBody(); 052 053 boolean disabled = linkComponent.isDisabled(); 054 055 if (!disabled) 056 { 057 ILink l = linkComponent.getLink(cycle); 058 059 if (hasBody) 060 writer.begin(getElement()); 061 else 062 writer.beginEmpty(getElement()); 063 064 writer.attribute(getUrlAttribute(), constructURL(l, linkComponent.getAnchor(), cycle)); 065 066 String target = linkComponent.getTarget(); 067 068 if (HiveMind.isNonBlank(target)) 069 writer.attribute(getTargetAttribute(), target); 070 071 beforeBodyRender(writer, cycle, linkComponent); 072 073 // Allow the wrapped components a chance to render. 074 // Along the way, they may interact with this component 075 // and cause the name variable to get set. 076 077 wrappedWriter = writer.getNestedWriter(); 078 } 079 else 080 wrappedWriter = writer; 081 082 if (hasBody) 083 linkComponent.renderBody(wrappedWriter, cycle); 084 085 if (!disabled) 086 { 087 afterBodyRender(writer, cycle, linkComponent); 088 089 linkComponent.renderAdditionalAttributes(writer, cycle); 090 091 if (hasBody) 092 { 093 wrappedWriter.close(); 094 095 // Close the <element> tag 096 097 writer.end(); 098 } 099 else 100 writer.closeTag(); 101 } 102 103 cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME); 104 } 105 106 /** 107 * Converts the EngineServiceLink into a URI or URL. This implementation simply invokes 108 * {@link ILink#getURL(String, boolean)}. 109 */ 110 111 protected String constructURL(ILink link, String anchor, IRequestCycle cycle) 112 { 113 return link.getURL(anchor, true); 114 } 115 116 /** 117 * Invoked after the href attribute has been written but before the body of the link is rendered 118 * (but only if the link is not disabled). 119 * <p> 120 * This implementation does nothing. 121 */ 122 123 protected void beforeBodyRender(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent link) 124 { 125 } 126 127 /** 128 * Invoked after the body of the link is rendered, but before 129 * {@link ILinkComponent#renderAdditionalAttributes(IMarkupWriter, IRequestCycle)}is invoked 130 * (but only if the link is not disabled). 131 * <p> 132 * This implementation does nothing. 133 */ 134 135 protected void afterBodyRender(IMarkupWriter writer, IRequestCycle cycle, ILinkComponent link) 136 { 137 } 138 139 /** @since 3.0 * */ 140 141 protected String getElement() 142 { 143 return "a"; 144 } 145 146 protected String getUrlAttribute() 147 { 148 return "href"; 149 } 150 151 protected String getTargetAttribute() 152 { 153 return "target"; 154 } 155 156 protected boolean getHasBody() 157 { 158 return true; 159 } 160 }