16
16
17
17
package org .springframework .web .socket .server .standard ;
18
18
19
- import java .lang .reflect .Method ;
20
- import java .util .ArrayList ;
21
19
import java .util .Arrays ;
20
+ import java .util .LinkedHashSet ;
22
21
import java .util .List ;
23
- import java .util .Map ;
22
+ import java .util .Set ;
23
+ import javax .servlet .ServletContext ;
24
24
import javax .websocket .DeploymentException ;
25
25
import javax .websocket .server .ServerContainer ;
26
26
import javax .websocket .server .ServerEndpoint ;
27
27
import javax .websocket .server .ServerEndpointConfig ;
28
28
29
- import org .apache .commons .logging .Log ;
30
- import org .apache .commons .logging .LogFactory ;
31
-
32
- import org .springframework .beans .BeansException ;
33
29
import org .springframework .beans .factory .InitializingBean ;
34
30
import org .springframework .beans .factory .config .BeanPostProcessor ;
35
31
import org .springframework .context .ApplicationContext ;
36
- import org .springframework .context .ApplicationContextAware ;
37
32
import org .springframework .util .Assert ;
38
- import org .springframework .util .ClassUtils ;
39
- import org .springframework .util .ReflectionUtils ;
33
+ import org .springframework .web .context .support .WebApplicationObjectSupport ;
40
34
41
35
/**
42
36
* Detects beans of type {@link javax.websocket.server.ServerEndpointConfig} and registers
50
44
* done with the help of the {@code <absolute-ordering>} element in web.xml.
51
45
*
52
46
* @author Rossen Stoyanchev
47
+ * @author Juergen Hoeller
53
48
* @since 4.0
54
49
* @see ServerEndpointRegistration
55
50
* @see SpringConfigurator
56
51
* @see ServletServerContainerFactoryBean
57
52
*/
58
- public class ServerEndpointExporter implements InitializingBean , BeanPostProcessor , ApplicationContextAware {
59
-
60
- private static final Log logger = LogFactory .getLog (ServerEndpointExporter .class );
53
+ public class ServerEndpointExporter extends WebApplicationObjectSupport implements BeanPostProcessor , InitializingBean {
61
54
55
+ private ServerContainer serverContainer ;
62
56
63
- private final List <Class <?>> annotatedEndpointClasses = new ArrayList < Class <?>>() ;
57
+ private List <Class <?>> annotatedEndpointClasses ;
64
58
65
- private final List <Class <?>> annotatedEndpointBeanTypes = new ArrayList < Class <?>>() ;
59
+ private Set <Class <?>> annotatedEndpointBeanTypes ;
66
60
67
- private ApplicationContext applicationContext ;
68
61
69
- private ServerContainer serverContainer ;
62
+ /**
63
+ * Set the JSR-356 {@link ServerContainer} to use for endpoint registration.
64
+ * If not set, the container is going to be retrieved via the {@code ServletContext}.
65
+ * @since 4.1
66
+ */
67
+ public void setServerContainer (ServerContainer serverContainer ) {
68
+ this .serverContainer = serverContainer ;
69
+ }
70
70
71
+ /**
72
+ * Return the JSR-356 {@link ServerContainer} to use for endpoint registration.
73
+ */
74
+ protected ServerContainer getServerContainer () {
75
+ return this .serverContainer ;
76
+ }
71
77
72
78
/**
73
79
* Explicitly list annotated endpoint types that should be registered on startup. This
@@ -76,84 +82,92 @@ public class ServerEndpointExporter implements InitializingBean, BeanPostProcess
76
82
* @param annotatedEndpointClasses {@link ServerEndpoint}-annotated types
77
83
*/
78
84
public void setAnnotatedEndpointClasses (Class <?>... annotatedEndpointClasses ) {
79
- this .annotatedEndpointClasses .clear ();
80
- this .annotatedEndpointClasses .addAll (Arrays .asList (annotatedEndpointClasses ));
85
+ this .annotatedEndpointClasses = Arrays .asList (annotatedEndpointClasses );
81
86
}
82
87
83
88
@ Override
84
- public void setApplicationContext (ApplicationContext applicationContext ) {
85
- this .applicationContext = applicationContext ;
86
- this .serverContainer = getServerContainer ();
87
- Map <String , Object > beans = applicationContext .getBeansWithAnnotation (ServerEndpoint .class );
88
- for (String beanName : beans .keySet ()) {
89
- Class <?> beanType = applicationContext .getType (beanName );
89
+ protected void initApplicationContext (ApplicationContext context ) {
90
+ // Initializes ServletContext given a WebApplicationContext
91
+ super .initApplicationContext (context );
92
+
93
+ // Retrieve beans which are annotated with @ServerEndpoint
94
+ this .annotatedEndpointBeanTypes = new LinkedHashSet <Class <?>>();
95
+ String [] beanNames = context .getBeanNamesForAnnotation (ServerEndpoint .class );
96
+ for (String beanName : beanNames ) {
97
+ Class <?> beanType = context .getType (beanName );
90
98
if (logger .isInfoEnabled ()) {
91
99
logger .info ("Detected @ServerEndpoint bean '" + beanName + "', registering it as an endpoint by type" );
92
100
}
93
101
this .annotatedEndpointBeanTypes .add (beanType );
94
102
}
95
103
}
96
104
97
- protected ServerContainer getServerContainer () {
98
- Class <?> servletContextClass ;
99
- try {
100
- servletContextClass = ClassUtils .forName ("javax.servlet.ServletContext" , getClass ().getClassLoader ());
105
+ @ Override
106
+ protected void initServletContext (ServletContext servletContext ) {
107
+ if (this .serverContainer == null ) {
108
+ this .serverContainer =
109
+ (ServerContainer ) servletContext .getAttribute ("javax.websocket.server.ServerContainer" );
110
+ }
111
+ }
112
+
113
+
114
+ @ Override
115
+ public void afterPropertiesSet () {
116
+ Assert .state (getServerContainer () != null , "javax.websocket.server.ServerContainer not available" );
117
+ registerEndpoints ();
118
+ }
119
+
120
+ /**
121
+ * Actually register the endpoints. Called by {@link #afterPropertiesSet()}.
122
+ * @since 4.1
123
+ */
124
+ protected void registerEndpoints () {
125
+ Set <Class <?>> endpointClasses = new LinkedHashSet <Class <?>>();
126
+ if (this .annotatedEndpointClasses != null ) {
127
+ endpointClasses .addAll (this .annotatedEndpointClasses );
128
+ }
129
+ if (this .annotatedEndpointBeanTypes != null ) {
130
+ endpointClasses .addAll (this .annotatedEndpointBeanTypes );
101
131
}
102
- catch ( Throwable ex ) {
103
- return null ;
132
+ for ( Class <?> endpointClass : endpointClasses ) {
133
+ registerEndpoint ( endpointClass ) ;
104
134
}
135
+ }
105
136
137
+ private void registerEndpoint (Class <?> endpointClass ) {
106
138
try {
107
- Method getter = ReflectionUtils . findMethod ( this . applicationContext . getClass (), "getServletContext" );
108
- Object servletContext = getter . invoke ( this . applicationContext );
109
- Method attrMethod = ReflectionUtils . findMethod ( servletContextClass , "getAttribute" , String . class );
110
- return ( ServerContainer ) attrMethod . invoke ( servletContext , "javax.websocket.server.ServerContainer" );
139
+ if ( logger . isInfoEnabled ()) {
140
+ logger . info ( "Registering @ServerEndpoint type: " + endpointClass );
141
+ }
142
+ getServerContainer (). addEndpoint ( endpointClass );
111
143
}
112
- catch (Exception ex ) {
113
- throw new IllegalStateException (
114
- "Failed to get javax.websocket.server.ServerContainer via ServletContext attribute" , ex );
144
+ catch (DeploymentException ex ) {
145
+ throw new IllegalStateException ("Failed to register @ServerEndpoint type " + endpointClass , ex );
115
146
}
116
147
}
117
148
118
- @ Override
119
- public void afterPropertiesSet () throws Exception {
120
- Assert .state (this .serverContainer != null , "javax.websocket.server.ServerContainer not available" );
121
-
122
- List <Class <?>> allClasses = new ArrayList <Class <?>>(this .annotatedEndpointClasses );
123
- allClasses .addAll (this .annotatedEndpointBeanTypes );
124
149
125
- for (Class <?> clazz : allClasses ) {
126
- try {
127
- logger .info ("Registering @ServerEndpoint type " + clazz );
128
- this .serverContainer .addEndpoint (clazz );
129
- }
130
- catch (DeploymentException e ) {
131
- throw new IllegalStateException ("Failed to register @ServerEndpoint type " + clazz , e );
132
- }
133
- }
150
+ @ Override
151
+ public Object postProcessBeforeInitialization (Object bean , String beanName ) {
152
+ return bean ;
134
153
}
135
154
136
155
@ Override
137
- public Object postProcessAfterInitialization (Object bean , String beanName ) throws BeansException {
156
+ public Object postProcessAfterInitialization (Object bean , String beanName ) {
138
157
if (bean instanceof ServerEndpointConfig ) {
139
- ServerEndpointConfig sec = (ServerEndpointConfig ) bean ;
158
+ ServerEndpointConfig endpointConfig = (ServerEndpointConfig ) bean ;
140
159
try {
141
160
if (logger .isInfoEnabled ()) {
142
161
logger .info ("Registering bean '" + beanName +
143
- "' as javax.websocket.Endpoint under path " + sec .getPath ());
162
+ "' as javax.websocket.Endpoint under path " + endpointConfig .getPath ());
144
163
}
145
- getServerContainer ().addEndpoint (sec );
164
+ getServerContainer ().addEndpoint (endpointConfig );
146
165
}
147
- catch (DeploymentException e ) {
148
- throw new IllegalStateException ("Failed to deploy Endpoint bean " + bean , e );
166
+ catch (DeploymentException ex ) {
167
+ throw new IllegalStateException ("Failed to deploy Endpoint bean with name ' " + bean + "'" , ex );
149
168
}
150
169
}
151
170
return bean ;
152
171
}
153
172
154
- @ Override
155
- public Object postProcessBeforeInitialization (Object bean , String beanName ) throws BeansException {
156
- return bean ;
157
- }
158
-
159
173
}
0 commit comments