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