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