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