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
035 * initialization) to the HTML response. [ <a
036 * 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 * Injected.
054 *
055 * @since 4.0
056 */
057
058 public abstract IScriptSource getScriptSource();
059
060 /**
061 * Constructs the symbols {@link Map}. This starts with the contents of the
062 * symbols parameter (if specified) to which is added any informal
063 * parameters. If both a symbols parameter and informal parameters are
064 * bound, then a copy of the symbols parameter's value is made (that is, the
065 * {@link Map}provided by the symbols parameter is read, but not modified).
066 */
067
068 private Map getInputSymbols()
069 {
070 Map result = new HashMap();
071
072 Map baseSymbols = getBaseSymbols();
073
074 if (baseSymbols != null) 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) 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
111 .multiAssetParameterError(getBinding("scriptAsset"),
112 getBinding("scriptPath")));
113
114 if (scriptPath == null && scriptAsset == null)
115 throw new ApplicationRuntimeException(HTMLMessages
116 .noScriptPathError());
117
118 IScriptSource source = getScriptSource();
119
120 Resource scriptLocation = null;
121 if (scriptPath != null)
122 {
123
124 // If the script path is relative, it should be relative to the
125 // Script component's
126 // container (i.e., relative to a page in the application).
127
128 Resource rootLocation = getContainer().getSpecification()
129 .getSpecificationLocation();
130 scriptLocation = rootLocation.getRelativeResource(scriptPath);
131 }
132 else scriptLocation = scriptAsset.getResourceLocation();
133
134 try
135 {
136 return source.getScript(scriptLocation);
137 }
138 catch (RuntimeException ex)
139 {
140 throw new ApplicationRuntimeException(ex.getMessage(), this,
141 getBinding("script").getLocation(), ex);
142 }
143
144 }
145
146 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
147 {
148 if (!cycle.isRewinding())
149 {
150 PageRenderSupport pageRenderSupport = TapestryUtils
151 .getPageRenderSupport(cycle, this);
152
153 _symbols = getInputSymbols();
154
155 getParsedScript().execute(this, cycle, pageRenderSupport, _symbols);
156 }
157
158 // Render the body of the Script;
159 renderBody(writer, cycle);
160 }
161
162 public abstract String getScriptPath();
163
164 public abstract IAsset getScriptAsset();
165
166 // Parameter
167
168 public abstract Map getBaseSymbols();
169
170 /**
171 * Returns the complete set of symbols (input and output) from the script
172 * execution. This is visible to the body of the Script, but is cleared
173 * after the Script finishes rendering.
174 *
175 * @since 2.2
176 */
177
178 public Map getSymbols()
179 {
180 return _symbols;
181 }
182
183 protected void cleanupAfterRender(IRequestCycle cycle)
184 {
185 _symbols = null;
186
187 super.cleanupAfterRender(cycle);
188 }
189
190 }