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 */ 017package org.apache.wicket; 018 019import java.io.File; 020 021import org.apache.wicket.page.IPageManager; 022import org.apache.wicket.page.PageManager; 023import org.apache.wicket.pageStore.AsynchronousPageStore; 024import org.apache.wicket.pageStore.CachingPageStore; 025import org.apache.wicket.pageStore.CryptingPageStore; 026import org.apache.wicket.pageStore.DiskPageStore; 027import org.apache.wicket.pageStore.FilePageStore; 028import org.apache.wicket.pageStore.GroupingPageStore; 029import org.apache.wicket.pageStore.IPageStore; 030import org.apache.wicket.pageStore.InMemoryPageStore; 031import org.apache.wicket.pageStore.InSessionPageStore; 032import org.apache.wicket.pageStore.NoopPageStore; 033import org.apache.wicket.pageStore.RequestPageStore; 034import org.apache.wicket.pageStore.SerializedPage; 035import org.apache.wicket.pageStore.SerializingPageStore; 036import org.apache.wicket.serialize.ISerializer; 037import org.apache.wicket.settings.FrameworkSettings; 038import org.apache.wicket.settings.StoreSettings; 039import org.apache.wicket.util.lang.Args; 040import org.apache.wicket.util.lang.Bytes; 041 042/** 043 * A provider of a {@link PageManager} managing @link IManageablePage}s with a default chain of {@link IPageStore}s: 044 * <ol> 045 * <li>{@link RequestPageStore} keeping pages until end of the request</li> 046 * <li>{@link CachingPageStore} caching with an ...</li> 047 * <li>{@link InSessionPageStore} keeping the last accessed page in the session</li> 048 * <li>{@link SerializingPageStore} serializing all pages (so they are available for back-button)</li> 049 * <li>{@link AsynchronousPageStore} moving storage of pages to an asynchronous worker thread (enabled by default with {@link StoreSettings#isAsynchronous()})</li> 050 * <li>{@link CryptingPageStore} encrypting all pages (disabled by default in {@link StoreSettings#isEncrypted()})</li> 051 * <li>{@link DiskPageStore} persisting all pages, configured according to {@link StoreSettings}</li> 052 * </ol> 053 * An alternative chain with all pages held in-memory could be: 054 * <ol> 055 * <li>{@link RequestPageStore} keeping pages until end of the request</li> 056 * <li>{@link CachingPageStore} caching with an ...</li> 057 * <li>{@link InSessionPageStore} keeping the last accessed page in the session</li> 058 * <li>{@link SerializingPageStore} serializing all pages (so they are available for back-button)</li> 059 * <li>{@link AsynchronousPageStore} moving storage of pages to a worker thread</li> 060 * <li>{@link InMemoryPageStore} keeping all pages in memory</li> 061 * </ol> 062 * ... or if all pages should be kept in the session only, without any serialization (no back-button 063 * support though): 064 * <ul> 065 * <li>{@link RequestPageStore} caching pages until end of the request</li> 066 * <li>{@link InSessionPageStore} keeping a limited count of pages in the session, e.g. 10</li> 067 * </ul> 068 * The chain's initial store should always be a {@link RequestPageStore}, buffering all adding of pages until the end of the request. 069 * Several stores accept {@link SerializedPage} only, these have to be preceded by a {@link SerializingPageStore}. 070 * <p> 071 * For back-button support <em>at least one</em> store in the chain must create copies of stored 072 * pages (usually through serialization), otherwise any following request will work on an identical 073 * page instance and the previous state of page is no longer accessible. 074 * <p> 075 * Other stores be may inserted ad libitum, e.g. 076 * <ul> 077 * <li>{@link NoopPageStore} discards all pages</li> 078 * <li>{@link GroupingPageStore} groups pages, e.g. to limit storage size on a per-group basis</li> 079 * <li>{@link FilePageStore} as an alternative to the trusted {@link DiskPageStore}</li> 080 * <li>other implementations from <a href="https://github.com/wicketstuff/core/tree/master/datastores-parent">wicketstuff-datastores</a></li> 081 * </ul> 082 */ 083public class DefaultPageManagerProvider implements IPageManagerProvider 084{ 085 protected final Application application; 086 087 /** 088 * Constructor. 089 * 090 * @param application 091 * The application instance 092 */ 093 public DefaultPageManagerProvider(Application application) 094 { 095 this.application = Args.notNull(application, "application"); 096 } 097 098 @Override 099 public IPageManager get() 100 { 101 IPageStore store = newPersistentStore(); 102 103 store = newCryptingStore(store); 104 105 store = newAsynchronousStore(store); 106 107 store = newSerializingStore(store); 108 109 store = newCachingStore(store); 110 111 store = newRequestStore(store); 112 113 return new PageManager(store); 114 } 115 116 /** 117 * Get the {@link ISerializer} to use for serializing of pages. 118 * <p> 119 * By default the serializer of the applications {@link FrameworkSettings}. 120 * 121 * @return how to serialize pages if needed for any {@link IPageStore} 122 * 123 * @see FrameworkSettings#getSerializer() 124 */ 125 protected ISerializer getSerializer() 126 { 127 return application.getFrameworkSettings().getSerializer(); 128 } 129 130 /** 131 * Keep pages in the request until it is finished. 132 * 133 * @see RequestPageStore 134 */ 135 protected IPageStore newRequestStore(IPageStore pageStore) 136 { 137 return new RequestPageStore(pageStore); 138 } 139 140 /** 141 * Cache last page non-serialized in the session for fast access. 142 * <p> 143 * On session serialization the cached page will be dropped and re-acquired from 144 * a persistent store. 145 * 146 * @see InSessionPageStore 147 */ 148 protected IPageStore newCachingStore(IPageStore pageStore) 149 { 150 return new CachingPageStore(pageStore, new InSessionCache()); 151 } 152 153 /** 154 * Store pages asynchronously into the persistent store, if enabled in {@link StoreSettings#isAsynchronous()}. 155 * 156 * @see AsynchronousPageStore 157 */ 158 protected IPageStore newAsynchronousStore(IPageStore pageStore) 159 { 160 StoreSettings storeSettings = application.getStoreSettings(); 161 162 if (storeSettings.isAsynchronous()) 163 { 164 int capacity = storeSettings.getAsynchronousQueueCapacity(); 165 pageStore = new AsynchronousPageStore(pageStore, capacity); 166 } 167 168 return pageStore; 169 } 170 171 /** 172 * Serialize pages. 173 * 174 * @see SerializingPageStore 175 */ 176 protected IPageStore newSerializingStore(IPageStore pageStore) 177 { 178 return new SerializingPageStore(pageStore, getSerializer()); 179 } 180 181 /** 182 * Crypt all pages, if enabled in {@link StoreSettings#isEncrypted()}. 183 * 184 * @see CryptingPageStore 185 */ 186 protected IPageStore newCryptingStore(IPageStore pageStore) 187 { 188 StoreSettings storeSettings = application.getStoreSettings(); 189 190 if (storeSettings.isEncrypted()) 191 { 192 pageStore = new CryptingPageStore(pageStore, application); 193 } 194 195 return pageStore; 196 } 197 198 /** 199 * Keep persistent copies of all pages on disk. 200 * 201 * @see DiskPageStore 202 * @see StoreSettings#getMaxSizePerSession() 203 * @see StoreSettings#getFileStoreFolder() 204 */ 205 protected IPageStore newPersistentStore() 206 { 207 StoreSettings storeSettings = application.getStoreSettings(); 208 Bytes maxSizePerSession = storeSettings.getMaxSizePerSession(); 209 File fileStoreFolder = storeSettings.getFileStoreFolder(); 210 211 return new DiskPageStore(application.getName(), fileStoreFolder, maxSizePerSession); 212 } 213 214 private static class InSessionCache extends InSessionPageStore { 215 216 private static final MetaDataKey<SessionData> KEY = new MetaDataKey<>() 217 { 218 private static final long serialVersionUID = 1L; 219 }; 220 221 InSessionCache() 222 { 223 super(1); 224 } 225 226 /** 227 * Use a separate key, so this store does not interfere with any additional {@link InSessionPageStore} 228 * the application might set up. 229 */ 230 @Override 231 protected MetaDataKey<SessionData> getKey() 232 { 233 return KEY; 234 } 235 } 236}