Source Code Cross Referenced for Session.java in  » J2EE » wicket » org » apache » wicket » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » wicket » org.apache.wicket 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:        package org.apache.wicket;
0018:
0019:        import java.io.Serializable;
0020:        import java.util.ArrayList;
0021:        import java.util.Collections;
0022:        import java.util.HashMap;
0023:        import java.util.HashSet;
0024:        import java.util.Iterator;
0025:        import java.util.LinkedList;
0026:        import java.util.List;
0027:        import java.util.Locale;
0028:        import java.util.Map;
0029:        import java.util.Set;
0030:        import java.util.Map.Entry;
0031:
0032:        import org.apache.wicket.application.IClassResolver;
0033:        import org.apache.wicket.authorization.IAuthorizationStrategy;
0034:        import org.apache.wicket.feedback.FeedbackMessage;
0035:        import org.apache.wicket.feedback.FeedbackMessages;
0036:        import org.apache.wicket.feedback.IFeedbackMessageFilter;
0037:        import org.apache.wicket.protocol.http.IgnoreAjaxRequestException;
0038:        import org.apache.wicket.request.ClientInfo;
0039:        import org.apache.wicket.session.ISessionStore;
0040:        import org.apache.wicket.settings.IRequestCycleSettings;
0041:        import org.apache.wicket.util.lang.Objects;
0042:        import org.apache.wicket.util.string.Strings;
0043:        import org.apache.wicket.util.time.Duration;
0044:        import org.slf4j.Logger;
0045:        import org.slf4j.LoggerFactory;
0046:
0047:        /**
0048:         * Holds information about a user session, including some fixed number of most
0049:         * recent pages (and all their nested component information).
0050:         * <ul>
0051:         * <li><b>Access via RequestCycle </b>- The Session for a {@link RequestCycle}
0052:         * can be retrieved by calling {@link RequestCycle#getSession()}.
0053:         * 
0054:         * <li><b>Access via Component </b>- If a RequestCycle object is not available,
0055:         * the Session can be retrieved for a Component by calling
0056:         * {@link Component#getSession()}. As currently implemented, each Component
0057:         * does not itself have a reference to the session that contains it. However,
0058:         * the Page component at the root of the containment hierarchy does have a
0059:         * reference to the Session that holds the Page. So
0060:         * {@link Component#getSession()} traverses the component hierarchy to the root
0061:         * Page and then calls {@link Page#getSession()}.
0062:         * 
0063:         * <li><b>Access via Thread Local </b>- In the odd case where neither a
0064:         * RequestCycle nor a Component is available, the currently active Session for
0065:         * the calling thread can be retrieved by calling the static method
0066:         * Session.get(). This last form should only be used if the first two forms
0067:         * cannot be used since thread local access can involve a potentially more
0068:         * expensive hash map lookup.
0069:         * 
0070:         * <li><b>Locale </b>- A session has a Locale property to support localization.
0071:         * The Locale for a session can be set by calling
0072:         * {@link Session#setLocale(Locale)}. The Locale for a Session determines how
0073:         * localized resources are found and loaded.
0074:         * 
0075:         * <li><b>Style </b>- Besides having an appearance based on locale, resources
0076:         * can also have different looks in the same locale (a.k.a. "skins"). The style
0077:         * for a session determines the look which is used within the appopriate locale.
0078:         * The session style ("skin") can be set with the setStyle() method.
0079:         * 
0080:         * <li><b>Resource Loading </b>- Based on the Session locale and style,
0081:         * searching for resources occurs in the following order (where sourcePath is
0082:         * set via the ApplicationSettings object for the current Application, and style
0083:         * and locale are Session properties):
0084:         * <ul>
0085:         * 1. [sourcePath]/name[style][locale].[extension] <br>
0086:         * 2. [sourcePath]/name[locale].[extension] <br>
0087:         * 3. [sourcePath]/name[style].[extension] <br>
0088:         * 4. [sourcePath]/name.[extension] <br>
0089:         * 5. [classPath]/name[style][locale].[extension] <br>
0090:         * 6. [classPath]/name[locale].[extension] <br>
0091:         * 7. [classPath]/name[style].[extension] <br>
0092:         * 8. [classPath]/name.[extension] <br>
0093:         * </ul>
0094:         * 
0095:         * <li><b>Session Properties </b>- Arbitrary objects can be attached to a
0096:         * Session by installing a session factory on your Application class which
0097:         * creates custom Session subclasses that have typesafe properties specific to
0098:         * the application (see {@link Application} for details). To discourage
0099:         * non-typesafe access to Session properties, no setProperty() or getProperty()
0100:         * method is provided. In a clustered environment, you should take care to call
0101:         * the dirty() method when you change a property or youre own. This way the
0102:         * session will be reset again in the http session so that the http session
0103:         * knows the session is changed.
0104:         * 
0105:         * <li><b>Class Resolver </b>- Sessions have a class resolver (
0106:         * {@link IClassResolver}) implementation that is used to locate classes for
0107:         * components such as pages.
0108:         * 
0109:         * <li><b>Page Factory </b>- A pluggable implementation of {@link IPageFactory}
0110:         * is used to instantiate pages for the session.
0111:         * 
0112:         * <li><b>Removal </b>- Pages can be removed from the Session forcibly by
0113:         * calling remove(Page) or removeAll(), although such an action should rarely be
0114:         * necessary.
0115:         * 
0116:         * <li><b>Flash Messages</b>- Flash messages are messages that are stored in
0117:         * session and are removed after they are displayed to the user. Session acts as
0118:         * a store for these messages because they can last across requests.
0119:         * 
0120:         * @author Jonathan Locke
0121:         * @author Eelco Hillenius
0122:         * @author Igor Vaynberg (ivaynberg)
0123:         */
0124:        public abstract class Session implements  IClusterable {
0125:            /**
0126:             * Visitor interface for visiting page maps
0127:             * 
0128:             * @author Jonathan Locke
0129:             */
0130:            public static interface IPageMapVisitor {
0131:                /**
0132:                 * @param pageMap
0133:                 *            The page map
0134:                 */
0135:                public void pageMap(final IPageMap pageMap);
0136:            }
0137:
0138:            /**
0139:             * meta data for recording map map access.
0140:             */
0141:            public static final class PageMapAccessMetaData implements 
0142:                    IClusterable {
0143:                private static final long serialVersionUID = 1L;
0144:
0145:                Set pageMapNames = new HashSet(2);
0146:
0147:                /**
0148:                 * @param pagemap
0149:                 *            the pagemap to add as used.
0150:                 * @return the boolean if it was added (didn't already contain the
0151:                 *         pagemap)
0152:                 */
0153:                public boolean add(IPageMap pagemap) {
0154:                    return pageMapNames.add(pagemap.getName());
0155:                }
0156:            }
0157:
0158:            /**
0159:             * Filter that returns all component scoped messages ({@link FeedbackMessage#getReporter()} !=
0160:             * null).
0161:             */
0162:            public static final IFeedbackMessageFilter MESSAGES_FOR_COMPONENTS = new IFeedbackMessageFilter() {
0163:                private static final long serialVersionUID = 1L;
0164:
0165:                public boolean accept(FeedbackMessage message) {
0166:                    return message.getReporter() != null;
0167:                }
0168:            };
0169:
0170:            /** meta data key for missing body tags logging. */
0171:            public static final MetaDataKey PAGEMAP_ACCESS_MDK = new MetaDataKey(
0172:                    PageMapAccessMetaData.class) {
0173:                private static final long serialVersionUID = 1L;
0174:            };
0175:
0176:            /** Name of session attribute under which this session is stored */
0177:            public static final String SESSION_ATTRIBUTE_NAME = "session";
0178:
0179:            /** Thread-local current session. */
0180:            private static final ThreadLocal current = new ThreadLocal();
0181:
0182:            /** A store for dirty objects for one request */
0183:            private static final ThreadLocal dirtyObjects = new ThreadLocal();
0184:
0185:            /** Logging object */
0186:            private static final Logger log = LoggerFactory
0187:                    .getLogger(Session.class);
0188:
0189:            /** Attribute prefix for page maps stored in the session */
0190:            private static final String pageMapAttributePrefix = "m:";
0191:
0192:            /**
0193:             * Filter that returns all session scoped messages ({@link FeedbackMessage#getReporter()} ==
0194:             * null).
0195:             */
0196:            private static final IFeedbackMessageFilter RENDERED_SESSION_SCOPED_MESSAGES = new IFeedbackMessageFilter() {
0197:                private static final long serialVersionUID = 1L;
0198:
0199:                public boolean accept(FeedbackMessage message) {
0200:                    return message.getReporter() == null
0201:                            && message.isRendered();
0202:                }
0203:            };
0204:
0205:            private static final long serialVersionUID = 1L;
0206:
0207:            /** A store for touched pages for one request */
0208:            private static final ThreadLocal touchedPages = new ThreadLocal();
0209:
0210:            /** Prefix for attributes holding page map entries */
0211:            static final String pageMapEntryAttributePrefix = "p:";
0212:
0213:            /**
0214:             * Checks if the <code>Session</code> threadlocal is set in this thread
0215:             * 
0216:             * @return true if {@link Session#get()} can return the instance of session,
0217:             *         false otherwise
0218:             */
0219:            public static boolean exists() {
0220:                return current.get() != null;
0221:            }
0222:
0223:            /**
0224:             * Locate the session for the client of this request in the
0225:             * {@link ISessionStore} or create a new one and attach it when none could
0226:             * be located and sets it as the current instance for this thread.
0227:             * Typically, clients never touch this method, but rather use
0228:             * {@link Session#get()}, which does the locating implicitly when not yet
0229:             * set as a thread local.
0230:             * 
0231:             * @return The session for the client of this request or a new, unbound
0232:             */
0233:            public static final Session findOrCreate() {
0234:                RequestCycle requestCycle = RequestCycle.get();
0235:                if (requestCycle == null) {
0236:                    throw new IllegalStateException(
0237:                            "you can only locate or create sessions in the context of a request cycle");
0238:                }
0239:                Application application = Application.get();
0240:                ISessionStore sessionStore = application.getSessionStore();
0241:                Session session = sessionStore
0242:                        .lookup(requestCycle.getRequest());
0243:
0244:                if (session == null) {
0245:                    // Create session using session factory
0246:                    session = application.newSession(requestCycle.getRequest(),
0247:                            requestCycle.getResponse());
0248:                }
0249:
0250:                // set thread local
0251:                set(session);
0252:
0253:                return session;
0254:            }
0255:
0256:            /**
0257:             * Get the session for the calling thread.
0258:             * 
0259:             * @return Session for calling thread
0260:             */
0261:            public static Session get() {
0262:                Session session = (Session) current.get();
0263:                if (session == null) {
0264:                    session = findOrCreate();
0265:                }
0266:                return session;
0267:            }
0268:
0269:            /**
0270:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0271:             * <p>
0272:             * Sets session for calling thread. Also triggers {@link #attach()} being
0273:             * called.
0274:             * 
0275:             * @param session
0276:             *            The session
0277:             */
0278:            public static void set(final Session session) {
0279:                if (session == null) {
0280:                    throw new IllegalArgumentException(
0281:                            "Argument session can not be null");
0282:                }
0283:
0284:                current.set(session);
0285:
0286:                // execute any attach logic now
0287:                session.attach();
0288:            }
0289:
0290:            /**
0291:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0292:             * <p>
0293:             * Clears the session for calling thread.
0294:             * 
0295:             */
0296:            public static void unset() {
0297:                current.set(null);
0298:            }
0299:
0300:            /** A number to generate names for auto create pagemaps */
0301:            private int autoCreatePageMapCounter = 0;
0302:
0303:            /**
0304:             * Cached instance of agent info which is typically designated by calling
0305:             * {@link RequestCycle#newClientInfo()}.
0306:             */
0307:            private ClientInfo clientInfo;
0308:
0309:            /** True if session state has been changed */
0310:            private transient boolean dirty = false;
0311:
0312:            /** feedback messages */
0313:            private final FeedbackMessages feedbackMessages = new FeedbackMessages();
0314:
0315:            /** cached id because you can't access the id after session unbound */
0316:            private String id = null;
0317:
0318:            /** The locale to use when loading resources for this session. */
0319:            private Locale locale;
0320:
0321:            /** Application level meta data. */
0322:            private MetaDataEntry[] metaData;
0323:
0324:            /**
0325:             * We need to know both thread that keeps the pagemap lock and the
0326:             * RequestCycle
0327:             */
0328:            private static class PageMapsUsedInRequestEntry {
0329:                Thread thread;
0330:                RequestCycle requestCycle;
0331:            };
0332:
0333:            private transient Map pageMapsUsedInRequest;
0334:
0335:            /** True, if session has been invalidated */
0336:            private transient boolean sessionInvalidated = false;
0337:
0338:            /**
0339:             * Temporary instance of the session store. Should be set on each request as
0340:             * it is not supposed to go in the session.
0341:             */
0342:            private transient ISessionStore sessionStore;
0343:
0344:            /** Any special "skin" style to use when loading resources. */
0345:            private String style;
0346:
0347:            /**
0348:             * Holds attributes for sessions that are still temporary/ not bound to a
0349:             * session store. Only used when {@link #isTemporary()} is true.
0350:             * <p>
0351:             * Note: this doesn't have to be synchronized, as the only time when this
0352:             * map is used is when a session is temporary, in which case it won't be
0353:             * shared between requests (it's a per request instance).
0354:             * </p>
0355:             */
0356:            private transient Map temporarySessionAttributes;
0357:
0358:            /** A linked list for last used pagemap queue */
0359:            private final LinkedList/* <IPageMap> */usedPageMaps = new LinkedList();
0360:
0361:            /**
0362:             * Constructor. Note that {@link RequestCycle} is not available until this
0363:             * constructor returns.
0364:             * 
0365:             * @param request
0366:             *            The current request
0367:             */
0368:            public Session(Request request) {
0369:                locale = request.getLocale();
0370:                if (locale == null) {
0371:                    throw new IllegalArgumentException(
0372:                            "Parameter 'locale' must not be null");
0373:                }
0374:            }
0375:
0376:            /**
0377:             * Constructor. Note that {@link RequestCycle} is not available until this
0378:             * constructor returns.
0379:             * 
0380:             * @deprecated Use #Session(Request)
0381:             * 
0382:             * @param application
0383:             *            The application that this is a session of
0384:             * @param request
0385:             *            The current request
0386:             */
0387:            protected Session(Application application, Request request) {
0388:                this (request);
0389:            }
0390:
0391:            /**
0392:             * Force binding this session to the application's
0393:             * {@link ISessionStore session store} if not already done so.
0394:             * <p>
0395:             * A Wicket application can operate in a session-less mode as long as
0396:             * stateless pages are used. Session objects will be then created for each
0397:             * request, but they will only live for that request. You can recognize
0398:             * temporary sessions by calling {@link #isTemporary()} which basically
0399:             * checks whether the session's id is null. Hence, temporary sessions have
0400:             * no session id.
0401:             * </p>
0402:             * <p>
0403:             * By calling this method, the session will be bound (made not-temporary) if
0404:             * it was not bound yet. It is useful for cases where you want to be
0405:             * absolutely sure this session object will be available in next requests.
0406:             * If the session was already bound ({@link ISessionStore#lookup(Request) returns a session}),
0407:             * this call will be a noop.
0408:             * </p>
0409:             */
0410:            public final void bind() {
0411:                ISessionStore store = getSessionStore();
0412:                Request request = RequestCycle.get().getRequest();
0413:                if (store.lookup(request) == null) {
0414:                    // explicitly create a session
0415:                    id = store.getSessionId(request, true);
0416:                    // bind it
0417:                    store.bind(request, this );
0418:
0419:                    if (temporarySessionAttributes != null) {
0420:                        for (Iterator i = temporarySessionAttributes.entrySet()
0421:                                .iterator(); i.hasNext();) {
0422:                            Entry entry = (Entry) i.next();
0423:                            store.setAttribute(request, String.valueOf(entry
0424:                                    .getKey()), entry.getValue());
0425:                        }
0426:                        temporarySessionAttributes = null;
0427:                    }
0428:                }
0429:            }
0430:
0431:            /**
0432:             * Cleans up all rendered feedback messages and any unrendered, dangling
0433:             * feedback messages there may be left after that.
0434:             */
0435:            public void cleanupFeedbackMessages() {
0436:                // remove all component feedback messages if we are either using one
0437:                // pass or render to buffer render strategy (in which case we can remove
0438:                // without further delay) or in case the redirect to render strategy is
0439:                // used, when we're doing the render request (isRedirect should return
0440:                // false in that case)
0441:                if (Application.get().getRequestCycleSettings()
0442:                        .getRenderStrategy() != IRequestCycleSettings.REDIRECT_TO_RENDER
0443:                        || (!RequestCycle.get().isRedirect())) {
0444:                    // If session scoped, rendered messages got indeed cleaned up, mark
0445:                    // the session as dirty
0446:                    if (feedbackMessages
0447:                            .clear(RENDERED_SESSION_SCOPED_MESSAGES) > 0) {
0448:                        dirty();
0449:                    }
0450:
0451:                    // clean up all component related feedback messages
0452:                    feedbackMessages.clear(MESSAGES_FOR_COMPONENTS);
0453:                }
0454:            }
0455:
0456:            /**
0457:             * Removes all pages from the session. Although this method should rarely be
0458:             * needed, it is available (possibly for security reasons).
0459:             */
0460:            public final void clear() {
0461:                visitPageMaps(new IPageMapVisitor() {
0462:                    public void pageMap(IPageMap pageMap) {
0463:                        pageMap.clear();
0464:                    }
0465:                });
0466:            }
0467:
0468:            /**
0469:             * Automatically creates a page map, giving it a session unique name.
0470:             * 
0471:             * @return Created PageMap
0472:             */
0473:            public final IPageMap createAutoPageMap() {
0474:                return newPageMap(createAutoPageMapName());
0475:            }
0476:
0477:            protected int currentCreateAutoPageMapCounter() {
0478:                return autoCreatePageMapCounter;
0479:            }
0480:
0481:            protected void incrementCreateAutoPageMapCounter() {
0482:                ++autoCreatePageMapCounter;
0483:            }
0484:
0485:            /**
0486:             * With this call you can create a pagemap name but not create the pagemap
0487:             * itself already. It will give the first pagemap name where it couldn't
0488:             * find a current pagemap for.
0489:             * 
0490:             * It will return the same name if you call it 2 times in a row.
0491:             * 
0492:             * @return The created pagemap name
0493:             */
0494:            public synchronized final String createAutoPageMapName() {
0495:                String name = getAutoPageMapNamePrefix()
0496:                        + currentCreateAutoPageMapCounter()
0497:                        + getAutoPageMapNameSuffix();
0498:                IPageMap pm = pageMapForName(name, false);
0499:                while (pm != null) {
0500:                    incrementCreateAutoPageMapCounter();
0501:                    name = getAutoPageMapNamePrefix()
0502:                            + currentCreateAutoPageMapCounter()
0503:                            + getAutoPageMapNameSuffix();
0504:                    pm = pageMapForName(name, false);
0505:                }
0506:                return name;
0507:            }
0508:
0509:            /**
0510:             * @return
0511:             */
0512:            protected String getAutoPageMapNamePrefix() {
0513:                return "wicket-";
0514:            }
0515:
0516:            /**
0517:             * @return
0518:             */
0519:            protected String getAutoPageMapNameSuffix() {
0520:                return "";
0521:            }
0522:
0523:            /**
0524:             * Registers an error feedback message for this session
0525:             * 
0526:             * @param message
0527:             *            The feedback message
0528:             */
0529:            public final void error(final String message) {
0530:                addFeedbackMessage(message, FeedbackMessage.ERROR);
0531:            }
0532:
0533:            /**
0534:             * Get the application that is currently working with this session.
0535:             * 
0536:             * @return Returns the application.
0537:             */
0538:            public final Application getApplication() {
0539:                return Application.get();
0540:            }
0541:
0542:            /**
0543:             * @return The authorization strategy for this session
0544:             */
0545:            public IAuthorizationStrategy getAuthorizationStrategy() {
0546:                return getApplication().getSecuritySettings()
0547:                        .getAuthorizationStrategy();
0548:            }
0549:
0550:            /**
0551:             * @return The class resolver for this Session
0552:             */
0553:            public final IClassResolver getClassResolver() {
0554:                return getApplication().getApplicationSettings()
0555:                        .getClassResolver();
0556:            }
0557:
0558:            /**
0559:             * Gets the client info object for this session. This method lazily gets the
0560:             * new agent info object for this session. It uses any cached or set ({@link #setClientInfo(ClientInfo)})
0561:             * client info object or uses {@link RequestCycle#newClientInfo()} to get
0562:             * the info object based on the current request when no client info object
0563:             * was set yet, and then caches the returned object; we can expect the
0564:             * client to stay the same for the whole session, and implementations of
0565:             * {@link RequestCycle#newClientInfo()} might be relatively expensive.
0566:             * 
0567:             * @return the client info object based on this request
0568:             */
0569:            public ClientInfo getClientInfo() {
0570:                if (clientInfo == null) {
0571:                    clientInfo = RequestCycle.get().newClientInfo();
0572:                }
0573:                return clientInfo;
0574:            }
0575:
0576:            /**
0577:             * @return The default page map
0578:             */
0579:            public final IPageMap getDefaultPageMap() {
0580:                return pageMapForName(PageMap.DEFAULT_NAME, true);
0581:            }
0582:
0583:            /**
0584:             * Gets feedback messages stored in session
0585:             * 
0586:             * @return unmodifiable list of feedback messages
0587:             */
0588:            public final FeedbackMessages getFeedbackMessages() {
0589:                return feedbackMessages;
0590:            }
0591:
0592:            /**
0593:             * Gets the unique id for this session from the underlying SessionStore. May
0594:             * be null if a concrete session is not yet created.
0595:             * 
0596:             * @return The unique id for this session or null if it is a temporary
0597:             *         session
0598:             */
0599:            public final String getId() {
0600:                if (id == null) {
0601:                    id = getSessionStore().getSessionId(
0602:                            RequestCycle.get().getRequest(), false);
0603:
0604:                    // we have one?
0605:                    if (id != null) {
0606:                        dirty();
0607:                    }
0608:                }
0609:                return id;
0610:            }
0611:
0612:            /**
0613:             * Get this session's locale.
0614:             * 
0615:             * @return This session's locale
0616:             */
0617:            public Locale getLocale() {
0618:                return locale;
0619:            }
0620:
0621:            /**
0622:             * Gets metadata for this session using the given key.
0623:             * 
0624:             * @param key
0625:             *            The key for the data
0626:             * @return The metadata
0627:             * @see MetaDataKey
0628:             */
0629:            public final Serializable getMetaData(final MetaDataKey key) {
0630:                return key.get(metaData);
0631:            }
0632:
0633:            /**
0634:             * When a regular request on certain page with certain version is being
0635:             * processed, we don't allow ajax requests to same page and version.
0636:             * 
0637:             * @param lockedRequestCycle
0638:             * @return whether current request is valid or sould be discarded
0639:             */
0640:            protected boolean isCurrentRequestValid(
0641:                    RequestCycle lockedRequestCycle) {
0642:                return true;
0643:            }
0644:
0645:            /**
0646:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0647:             * 
0648:             * Returns the page with given id and versionNumber. It keeps asking
0649:             * pageMaps for given page until it finds one that contains it.
0650:             * 
0651:             * @param pageId
0652:             * @param versionNumber
0653:             * @return
0654:             */
0655:            public final Page getPage(final int pageId, final int versionNumber) {
0656:                if (Application.get().getSessionSettings()
0657:                        .isPageIdUniquePerSession() == false) {
0658:                    throw new IllegalStateException(
0659:                            "To call this method ISessionSettings.setPageIdUniquePerSession must be set to true");
0660:                }
0661:
0662:                List pageMaps = getPageMaps();
0663:
0664:                for (Iterator i = pageMaps.iterator(); i.hasNext();) {
0665:                    IPageMap pm = (IPageMap) i.next();
0666:                    if (pm.containsPage(pageId, versionNumber)) {
0667:                        return getPage(pm.getName(), "" + pageId, versionNumber);
0668:                    }
0669:                }
0670:
0671:                return null;
0672:            }
0673:
0674:            /**
0675:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0676:             * 
0677:             * Get the page for the given path.
0678:             * 
0679:             * @param pageMapName
0680:             *            The name of the page map where the page is
0681:             * @param path
0682:             *            Component path
0683:             * @param versionNumber
0684:             *            The version of the page required
0685:             * @return The page based on the first path component (the page id), or null
0686:             *         if the requested version of the page cannot be found.
0687:             */
0688:            public final Page getPage(final String pageMapName,
0689:                    final String path, final int versionNumber) {
0690:                if (log.isDebugEnabled()) {
0691:                    log.debug("Getting page [path = " + path
0692:                            + ", versionNumber = " + versionNumber + "]");
0693:                }
0694:
0695:                // Get page map by name, creating the default page map automatically
0696:                IPageMap pageMap = pageMapForName(pageMapName,
0697:                        pageMapName == PageMap.DEFAULT_NAME);
0698:                if (pageMap != null) {
0699:                    synchronized (usedPageMaps) // get a lock so be sure that only one
0700:                    // is made
0701:                    {
0702:                        if (pageMapsUsedInRequest == null) {
0703:                            pageMapsUsedInRequest = new HashMap(3);
0704:                        }
0705:                    }
0706:                    synchronized (pageMapsUsedInRequest) {
0707:                        long startTime = System.currentTimeMillis();
0708:
0709:                        // TODO For now only use the setting. Might be extended with
0710:                        // something overridable on request/ page/ request target level
0711:                        // later
0712:                        Duration timeout = Application.get()
0713:                                .getRequestCycleSettings().getTimeout();
0714:
0715:                        PageMapsUsedInRequestEntry entry = (PageMapsUsedInRequestEntry) pageMapsUsedInRequest
0716:                                .get(pageMap);
0717:
0718:                        // Get page entry for id and version
0719:                        Thread t = entry != null ? entry.thread : null;
0720:                        while (t != null && t != Thread.currentThread()) {
0721:                            if (isCurrentRequestValid(entry.requestCycle) == false) {
0722:                                // we need to ignore this request. That's because it is
0723:                                // an ajax request
0724:                                // while regular page request is being processed
0725:                                throw new IgnoreAjaxRequestException();
0726:                            }
0727:
0728:                            try {
0729:                                pageMapsUsedInRequest.wait(timeout
0730:                                        .getMilliseconds());
0731:                            } catch (InterruptedException ex) {
0732:                                throw new WicketRuntimeException(ex);
0733:                            }
0734:
0735:                            entry = (PageMapsUsedInRequestEntry) pageMapsUsedInRequest
0736:                                    .get(pageMap);
0737:                            t = entry != null ? entry.thread : null;
0738:
0739:                            if (t != null
0740:                                    && t != Thread.currentThread()
0741:                                    && (startTime + timeout.getMilliseconds()) < System
0742:                                            .currentTimeMillis()) {
0743:                                // if it is still not the right thread..
0744:                                // This either points to long running code (a report
0745:                                // page?) or a deadlock or such
0746:                                throw new WicketRuntimeException(
0747:                                        "After "
0748:                                                + timeout
0749:                                                + " the Pagemap "
0750:                                                + pageMapName
0751:                                                + " is still locked by: "
0752:                                                + t
0753:                                                + ", giving up trying to get the page for path: "
0754:                                                + path);
0755:                            }
0756:                        }
0757:
0758:                        PageMapsUsedInRequestEntry newEntry = new PageMapsUsedInRequestEntry();
0759:                        newEntry.thread = Thread.currentThread();
0760:                        newEntry.requestCycle = RequestCycle.get();
0761:                        pageMapsUsedInRequest.put(pageMap, newEntry);
0762:                        final String id = Strings.firstPathComponent(path,
0763:                                Component.PATH_SEPARATOR);
0764:                        Page page = pageMap.get(Integer.parseInt(id),
0765:                                versionNumber);
0766:                        if (page == null) {
0767:                            pageMapsUsedInRequest.remove(pageMap);
0768:                            pageMapsUsedInRequest.notifyAll();
0769:                        } else {
0770:                            // attach the page now.
0771:                            page.attach();
0772:                            touch(page);
0773:                        }
0774:                        return page;
0775:                    }
0776:                }
0777:                return null;
0778:            }
0779:
0780:            /**
0781:             * @return The page factory for this session
0782:             */
0783:            public final IPageFactory getPageFactory() {
0784:                return getApplication().getSessionSettings().getPageFactory();
0785:            }
0786:
0787:            /**
0788:             * @param page
0789:             *            The page, or null if no page context is available
0790:             * @return The page factory for the page, or the default page factory if
0791:             *         page was null
0792:             */
0793:            public final IPageFactory getPageFactory(final Page page) {
0794:                if (page != null) {
0795:                    return page.getPageFactory();
0796:                }
0797:                return getPageFactory();
0798:            }
0799:
0800:            /**
0801:             * @return A list of all PageMaps in this session.
0802:             */
0803:            public final List getPageMaps() {
0804:                final List list = new ArrayList();
0805:                for (final Iterator iterator = getAttributeNames().iterator(); iterator
0806:                        .hasNext();) {
0807:                    final String attribute = (String) iterator.next();
0808:                    if (attribute.startsWith(pageMapAttributePrefix)) {
0809:                        list.add(getAttribute(attribute));
0810:                    }
0811:                }
0812:                return list;
0813:            }
0814:
0815:            /**
0816:             * @return Size of this session, including all the pagemaps it contains
0817:             */
0818:            public final long getSizeInBytes() {
0819:                long size = Objects.sizeof(this );
0820:                for (final Iterator iterator = getPageMaps().iterator(); iterator
0821:                        .hasNext();) {
0822:                    final IPageMap pageMap = (IPageMap) iterator.next();
0823:                    size += pageMap.getSizeInBytes();
0824:                }
0825:                return size;
0826:            }
0827:
0828:            /**
0829:             * Get the style (see {@link org.apache.wicket.Session}).
0830:             * 
0831:             * @return Returns the style (see {@link org.apache.wicket.Session})
0832:             */
0833:            public final String getStyle() {
0834:                return style;
0835:            }
0836:
0837:            /**
0838:             * Registers an informational feedback message for this session
0839:             * 
0840:             * @param message
0841:             *            The feedback message
0842:             */
0843:            public final void info(final String message) {
0844:                addFeedbackMessage(message, FeedbackMessage.INFO);
0845:            }
0846:
0847:            /**
0848:             * Invalidates this session at the end of the current request. If you need
0849:             * to invalidate the session immediately, you can do this by calling
0850:             * invalidateNow(), however this will remove all Wicket components from this
0851:             * session, which means that you will no longer be able to work with them.
0852:             */
0853:            public void invalidate() {
0854:                sessionInvalidated = true;
0855:            }
0856:
0857:            /**
0858:             * Invalidates this session immediately. Calling this method will remove all
0859:             * Wicket components from this session, which means that you will no longer
0860:             * be able to work with them.
0861:             */
0862:            public void invalidateNow() {
0863:                sessionInvalidated = true; // set this for isSessionInvalidated
0864:                getSessionStore().invalidate(RequestCycle.get().getRequest());
0865:            }
0866:
0867:            /**
0868:             * Whether the session is invalid now, or will be invalidated by the end of
0869:             * the request. Clients should rarely need to use this method if ever.
0870:             * 
0871:             * @return Whether the session is invalid when the current request is done
0872:             * 
0873:             * @see #invalidate()
0874:             * @see #invalidateNow()
0875:             */
0876:            public final boolean isSessionInvalidated() {
0877:                return sessionInvalidated;
0878:            }
0879:
0880:            /**
0881:             * Whether this session is temporary. A Wicket application can operate in a
0882:             * session-less mode as long as stateless pages are used. If this session
0883:             * object is temporary, it will not be available on a next request.
0884:             * 
0885:             * @return Whether this session is temporary (which is the same as it's id
0886:             *         being null)
0887:             */
0888:            public final boolean isTemporary() {
0889:                return getId() == null;
0890:            }
0891:
0892:            /**
0893:             * Creates a new page map with a given name
0894:             * 
0895:             * @param name
0896:             *            The name for the new page map
0897:             * @return The newly created page map
0898:             */
0899:            public final IPageMap newPageMap(final String name) {
0900:                // Check that session doesn't have too many page maps already
0901:                final int maxPageMaps = getApplication().getSessionSettings()
0902:                        .getMaxPageMaps();
0903:                synchronized (usedPageMaps) {
0904:                    if (usedPageMaps.size() >= maxPageMaps) {
0905:                        IPageMap pm = (IPageMap) usedPageMaps.getFirst();
0906:                        pm.remove();
0907:                    }
0908:                }
0909:
0910:                // Create new page map
0911:                final IPageMap pageMap = getSessionStore().createPageMap(name);
0912:                setAttribute(attributeForPageMapName(name), pageMap);
0913:                dirty();
0914:                return pageMap;
0915:            }
0916:
0917:            /**
0918:             * Gets a page map for the given name, automatically creating it if need be.
0919:             * 
0920:             * @param pageMapName
0921:             *            Name of page map, or null for default page map
0922:             * @param autoCreate
0923:             *            True if the page map should be automatically created if it
0924:             *            does not exist
0925:             * @return PageMap for name
0926:             */
0927:            public final IPageMap pageMapForName(String pageMapName,
0928:                    final boolean autoCreate) {
0929:                IPageMap pageMap = (IPageMap) getAttribute(attributeForPageMapName(pageMapName));
0930:                if (pageMap == null && autoCreate) {
0931:                    pageMap = newPageMap(pageMapName);
0932:                }
0933:                return pageMap;
0934:            }
0935:
0936:            /**
0937:             * @param pageMap
0938:             *            Page map to remove
0939:             */
0940:            public final void removePageMap(final IPageMap pageMap) {
0941:                PageMapAccessMetaData pagemapMetaData = (PageMapAccessMetaData) getMetaData(PAGEMAP_ACCESS_MDK);
0942:                if (pagemapMetaData != null) {
0943:                    pagemapMetaData.pageMapNames.remove(pageMap.getName());
0944:                }
0945:
0946:                synchronized (usedPageMaps) {
0947:                    usedPageMaps.remove(pageMap);
0948:                }
0949:
0950:                removeAttribute(attributeForPageMapName(pageMap.getName()));
0951:                dirty();
0952:            }
0953:
0954:            /**
0955:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0956:             * <p>
0957:             * Sets the application that this session is associated with.
0958:             * 
0959:             * @param application
0960:             *            The application
0961:             */
0962:            public final void setApplication(final Application application) {
0963:            }
0964:
0965:            /**
0966:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
0967:             * <p>
0968:             * Sets the client info object for this session. This will only work when
0969:             * {@link #getClientInfo()} is not overriden.
0970:             * 
0971:             * @param clientInfo
0972:             *            the client info object
0973:             */
0974:            public final void setClientInfo(ClientInfo clientInfo) {
0975:                this .clientInfo = clientInfo;
0976:                dirty();
0977:            }
0978:
0979:            /**
0980:             * Set the locale for this session.
0981:             * 
0982:             * @param locale
0983:             *            New locale
0984:             */
0985:            public final void setLocale(final Locale locale) {
0986:                if (locale == null) {
0987:                    throw new IllegalArgumentException(
0988:                            "Parameter 'locale' must not be null");
0989:                }
0990:                this .locale = locale;
0991:                dirty();
0992:            }
0993:
0994:            /**
0995:             * Sets the metadata for this session using the given key. If the metadata
0996:             * object is not of the correct type for the metadata key, an
0997:             * IllegalArgumentException will be thrown. For information on creating
0998:             * MetaDataKeys, see {@link MetaDataKey}.
0999:             * 
1000:             * @param key
1001:             *            The singleton key for the metadata
1002:             * @param object
1003:             *            The metadata object
1004:             * @throws IllegalArgumentException
1005:             * @see MetaDataKey
1006:             */
1007:            public final void setMetaData(final MetaDataKey key,
1008:                    final Serializable object) {
1009:                metaData = key.set(metaData, object);
1010:            }
1011:
1012:            /**
1013:             * Set the style (see {@link org.apache.wicket.Session}).
1014:             * 
1015:             * @param style
1016:             *            The style to set.
1017:             * @return the Session object
1018:             */
1019:            public final Session setStyle(final String style) {
1020:                this .style = style;
1021:                dirty();
1022:                return this ;
1023:            }
1024:
1025:            /**
1026:             * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT CALL IT.
1027:             * <p>
1028:             * The page will be 'touched' in the session. If it wasn't added yet to the
1029:             * pagemap, it will be added to the page map else it will set this page to
1030:             * the front.
1031:             * 
1032:             * If another page was removed because of this it will be cleaned up.
1033:             * 
1034:             * @param page
1035:             */
1036:            public final void touch(Page page) {
1037:                // store it in a list, so that the pages are really pushed
1038:                // to the pagemap when the session does it update/detaches.
1039:                // all the pages are then detached
1040:                List lst = (List) touchedPages.get();
1041:                if (lst == null) {
1042:                    lst = new ArrayList();
1043:                    touchedPages.set(lst);
1044:                    lst.add(page);
1045:                } else if (!lst.contains(page)) {
1046:                    lst.add(page);
1047:                }
1048:            }
1049:
1050:            /**
1051:             * @param visitor
1052:             *            The visitor to call at each Page in this PageMap.
1053:             */
1054:            public final void visitPageMaps(final IPageMapVisitor visitor) {
1055:                for (final Iterator iterator = getAttributeNames().iterator(); iterator
1056:                        .hasNext();) {
1057:                    final String attribute = (String) iterator.next();
1058:                    if (attribute.startsWith(pageMapAttributePrefix)) {
1059:                        visitor.pageMap((IPageMap) getAttribute(attribute));
1060:                    }
1061:                }
1062:            }
1063:
1064:            /**
1065:             * Registers a warning feedback message for this session
1066:             * 
1067:             * @param message
1068:             *            The feedback message
1069:             */
1070:            public final void warn(final String message) {
1071:                addFeedbackMessage(message, FeedbackMessage.WARNING);
1072:            }
1073:
1074:            /**
1075:             * Adds a feedback message to the list of messages
1076:             * 
1077:             * @param message
1078:             * @param level
1079:             * 
1080:             */
1081:            private void addFeedbackMessage(String message, int level) {
1082:                getFeedbackMessages().add(null, message, level);
1083:                dirty();
1084:            }
1085:
1086:            /**
1087:             * @param pageMapName
1088:             *            Name of page map
1089:             * @return Session attribute holding page map
1090:             */
1091:            private final String attributeForPageMapName(
1092:                    final String pageMapName) {
1093:                return pageMapAttributePrefix + pageMapName;
1094:            }
1095:
1096:            /**
1097:             * Any attach logic for session subclasses. Called when a session is set for
1098:             * the thread.
1099:             */
1100:            protected void attach() {
1101:            }
1102:
1103:            /**
1104:             * Any detach logic for session subclasses. This is called on the end of
1105:             * handling a request, when the RequestCycle is about to be detached from
1106:             * the current thread.
1107:             */
1108:            protected void detach() {
1109:                if (sessionInvalidated) {
1110:                    invalidateNow();
1111:                }
1112:            }
1113:
1114:            /**
1115:             * Marks session state as dirty so that it will be flushed at the end of the
1116:             * request.
1117:             */
1118:            public final void dirty() {
1119:                dirty = true;
1120:            }
1121:
1122:            /**
1123:             * Gets the attribute value with the given name
1124:             * 
1125:             * @param name
1126:             *            The name of the attribute to store
1127:             * @return The value of the attribute
1128:             */
1129:            protected final Object getAttribute(final String name) {
1130:                if (!isTemporary()) {
1131:                    RequestCycle cycle = RequestCycle.get();
1132:                    if (cycle != null) {
1133:                        return getSessionStore().getAttribute(
1134:                                cycle.getRequest(), name);
1135:                    }
1136:                } else {
1137:                    if (temporarySessionAttributes != null) {
1138:                        return temporarySessionAttributes.get(name);
1139:                    }
1140:                }
1141:                return null;
1142:            }
1143:
1144:            /**
1145:             * @return List of attributes for this session
1146:             */
1147:            protected final List getAttributeNames() {
1148:                if (!isTemporary()) {
1149:                    RequestCycle cycle = RequestCycle.get();
1150:                    if (cycle != null) {
1151:                        return getSessionStore().getAttributeNames(
1152:                                cycle.getRequest());
1153:                    }
1154:                } else {
1155:                    if (temporarySessionAttributes != null) {
1156:                        return new ArrayList(temporarySessionAttributes
1157:                                .keySet());
1158:                    }
1159:                }
1160:                return Collections.EMPTY_LIST;
1161:            }
1162:
1163:            /**
1164:             * Gets the session store.
1165:             * 
1166:             * @return the session store
1167:             */
1168:            protected ISessionStore getSessionStore() {
1169:                if (sessionStore == null) {
1170:                    sessionStore = getApplication().getSessionStore();
1171:                }
1172:                return sessionStore;
1173:            }
1174:
1175:            /**
1176:             * Removes the attribute with the given name.
1177:             * 
1178:             * @param name
1179:             *            the name of the attribute to remove
1180:             */
1181:            protected final void removeAttribute(String name) {
1182:                if (!isTemporary()) {
1183:                    RequestCycle cycle = RequestCycle.get();
1184:                    if (cycle != null) {
1185:                        getSessionStore().removeAttribute(cycle.getRequest(),
1186:                                name);
1187:                    }
1188:                } else {
1189:                    if (temporarySessionAttributes != null) {
1190:                        temporarySessionAttributes.remove(name);
1191:                    }
1192:                }
1193:            }
1194:
1195:            /**
1196:             * Adds or replaces the attribute with the given name and value.
1197:             * 
1198:             * @param name
1199:             *            The name of the attribute
1200:             * @param value
1201:             *            The value of the attribute
1202:             */
1203:            protected final void setAttribute(String name, Object value) {
1204:                if (!isTemporary()) {
1205:                    RequestCycle cycle = RequestCycle.get();
1206:                    if (cycle == null) {
1207:                        throw new IllegalStateException(
1208:                                "Cannot set the attribute: no RequestCycle available");
1209:                    }
1210:
1211:                    ISessionStore store = getSessionStore();
1212:                    Request request = cycle.getRequest();
1213:
1214:                    // extra check on session binding event
1215:                    if (value == this ) {
1216:                        Object current = store.getAttribute(request, name);
1217:                        if (current == null) {
1218:                            String id = store.getSessionId(request, false);
1219:                            if (id != null) {
1220:                                // this is a new instance. wherever it came from, bind
1221:                                // the session now
1222:                                store.bind(request, (Session) value);
1223:                            }
1224:                        }
1225:                    }
1226:
1227:                    // Set the actual attribute
1228:                    store.setAttribute(request, name, value);
1229:                } else {
1230:                    // we don't have to synchronize, as it is impossible a temporary
1231:                    // session instance gets shared across threads
1232:                    if (temporarySessionAttributes == null) {
1233:                        temporarySessionAttributes = new HashMap(3);
1234:                    }
1235:                    temporarySessionAttributes.put(name, value);
1236:                }
1237:            }
1238:
1239:            /**
1240:             * NOT TO BE CALLED BY FRAMEWORK USERS.
1241:             * 
1242:             * @deprecated obsolete method (was meant for internal book keeping really).
1243:             *             Clients should override {@link #detach()} instead.
1244:             */
1245:            protected final void update() {
1246:                throw new UnsupportedOperationException();
1247:            }
1248:
1249:            /**
1250:             * @param page
1251:             *            The page to add to dirty objects list
1252:             */
1253:            void dirtyPage(final Page page) {
1254:                List dirtyObjects = getDirtyObjectsList();
1255:                if (!dirtyObjects.contains(page)) {
1256:                    dirtyObjects.add(page);
1257:                }
1258:            }
1259:
1260:            /**
1261:             * @param map
1262:             *            The page map to add to dirty objects list
1263:             */
1264:            void dirtyPageMap(final IPageMap map) {
1265:                if (!map.isDefault()) {
1266:                    synchronized (usedPageMaps) {
1267:                        usedPageMaps.remove(map);
1268:                        usedPageMaps.addLast(map);
1269:                    }
1270:                }
1271:                List dirtyObjects = getDirtyObjectsList();
1272:                if (!dirtyObjects.contains(map)) {
1273:                    dirtyObjects.add(map);
1274:                }
1275:            }
1276:
1277:            /**
1278:             * @return The current thread dirty objects list
1279:             */
1280:            List getDirtyObjectsList() {
1281:                List list = (List) dirtyObjects.get();
1282:                if (list == null) {
1283:                    list = new ArrayList(4);
1284:                    dirtyObjects.set(list);
1285:                }
1286:                return list;
1287:            }
1288:
1289:            // TODO remove after deprecation release
1290:
1291:            /**
1292:             * INTERNAL API. The request cycle when detached will call this.
1293:             * 
1294:             */
1295:            final void requestDetached() {
1296:                List touchedPages = (List) Session.touchedPages.get();
1297:                Session.touchedPages.set(null);
1298:                if (touchedPages != null) {
1299:                    for (int i = 0; i < touchedPages.size(); i++) {
1300:                        Page page = (Page) touchedPages.get(i);
1301:                        page.getPageMap().put(page);
1302:                    }
1303:                }
1304:
1305:                // If state is dirty
1306:                if (dirty) {
1307:                    // State is no longer dirty
1308:                    dirty = false;
1309:
1310:                    // Set attribute.
1311:                    setAttribute(SESSION_ATTRIBUTE_NAME, this );
1312:                } else {
1313:                    if (log.isDebugEnabled()) {
1314:                        log.debug("update: Session not dirty.");
1315:                    }
1316:                }
1317:
1318:                List dirtyObjects = (List) Session.dirtyObjects.get();
1319:                Session.dirtyObjects.set(null);
1320:
1321:                Map tempMap = new HashMap();
1322:
1323:                // Go through all dirty entries, replicating any dirty objects
1324:                if (dirtyObjects != null) {
1325:                    for (final Iterator iterator = dirtyObjects.iterator(); iterator
1326:                            .hasNext();) {
1327:                        String attribute = null;
1328:                        Object object = iterator.next();
1329:                        if (object instanceof  Page) {
1330:                            final Page page = (Page) object;
1331:                            if (page.isStateless()) {
1332:                                // check, can it be that stateless pages where added to
1333:                                // the session?
1334:                                // and should be removed now?
1335:                                continue;
1336:                            }
1337:                            attribute = page.getPageMap().attributeForId(
1338:                                    page.getNumericId());
1339:                            if (getAttribute(attribute) == null) {
1340:                                // page removed by another thread. don't add it again.
1341:                                continue;
1342:                            }
1343:                            object = page.getPageMapEntry();
1344:                        } else if (object instanceof  IPageMap) {
1345:                            attribute = attributeForPageMapName(((IPageMap) object)
1346:                                    .getName());
1347:                        }
1348:
1349:                        // we might override some attributes, so we use a temporary map
1350:                        // and then just copy the last values to real sesssion
1351:                        tempMap.put(attribute, object);
1352:                    }
1353:                }
1354:
1355:                // in case we have dirty attributes, set them to session
1356:                if (tempMap.isEmpty() == false) {
1357:                    for (Iterator i = tempMap.entrySet().iterator(); i
1358:                            .hasNext();) {
1359:                        Map.Entry entry = (Map.Entry) i.next();
1360:                        setAttribute((String) entry.getKey(), entry.getValue());
1361:                    }
1362:                }
1363:
1364:                if (pageMapsUsedInRequest != null) {
1365:                    synchronized (pageMapsUsedInRequest) {
1366:                        Thread t = Thread.currentThread();
1367:                        Iterator it = pageMapsUsedInRequest.entrySet()
1368:                                .iterator();
1369:                        while (it.hasNext()) {
1370:                            Entry entry = (Entry) it.next();
1371:                            if (((PageMapsUsedInRequestEntry) entry.getValue()).thread == t) {
1372:                                it.remove();
1373:                            }
1374:                        }
1375:                        pageMapsUsedInRequest.notifyAll();
1376:                    }
1377:                }
1378:            }
1379:
1380:            private int pageIdCounter = 0;
1381:
1382:            synchronized protected int nextPageId() {
1383:                return pageIdCounter++;
1384:            }
1385:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.