001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.tasks;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.List;
033
034 import org.opends.server.admin.std.server.ConnectionHandlerCfg;
035 import org.opends.server.backends.task.Task;
036 import org.opends.server.backends.task.TaskState;
037 import org.opends.server.api.ClientConnection;
038 import org.opends.server.api.ConnectionHandler;
039 import org.opends.server.core.DirectoryServer;
040 import org.opends.server.types.Attribute;
041 import org.opends.server.types.AttributeType;
042 import org.opends.server.types.AttributeValue;
043 import org.opends.server.types.DirectoryException;
044 import org.opends.server.types.DisconnectReason;
045 import org.opends.server.types.Entry;
046 import org.opends.server.types.Operation;
047 import org.opends.server.types.Privilege;
048 import org.opends.server.types.ResultCode;
049
050 import static org.opends.messages.TaskMessages.*;
051 import static org.opends.server.util.ServerConstants.*;
052 import static org.opends.server.util.StaticUtils.*;
053
054
055
056 /**
057 * This class provides an implementation of a Directory Server task that can be
058 * used to terminate a client connection.
059 */
060 public class DisconnectClientTask
061 extends Task
062 {
063 // Indicates whether to send a notification message to the client.
064 private boolean notifyClient;
065
066 // The connection ID for the client connection to terminate.
067 private long connectionID;
068
069 // The disconnect message to send to the client.
070 private Message disconnectMessage;
071
072 /**
073 * {@inheritDoc}
074 */
075 public Message getDisplayName() {
076 return INFO_TASK_DISCONNECT_CLIENT_NAME.get();
077 }
078
079 /**
080 * {@inheritDoc}
081 */
082 @Override
083 public void initializeTask()
084 throws DirectoryException
085 {
086 // If the client connection is available, then make sure the client has the
087 // DISCONNECT_CLIENT privilege.
088 Operation operation = getOperation();
089 if (operation != null)
090 {
091 ClientConnection conn = operation.getClientConnection();
092 if (! conn.hasPrivilege(Privilege.DISCONNECT_CLIENT, operation))
093 {
094 Message message = ERR_TASK_DISCONNECT_NO_PRIVILEGE.get();
095 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
096 message);
097 }
098 }
099
100
101 // Get the connection ID for the client connection.
102 Entry taskEntry = getTaskEntry();
103 connectionID = -1L;
104 AttributeType attrType =
105 DirectoryServer.getAttributeType(ATTR_TASK_DISCONNECT_CONN_ID, true);
106 List<Attribute> attrList = taskEntry.getAttribute(attrType);
107 if (attrList != null)
108 {
109 connIDLoop:
110 for (Attribute a : attrList)
111 {
112 for (AttributeValue v : a.getValues())
113 {
114 try
115 {
116 connectionID = Long.parseLong(v.getStringValue());
117 break connIDLoop;
118 }
119 catch (Exception e)
120 {
121 Message message =
122 ERR_TASK_DISCONNECT_INVALID_CONN_ID.get(v.getStringValue());
123 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
124 message, e);
125 }
126 }
127 }
128 }
129
130 if (connectionID < 0)
131 {
132 Message message =
133 ERR_TASK_DISCONNECT_NO_CONN_ID.get(ATTR_TASK_DISCONNECT_CONN_ID);
134 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
135 message);
136 }
137
138
139 // Determine whether to notify the client.
140 notifyClient = false;
141 attrType =
142 DirectoryServer.getAttributeType(ATTR_TASK_DISCONNECT_NOTIFY_CLIENT,
143 true);
144 attrList = taskEntry.getAttribute(attrType);
145 if (attrList != null)
146 {
147 notifyClientLoop:
148 for (Attribute a : attrList)
149 {
150 for (AttributeValue v : a.getValues())
151 {
152 String stringValue = toLowerCase(v.getStringValue());
153 if (stringValue.equals("true"))
154 {
155 notifyClient = true;
156 break notifyClientLoop;
157 }
158 else if (stringValue.equals("false"))
159 {
160 break notifyClientLoop;
161 }
162 else
163 {
164 Message message =
165 ERR_TASK_DISCONNECT_INVALID_NOTIFY_CLIENT.get(stringValue);
166 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
167 message);
168 }
169 }
170 }
171 }
172
173
174 // Get the disconnect message.
175 disconnectMessage = INFO_TASK_DISCONNECT_GENERIC_MESSAGE.get();
176 attrType = DirectoryServer.getAttributeType(ATTR_TASK_DISCONNECT_MESSAGE,
177 true);
178 attrList = taskEntry.getAttribute(attrType);
179 if (attrList != null)
180 {
181 disconnectMessageLoop:
182 for (Attribute a : attrList)
183 {
184 for (AttributeValue v : a.getValues())
185 {
186 disconnectMessage = Message.raw(v.getStringValue());
187 break disconnectMessageLoop;
188 }
189 }
190 }
191 }
192
193
194
195 /**
196 * {@inheritDoc}
197 */
198 protected TaskState runTask()
199 {
200 // Get the specified client connection.
201 ClientConnection clientConnection = null;
202 for (ConnectionHandler handler : DirectoryServer.getConnectionHandlers())
203 {
204 ConnectionHandler<? extends ConnectionHandlerCfg> connHandler =
205 (ConnectionHandler<? extends ConnectionHandlerCfg>) handler;
206 for (ClientConnection c : connHandler.getClientConnections())
207 {
208 if (c.getConnectionID() == connectionID)
209 {
210 clientConnection = c;
211 break;
212 }
213 }
214 }
215
216
217 // If there is no such client connection, then return an error. Otherwise,
218 // terminate it.
219 if (clientConnection == null)
220 {
221 Message message =
222 ERR_TASK_DISCONNECT_NO_SUCH_CONNECTION.get(
223 String.valueOf(connectionID));
224 logError(message);
225
226 return TaskState.COMPLETED_WITH_ERRORS;
227 }
228 else
229 {
230 clientConnection.disconnect(DisconnectReason.ADMIN_DISCONNECT,
231 notifyClient, disconnectMessage);
232 return TaskState.COMPLETED_SUCCESSFULLY;
233 }
234 }
235 }
236