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.ArrayList;
018import java.util.HashMap;
019import java.util.Iterator;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.hivemind.util.Defense;
024
025/**
026 * Stores persistent property changes concerning a single page. The data may be stored as an encoded
027 * string and the PPD can turn between encoded and object form.
028 * 
029 * @author Howard M. Lewis Ship
030 * @since 4.0
031 */
032public class PersistentPropertyData
033{
034    /**
035     * Keyed on {@link org.apache.tapestry.record.ChangeKey}, values are new objects.
036     */
037
038    private Map _changes;
039
040    private String _encoded;
041
042    private final PersistentPropertyDataEncoder _encoder;
043
044    /**
045     * Creates a new data using the specified encoder. The set of page changes is initially empty.
046     */
047
048    public PersistentPropertyData(PersistentPropertyDataEncoder encoder)
049    {
050        Defense.notNull(encoder, "encoder");
051
052        _encoder = encoder;
053        _changes = new HashMap();
054    }
055
056    public String getEncoded()
057    {
058        if (_encoded == null)
059            _encoded = encode();
060
061        return _encoded;
062    }
063
064    public List getPageChanges()
065    {
066        if (_changes == null)
067        {
068            List pageChanges = _encoder.decodePageChanges(_encoded);
069
070            _changes = decode(pageChanges);
071
072            return pageChanges;
073        }
074
075        return createPageChangeList();
076    }
077
078    public void store(String componentPath, String propertyName, Object newValue)
079    {
080        Defense.notNull(propertyName, "propertyName");
081
082        if (_changes == null)
083            _changes = decode(_encoder.decodePageChanges(_encoded));
084
085        ChangeKey key = new ChangeKey(componentPath, propertyName);
086
087        _changes.put(key, newValue);
088
089        // With the new (or changed) value, the encoded string is no
090        // longer valid.
091
092        _encoded = null;
093    }
094
095    public void storeEncoded(String encoded)
096    {
097        Defense.notNull(encoded, "encoded");
098
099        _encoded = encoded;
100
101        // The decoded data is no longer valid now.
102
103        _changes = null;
104    }
105
106    private List createPageChangeList()
107    {
108        List result = new ArrayList();
109
110        Iterator i = _changes.entrySet().iterator();
111
112        while (i.hasNext())
113        {
114            Map.Entry me = (Map.Entry) i.next();
115
116            ChangeKey changeKey = (ChangeKey) me.getKey();
117            Object value = me.getValue();
118
119            PropertyChange change = new PropertyChangeImpl(changeKey.getComponentPath(), changeKey
120                    .getPropertyName(), value);
121            
122            result.add(change);
123        }
124
125        return result;
126    }
127
128    private String encode()
129    {
130        List changes = createPageChangeList();
131
132        return _encoder.encodePageChanges(changes);
133    }
134
135    private Map decode(List pageChanges)
136    {
137        Map result = new HashMap();
138
139        Iterator i = pageChanges.iterator();
140        while (i.hasNext())
141        {
142            PropertyChange pc = (PropertyChange) i.next();
143
144            String propertyName = pc.getPropertyName();
145            String componentPath = pc.getComponentPath();
146
147            ChangeKey key = new ChangeKey(componentPath, propertyName);
148
149            result.put(key, pc.getNewValue());
150        }
151
152        return result;
153    }
154}