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