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