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