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