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 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.tasks;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.LinkedHashSet;
033 import java.util.List;
034
035 import org.opends.server.api.ClientConnection;
036 import org.opends.server.backends.task.Task;
037 import org.opends.server.backends.task.TaskState;
038 import org.opends.server.core.DirectoryServer;
039 import org.opends.server.types.Attribute;
040 import org.opends.server.types.AttributeType;
041 import org.opends.server.types.AttributeValue;
042 import org.opends.server.types.DirectoryException;
043 import org.opends.server.types.Entry;
044 import org.opends.server.types.Operation;
045 import org.opends.server.types.Privilege;
046 import org.opends.server.types.ResultCode;
047
048 import static org.opends.server.config.ConfigConstants.*;
049 import static org.opends.messages.TaskMessages.*;
050 import static org.opends.server.util.StaticUtils.*;
051
052
053
054 /**
055 * This class provides an implementation of a Directory Server task that can be
056 * used to stop the server.
057 */
058 public class ShutdownTask
059 extends Task
060 {
061
062
063
064 // Indicates whether to use an exit code that indicates the server should be
065 // restarted.
066 private boolean restart;
067
068 // The shutdown message that will be used.
069 private Message shutdownMessage;
070
071
072 /**
073 * {@inheritDoc}
074 */
075 public Message getDisplayName() {
076 return INFO_TASK_SHUTDOWN_NAME.get();
077 }
078
079 /**
080 * Performs any task-specific initialization that may be required before
081 * processing can start. This default implementation does not do anything,
082 * but subclasses may override it as necessary. This method will be called at
083 * the time the task is scheduled, and therefore any failure in this method
084 * will be returned to the client.
085 *
086 * @throws DirectoryException If a problem occurs during initialization that
087 * should be returned to the client.
088 */
089 public void initializeTask()
090 throws DirectoryException
091 {
092 // See if the entry contains a shutdown message. If so, then use it.
093 // Otherwise, use a default message.
094 Entry taskEntry = getTaskEntry();
095
096 restart = false;
097 shutdownMessage = INFO_TASK_SHUTDOWN_DEFAULT_MESSAGE.get(
098 String.valueOf(taskEntry.getDN()));
099
100 AttributeType attrType =
101 DirectoryServer.getAttributeType(ATTR_SHUTDOWN_MESSAGE, true);
102 List<Attribute> attrList = taskEntry.getAttribute(attrType);
103 if ((attrList != null) && (attrList.size() > 0))
104 {
105 Attribute attr = attrList.get(0);
106 LinkedHashSet<AttributeValue> values = attr.getValues();
107 if ((values != null) && (! values.isEmpty()))
108 {
109 String valueString = values.iterator().next().getStringValue();
110
111 shutdownMessage = INFO_TASK_SHUTDOWN_CUSTOM_MESSAGE.get(
112 String.valueOf(taskEntry.getDN()), String.valueOf(valueString));
113 }
114 }
115
116
117 attrType = DirectoryServer.getAttributeType(ATTR_RESTART_SERVER, true);
118 attrList = taskEntry.getAttribute(attrType);
119 if ((attrList != null) && (attrList.size() > 0))
120 {
121 Attribute attr = attrList.get(0);
122 LinkedHashSet<AttributeValue> values = attr.getValues();
123 if ((values != null) && (! values.isEmpty()))
124 {
125 String valueString =
126 toLowerCase(values.iterator().next().getStringValue());
127
128 restart = (valueString.equals("true") || valueString.equals("yes") ||
129 valueString.equals("on") || valueString.equals("1"));
130 }
131 }
132
133
134 // If the client connection is available, then make sure the associated
135 // client has either the SERVER_SHUTDOWN or SERVER_RESTART privilege, based
136 // on the appropriate action.
137 Operation operation = getOperation();
138 if (operation != null)
139 {
140 ClientConnection clientConnection = operation.getClientConnection();
141 if (restart)
142 {
143 if (! clientConnection.hasPrivilege(Privilege.SERVER_RESTART,
144 operation))
145 {
146 Message message =
147 ERR_TASK_SHUTDOWN_INSUFFICIENT_RESTART_PRIVILEGES.get();
148 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
149 message);
150 }
151 }
152 else
153 {
154 if (! clientConnection.hasPrivilege(Privilege.SERVER_SHUTDOWN,
155 operation))
156 {
157 Message message =
158 ERR_TASK_SHUTDOWN_INSUFFICIENT_SHUTDOWN_PRIVILEGES.get();
159 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
160 message);
161 }
162 }
163 }
164 }
165
166
167
168 /**
169 * Performs the actual core processing for this task. This method should not
170 * return until all processing associated with this task has completed.
171 *
172 * @return The final state to use for the task.
173 */
174 public TaskState runTask()
175 {
176 // This is a unique case in that the shutdown cannot finish until this task
177 // is finished, but this task can't really be finished until the shutdown is
178 // complete. To work around this catch-22, we'll spawn a separate thread
179 // that will be responsible for really invoking the shutdown and then this
180 // method will return. We'll have to use different types of threads
181 // depending on whether we're doing a restart or a shutdown.
182 if (restart)
183 {
184 RestartTaskThread restartThread = new RestartTaskThread(shutdownMessage);
185 restartThread.start();
186 }
187 else
188 {
189 ShutdownTaskThread shutdownThread =
190 new ShutdownTaskThread(shutdownMessage);
191 shutdownThread.start();
192 }
193
194 return TaskState.COMPLETED_SUCCESSFULLY;
195 }
196 }
197