All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.wicket.page.PageStoreManager Maven / Gradle / Ivy

Go to download

Wicket is a Java web application framework that takes simplicity, separation of concerns and ease of development to a whole new level. Wicket pages can be mocked up, previewed and later revised using standard WYSIWYG HTML design tools. Dynamic content processing and form handling is all handled in Java code using a first-class component model backed by POJO data beans that can easily be persisted using your favorite technology.

There is a newer version: 10.0.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.page;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

import org.apache.wicket.pageStore.IPageStore;

/**
 * 
 */
public class PageStoreManager extends AbstractPageManager
{
	/**
	 * A cache that holds all registered page managers. 
* applicationName -> page manager */ private static final ConcurrentMap managers = new ConcurrentHashMap(); private static final String ATTRIBUTE_NAME = "wicket:persistentPageManagerData"; private final IPageStore pageStore; private final String applicationName; /** * Construct. * * @param applicationName * @param pageStore * @param context */ public PageStoreManager(final String applicationName, final IPageStore pageStore, final IPageManagerContext context) { super(context); this.applicationName = applicationName; this.pageStore = pageStore; if (managers.containsKey(applicationName)) { throw new IllegalStateException("Manager for application with key '" + applicationName + "' already exists."); } managers.put(applicationName, this); } /** * Represents entry for single session. This is stored as session attribute and caches pages * between requests. * * @author Matej Knopp */ private static class SessionEntry implements Serializable, HttpSessionBindingListener { private static final long serialVersionUID = 1L; private final String applicationName; /** * The id handed to the {@link IPageStore} to identify the session. *

* Note: If the container changes a session's id, this field remains unchanged on its * initial value. */ private final String sessionId; private transient List sessionCache; private transient List afterReadObject; /** * Construct. * * @param applicationName * @param sessionId */ public SessionEntry(String applicationName, String sessionId) { this.applicationName = applicationName; this.sessionId = sessionId; } /** * * @return page store */ private IPageStore getPageStore() { PageStoreManager manager = managers.get(applicationName); if (manager == null) { return null; } return manager.pageStore; } /** * * @param id * @return null, if not found */ private IManageablePage findPage(int id) { for (IManageablePage p : sessionCache) { if (p.getPageId() == id) { return p; } } return null; } /** * Add the page to cached pages if page with same id is not already there * * @param page */ private void addPage(IManageablePage page) { if (page != null) { if (findPage(page.getPageId()) != null) { return; } sessionCache.add(page); } } /** * If the pages are stored in temporary state (after deserialization) this method convert * them to list of "real" pages */ private void convertAfterReadObjects() { if (sessionCache == null) { sessionCache = new ArrayList(); } for (Object o : afterReadObject) { IManageablePage page = getPageStore().convertToPage(o); addPage(page); } afterReadObject = null; } /** * * @param id * @return manageable page */ public synchronized IManageablePage getPage(int id) { // check if pages are in deserialized state if (afterReadObject != null && afterReadObject.isEmpty() == false) { convertAfterReadObjects(); } // try to find page with same id if (sessionCache != null) { IManageablePage page = findPage(id); if (page != null) { return page; } } // not found, ask pagestore for the page return getPageStore().getPage(sessionId, id); } /** * set the list of pages to remember after the request * * @param pages */ public synchronized void setSessionCache(final List pages) { sessionCache = new ArrayList(pages); afterReadObject = null; } /** * Serializes all pages in this {@link SessionEntry}. If this is http worker thread then * there is available {@link IPageStore} which will be asked to prepare the page for * serialization (see DefaultPageStore$SerializePage). If there is no {@link IPageStore} * available (session loading/persisting in application initialization/destruction thread) * then the pages are serialized without any pre-processing * * @param s * @throws IOException */ private void writeObject(final ObjectOutputStream s) throws IOException { s.defaultWriteObject(); // prepare for serialization and store the pages List serializedPages = new ArrayList(); if (sessionCache != null) { IPageStore pageStore = getPageStore(); for (IManageablePage p : sessionCache) { Serializable preparedPage; if (pageStore != null) { preparedPage = pageStore.prepareForSerialization(sessionId, p); } else { preparedPage = p; } if (preparedPage != null) { serializedPages.add(preparedPage); } } } s.writeObject(serializedPages); } /** * Deserializes the pages in this {@link SessionEntry}. If this is http worker thread then * there is available {@link IPageStore} which will be asked to restore the page from its * optimized state (see DefaultPageStore$SerializePage). If there is no {@link IPageStore} * available (session loading/persisting in application initialization/destruction thread) * then the pages are deserialized without any post-processing * * @param s * @throws IOException * @throws ClassNotFoundException */ @SuppressWarnings("unchecked") private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); afterReadObject = new ArrayList(); List l = (List)s.readObject(); // convert to temporary state after deserialization (will need to be processed // by convertAfterReadObject before the pages can be accessed) IPageStore pageStore = getPageStore(); for (Serializable ser : l) { Object page; if (pageStore != null) { page = pageStore.restoreAfterSerialization(ser); } else { page = ser; } afterReadObject.add(page); } } @Override public void valueBound(HttpSessionBindingEvent event) { } @Override public void valueUnbound(HttpSessionBindingEvent event) { // WICKET-5164 use the original sessionId IPageStore store = getPageStore(); // store might be null if destroyed already if (store != null) { store.unbind(sessionId); } } @Override public boolean equals(Object o) { // see https://issues.apache.org/jira/browse/WICKET-5390 return false; } } private String getAttributeName() { return ATTRIBUTE_NAME + " - " + applicationName; } /** * {@link RequestAdapter} for {@link PageStoreManager} * * @author Matej Knopp */ protected class PersistentRequestAdapter extends RequestAdapter { /** * Construct. * * @param context */ public PersistentRequestAdapter(IPageManagerContext context) { super(context); } /** * @see org.apache.wicket.page.RequestAdapter#getPage(int) */ @Override protected IManageablePage getPage(int id) { IManageablePage touchedPage = findPage(id); if (touchedPage != null) { return touchedPage; } // try to get session entry for this session SessionEntry entry = getSessionEntry(false); if (entry != null) { return entry.getPage(id); } else { return null; } } /** * * @param create * @return Session Entry */ private SessionEntry getSessionEntry(boolean create) { String attributeName = getAttributeName(); SessionEntry entry = (SessionEntry)getSessionAttribute(attributeName); if (entry == null && create) { bind(); entry = new SessionEntry(applicationName, getSessionId()); setSessionAttribute(attributeName, entry); } return entry; } /** * @see org.apache.wicket.page.RequestAdapter#newSessionCreated() */ @Override protected void newSessionCreated() { // if the session is not temporary bind a session entry to it if (getSessionId() != null) { getSessionEntry(true); } } /** * @see org.apache.wicket.page.RequestAdapter#storeTouchedPages(java.util.List) */ @Override protected void storeTouchedPages(final List touchedPages) { if (!touchedPages.isEmpty()) { SessionEntry entry = getSessionEntry(true); entry.setSessionCache(touchedPages); for (IManageablePage page : touchedPages) { // WICKET-5103 use the same sessionId as used in SessionEntry#getPage() pageStore.storePage(entry.sessionId, page); } } } } /** * @see org.apache.wicket.page.AbstractPageManager#newRequestAdapter(org.apache.wicket.page.IPageManagerContext) */ @Override protected RequestAdapter newRequestAdapter(IPageManagerContext context) { return new PersistentRequestAdapter(context); } /** * @see org.apache.wicket.page.AbstractPageManager#supportsVersioning() */ @Override public boolean supportsVersioning() { return true; } /** * @see org.apache.wicket.page.AbstractPageManager#sessionExpired(java.lang.String) */ @Override public void sessionExpired(String sessionId) { RequestAdapter requestAdapter = getRequestAdapter(); String sessionEntryAttributeName = getAttributeName(); Serializable sessionEntry = requestAdapter.getSessionAttribute(sessionEntryAttributeName); if (sessionEntry instanceof SessionEntry) { ((SessionEntry)sessionEntry).valueUnbound(null); } } /** * @see org.apache.wicket.page.IPageManager#destroy() */ @Override public void destroy() { managers.remove(applicationName); pageStore.destroy(); } }