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.html; 016 017 import java.util.HashMap; 018 import java.util.Iterator; 019 import java.util.Map; 020 021 import org.apache.hivemind.ApplicationRuntimeException; 022 import org.apache.hivemind.Resource; 023 import org.apache.tapestry.AbstractComponent; 024 import org.apache.tapestry.IBinding; 025 import org.apache.tapestry.IEngine; 026 import org.apache.tapestry.IMarkupWriter; 027 import org.apache.tapestry.IRequestCycle; 028 import org.apache.tapestry.IScript; 029 import org.apache.tapestry.PageRenderSupport; 030 import org.apache.tapestry.Tapestry; 031 import org.apache.tapestry.TapestryUtils; 032 import org.apache.tapestry.engine.IScriptSource; 033 034 /** 035 * Works with the {@link Body}component to add a script (and perhaps some initialization) to the 036 * HTML response. [ <a href="../../../../../ComponentReference/Script.html">Component Reference 037 * </a>] 038 * 039 * @author Howard Lewis Ship 040 */ 041 042 public abstract class Script extends AbstractComponent 043 { 044 /** 045 * Injected 046 * 047 * @since 4.0 048 */ 049 050 public abstract IScriptSource getScriptSource(); 051 052 /** 053 * A Map of input and output symbols visible to the body of the Script. 054 * 055 * @since 2.2 056 */ 057 058 private Map _symbols; 059 060 /** 061 * Constructs the symbols {@link Map}. This starts with the contents of the symbols parameter 062 * (if specified) to which is added any informal parameters. If both a symbols parameter and 063 * informal parameters are bound, then a copy of the symbols parameter's value is made (that is, 064 * the {@link Map}provided by the symbols parameter is read, but not modified). 065 */ 066 067 private Map getInputSymbols() 068 { 069 Map result = new HashMap(); 070 071 Map baseSymbols = getBaseSymbols(); 072 073 if (baseSymbols != null) 074 result.putAll(baseSymbols); 075 076 // Now, iterate through all the binding names (which includes both 077 // formal and informal parmeters). Skip the formal ones and 078 // access the informal ones. 079 080 Iterator i = getBindingNames().iterator(); 081 while (i.hasNext()) 082 { 083 String bindingName = (String) i.next(); 084 085 // Skip formal parameters 086 087 if (getSpecification().getParameter(bindingName) != null) 088 continue; 089 090 IBinding binding = getBinding(bindingName); 091 092 Object value = binding.getObject(); 093 094 result.put(bindingName, value); 095 } 096 097 return result; 098 } 099 100 /** 101 * Gets the {@link IScript}for the correct script. 102 */ 103 104 private IScript getParsedScript() 105 { 106 String scriptPath = getScriptPath(); 107 108 if (scriptPath == null) 109 throw Tapestry.createRequiredParameterException(this, "scriptPath"); 110 111 IScriptSource source = getScriptSource(); 112 113 // If the script path is relative, it should be relative to the Script component's 114 // container (i.e., relative to a page in the application). 115 116 Resource rootLocation = getContainer().getSpecification().getSpecificationLocation(); 117 Resource scriptLocation = rootLocation.getRelativeResource(scriptPath); 118 119 try 120 { 121 return source.getScript(scriptLocation); 122 } 123 catch (RuntimeException ex) 124 { 125 throw new ApplicationRuntimeException(ex.getMessage(), this, getBinding("script") 126 .getLocation(), ex); 127 } 128 129 } 130 131 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) 132 { 133 if (!cycle.isRewinding()) 134 { 135 PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this); 136 137 _symbols = getInputSymbols(); 138 139 getParsedScript().execute(cycle, pageRenderSupport, _symbols); 140 } 141 142 // Render the body of the Script; 143 renderBody(writer, cycle); 144 } 145 146 public abstract String getScriptPath(); 147 148 // Parameter 149 150 public abstract Map getBaseSymbols(); 151 152 /** 153 * Returns the complete set of symbols (input and output) from the script execution. This is 154 * visible to the body of the Script, but is cleared after the Script finishes rendering. 155 * 156 * @since 2.2 157 */ 158 159 public Map getSymbols() 160 { 161 return _symbols; 162 } 163 164 protected void cleanupAfterRender(IRequestCycle cycle) 165 { 166 _symbols = null; 167 168 super.cleanupAfterRender(cycle); 169 } 170 171 }