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