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.ArrayList;
018    import java.util.HashMap;
019    import java.util.Iterator;
020    import java.util.List;
021    import java.util.Map;
022    
023    import 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     */
032    public 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    }