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.services.impl;
016    
017    import org.apache.hivemind.ApplicationRuntimeException;
018    import org.apache.hivemind.ErrorHandler;
019    import org.apache.tapestry.IEngine;
020    import org.apache.tapestry.IRequestCycle;
021    import org.apache.tapestry.Tapestry;
022    import org.apache.tapestry.engine.RequestCycle;
023    import org.apache.tapestry.engine.RequestCycleEnvironment;
024    import org.apache.tapestry.engine.ServiceEncoder;
025    import org.apache.tapestry.engine.ServiceEncodingImpl;
026    import org.apache.tapestry.record.PropertyPersistenceStrategySource;
027    import org.apache.tapestry.services.*;
028    import org.apache.tapestry.util.QueryParameterMap;
029    import org.apache.tapestry.web.WebRequest;
030    
031    import java.io.IOException;
032    import java.util.Iterator;
033    
034    /**
035     * Service that creates instances of {@link org.apache.tapestry.IRequestCycle}on behalf of an
036     * engine.
037     *
038     * @author Howard M. Lewis Ship
039     * @since 4.0
040     */
041    public class RequestCycleFactoryImpl implements RequestCycleFactory
042    {
043        private ServiceEncoder[] _encoders;
044    
045        private PropertyPersistenceStrategySource _strategySource;
046    
047        private ErrorHandler _errorHandler;
048    
049        private Infrastructure _infrastructure;
050    
051        private AbsoluteURLBuilder _absoluteURLBuilder;
052    
053        private RequestCycleEnvironment _environment;
054    
055        private RequestGlobals _requestGlobals;
056    
057        private ResponseDelegateFactory _responseDelegateFactory;
058    
059        public void initializeService()
060        {
061            _environment = new RequestCycleEnvironment(_errorHandler, _infrastructure, _strategySource,
062                                                       _absoluteURLBuilder);
063        }
064    
065        public IRequestCycle newRequestCycle(IEngine engine)
066        {
067            WebRequest request = _infrastructure.getRequest();
068    
069            QueryParameterMap parameters = extractParameters(request);
070    
071            decodeParameters(request.getActivationPath(), request.getPathInfo(), parameters);
072    
073            String serviceName = findService(parameters);
074    
075            IRequestCycle cycle = new RequestCycle(engine, parameters, serviceName, _environment);
076    
077            _requestGlobals.store(cycle);
078    
079            try {
080    
081                _requestGlobals.store(_responseDelegateFactory.getResponseBuilder(cycle));
082    
083                cycle.setResponseBuilder(_requestGlobals.getResponseBuilder());
084    
085            } catch (IOException e) {
086                throw new ApplicationRuntimeException("Error creating response builder.", e);
087            }
088    
089            return cycle;
090        }
091    
092        private String findService(QueryParameterMap parameters)
093        {
094            String serviceName = parameters.getParameterValue(ServiceConstants.SERVICE);
095    
096            return serviceName == null ? Tapestry.HOME_SERVICE : serviceName;
097        }
098    
099        /**
100         * Constructs a {@link org.apache.tapestry.util.QueryParameterMap}using the parameters
101         * available from the {@link WebRequest} (but ignoring any
102         * file upload parameters!).
103         */
104    
105        private QueryParameterMap extractParameters(WebRequest request)
106        {
107            QueryParameterMap result = new QueryParameterMap();
108    
109            Iterator i = request.getParameterNames().iterator();
110    
111            while (i.hasNext())
112            {
113                String name = (String) i.next();
114    
115                String[] values = request.getParameterValues(name);
116    
117                if (values.length == 1)
118                    result.setParameterValue(name, values[0]);
119                else
120                    result.setParameterValues(name, values);
121            }
122    
123            return result;
124        }
125    
126        private void decodeParameters(String servletPath, String pathInfo, QueryParameterMap map)
127        {
128            ServiceEncodingImpl se = new ServiceEncodingImpl(servletPath, pathInfo, map);
129    
130            for (int i = 0; i < _encoders.length; i++)
131            {
132                _encoders[i].decode(se);
133    
134                if (se.isModified())
135                    return;
136            }
137        }
138    
139        public void setEncoders(ServiceEncoder[] encoders)
140        {
141            _encoders = encoders;
142        }
143    
144        public void setStrategySource(PropertyPersistenceStrategySource strategySource)
145        {
146            _strategySource = strategySource;
147        }
148    
149        public void setErrorHandler(ErrorHandler errorHandler)
150        {
151            _errorHandler = errorHandler;
152        }
153    
154        public void setInfrastructure(Infrastructure infrastructure)
155        {
156            _infrastructure = infrastructure;
157        }
158    
159        public void setAbsoluteURLBuilder(AbsoluteURLBuilder absoluteURLBuilder)
160        {
161            _absoluteURLBuilder = absoluteURLBuilder;
162        }
163    
164        public void setRequestGlobals(RequestGlobals requestGlobals)
165        {
166            _requestGlobals = requestGlobals;
167        }
168    
169        /**
170         * For injection.
171         */
172        public void setResponseDelegateFactory(ResponseDelegateFactory responseDelegate)
173        {
174            _responseDelegateFactory = responseDelegate;
175        }
176    
177        /**
178         * For subclass access.
179         */
180        public ResponseDelegateFactory getResponseDelegateFactory()
181        {
182            return _responseDelegateFactory;
183        }
184    }