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