001    // Copyright 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.record;
016    
017    import org.apache.hivemind.util.Defense;
018    import org.apache.tapestry.engine.ServiceEncoding;
019    import org.apache.tapestry.web.WebRequest;
020    
021    import java.util.*;
022    
023    /**
024     * Service tapestry.persist.ClientPropertyPersistenceStrategy. Encodes persistent page properties on
025     * the client as query parameters.
026     * <p>
027     * Uses the threaded model.
028     * 
029     * @author Howard M. Lewis Ship
030     * @since 4.0
031     * @see org.apache.tapestry.engine.ILink
032     */
033    public class ClientPropertyPersistenceStrategy implements PropertyPersistenceStrategy
034    {
035        /**
036         * Keyed on page name (String), values are
037         * {@link org.apache.tapestry.record.PersistentPropertyData}.
038         */
039        protected final Map _data = new LinkedHashMap();
040    
041        protected PersistentPropertyDataEncoder _encoder;
042    
043        protected WebRequest _request;
044    
045        protected ClientPropertyPersistenceScope _scope;
046    
047        /**
048         * Initializer for this service, invoked every time a service instance is created. This
049         * initializer pulls out of the request and query parameters whose prefix is "client:" and
050         * expects them to be encoded {@link PersistentPropertyData}, which are stored internally.
051         * Because the service model is threaded, this information is specific to a single request, and
052         * will be discarded at the end of the request.
053         */
054    
055        public void initializeService()
056        {
057            List names = _request.getParameterNames();
058            Iterator i = names.iterator();
059            while (i.hasNext())
060            {
061                String name = (String) i.next();
062    
063                if (!_scope.isParameterForScope(name))
064                    continue;
065    
066                String pageName = _scope.extractPageName(name);
067    
068                String encoded = _request.getParameterValue(name);
069    
070                PersistentPropertyData data = new PersistentPropertyData(_encoder);
071                data.storeEncoded(encoded);
072    
073                _data.put(pageName, data);
074            }
075        }
076    
077        public void store(String pageName, String idPath, String propertyName, Object newValue)
078        {
079            PersistentPropertyData data = (PersistentPropertyData) _data.get(pageName);
080            if (data == null)
081            {
082                data = new PersistentPropertyData(_encoder);
083                _data.put(pageName, data);
084            }
085    
086            data.store(idPath, propertyName, newValue);
087        }
088    
089        public Collection getStoredChanges(String pageName)
090        {
091            PersistentPropertyData data = (PersistentPropertyData) _data.get(pageName);
092    
093            if (data == null)
094                return Collections.EMPTY_LIST;
095    
096            return data.getPageChanges();
097        }
098    
099        public void discardStoredChanges(String pageName)
100        {
101            _data.remove(pageName);
102        }
103    
104        public void addParametersForPersistentProperties(ServiceEncoding encoding, boolean post)
105        {
106            Defense.notNull(encoding, "encoding");
107     
108            Iterator i = _data.entrySet().iterator();
109            while (i.hasNext())
110            {
111                Map.Entry e = (Map.Entry) i.next();
112    
113                String pageName = (String) e.getKey();
114                PersistentPropertyData data = (PersistentPropertyData) e.getValue();
115    
116                ClientPropertyPersistenceScope scope = getScope();
117    
118                if (scope.shouldEncodeState(encoding, pageName, data))
119                {
120                    String parameterName = _scope.constructParameterName(pageName);
121                    encoding.setParameterValue(parameterName, data.getEncoded());
122                }
123            }
124        }
125    
126        public void setRequest(WebRequest request)
127        {
128            _request = request;
129        }
130    
131        public ClientPropertyPersistenceScope getScope()
132        {
133            return _scope;
134        }
135    
136        public void setScope(ClientPropertyPersistenceScope scope)
137        {
138            _scope = scope;
139        }
140    
141        public void setEncoder(PersistentPropertyDataEncoder encoder)
142        {
143            _encoder = encoder;
144        }
145    }