001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.tasks; 018 019import static org.opends.messages.TaskMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021import static org.opends.server.util.StaticUtils.*; 022 023import java.util.List; 024 025import org.forgerock.i18n.LocalizableMessage; 026import org.forgerock.opendj.ldap.ResultCode; 027import org.forgerock.opendj.ldap.schema.AttributeType; 028import org.opends.server.api.ClientConnection; 029import org.opends.server.backends.task.Task; 030import org.opends.server.backends.task.TaskState; 031import org.opends.server.core.DirectoryServer; 032import org.opends.server.types.Attribute; 033import org.opends.server.types.DirectoryException; 034import org.opends.server.types.Entry; 035import org.opends.server.types.Operation; 036import org.opends.server.types.Privilege; 037 038/** 039 * This class provides an implementation of a Directory Server task that can be 040 * used to stop the server. 041 */ 042public class ShutdownTask 043 extends Task 044{ 045 /** Indicates whether to use an exit code that indicates the server should be restarted. */ 046 private boolean restart; 047 048 /** The shutdown message that will be used. */ 049 private LocalizableMessage shutdownMessage; 050 051 @Override 052 public LocalizableMessage getDisplayName() { 053 return INFO_TASK_SHUTDOWN_NAME.get(); 054 } 055 056 /** 057 * Performs any task-specific initialization that may be required before 058 * processing can start. This default implementation does not do anything, 059 * but subclasses may override it as necessary. This method will be called at 060 * the time the task is scheduled, and therefore any failure in this method 061 * will be returned to the client. 062 * 063 * @throws DirectoryException If a problem occurs during initialization that 064 * should be returned to the client. 065 */ 066 @Override 067 public void initializeTask() 068 throws DirectoryException 069 { 070 // See if the entry contains a shutdown message. If so, then use it. 071 // Otherwise, use a default message. 072 Entry taskEntry = getTaskEntry(); 073 074 restart = false; 075 shutdownMessage = INFO_TASK_SHUTDOWN_DEFAULT_MESSAGE.get(taskEntry.getName()); 076 077 AttributeType attrType = DirectoryServer.getSchema().getAttributeType(ATTR_SHUTDOWN_MESSAGE); 078 List<Attribute> attrList = taskEntry.getAttribute(attrType); 079 if (!attrList.isEmpty()) 080 { 081 Attribute attr = attrList.get(0); 082 if (!attr.isEmpty()) 083 { 084 String valueString = attr.iterator().next().toString(); 085 shutdownMessage = INFO_TASK_SHUTDOWN_CUSTOM_MESSAGE.get(taskEntry.getName(), valueString); 086 } 087 } 088 089 attrType = DirectoryServer.getSchema().getAttributeType(ATTR_RESTART_SERVER); 090 attrList = taskEntry.getAttribute(attrType); 091 if (!attrList.isEmpty()) 092 { 093 Attribute attr = attrList.get(0); 094 if (!attr.isEmpty()) 095 { 096 String valueString = toLowerCase(attr.iterator().next().toString()); 097 restart = valueString.equals("true") || valueString.equals("yes") 098 || valueString.equals("on") || valueString.equals("1"); 099 } 100 } 101 102 103 // If the client connection is available, then make sure the associated 104 // client has either the SERVER_SHUTDOWN or SERVER_RESTART privilege, based 105 // on the appropriate action. 106 Operation operation = getOperation(); 107 if (operation != null) 108 { 109 ClientConnection clientConnection = operation.getClientConnection(); 110 if (restart) 111 { 112 if (! clientConnection.hasPrivilege(Privilege.SERVER_RESTART, 113 operation)) 114 { 115 LocalizableMessage message = 116 ERR_TASK_SHUTDOWN_INSUFFICIENT_RESTART_PRIVILEGES.get(); 117 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, 118 message); 119 } 120 } 121 else 122 { 123 if (! clientConnection.hasPrivilege(Privilege.SERVER_SHUTDOWN, 124 operation)) 125 { 126 LocalizableMessage message = 127 ERR_TASK_SHUTDOWN_INSUFFICIENT_SHUTDOWN_PRIVILEGES.get(); 128 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, 129 message); 130 } 131 } 132 } 133 } 134 135 136 137 /** 138 * Performs the actual core processing for this task. This method should not 139 * return until all processing associated with this task has completed. 140 * 141 * @return The final state to use for the task. 142 */ 143 @Override 144 public TaskState runTask() 145 { 146 // This is a unique case in that the shutdown cannot finish until this task 147 // is finished, but this task can't really be finished until the shutdown is 148 // complete. To work around this catch-22, we'll spawn a separate thread 149 // that will be responsible for really invoking the shutdown and then this 150 // method will return. We'll have to use different types of threads 151 // depending on whether we're doing a restart or a shutdown. 152 boolean configuredAsService = 153 DirectoryServer.isRunningAsWindowsService(); 154 if (configuredAsService && !restart) 155 { 156 ShutdownTaskThread shutdownThread = 157 new ShutdownTaskThread(shutdownMessage) 158 { 159 @Override 160 public void run() 161 { 162 org.opends.server.tools.StopWindowsService.main(new String[]{}); 163 } 164 }; 165 shutdownThread.start(); 166 } 167 else if (restart) 168 { 169 // Since the process will not be killed, we can proceed exactly the same 170 // way with or without windows service configured. 171 RestartTaskThread restartThread = new RestartTaskThread(shutdownMessage); 172 restartThread.start(); 173 } 174 else 175 { 176 ShutdownTaskThread shutdownThread = 177 new ShutdownTaskThread(shutdownMessage); 178 shutdownThread.start(); 179 } 180 181 return TaskState.COMPLETED_SUCCESSFULLY; 182 } 183}