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.IAsset; 025 import org.apache.tapestry.IBinding; 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.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 IAsset scriptAsset = getScriptAsset(); 106 String scriptPath = getScriptPath(); 107 108 //only one of the two is allowed 109 if (scriptAsset != null && scriptPath != null) 110 throw new ApplicationRuntimeException(HTMLMessages.multiAssetParameterError(getBinding("scriptAsset"), 111 getBinding("scriptPath"))); 112 113 if (scriptPath == null && scriptAsset == null) 114 throw new ApplicationRuntimeException(HTMLMessages.noScriptPathError()); 115 116 IScriptSource source = getScriptSource(); 117 118 Resource scriptLocation = null; 119 if (scriptPath != null) { 120 121 // If the script path is relative, it should be relative to the Script component's 122 // container (i.e., relative to a page in the application). 123 124 Resource rootLocation = getContainer().getSpecification().getSpecificationLocation(); 125 scriptLocation = rootLocation.getRelativeResource(scriptPath); 126 } else 127 scriptLocation = scriptAsset.getResourceLocation(); 128 129 try 130 { 131 return source.getScript(scriptLocation); 132 } 133 catch (RuntimeException ex) 134 { 135 throw new ApplicationRuntimeException(ex.getMessage(), this, getBinding("script") 136 .getLocation(), ex); 137 } 138 139 } 140 141 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) 142 { 143 if (!cycle.isRewinding()) 144 { 145 PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this); 146 147 _symbols = getInputSymbols(); 148 149 getParsedScript().execute(cycle, pageRenderSupport, _symbols); 150 } 151 152 // Render the body of the Script; 153 renderBody(writer, cycle); 154 } 155 156 public abstract String getScriptPath(); 157 158 public abstract IAsset getScriptAsset(); 159 160 // Parameter 161 162 public abstract Map getBaseSymbols(); 163 164 /** 165 * Returns the complete set of symbols (input and output) from the script execution. This is 166 * visible to the body of the Script, but is cleared after the Script finishes rendering. 167 * 168 * @since 2.2 169 */ 170 171 public Map getSymbols() 172 { 173 return _symbols; 174 } 175 176 protected void cleanupAfterRender(IRequestCycle cycle) 177 { 178 _symbols = null; 179 180 super.cleanupAfterRender(cycle); 181 } 182 183 }