001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket;
018:
019: import java.io.Serializable;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023:
024: import org.apache.wicket.request.target.basic.RedirectRequestTarget;
025: import org.apache.wicket.session.pagemap.IPageMapEntry;
026: import org.apache.wicket.util.lang.Objects;
027:
028: /**
029: * @author Jonathan Locke
030: * @author jcompagner
031: */
032: public abstract class PageMap implements IClusterable, IPageMap {
033: /**
034: * Visitor interface for visiting entries in this map
035: *
036: * @author Jonathan Locke
037: */
038: static interface IVisitor {
039: /**
040: * @param entry
041: * The page map entry
042: */
043: public void entry(final IPageMapEntry entry);
044: }
045:
046: /** Name of default pagemap */
047: public static final String DEFAULT_NAME = null;
048:
049: private static final long serialVersionUID = 1L;
050:
051: /**
052: * Gets a page map for a page map name, automatically creating the page map
053: * if it does not exist. If you do not want the pagemap to be automatically
054: * created, you can call Session.pageMapForName(pageMapName, false).
055: *
056: * @param pageMapName
057: * The name of the page map to get
058: * @return The PageMap with the given name from the current session
059: */
060: public static IPageMap forName(final String pageMapName) {
061: Session session = Session.get();
062: return (session != null) ? session.pageMapForName(pageMapName,
063: true) : null;
064: }
065:
066: /** URL to continue to after a given page. */
067: private String interceptContinuationURL;
068:
069: /** Name of this page map */
070: private final String name;
071:
072: /** Next available page identifier in this page map. */
073: private int pageId = 0;
074:
075: /**
076: * Constructor
077: *
078: * @param name
079: * The name of this page map
080: * @param session
081: * The session holding this page map
082: */
083: public PageMap(String name) {
084: if ("".equals(name)) {
085: throw new IllegalStateException(
086: "Empty string name for pagemaps is not allowed");
087: }
088: this .name = name;
089: }
090:
091: /**
092: * @see org.apache.wicket.IPageMap#attributeForId(int)
093: */
094: public final String attributeForId(final int id) {
095: return attributePrefix() + id;
096: }
097:
098: /**
099: * @see org.apache.wicket.IPageMap#clear()
100: */
101: public void clear() {
102: // Remove all entries
103: visitEntries(new IVisitor() {
104: public void entry(IPageMapEntry entry) {
105: removeEntry(entry);
106: }
107: });
108: }
109:
110: /**
111: * Redirects to any intercept page previously specified by a call to
112: * redirectToInterceptPage.
113: *
114: * @return True if an original destination was redirected to
115: * @see PageMap#redirectToInterceptPage(Page)
116: */
117: public final boolean continueToOriginalDestination() {
118: // Get request cycle
119: final RequestCycle cycle = RequestCycle.get();
120:
121: // If there's a place to go to
122: if (interceptContinuationURL != null) {
123: cycle.setRequestTarget(new RedirectRequestTarget(
124: interceptContinuationURL));
125:
126: // Reset interception URL
127: interceptContinuationURL = null;
128:
129: // Force session to replicate page maps
130: dirty();
131: return true;
132: }
133: return false;
134: }
135:
136: /**
137: * @see org.apache.wicket.IPageMap#get(int, int)
138: */
139: public abstract Page get(final int id, int versionNumber);
140:
141: /**
142: * @see org.apache.wicket.IPageMap#getEntry(int)
143: */
144: public final IPageMapEntry getEntry(final int id) {
145: return (IPageMapEntry) Session.get().getAttribute(
146: attributeForId(id));
147: }
148:
149: /**
150: * @see org.apache.wicket.IPageMap#getName()
151: */
152: public final String getName() {
153: return name;
154: }
155:
156: /**
157: * @return Session this page map is in
158: */
159: public final Session getSession() {
160: return Session.get();
161: }
162:
163: /**
164: * @see org.apache.wicket.IPageMap#getSizeInBytes()
165: */
166: public final long getSizeInBytes() {
167: long size = Objects.sizeof(this );
168: Iterator it = getEntries().iterator();
169: while (it.hasNext()) {
170: IPageMapEntry entry = (IPageMapEntry) it.next();
171: if (entry instanceof Page) {
172: size += ((Page) entry).getSizeInBytes();
173: } else {
174: size += Objects.sizeof(entry);
175: }
176: }
177: return size;
178: }
179:
180: /**
181: * @see org.apache.wicket.IPageMap#isDefault()
182: */
183: public final boolean isDefault() {
184: return name == PageMap.DEFAULT_NAME;
185: }
186:
187: /**
188: * @see org.apache.wicket.IPageMap#nextId()
189: */
190: public final int nextId() {
191: dirty();
192: return pageId++;
193: }
194:
195: /**
196: * @see org.apache.wicket.IPageMap#put(org.apache.wicket.Page)
197: */
198: public abstract void put(final Page page);
199:
200: /**
201: * Redirects browser to an intermediate page such as a sign-in page. The
202: * current request's URL is saved exactly as it was requested for future use
203: * by continueToOriginalDestination(); Only use this method when you plan to
204: * continue to the current URL at some later time; otherwise just use
205: * setResponsePage or, when you are in a constructor, redirectTo.
206: *
207: * @param pageClazz
208: * The page clazz to temporarily redirect to
209: */
210: public final void redirectToInterceptPage(final Class pageClazz) {
211: final RequestCycle cycle = RequestCycle.get();
212: setUpRedirect(cycle);
213: cycle.setResponsePage(pageClazz);
214: }
215:
216: /**
217: * Redirects browser to an intermediate page such as a sign-in page. The
218: * current request's URL is saved exactly as it was requested for future use
219: * by continueToOriginalDestination(); Only use this method when you plan to
220: * continue to the current URL at some later time; otherwise just use
221: * setResponsePage or, when you are in a constructor, redirectTo.
222: *
223: * @param page
224: * The page to temporarily redirect to
225: */
226: public final void redirectToInterceptPage(final Page page) {
227: final RequestCycle cycle = RequestCycle.get();
228: setUpRedirect(cycle);
229: cycle.setResponsePage(page);
230: }
231:
232: private void setUpRedirect(final RequestCycle cycle) {
233: Session session = Session.get();
234: if (session.isTemporary()) {
235: session.bind();
236: }
237:
238: // The intercept continuation URL should be saved exactly as the
239: // original request specified.
240: interceptContinuationURL = "/" + cycle.getRequest().getURL();
241:
242: // Page map is dirty
243: dirty();
244:
245: // Redirect to the page
246: cycle.setRedirect(true);
247: }
248:
249: /**
250: * @see org.apache.wicket.IPageMap#remove()
251: */
252: public final void remove() {
253: // First clear all pages from the session for this pagemap
254: clear();
255:
256: // Then remove the pagemap itself
257: Session.get().removePageMap(this );
258: }
259:
260: /**
261: * @see org.apache.wicket.IPageMap#remove(org.apache.wicket.Page)
262: */
263: public final void remove(final Page page) {
264: // Remove the pagemap entry from session
265: removeEntry(page.getPageMapEntry());
266: }
267:
268: /**
269: * @see org.apache.wicket.IPageMap#removeEntry(org.apache.wicket.session.pagemap.IPageMapEntry)
270: */
271: public abstract void removeEntry(final IPageMapEntry entry);
272:
273: /**
274: * @see java.lang.Object#toString()
275: */
276: public String toString() {
277: return "[PageMap name=" + name + "]";
278: }
279:
280: /**
281: * @return List of entries in this page map
282: */
283: private final List getEntries() {
284: final Session session = Session.get();
285: final List attributes = session.getAttributeNames();
286: final List list = new ArrayList();
287: for (final Iterator iterator = attributes.iterator(); iterator
288: .hasNext();) {
289: final String attribute = (String) iterator.next();
290: if (attribute.startsWith(attributePrefix())) {
291: list.add(session.getAttribute(attribute));
292: }
293: }
294: return list;
295: }
296:
297: protected final void dirty() {
298: Session.get().dirtyPageMap(this );
299: }
300:
301: /**
302: * @param visitor
303: * The visitor to call at each Page in this PageMap.
304: */
305: protected final void visitEntries(final IVisitor visitor) {
306: final Session session = Session.get();
307: final List attributes = session.getAttributeNames();
308: for (final Iterator iterator = attributes.iterator(); iterator
309: .hasNext();) {
310: final String attribute = (String) iterator.next();
311: if (attribute.startsWith(attributePrefix())) {
312: visitor.entry((IPageMapEntry) session
313: .getAttribute(attribute));
314: }
315: }
316: }
317:
318: /**
319: * MetaDataEntry array.
320: */
321: private MetaDataEntry[] metaData;
322:
323: /**
324: * Sets the metadata for this PageMap using the given key. If the metadata
325: * object is not of the correct type for the metadata key, an
326: * IllegalArgumentException will be thrown. For information on creating
327: * MetaDataKeys, see {@link MetaDataKey}.
328: *
329: * @param key
330: * The singleton key for the metadata
331: * @param object
332: * The metadata object
333: * @throws IllegalArgumentException
334: * @see MetaDataKey
335: */
336: public final void setMetaData(final MetaDataKey key,
337: final Serializable object) {
338: metaData = key.set(metaData, object);
339: }
340:
341: /**
342: * Gets metadata for this PageMap using the given key.
343: *
344: * @param key
345: * The key for the data
346: * @return The metadata or null of no metadata was found for the given key
347: * @see MetaDataKey
348: */
349: public final Serializable getMetaData(final MetaDataKey key) {
350: return key.get(metaData);
351: }
352:
353: /**
354: * @return The attribute prefix for this page map
355: */
356: final String attributePrefix() {
357: return Session.pageMapEntryAttributePrefix + name + ":";
358: }
359: }
|