1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.orchestra.conversation;
20
21 import java.util.HashSet;
22 import java.util.Set;
23
24 import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
25
26 /**
27 * Manager to deal with page scoped beans.
28 * <p>
29 * Instances of this type are expected to be request-scoped, ie a new instance is used for
30 * each request. The AccessScopeManagerConfiguration object that it references can be
31 * of application scope.
32 *
33 * @since 1.1
34 */
35 public class AccessScopeManager
36 {
37 private static final String REQ_ATTR_KEY = AccessScopeManager.class.getName();
38 private AccessScopeManagerConfiguration accessScopeManagerConfiguration;
39
40 private boolean recordAccess;
41 private boolean ignoreRequest;
42 private Set accessedConversations = new HashSet();
43
44 public static AccessScopeManager getInstance()
45 {
46 // Get the instance by looking up a variable whose name is this class name, using the normal
47 // managed bean lookup process. When an IOC framework like Spring is being used to extend
48 // the standard JSF managed bean declaration facilities, then the bean may be retrieved
49 // from there.
50 //
51 // Using a lookup of a managed bean allows the user to set configuration properties on the
52 // manager class and its properties.
53
54 FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
55 AccessScopeManager manager = (AccessScopeManager) fa.getRequestAttribute(REQ_ATTR_KEY);
56 if (manager != null)
57 {
58 // already found and cached in request attributes
59 return manager;
60 }
61
62 // Backwards compatibility hack: look for FlashScopeManager. It is possible that
63 // a user of Orchestra 1.0 has copied the declaration from the original Orchestra
64 // config file into their own code to inject special settings.
65 manager = (AccessScopeManager) fa.getBean(FlashScopeManager.class.getName());
66 if (manager != null)
67 {
68 fa.setRequestAttribute(REQ_ATTR_KEY, manager);
69 return manager;
70 }
71
72 // Backwards compatibility hack: look for FlashScopeManagerConfiguration. It is
73 // possible that a user of Orchestra 1.0 has overridden just the Configuration
74 // bit to set their own ignoredViewId values (as recommended!):
75 //
76 // This is a little dodgy as settings made through the new AccessScopeManage
77 // bean will will now be silently ignored.
78 FlashScopeManagerConfiguration cfg = (FlashScopeManagerConfiguration) fa.getBean(
79 FlashScopeManagerConfiguration.class.getName());
80 if (cfg != null)
81 {
82 manager = new AccessScopeManager();
83 manager.setAccessScopeManagerConfiguration(cfg);
84 fa.setRequestAttribute(REQ_ATTR_KEY, manager);
85 return manager;
86 }
87
88 // normal case
89 manager = (AccessScopeManager) fa.getBean(AccessScopeManager.class.getName());
90 if (manager != null)
91 {
92 fa.setRequestAttribute(REQ_ATTR_KEY, manager);
93 return manager;
94 }
95
96 // TODO: Make this error message less spring-specific. Spring is not the only IOC container
97 // that Orchestra can be used with.
98 throw new IllegalArgumentException(
99 "Orchestra was unable to create an instance of bean with name 'AccessScopeManager'." +
100 " Ensure that JSF variable resolution uses your dependency injection (DI) framework" +
101 " (eg Spring's DelegatingVariableResolver is in your faces-config.xml file) and" +
102 " the standard Orchestra configuration beans are defined (eg by using"+
103 " <import resource=\"classpath*:/META-INF/spring-orchestra-init.xml\" />).");
104 }
105
106 public AccessScopeManagerConfiguration getAccessScopeManagerConfiguration()
107 {
108 return accessScopeManagerConfiguration;
109 }
110
111 public void setAccessScopeManagerConfiguration(AccessScopeManagerConfiguration accessScopeManagerConfiguration)
112 {
113 this.accessScopeManagerConfiguration = accessScopeManagerConfiguration;
114 }
115
116 /**
117 * This is invoked at the point in the request lifecycle after which we want to
118 * start tracking use of access-scoped objects.
119 */
120 public void beginRecording()
121 {
122 recordAccess = true;
123 }
124
125 /**
126 * Add a conversation to the list of accessed conversations.
127 * <p>
128 * This method is expected to be called via AOP proxies wrapped around each conversation-scoped
129 * bean; any invocation of a method on such a bean causes the conversation associated with that
130 * bean to be added to the accessed list here.
131 */
132 public void addConversationAccess(String conversationName)
133 {
134 // Don't bother tracking accessed conversations if we will never use the data.
135 // Otherwise, add this conversation name to the list of accessed conversations.
136 if (recordAccess && !ignoreRequest && !accessedConversations.contains(conversationName))
137 {
138 accessedConversations.add(conversationName);
139 }
140 }
141
142 public boolean isIgnoreRequest()
143 {
144 return ignoreRequest;
145 }
146
147 /**
148 * Suppress access scope for the current request, ie do not terminate conversations that are
149 * not accessed by this request.
150 * <p>
151 * This can come in useful occasionally, particularly when handling AJAX requests which
152 * only access some of the beans associated with the current view.
153 */
154 public void setIgnoreRequest()
155 {
156 this.ignoreRequest = true;
157 }
158
159 public boolean isConversationAccessed(String name)
160 {
161 if (ignoreRequest)
162 {
163 throw new IllegalStateException();
164 }
165
166 return accessedConversations.contains(name);
167 }
168 }