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.Iterator;
018    
019    import org.apache.hivemind.util.Defense;
020    import org.apache.tapestry.TapestryUtils;
021    import org.apache.tapestry.web.WebSession;
022    
023    /**
024     * Utility methods to support implementations of
025     * {@link org.apache.tapestry.record.PropertyPersistenceStrategy}. This consists of code refactored
026     * out of {@link org.apache.tapestry.record.SessionPropertyPersistenceStrategy} to support other,
027     * similar, persistence types with different rules for how long values are stored in the session.
028     * 
029     * @author Howard M. Lewis Ship
030     * @since 4.0
031     */
032    public class RecordUtils
033    {
034        /**
035         * Builds a {@link PropertyChange} instance for the given key and value pulled from the
036         * {@link org.apache.tapestry.web.WebSession}.
037         * 
038         * @param key
039         *            a key, previously created by
040         *            {@link #buildChangeKey(String, String, String, String, String)}, consisting of a
041         *            strategy id, application id, page name, id path (optional), and a property name,
042         *            all seperated by commas.
043         * @param value
044         *            the value stored in the session with this key
045         * @return a {@link PropertyChange} storing the property name and id path (if any), and the
046         *         value
047         */
048        public static PropertyChange buildChange(String key, Object value)
049        {
050            String[] tokens = TapestryUtils.split(key);
051    
052            // Either strategy-id, app-name,page-name,id-path,property
053            // or strategy-id,app-name,page-name,property
054    
055            String idPath = (tokens.length == 5) ? tokens[3] : null;
056            String propertyName = tokens[tokens.length - 1];
057    
058            return new PropertyChangeImpl(idPath, propertyName, value);
059        }
060    
061        /**
062         * Iterates over the attributes stored in the session, invoking a callback on each one that
063         * matches the given prefix, applicationid and page name. This is used to operate over all
064         * stored data for a particular combination of strategy, applicationId and page.
065         * 
066         * @param strategyId
067         *            a unique identifier for a particular implementation of
068         *            {@link PropertyPersistenceStrategy}
069         * @param applicationId
070         *            a unique id for the application
071         * @param pageName
072         *            the name of the page
073         * @param session
074         *            the session to search
075         * @param callback
076         *            the callback to invoke on each matching attibute name
077         */
078        public static void iterateOverMatchingAttributes(String strategyId, String applicationId,
079                String pageName, WebSession session, WebSessionAttributeCallback callback)
080        {
081            Defense.notNull(strategyId, "strategyId");
082            Defense.notNull(applicationId, "applicationId");
083            Defense.notNull(pageName, "pageName");
084            Defense.notNull(session, "session");
085    
086            String prefix = strategyId + "," + applicationId + "," + pageName + ",";
087    
088            Iterator i = session.getAttributeNames().iterator();
089            while (i.hasNext())
090            {
091                String name = (String) i.next();
092    
093                if (name.startsWith(prefix))
094                    callback.handleAttribute(session, name);
095            }
096        }
097    
098        /**
099         * Builds a change key, used to identify the change within the {@link WebSession}. A change key
100         * can be used as a session attribute name, without reasonable fear of conflict.
101         * 
102         * @param strategyId
103         *            a unique identifier for a particular implementation of
104         *            {@link PropertyPersistenceStrategy}
105         * @param applicationId
106         *            a unique identifier for the application
107         * @param pageName
108         *            the name of the page containing the change
109         * @param idPath
110         *            the id path of the component within the page containing the page, possibly null
111         * @param propertyName
112         *            the name of the property
113         * @return the above values, seperated by commas (well, no comma between the prefix and the
114         *         application id)
115         */
116        public static String buildChangeKey(String strategyId, String applicationId, String pageName,
117                String idPath, String propertyName)
118        {
119            Defense.notNull(strategyId, "strategyId");
120            Defense.notNull(applicationId, "applicationId");
121            Defense.notNull(pageName, "pageName");
122            Defense.notNull(propertyName, "propertyName");
123    
124            StringBuffer buffer = new StringBuffer(strategyId);
125    
126            buffer.append(",");
127            buffer.append(applicationId);
128            buffer.append(",");
129            buffer.append(pageName);
130    
131            if (idPath != null)
132            {
133                buffer.append(",");
134                buffer.append(idPath);
135            }
136    
137            buffer.append(",");
138            buffer.append(propertyName);
139    
140            return buffer.toString();
141        }
142    }