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 }