1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.ldap.handlers.extended;
21
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Set;
29
30 import org.apache.directory.server.ldap.ExtendedOperationHandler;
31 import org.apache.directory.server.ldap.LdapService;
32 import org.apache.directory.server.ldap.LdapSession;
33 import org.apache.directory.shared.ldap.message.ExtendedRequest;
34 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
35 import org.apache.directory.shared.ldap.message.extended.GracefulDisconnect;
36 import org.apache.directory.shared.ldap.message.extended.GracefulShutdownRequest;
37 import org.apache.directory.shared.ldap.message.extended.GracefulShutdownResponse;
38 import org.apache.directory.shared.ldap.message.extended.NoticeOfDisconnect;
39 import org.apache.mina.common.IoAcceptor;
40 import org.apache.mina.common.IoSession;
41 import org.apache.mina.common.WriteFuture;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49
50 public class GracefulShutdownHandler implements ExtendedOperationHandler
51 {
52 private static final Logger LOG = LoggerFactory.getLogger( GracefulShutdownHandler.class );
53 public static final Set<String> EXTENSION_OIDS;
54
55 static
56 {
57 Set<String> set = new HashSet<String>( 3 );
58 set.add( GracefulShutdownRequest.EXTENSION_OID );
59 set.add( GracefulShutdownResponse.EXTENSION_OID );
60 set.add( GracefulDisconnect.EXTENSION_OID );
61 EXTENSION_OIDS = Collections.unmodifiableSet( set );
62 }
63
64
65 public String getOid()
66 {
67 return GracefulShutdownRequest.EXTENSION_OID;
68 }
69
70
71 public void handleExtendedOperation( LdapSession requestor, ExtendedRequest req ) throws Exception
72 {
73
74
75 if ( ! requestor.getCoreSession().isAnAdministrator() )
76 {
77 if ( LOG.isInfoEnabled() )
78 {
79 LOG.info( "Rejected with insufficientAccessRights to attempt for server shutdown by "
80 + requestor.getCoreSession().getEffectivePrincipal().getName() );
81 }
82
83 requestor.getIoSession().write( new GracefulShutdownResponse(
84 req.getMessageId(), ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS ) );
85 return;
86 }
87
88
89
90
91
92 IoAcceptor acceptor = ( IoAcceptor ) requestor.getIoSession().getService();
93 List<IoSession> sessions = new ArrayList<IoSession>(
94 acceptor.getManagedSessions( requestor.getIoSession().getServiceAddress() ) );
95 GracefulShutdownRequest gsreq = ( GracefulShutdownRequest ) req;
96
97
98 GracefulDisconnect notice = getGracefulDisconnect( gsreq.getTimeOffline(), gsreq.getDelay() );
99
100
101 sendGracefulDisconnect( sessions, notice, requestor.getIoSession() );
102
103
104 waitForDelay( gsreq.getDelay() );
105
106
107
108
109
110
111
112
113
114
115
116 acceptor.unbind( requestor.getIoSession().getServiceAddress() );
117
118
119
120
121
122 sendNoticeOfDisconnect( sessions, requestor.getIoSession() );
123
124
125
126
127
128
129
130
131 sendShutdownResponse( requestor.getIoSession(), req.getMessageId() );
132 }
133
134
135
136
137
138
139
140
141 public static void sendShutdownResponse( IoSession requestor, int messageId )
142 {
143 GracefulShutdownResponse msg = new GracefulShutdownResponse( messageId, ResultCodeEnum.SUCCESS );
144 WriteFuture future = requestor.write( msg );
145 future.join();
146 if ( future.isWritten() )
147 {
148 if ( LOG.isInfoEnabled() )
149 {
150 LOG.info( "Sent GracefulShutdownResponse to client: " + requestor.getRemoteAddress() );
151 }
152 }
153 else
154 {
155 LOG.error( "Failed to write GracefulShutdownResponse to client: " + requestor.getRemoteAddress() );
156 }
157 requestor.close();
158 }
159
160
161
162
163
164
165
166
167
168
169 public static void sendGracefulDisconnect( List<IoSession> sessions, GracefulDisconnect msg, IoSession requestor )
170 {
171 List<WriteFuture> writeFutures = new ArrayList<WriteFuture>();
172
173
174
175
176
177 if ( sessions != null )
178 {
179 for ( IoSession session : sessions )
180 {
181
182
183 if ( session.equals( requestor ) )
184 {
185 continue;
186 }
187
188 try
189 {
190 writeFutures.add( session.write( msg ) );
191 }
192 catch ( Exception e )
193 {
194 LOG.warn( "Failed to write GracefulDisconnect to client session: " + session, e );
195 }
196 }
197 }
198
199
200 for ( WriteFuture future : writeFutures )
201 {
202 try
203 {
204 future.join( 1000 );
205 }
206 catch ( Exception e )
207 {
208 LOG.warn( "Failed to sent GracefulDisconnect", e );
209 }
210 }
211 }
212
213
214
215
216
217
218
219
220
221
222 public static void sendNoticeOfDisconnect( List<IoSession> sessions, IoSession requestor )
223 {
224 List<WriteFuture> writeFutures = new ArrayList<WriteFuture>();
225
226
227 if ( sessions != null )
228 {
229 for ( IoSession session : sessions )
230 {
231
232
233 if ( session.equals( requestor ) )
234 {
235 continue;
236 }
237
238 try
239 {
240 writeFutures.add( session.write( NoticeOfDisconnect.UNAVAILABLE ) );
241 }
242 catch ( Exception e )
243 {
244 LOG.warn( "Failed to sent NoD for client: " + session, e );
245 }
246 }
247 }
248
249
250 Iterator<IoSession> sessionIt = sessions.iterator();
251
252 for ( WriteFuture future : writeFutures )
253 {
254 try
255 {
256 future.join( 1000 );
257 sessionIt.next().close();
258 }
259 catch ( Exception e )
260 {
261 LOG.warn( "Failed to sent NoD.", e );
262 }
263 }
264 }
265
266
267 public static GracefulDisconnect getGracefulDisconnect( int timeOffline, int delay )
268 {
269
270
271
272
273
274
275
276
277 return new GracefulDisconnect( timeOffline, delay );
278 }
279
280
281 public static void waitForDelay( int delay )
282 {
283 if ( delay > 0 )
284 {
285
286 long delayMillis = delay * 1000L;
287 long startTime = System.currentTimeMillis();
288
289 while ( ( System.currentTimeMillis() - startTime ) < delayMillis )
290 {
291 try
292 {
293 Thread.sleep( 250 );
294 }
295 catch ( InterruptedException e )
296 {
297 LOG.warn( "Got interrupted while waiting for delay before shutdown", e );
298 }
299 }
300 }
301 }
302
303
304 public Set<String> getExtensionOids()
305 {
306 return EXTENSION_OIDS;
307 }
308
309
310 public void setLdapServer( LdapService ldapService )
311 {
312 }
313 }