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