|
1 /* |
|
2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package com.sun.xml.internal.ws.api.server; |
|
27 |
|
28 import com.sun.xml.internal.ws.server.WSEndpointImpl; |
|
29 import java.util.HashSet; |
|
30 import java.util.Set; |
|
31 import com.sun.org.glassfish.external.amx.AMXGlassfish; |
|
32 import com.sun.org.glassfish.external.amx.MBeanListener; |
|
33 import com.sun.org.glassfish.gmbal.ManagedObjectManager; |
|
34 |
|
35 /** |
|
36 * The lazy provider is intended to defer Gmbal API calls until there is a JMX connection. The provider is scope |
|
37 * (environment) aware and behaves accordingly to actual scope. The default behaviour does not defers Gmbal API calls. |
|
38 * |
|
39 * There are two kind of method allowing registration of an object as a listener. One is for {@code WSEndpointImpl} |
|
40 * instances (implementing {@code WSEndpointScopeChangeListener}) and the other is for arbitrary objects |
|
41 * (implementing {@code DefaultScopeChangeListener}) that want to be notified about scope changes. The distinction is made |
|
42 * because of the fact that endpoints should be registered first and other objects (e.g. dependants on endpoints) must |
|
43 * be registered after all the endpoints are processed so no inconsistency is present. |
|
44 * |
|
45 * Glassfish: |
|
46 * {@link WebServicesContainer} is one of two classes for which a {@link ManagedObjectManager} instance (see Gmbal API) |
|
47 * is created when a webservice application is deployed into the Glassfish. For the purpose of postponing Gmbal API calls |
|
48 * the {@code WebServicesContainer} extends {@link MBeanListener.CallbackImpl} so it can register itself as a listener of |
|
49 * {@link AMXGlassfish} and receive a notification about a connection of a JMX client to the Glassfish server (see |
|
50 * {@code WebServicesContainer#postConstruct} for registration details). The moment the JMX client is connected a notification |
|
51 * is sent to the listeners of {@code AMXGlassfish}. When this event is received by {@code WebServiceContainer} (see the |
|
52 * callback method {@code mbeanRegistered}) a {@code ManagedObjectManager} instance is created and no further deferring |
|
53 * of Gmbal API calls is needed. |
|
54 * |
|
55 * Metro/JAX-WS: |
|
56 * The situation in Metro/JAX-WS is slightly different from the one described above. Metro/JAX-WS can be used as standalone |
|
57 * libraries (outside of Glassfish) so no notification from the Glassfish server can be expected in this case. This leads |
|
58 * to a situation when Metro/JAX-WS has to be aware of context in which it is used and acts appropriately. There are 3 |
|
59 * scopes an application using Metro/JAX-WS can be in: {@code STANDALONE}, {@code GLASSFISH_NO_JMX}, {@code GLASSFISH_JMX} |
|
60 * ({@link LazyMOMProvider#scope}). The default scope is {@code STANDALONE} and all Gmbal API calls are invoked as they |
|
61 * are requested. The other two scopes are applied only when an application is deployed into a Glassfish server. The |
|
62 * {@code GLASSFISH_NO_JMX} is set at the moment the application is deployed (see below) and its purpose is to defer Gmbal |
|
63 * API calls for as long as possible. For some classes e.g. {@code ManagedObjectManager} proxy classes were introduced to |
|
64 * avoid the necessity of creating the real Gmbal objects but if a method is invoked on these proxies the creation of real |
|
65 * Gmbal objects is forced even in this scope. The {@code GLASSFISH_JMX} scope is set when a JMX client is connected to |
|
66 * the Glassfish server and it processes Gmbal API calls without deferring (as if the application was in the |
|
67 * {@code STANDALONE} scope). The entry point for postponing the Gmbal API calls / creating Gmbal objects in Metro/JAX-WS |
|
68 * is {@link LazyMOMProvider}. This class is capable of receiving notifications from the Glassfish server |
|
69 * ({@code LazyMOMProvider.initMOMForScope}) about the scope change and it also spread this information to its listeners. |
|
70 * The listeners of {@code LazyMOMProvider} are of two kinds: {@link LazyMOMProvider.WSEndpointScopeChangeListener} and |
|
71 * {@link LazyMOMProvider.DefaultScopeChangeListener}. Extensions of {@link WSEndpoint} (e.g. {@link WSEndpointImpl}) |
|
72 * should implement the {@code LazyMOMProvider.WSEndpointScopeChangeListener} and register themselves as endpoint listeners |
|
73 * of {@code LazyMOMProvider}. Other classes should implement the latter mentioned interface and register themselves as |
|
74 * a non-endpoint listener. The differences between these two kind of listeners are described in {@code LazyMOMProvider} |
|
75 * class comment. An implementation of {@code LazyMOMProvider.DefaultScopeChangeListener} is provided in Metro |
|
76 * ({@link WSEndpointCollectionBasedMOMListener}). As mentioned above this listener register itself as a non-endpoint |
|
77 * listener of {@code LazyMOMProvider} ({@code WSEndpointCollectionBasedMOMListener.init}). An instance of this class is |
|
78 * used in these factories: {@link SessionManager}, {@link NonceManager} and {@link SequenceManagerFactory}. |
|
79 * {@code SessionManager}, {@code NonceManager}, {@code PersistentSequenceManager} and {@code InVmSequenceManager} also |
|
80 * (indirectly) implement {@link MOMRegistrationAware} for providing information whether a manager is registered at |
|
81 * {@code ManagedObjectManager} or not. Registration of a manager at {@code ManagedObjectManager} can be processed directly |
|
82 * (if {@code WSEndpointCollectionBasedMOMListener.canRegisterAtMOM} returns {@code true}) via |
|
83 * {@code WSEndpointCollectionBasedMOMListener.registerAtMOM} or is deferred by putting the manager into |
|
84 * {@code WSEndpointCollectionBasedMOMListener.registrationAwareMap}. Managers stored in for deferred registration are |
|
85 * processed at the moment the {@code LazyMOMProvider} notifies the {@code WSEndpointCollectionBasedMOMListener} about |
|
86 * the scope change. |
|
87 * The mentioned postponing of Gmbal API calls applies only to the server side of the webservice application. |
|
88 */ |
|
89 public enum LazyMOMProvider { |
|
90 |
|
91 INSTANCE; |
|
92 |
|
93 /** |
|
94 * Possible scopes (environments) in which the provider (and object associated with it) could be in. |
|
95 * Default scope is STANDALONE - applied during initialization of classes. For now, only possible scope change for a |
|
96 * object can be in this direction: STANDALONE -> GLASSFISH_NO_JMX -> GLASSFISH_JMX. |
|
97 */ |
|
98 public static enum Scope { |
|
99 |
|
100 //** Default scope where lazy flag is not applied and all Gmbal API calls are processed immediately. */ |
|
101 STANDALONE, |
|
102 |
|
103 /** In this scope almost all Gmbal API call are deferred until a JMX connection to a Glassfish server is created */ |
|
104 GLASSFISH_NO_JMX, |
|
105 |
|
106 /** Same as STANDALONE. Gmbal API calls are processed immediately. */ |
|
107 GLASSFISH_JMX |
|
108 |
|
109 } |
|
110 |
|
111 /** |
|
112 * Interface for all object that want to be notified about scope change, introducing required methods. |
|
113 */ |
|
114 public static interface ScopeChangeListener { |
|
115 |
|
116 void scopeChanged(Scope scope); |
|
117 |
|
118 } |
|
119 |
|
120 /** |
|
121 * Default interface for all object that want to be notified about scope change. This interface should not be |
|
122 * implemented directly. |
|
123 */ |
|
124 public static interface DefaultScopeChangeListener extends ScopeChangeListener { |
|
125 } |
|
126 |
|
127 /** |
|
128 * Interface used for distinguishing between a registration of a WSEndpointImpl rather than of other classes. |
|
129 * Webservice Endpoints should get a notification about scope change sooner than the rest of the registered listeners |
|
130 * (there is a possibility that other listeners are dependant on Webservice Endpoints). |
|
131 */ |
|
132 public static interface WSEndpointScopeChangeListener extends ScopeChangeListener { |
|
133 } |
|
134 |
|
135 private final Set<WSEndpointScopeChangeListener> endpointsWaitingForMOM = new HashSet<WSEndpointScopeChangeListener>(); |
|
136 private final Set<DefaultScopeChangeListener> listeners = new HashSet<DefaultScopeChangeListener>(); |
|
137 |
|
138 private volatile Scope scope = Scope.STANDALONE; |
|
139 |
|
140 /** |
|
141 * Initializes this provider with a given scope. If the given scope is different than the one this provider is |
|
142 * currently in and the transition between scopes is valid then a event is fired to all registered listeners. |
|
143 * |
|
144 * @param scope a scope to initialize this provider with |
|
145 */ |
|
146 public void initMOMForScope(LazyMOMProvider.Scope scope) { |
|
147 // cannot go backwards between scopes, for possible scope changes see #Scope |
|
148 if ((this.scope == Scope.GLASSFISH_JMX) |
|
149 || (scope == Scope.STANDALONE && (this.scope == Scope.GLASSFISH_JMX || this.scope == Scope.GLASSFISH_NO_JMX)) |
|
150 || this.scope == scope) { |
|
151 return; |
|
152 } |
|
153 |
|
154 this.scope = scope; |
|
155 |
|
156 fireScopeChanged(); |
|
157 } |
|
158 |
|
159 /** |
|
160 * Notifies the registered listeners about the scope change. |
|
161 */ |
|
162 private void fireScopeChanged() { |
|
163 for (ScopeChangeListener wsEndpoint : endpointsWaitingForMOM) { |
|
164 wsEndpoint.scopeChanged(this.scope); |
|
165 } |
|
166 |
|
167 for (ScopeChangeListener listener : listeners) { |
|
168 listener.scopeChanged(this.scope); |
|
169 } |
|
170 } |
|
171 |
|
172 /** |
|
173 * Registers the given object as a listener. |
|
174 * |
|
175 * @param listener a listener to be registered |
|
176 */ |
|
177 public void registerListener(DefaultScopeChangeListener listener) { |
|
178 listeners.add(listener); |
|
179 |
|
180 if (!isProviderInDefaultScope()) { |
|
181 listener.scopeChanged(this.scope); |
|
182 } |
|
183 } |
|
184 |
|
185 /** |
|
186 * Returns {@code true} if this provider is in the default scope. |
|
187 * |
|
188 * @return {@code true} if this provider is in the default scope, |
|
189 * {@code false} otherwise |
|
190 */ |
|
191 private boolean isProviderInDefaultScope() { |
|
192 return this.scope == Scope.STANDALONE; |
|
193 } |
|
194 |
|
195 public Scope getScope() { |
|
196 return scope; |
|
197 } |
|
198 |
|
199 /** |
|
200 * Registers a Webservice Endpoint as a listener. |
|
201 * Webservice Endpoints should rather register through this method than through LazyMOMProvider#registerListener |
|
202 * because generally they need to be notified sooner than arbitrary listener (i.e. object that is dependant on |
|
203 * Webservice Endpoint) |
|
204 * |
|
205 * @param wsEndpoint a Webservice Endpoint to be registered |
|
206 */ |
|
207 public void registerEndpoint(WSEndpointScopeChangeListener wsEndpoint) { |
|
208 endpointsWaitingForMOM.add(wsEndpoint); |
|
209 |
|
210 if (!isProviderInDefaultScope()) { |
|
211 wsEndpoint.scopeChanged(this.scope); |
|
212 } |
|
213 } |
|
214 |
|
215 /** |
|
216 * Unregisters a Webservice Endpoint from the list of listeners. |
|
217 * |
|
218 * @param wsEndpoint a Webservice Endpoint to be unregistered |
|
219 */ |
|
220 public void unregisterEndpoint(WSEndpointScopeChangeListener wsEndpoint) { |
|
221 endpointsWaitingForMOM.remove(wsEndpoint); |
|
222 } |
|
223 |
|
224 } |