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 }