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, IRequestCycle cycle,
111                boolean post)
112        {
113            Defense.notNull(encoding, "encoding");
114            Defense.notNull(cycle, "cycle");
115    
116            Iterator i = _data.entrySet().iterator();
117            while (i.hasNext())
118            {
119                Map.Entry e = (Map.Entry) i.next();
120    
121                String pageName = (String) e.getKey();
122                PersistentPropertyData data = (PersistentPropertyData) e.getValue();
123    
124                ClientPropertyPersistenceScope scope = getScope();
125    
126                if (scope.shouldEncodeState(encoding, cycle, pageName, data))
127                {
128                    String parameterName = _scope.constructParameterName(pageName);
129                    encoding.setParameterValue(parameterName, data.getEncoded());
130                }
131            }
132        }
133    
134        public void setRequest(WebRequest request)
135        {
136            _request = request;
137        }
138    
139        public ClientPropertyPersistenceScope getScope()
140        {
141            return _scope;
142        }
143    
144        public void setScope(ClientPropertyPersistenceScope scope)
145        {
146            _scope = scope;
147        }
148    
149        public void setEncoder(PersistentPropertyDataEncoder encoder)
150        {
151            _encoder = encoder;
152        }
153    }