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.Iterator;
018
019import org.apache.hivemind.util.Defense;
020import org.apache.tapestry.TapestryUtils;
021import 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 */
032public 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}