/*
|
* CDDL HEADER START
|
*
|
* The contents of this file are subject to the terms of the
|
* Common Development and Distribution License, Version 1.0 only
|
* (the "License"). You may not use this file except in compliance
|
* with the License.
|
*
|
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
|
* or http://forgerock.org/license/CDDLv1.0.html.
|
* See the License for the specific language governing permissions
|
* and limitations under the License.
|
*
|
* When distributing Covered Code, include this CDDL HEADER in each
|
* file and include the License file at legal-notices/CDDLv1_0.txt.
|
* If applicable, add the following below this CDDL HEADER, with the
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
* information:
|
* Portions Copyright [yyyy] [name of copyright owner]
|
*
|
* CDDL HEADER END
|
*
|
*
|
* Copyright 2006-2009 Sun Microsystems, Inc.
|
* Portions Copyright 2014 ForgeRock AS
|
*/
|
package org.opends.server.tasks;
|
|
|
|
import static org.opends.messages.TaskMessages.*;
|
import static org.opends.server.config.ConfigConstants.*;
|
import static org.opends.server.util.StaticUtils.*;
|
|
import java.util.List;
|
|
import org.forgerock.i18n.LocalizableMessage;
|
import org.opends.server.api.ClientConnection;
|
import org.opends.server.backends.task.Task;
|
import org.opends.server.backends.task.TaskState;
|
import org.opends.server.core.DirectoryServer;
|
import org.opends.server.types.Attribute;
|
import org.opends.server.types.AttributeType;
|
import org.opends.server.types.DirectoryException;
|
import org.opends.server.types.Entry;
|
import org.opends.server.types.Operation;
|
import org.opends.server.types.Privilege;
|
import org.forgerock.opendj.ldap.ResultCode;
|
|
|
|
/**
|
* This class provides an implementation of a Directory Server task that can be
|
* used to stop the server.
|
*/
|
public class ShutdownTask
|
extends Task
|
{
|
|
|
|
// Indicates whether to use an exit code that indicates the server should be
|
// restarted.
|
private boolean restart;
|
|
// The shutdown message that will be used.
|
private LocalizableMessage shutdownMessage;
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public LocalizableMessage getDisplayName() {
|
return INFO_TASK_SHUTDOWN_NAME.get();
|
}
|
|
/**
|
* Performs any task-specific initialization that may be required before
|
* processing can start. This default implementation does not do anything,
|
* but subclasses may override it as necessary. This method will be called at
|
* the time the task is scheduled, and therefore any failure in this method
|
* will be returned to the client.
|
*
|
* @throws DirectoryException If a problem occurs during initialization that
|
* should be returned to the client.
|
*/
|
public void initializeTask()
|
throws DirectoryException
|
{
|
// See if the entry contains a shutdown message. If so, then use it.
|
// Otherwise, use a default message.
|
Entry taskEntry = getTaskEntry();
|
|
restart = false;
|
shutdownMessage = INFO_TASK_SHUTDOWN_DEFAULT_MESSAGE.get(taskEntry.getName());
|
|
AttributeType attrType =
|
DirectoryServer.getAttributeType(ATTR_SHUTDOWN_MESSAGE, true);
|
List<Attribute> attrList = taskEntry.getAttribute(attrType);
|
if ((attrList != null) && (attrList.size() > 0))
|
{
|
Attribute attr = attrList.get(0);
|
if (!attr.isEmpty())
|
{
|
String valueString = attr.iterator().next().toString();
|
shutdownMessage = INFO_TASK_SHUTDOWN_CUSTOM_MESSAGE.get(taskEntry.getName(), valueString);
|
}
|
}
|
|
|
attrType = DirectoryServer.getAttributeType(ATTR_RESTART_SERVER, true);
|
attrList = taskEntry.getAttribute(attrType);
|
if ((attrList != null) && (attrList.size() > 0))
|
{
|
Attribute attr = attrList.get(0);
|
if (!attr.isEmpty())
|
{
|
String valueString = toLowerCase(attr.iterator().next().toString());
|
restart = (valueString.equals("true") || valueString.equals("yes")
|
|| valueString.equals("on") || valueString.equals("1"));
|
}
|
}
|
|
|
// If the client connection is available, then make sure the associated
|
// client has either the SERVER_SHUTDOWN or SERVER_RESTART privilege, based
|
// on the appropriate action.
|
Operation operation = getOperation();
|
if (operation != null)
|
{
|
ClientConnection clientConnection = operation.getClientConnection();
|
if (restart)
|
{
|
if (! clientConnection.hasPrivilege(Privilege.SERVER_RESTART,
|
operation))
|
{
|
LocalizableMessage message =
|
ERR_TASK_SHUTDOWN_INSUFFICIENT_RESTART_PRIVILEGES.get();
|
throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
|
message);
|
}
|
}
|
else
|
{
|
if (! clientConnection.hasPrivilege(Privilege.SERVER_SHUTDOWN,
|
operation))
|
{
|
LocalizableMessage message =
|
ERR_TASK_SHUTDOWN_INSUFFICIENT_SHUTDOWN_PRIVILEGES.get();
|
throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
|
message);
|
}
|
}
|
}
|
}
|
|
|
|
/**
|
* Performs the actual core processing for this task. This method should not
|
* return until all processing associated with this task has completed.
|
*
|
* @return The final state to use for the task.
|
*/
|
public TaskState runTask()
|
{
|
// This is a unique case in that the shutdown cannot finish until this task
|
// is finished, but this task can't really be finished until the shutdown is
|
// complete. To work around this catch-22, we'll spawn a separate thread
|
// that will be responsible for really invoking the shutdown and then this
|
// method will return. We'll have to use different types of threads
|
// depending on whether we're doing a restart or a shutdown.
|
boolean configuredAsService =
|
DirectoryServer.isRunningAsWindowsService();
|
if (configuredAsService && !restart)
|
{
|
ShutdownTaskThread shutdownThread =
|
new ShutdownTaskThread(shutdownMessage)
|
{
|
public void run()
|
{
|
org.opends.server.tools.StopWindowsService.main(new String[]{});
|
}
|
};
|
shutdownThread.start();
|
}
|
else if (restart)
|
{
|
// Since the process will not be killed, we can proceed exactly the same
|
// way with or without windows service configured.
|
RestartTaskThread restartThread = new RestartTaskThread(shutdownMessage);
|
restartThread.start();
|
}
|
else
|
{
|
ShutdownTaskThread shutdownThread =
|
new ShutdownTaskThread(shutdownMessage);
|
shutdownThread.start();
|
}
|
|
return TaskState.COMPLETED_SUCCESSFULLY;
|
}
|
}
|