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