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-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools; 018 019import static com.forgerock.opendj.cli.ArgumentConstants.*; 020import static com.forgerock.opendj.cli.CliMessages.INFO_BINDPWD_FILE_PLACEHOLDER; 021import static com.forgerock.opendj.cli.CliMessages.INFO_KEYSTORE_PWD_FILE_PLACEHOLDER; 022import static com.forgerock.opendj.cli.CliMessages.INFO_PORT_PLACEHOLDER; 023import static com.forgerock.opendj.cli.CliMessages.INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER; 024import static com.forgerock.opendj.cli.Utils.*; 025import static com.forgerock.opendj.cli.CommonArguments.*; 026 027import static org.opends.messages.ToolMessages.*; 028import static org.opends.server.config.ConfigConstants.*; 029import static org.opends.server.util.CollectionUtils.*; 030import static org.opends.server.protocols.ldap.LDAPResultCode.*; 031import static org.opends.server.util.ServerConstants.*; 032import static org.opends.server.util.StaticUtils.*; 033 034import java.io.IOException; 035import java.io.OutputStream; 036import java.io.PrintStream; 037import java.text.SimpleDateFormat; 038import java.util.ArrayList; 039import java.util.Date; 040import java.util.LinkedList; 041import java.util.TimeZone; 042import java.util.UUID; 043import java.util.concurrent.atomic.AtomicInteger; 044 045import javax.net.ssl.SSLException; 046 047import org.forgerock.i18n.LocalizableMessage; 048import org.forgerock.opendj.ldap.ByteString; 049import org.forgerock.opendj.ldap.DecodeException; 050import org.opends.server.config.AdministrationConnector; 051import org.opends.server.controls.ProxiedAuthV2Control; 052import org.opends.server.core.DirectoryServer; 053import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 054import org.opends.server.core.LockFileManager; 055import org.opends.server.loggers.JDKLogging; 056import org.opends.server.protocols.ldap.AddRequestProtocolOp; 057import org.opends.server.protocols.ldap.AddResponseProtocolOp; 058import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp; 059import org.opends.server.protocols.ldap.LDAPAttribute; 060import org.opends.server.protocols.ldap.LDAPConstants; 061import org.opends.server.protocols.ldap.LDAPMessage; 062import org.opends.server.protocols.ldap.LDAPResultCode; 063import org.opends.server.tasks.ShutdownTask; 064import org.opends.server.tools.tasks.TaskTool; 065import org.opends.server.types.Control; 066import org.opends.server.types.LDAPException; 067import org.opends.server.types.NullOutputStream; 068import org.opends.server.types.RawAttribute; 069import org.opends.server.util.cli.LDAPConnectionArgumentParser; 070 071import com.forgerock.opendj.cli.Argument; 072import com.forgerock.opendj.cli.ArgumentConstants; 073import com.forgerock.opendj.cli.ArgumentException; 074import com.forgerock.opendj.cli.ArgumentParser; 075import com.forgerock.opendj.cli.BooleanArgument; 076import com.forgerock.opendj.cli.FileBasedArgument; 077import com.forgerock.opendj.cli.IntegerArgument; 078import com.forgerock.opendj.cli.StringArgument; 079 080/** 081 * This class provides a tool that can send a request to the Directory Server 082 * that will cause it to shut down. 083 */ 084public class StopDS 085{ 086 /** The fully-qualified name of this class. */ 087 private static final String CLASS_NAME = "org.opends.server.tools.StopDS"; 088 089 /** 090 * Return codes used when the hidden option --checkStoppability is used. 091 * NOTE: when checkStoppability is specified is recommended not to allocate 092 * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might 093 * be calls to Runtime.exec. 094 */ 095 /** The server is already stopped. */ 096 private static int SERVER_ALREADY_STOPPED = 98; 097 /** The server must be started. */ 098 private static int START_SERVER = 99; 099 /** The server must be stopped using a system call. */ 100 private static int STOP_USING_SYSTEM_CALL = 100; 101 /** The server must be restarted using system calls. */ 102 private static int RESTART_USING_SYSTEM_CALL = 101; 103 /** The server must be stopped using protocol. */ 104 private static int STOP_USING_PROTOCOL = 102; 105 /** The server must be stopped as a window service. */ 106 private static int STOP_AS_WINDOW_SERVICE = 103; 107 /** The server must be restarted as a window service. */ 108 private static int RESTART_AS_WINDOW_SERVICE = 104; 109 /** The server must be started and it should use quiet mode. */ 110 private static int START_SERVER_QUIET = 105; 111 /** The server must be restarted using system calls and it should use quiet mode. */ 112 private static int RESTART_USING_SYSTEM_CALL_QUIET = 106; 113 114 /** 115 * Invokes the <CODE>stopDS</CODE> method, passing it the provided command 116 * line arguments. If the call to <CODE>stopDS</CODE> returns a nonzero 117 * value, then that will be used as the exit code for this program. 118 * 119 * @param args The command-line arguments provided to this program. 120 */ 121 public static void main(String[] args) 122 { 123 int result = stopDS(args, System.out, System.err); 124 125 if (result != LDAPResultCode.SUCCESS) 126 { 127 System.exit(filterExitCode(result)); 128 } 129 } 130 131 132 133 /** 134 * Parses the provided set of command-line arguments and attempts to contact 135 * the Directory Server in order to send it the shutdown request. 136 * 137 * @param args The command-line arguments provided to this program. 138 * 139 * @return An integer value that indicates whether the shutdown request was 140 * accepted by the Directory Server. A nonzero value should be 141 * interpreted as a failure of some kind. 142 */ 143 public static int stopDS(String[] args) 144 { 145 return stopDS(args, System.out, System.err); 146 } 147 148 149 150 /** 151 * Parses the provided set of command-line arguments and attempts to contact 152 * the Directory Server in order to send it the shutdown request. 153 * 154 * @param args The command-line arguments provided to this program. 155 * @param outStream The output stream to use for standard output, or 156 * <CODE>null</CODE> if standard output is not needed. 157 * @param errStream The output stream to use for standard error, or 158 * <CODE>null</CODE> if standard error is not needed. 159 * 160 * @return An integer value that indicates whether the shutdown request was 161 * accepted by the Directory Server. A nonzero value should be 162 * interpreted as a failure of some kind. 163 */ 164 public static int stopDS(String[] args, OutputStream outStream, 165 OutputStream errStream) 166 { 167 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 168 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 169 JDKLogging.disableLogging(); 170 171 // Define all the arguments that may be used with this program. 172 LocalizableMessage toolDescription = INFO_STOPDS_TOOL_DESCRIPTION.get(); 173 ArgumentParser argParser = new ArgumentParser(CLASS_NAME, 174 toolDescription, false); 175 argParser.setShortToolDescription(REF_SHORT_DESC_STOP_DS.get()); 176 177 argParser.setVersionHandler(new DirectoryServerVersionHandler()); 178 BooleanArgument checkStoppability; 179 BooleanArgument quietMode; 180 BooleanArgument restart; 181 BooleanArgument showUsage; 182 BooleanArgument trustAll; 183 FileBasedArgument bindPWFile; 184 FileBasedArgument keyStorePWFile; 185 FileBasedArgument trustStorePWFile; 186 IntegerArgument port; 187 StringArgument bindDN; 188 StringArgument bindPW; 189 StringArgument certNickname; 190 StringArgument host; 191 StringArgument keyStoreFile; 192 StringArgument keyStorePW; 193 StringArgument proxyAuthzID; 194 StringArgument saslOption; 195 StringArgument stopReason; 196 StringArgument stopTimeStr; 197 StringArgument trustStoreFile; 198 StringArgument trustStorePW; 199 StringArgument propertiesFileArgument; 200 BooleanArgument noPropertiesFileArgument; 201 202 try 203 { 204 propertiesFileArgument = 205 StringArgument.builder(OPTION_LONG_PROP_FILE_PATH) 206 .description(INFO_DESCRIPTION_PROP_FILE_PATH.get()) 207 .valuePlaceholder(INFO_PROP_FILE_PATH_PLACEHOLDER.get()) 208 .buildAndAddToParser(argParser); 209 argParser.setFilePropertiesArgument(propertiesFileArgument); 210 211 noPropertiesFileArgument = 212 BooleanArgument.builder(OPTION_LONG_NO_PROP_FILE) 213 .description(INFO_DESCRIPTION_NO_PROP_FILE.get()) 214 .buildAndAddToParser(argParser); 215 argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); 216 217 host = 218 StringArgument.builder(OPTION_LONG_HOST) 219 .shortIdentifier(OPTION_SHORT_HOST) 220 .description(INFO_STOPDS_DESCRIPTION_HOST.get()) 221 .defaultValue("127.0.0.1") 222 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 223 .buildAndAddToParser(argParser); 224 port = 225 IntegerArgument.builder(OPTION_LONG_PORT) 226 .shortIdentifier(OPTION_SHORT_PORT) 227 .description(INFO_STOPDS_DESCRIPTION_PORT.get()) 228 .range(1, 65535) 229 .defaultValue(AdministrationConnector.DEFAULT_ADMINISTRATION_CONNECTOR_PORT) 230 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 231 .buildAndAddToParser(argParser); 232 bindDN = 233 StringArgument.builder(OPTION_LONG_BINDDN) 234 .shortIdentifier(OPTION_SHORT_BINDDN) 235 .description(INFO_STOPDS_DESCRIPTION_BINDDN.get()) 236 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 237 .buildAndAddToParser(argParser); 238 bindPW = 239 StringArgument.builder(OPTION_LONG_BINDPWD) 240 .shortIdentifier(OPTION_SHORT_BINDPWD) 241 .description(INFO_STOPDS_DESCRIPTION_BINDPW.get()) 242 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 243 .buildAndAddToParser(argParser); 244 bindPWFile = 245 FileBasedArgument.builder(OPTION_LONG_BINDPWD_FILE) 246 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 247 .description(INFO_STOPDS_DESCRIPTION_BINDPWFILE.get()) 248 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 249 .buildAndAddToParser(argParser); 250 saslOption = 251 StringArgument.builder(OPTION_LONG_SASLOPTION) 252 .shortIdentifier(OPTION_SHORT_SASLOPTION) 253 .description(INFO_STOPDS_DESCRIPTION_SASLOPTIONS.get()) 254 .multiValued() 255 .valuePlaceholder(INFO_SASL_OPTION_PLACEHOLDER.get()) 256 .buildAndAddToParser(argParser); 257 proxyAuthzID = 258 StringArgument.builder(OPTION_LONG_PROXYAUTHID) 259 .shortIdentifier(OPTION_SHORT_PROXYAUTHID) 260 .description(INFO_STOPDS_DESCRIPTION_PROXYAUTHZID.get()) 261 .valuePlaceholder(INFO_PROXYAUTHID_PLACEHOLDER.get()) 262 .buildAndAddToParser(argParser); 263 stopReason = 264 StringArgument.builder("stopReason") 265 .shortIdentifier('r') 266 .description(INFO_STOPDS_DESCRIPTION_STOP_REASON.get()) 267 .valuePlaceholder(INFO_STOP_REASON_PLACEHOLDER.get()) 268 .buildAndAddToParser(argParser); 269 checkStoppability = 270 BooleanArgument.builder(OPTION_LONG_CHECK_STOPPABILITY) 271 .description(INFO_STOPDS_CHECK_STOPPABILITY.get()) 272 .hidden() 273 .buildAndAddToParser(argParser); 274 BooleanArgument.builder(OPTION_LONG_WINDOWS_NET_STOP) 275 .description(INFO_STOPDS_DESCRIPTION_WINDOWS_NET_STOP.get()) 276 .hidden() 277 .buildAndAddToParser(argParser); 278 279 restart = restartArgument(); 280 argParser.addArgument(restart); 281 282 stopTimeStr = 283 StringArgument.builder("stopTime") 284 .shortIdentifier('t') 285 .description(INFO_STOPDS_DESCRIPTION_STOP_TIME.get()) 286 .valuePlaceholder(INFO_STOP_TIME_PLACEHOLDER.get()) 287 .buildAndAddToParser(argParser); 288 289 trustAll = trustAllArgument(); 290 argParser.addArgument(trustAll); 291 292 keyStoreFile = 293 StringArgument.builder(OPTION_LONG_KEYSTOREPATH) 294 .shortIdentifier(OPTION_SHORT_KEYSTOREPATH) 295 .description(INFO_STOPDS_DESCRIPTION_KSFILE.get()) 296 .valuePlaceholder(INFO_KEYSTOREPATH_PLACEHOLDER.get()) 297 .buildAndAddToParser(argParser); 298 keyStorePW = 299 StringArgument.builder(OPTION_LONG_KEYSTORE_PWD) 300 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD) 301 .description(INFO_STOPDS_DESCRIPTION_KSPW.get()) 302 .valuePlaceholder(INFO_KEYSTORE_PWD_PLACEHOLDER.get()) 303 .buildAndAddToParser(argParser); 304 keyStorePWFile = 305 FileBasedArgument.builder(OPTION_LONG_KEYSTORE_PWD_FILE) 306 .shortIdentifier(OPTION_SHORT_KEYSTORE_PWD_FILE) 307 .description(INFO_STOPDS_DESCRIPTION_KSPWFILE.get()) 308 .valuePlaceholder(INFO_KEYSTORE_PWD_FILE_PLACEHOLDER.get()) 309 .buildAndAddToParser(argParser); 310 certNickname = 311 StringArgument.builder("certNickname") 312 .shortIdentifier('N') 313 .description(INFO_DESCRIPTION_CERT_NICKNAME.get()) 314 .valuePlaceholder(INFO_NICKNAME_PLACEHOLDER.get()) 315 .buildAndAddToParser(argParser); 316 trustStoreFile = 317 StringArgument.builder(OPTION_LONG_TRUSTSTOREPATH) 318 .shortIdentifier(OPTION_SHORT_TRUSTSTOREPATH) 319 .description(INFO_STOPDS_DESCRIPTION_TSFILE.get()) 320 .valuePlaceholder(INFO_TRUSTSTOREPATH_PLACEHOLDER.get()) 321 .buildAndAddToParser(argParser); 322 trustStorePW = 323 StringArgument.builder(OPTION_LONG_TRUSTSTORE_PWD) 324 .shortIdentifier('T') 325 .description(INFO_STOPDS_DESCRIPTION_TSPW.get()) 326 .valuePlaceholder(INFO_TRUSTSTORE_PWD_PLACEHOLDER.get()) 327 .buildAndAddToParser(argParser); 328 trustStorePWFile = 329 FileBasedArgument.builder(OPTION_LONG_TRUSTSTORE_PWD_FILE) 330 .shortIdentifier(OPTION_SHORT_TRUSTSTORE_PWD_FILE) 331 .description(INFO_STOPDS_DESCRIPTION_TSPWFILE.get()) 332 .valuePlaceholder(INFO_TRUSTSTORE_PWD_FILE_PLACEHOLDER.get()) 333 .buildAndAddToParser(argParser); 334 335 quietMode = quietArgument(); 336 argParser.addArgument(quietMode); 337 338 showUsage = showUsageArgument(); 339 argParser.addArgument(showUsage); 340 argParser.setUsageArgument(showUsage, out); 341 } 342 catch (ArgumentException ae) 343 { 344 printWrappedText(err, ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 345 return CLIENT_SIDE_PARAM_ERROR; 346 } 347 348 349 // Parse the command-line arguments provided to the program. 350 try 351 { 352 argParser.parseArguments(args); 353 } 354 catch (ArgumentException ae) 355 { 356 argParser.displayMessageAndUsageReference(err, ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 357 return CLIENT_SIDE_PARAM_ERROR; 358 } 359 360 361 // If we should just display usage or version information, 362 // then exit because it will have already been done. 363 if (argParser.usageOrVersionDisplayed()) 364 { 365 return LDAPResultCode.SUCCESS; 366 } 367 368 if (quietMode.isPresent()) 369 { 370 out = NullOutputStream.printStream(); 371 } 372 373 if (checkStoppability.isPresent()) 374 { 375 System.exit(checkStoppability(argParser, out, err)); 376 } 377 378 // If both a bind password and bind password file were provided, then return 379 // an error. 380 if (bindPW.isPresent() && bindPWFile.isPresent()) 381 { 382 printWrappedText(err, 383 ERR_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS.get(bindPW.getLongIdentifier(), bindPWFile.getLongIdentifier())); 384 return CLIENT_SIDE_PARAM_ERROR; 385 } 386 387 388 // If both a key store password and key store password file were provided, 389 // then return an error. 390 if (keyStorePW.isPresent() && keyStorePWFile.isPresent()) 391 { 392 printWrappedText(err, ERR_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS.get( 393 keyStorePW.getLongIdentifier(), keyStorePWFile.getLongIdentifier())); 394 return CLIENT_SIDE_PARAM_ERROR; 395 } 396 397 398 // If both a trust store password and trust store password file were 399 // provided, then return an error. 400 if (trustStorePW.isPresent() && trustStorePWFile.isPresent()) 401 { 402 printWrappedText(err, ERR_STOPDS_MUTUALLY_EXCLUSIVE_ARGUMENTS.get( 403 trustStorePW.getLongIdentifier(), trustStorePWFile.getLongIdentifier())); 404 return CLIENT_SIDE_PARAM_ERROR; 405 } 406 407 408 // Make sure that we can decode the stop time string if one was provided. 409 Date stopTime = new Date(); 410 if (stopTimeStr.isPresent()) 411 { 412 String timeStr = stopTimeStr.getValue(); 413 if (!TaskTool.NOW.equals(timeStr)) 414 { 415 try 416 { 417 stopTime = parseDateTimeString(timeStr); 418 } 419 catch (Exception e) 420 { 421 printWrappedText(err, ERR_STOPDS_CANNOT_DECODE_STOP_TIME.get()); 422 return CLIENT_SIDE_PARAM_ERROR; 423 } 424 // Check that the provided date is not previous to the current date. 425 Date currentDate = new Date(System.currentTimeMillis()); 426 if (currentDate.after(stopTime)) 427 { 428 printWrappedText(err, ERR_STOPDS_DATETIME_ALREADY_PASSED.get(timeStr)); 429 return CLIENT_SIDE_PARAM_ERROR; 430 } 431 } 432 } 433 434 435 // Create the LDAP connection options object, which will be used to 436 // customize the way that we connect to the server and specify a set of 437 // basic defaults. 438 LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); 439 connectionOptions.setVersionNumber(3); 440 441 442 try { 443 String clientAlias; 444 if (certNickname.isPresent()) { 445 clientAlias = certNickname.getValue(); 446 } else { 447 clientAlias = null; 448 } 449 450 SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory(); 451 sslConnectionFactory.init(trustAll.isPresent(), keyStoreFile.getValue(), 452 keyStorePW.getValue(), clientAlias, 453 trustStoreFile.getValue(), 454 trustStorePW.getValue()); 455 456 connectionOptions.setSSLConnectionFactory(sslConnectionFactory); 457 } catch (SSLConnectionException sce) { 458 printWrappedText(err, ERR_STOPDS_CANNOT_INITIALIZE_SSL.get(sce.getMessage())); 459 return CLIENT_SIDE_LOCAL_ERROR; 460 } 461 462 463 // If one or more SASL options were provided, then make sure that one of 464 // them was "mech" and specified a valid SASL mechanism. 465 if (saslOption.isPresent()) 466 { 467 String mechanism = null; 468 LinkedList<String> options = new LinkedList<>(); 469 470 for (String s : saslOption.getValues()) 471 { 472 int equalPos = s.indexOf('='); 473 if (equalPos <= 0) 474 { 475 printWrappedText(err, ERR_STOPDS_CANNOT_PARSE_SASL_OPTION.get(s)); 476 return CLIENT_SIDE_PARAM_ERROR; 477 } 478 else 479 { 480 String name = s.substring(0, equalPos); 481 482 if (name.equalsIgnoreCase("mech")) 483 { 484 mechanism = s; 485 } 486 else 487 { 488 options.add(s); 489 } 490 } 491 } 492 493 if (mechanism == null) 494 { 495 printWrappedText(err, ERR_STOPDS_NO_SASL_MECHANISM.get()); 496 return CLIENT_SIDE_PARAM_ERROR; 497 } 498 499 connectionOptions.setSASLMechanism(mechanism); 500 501 for (String option : options) 502 { 503 connectionOptions.addSASLProperty(option); 504 } 505 } 506 507 508 // Attempt to connect and authenticate to the Directory Server. 509 AtomicInteger nextMessageID = new AtomicInteger(1); 510 LDAPConnection connection; 511 try 512 { 513 connection = new LDAPConnection(host.getValue(), port.getIntValue(), 514 connectionOptions, out, err); 515 connection.connectToHost(bindDN.getValue(), 516 LDAPConnectionArgumentParser.getPasswordValue(bindPW, bindPWFile, 517 bindDN, out, err), 518 nextMessageID); 519 } 520 catch (ArgumentException ae) 521 { 522 argParser.displayMessageAndUsageReference( 523 err, ERR_STOPDS_CANNOT_DETERMINE_PORT.get(port.getLongIdentifier(), ae.getMessage())); 524 return CLIENT_SIDE_PARAM_ERROR; 525 } 526 catch (LDAPConnectionException lce) 527 { 528 LocalizableMessage message = null; 529 if (lce.getCause() != null && lce.getCause().getCause() != null && 530 lce.getCause().getCause() instanceof SSLException) { 531 message = ERR_STOPDS_CANNOT_CONNECT_SSL.get(host.getValue(), 532 port.getValue()); 533 } else { 534 String hostPort = host.getValue() + ":" + port.getValue(); 535 message = ERR_STOPDS_CANNOT_CONNECT.get(hostPort, 536 lce.getMessage()); 537 } 538 printWrappedText(err, message); 539 return CLIENT_SIDE_CONNECT_ERROR; 540 } 541 542 LDAPReader reader = connection.getLDAPReader(); 543 LDAPWriter writer = connection.getLDAPWriter(); 544 545 546 // Construct the add request to send to the server. 547 String taskID = UUID.randomUUID().toString(); 548 ByteString entryDN = 549 ByteString.valueOfUtf8(ATTR_TASK_ID + "=" + taskID + "," + 550 SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT); 551 552 ArrayList<RawAttribute> attributes = new ArrayList<>(); 553 attributes.add(new LDAPAttribute(ATTR_OBJECTCLASS, newArrayList("top", "ds-task", "ds-task-shutdown"))); 554 attributes.add(new LDAPAttribute(ATTR_TASK_ID, taskID)); 555 attributes.add(new LDAPAttribute(ATTR_TASK_CLASS, ShutdownTask.class.getName())); 556 if (restart.isPresent()) 557 { 558 attributes.add(new LDAPAttribute(ATTR_RESTART_SERVER, "true")); 559 } 560 if (stopReason.isPresent()) 561 { 562 attributes.add(new LDAPAttribute(ATTR_SHUTDOWN_MESSAGE, stopReason.getValue())); 563 } 564 565 if (stopTime != null) 566 { 567 SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_GMT_TIME); 568 dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 569 String stopTimeValues = dateFormat.format(stopTime); 570 attributes.add(new LDAPAttribute(ATTR_TASK_SCHEDULED_START_TIME, stopTimeValues)); 571 } 572 573 ArrayList<Control> controls = new ArrayList<>(); 574 if (proxyAuthzID.isPresent()) 575 { 576 controls.add(new ProxiedAuthV2Control( 577 ByteString.valueOfUtf8(proxyAuthzID.getValue()))); 578 } 579 580 AddRequestProtocolOp addRequest = new AddRequestProtocolOp(entryDN, attributes); 581 LDAPMessage requestMessage = 582 new LDAPMessage(nextMessageID.getAndIncrement(), addRequest, controls); 583 584 585 // Send the request to the server and read the response. 586 LDAPMessage responseMessage; 587 try 588 { 589 writer.writeMessage(requestMessage); 590 591 responseMessage = reader.readMessage(); 592 if (responseMessage == null) 593 { 594 printWrappedText(err, ERR_STOPDS_UNEXPECTED_CONNECTION_CLOSURE.get()); 595 return CLIENT_SIDE_SERVER_DOWN; 596 } 597 } 598 catch (DecodeException | LDAPException e) 599 { 600 printWrappedText(err, ERR_STOPDS_DECODE_ERROR.get(e.getMessage())); 601 return CLIENT_SIDE_DECODING_ERROR; 602 } 603 catch (IOException ioe) 604 { 605 printWrappedText(err, ERR_STOPDS_IO_ERROR.get(ioe)); 606 return LDAPResultCode.CLIENT_SIDE_SERVER_DOWN; 607 } 608 609 610 if (responseMessage.getProtocolOpType() != 611 LDAPConstants.OP_TYPE_ADD_RESPONSE) 612 { 613 if (responseMessage.getProtocolOpType() == 614 LDAPConstants.OP_TYPE_EXTENDED_RESPONSE) 615 { 616 // It's possible that this is a notice of disconnection, which we can 617 // probably interpret as a "success" in this case. 618 ExtendedResponseProtocolOp extendedResponse = 619 responseMessage.getExtendedResponseProtocolOp(); 620 String responseOID = extendedResponse.getOID(); 621 if (LDAPConstants.OID_NOTICE_OF_DISCONNECTION.equals(responseOID)) 622 { 623 printWrappedText(err, extendedResponse.getErrorMessage()); 624 return extendedResponse.getResultCode(); 625 } 626 } 627 628 629 printWrappedText(err, ERR_STOPDS_INVALID_RESPONSE_TYPE.get(responseMessage.getProtocolOpName())); 630 631 632 return CLIENT_SIDE_LOCAL_ERROR; 633 } 634 635 636 AddResponseProtocolOp addResponse = responseMessage.getAddResponseProtocolOp(); 637 printWrappedText(err, addResponse.getErrorMessage()); 638 return addResponse.getResultCode(); 639 } 640 641 /** 642 * Returns the error code that we return when we are checking the stoppability 643 * of the server. This basically tells the invoker what must be done based 644 * on the different parameters passed. 645 * @param argParser the ArgumentParser with the arguments already parsed. 646 * @param out the print stream to use for standard output. 647 * @param err the print stream to use for standard error. 648 * @return the error code that we return when we are checking the stoppability 649 * of the server. 650 */ 651 private static int checkStoppability(ArgumentParser argParser, 652 PrintStream out, PrintStream err) 653 { 654 int returnValue; 655 boolean isServerRunning; 656 657 boolean quietMode = false; 658 Argument quietArg = argParser.getArgumentForLongID(ArgumentConstants.OPTION_LONG_QUIET); 659 if (quietArg != null && quietArg.isPresent()) 660 { 661 quietMode = true; 662 } 663 664 final boolean restartPresent = argParser.getArgumentForLongID(OPTION_LONG_RESTART).isPresent(); 665 final boolean windowsNetStopPresent = argParser.getArgumentForLongID(OPTION_LONG_WINDOWS_NET_STOP).isPresent(); 666 667 // Check if this is a stop through protocol. 668 boolean stopThroughProtocol = false; 669 for (final Argument arg: argParser.getArgumentList()) 670 { 671 if (!OPTION_LONG_RESTART.equals(arg.getLongIdentifier()) && 672 !OPTION_LONG_QUIET.equals(arg.getLongIdentifier()) && 673 !OPTION_LONG_HELP.equals(arg.getLongIdentifier()) && 674 !OPTION_LONG_CHECK_STOPPABILITY.equals(arg.getLongIdentifier()) && 675 !OPTION_LONG_WINDOWS_NET_STOP.equals(arg.getLongIdentifier()) && 676 !OPTION_LONG_NO_PROP_FILE.equals(arg.getLongIdentifier())) 677 { 678 stopThroughProtocol |= arg.isPresent(); 679 } 680 } 681 682 if (stopThroughProtocol) 683 { 684 // Assume that this is done on a remote server and do no more checks. 685 returnValue = STOP_USING_PROTOCOL; 686 } 687 else 688 { 689 String lockFile = LockFileManager.getServerLockFileName(); 690 try 691 { 692 StringBuilder failureReason = new StringBuilder(); 693 if (LockFileManager.acquireExclusiveLock(lockFile, failureReason)) 694 { 695 // The server is not running: write a message informing of that 696 // in the standard out (this is not an error message). 697 LocalizableMessage message = INFO_STOPDS_SERVER_ALREADY_STOPPED.get(); 698 out.println(message); 699 LockFileManager.releaseLock(lockFile, failureReason); 700 isServerRunning = false; 701 } 702 else 703 { 704 isServerRunning = true; 705 } 706 } 707 catch (Exception e) 708 { 709 // Assume that if we cannot acquire the lock file the server is 710 // running. 711 isServerRunning = true; 712 } 713 714 boolean configuredAsService = 715 DirectoryServer.isRunningAsWindowsService(); 716 717 if (!isServerRunning) 718 { 719 if (configuredAsService && !windowsNetStopPresent) 720 { 721 if (restartPresent) 722 { 723 returnValue = RESTART_AS_WINDOW_SERVICE; 724 } 725 else 726 { 727 returnValue = STOP_AS_WINDOW_SERVICE; 728 } 729 } 730 else if (restartPresent) 731 { 732 if (quietMode) 733 { 734 returnValue = START_SERVER_QUIET; 735 } 736 else 737 { 738 returnValue = START_SERVER; 739 } 740 } 741 else 742 { 743 returnValue = SERVER_ALREADY_STOPPED; 744 } 745 } 746 else 747 { 748 if (configuredAsService) 749 { 750 if (windowsNetStopPresent) 751 { 752 // stop-ds.bat is being called through net stop, so return 753 // STOP_USING_SYSTEM_CALL or RESTART_USING_SYSTEM_CALL so that the 754 // batch file actually stops the server. 755 if (restartPresent) 756 { 757 if (quietMode) 758 { 759 returnValue = RESTART_USING_SYSTEM_CALL_QUIET; 760 } 761 else 762 { 763 returnValue = RESTART_USING_SYSTEM_CALL; 764 } 765 } 766 else 767 { 768 returnValue = STOP_USING_SYSTEM_CALL; 769 } 770 } 771 else 772 { 773 if (restartPresent) 774 { 775 returnValue = RESTART_AS_WINDOW_SERVICE; 776 } 777 else 778 { 779 returnValue = STOP_AS_WINDOW_SERVICE; 780 } 781 // Display a message informing that we are going to the server. 782 783 LocalizableMessage message = INFO_STOPDS_GOING_TO_STOP.get(); 784 out.println(message); 785 } 786 } 787 else 788 { 789 // Display a message informing that we are going to the server. 790 791 LocalizableMessage message = INFO_STOPDS_GOING_TO_STOP.get(); 792 out.println(message); 793 794 if (restartPresent) 795 { 796 if (quietMode) 797 { 798 returnValue = RESTART_USING_SYSTEM_CALL_QUIET; 799 } 800 else 801 { 802 returnValue = RESTART_USING_SYSTEM_CALL; 803 } 804 } 805 else 806 { 807 returnValue = STOP_USING_SYSTEM_CALL; 808 } 809 } 810 } 811 } 812 return returnValue; 813 } 814} 815