1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.zookeeper.server.controller;
20 
21 /**
22  * Set of commands that this controller can execute. Commands are comprised
23  * of an action and an optional parameter specific to that action.
24  */
25 public class ControlCommand {
26     /**
27      * Actions available to the controller
28       */
29     public enum Action {
30         // Simple "are you there" ping to confirm the controller is up and running.
31         PING,
32         // Shutdown everything, including CommandListener, ControllerService, Controller and the ZooKeeperServer.
33         SHUTDOWN,
34         // Close a connection triggering a client disconnect (and then reconnect attempt).
35         // No parameter indicates close all connections. Optional parameter indicates a specific session id (as long).
36         CLOSECONNECTION,
37         // More actions go here in the future (force drop sessions, etc).
38         EXPIRESESSION,
39         // Reject all future connections. No parameter required.
40         REJECTCONNECTIONS,
41         // Add latency to server replies.
42         // Optional parameter indicates time in milliseconds to delay
43         // (default = 1 second).
44         ADDDELAY,
45         // Fail requests.
46         // Optional parameter indicates how many requests to fail.
47         // (default = all requests until RESET).
48         FAILREQUESTS,
49         // Process requests but do not send a response.
50         // Optional parameter indicates how many requests to fail.
51         // (default = all requests until RESET).
52         NORESPONSE,
53         // No parameter indicates fail all requests.
54         // Optional parameter indicates undo all the chaotic action commands
55         // (reject connections, add delay, fail requests, eat requests and so on...).
56         RESET,
57         // Force the quorum to elect a new leader.
58         ELECTNEWLEADER,
59         // More actions go here in the future...
60     }
61 
62     public static final String ENDPOINT = "command";
63     public static final String ENDPOINT_PREFIX = ENDPOINT + "/";
64 
65     private Action action;
getAction()66     public Action getAction() {
67         return action;
68     }
69 
70     private String parameter;
getParameter()71     protected String getParameter() {
72         return parameter;
73     }
74 
ControlCommand(Action action)75     public ControlCommand(Action action) {
76         this(action, null);
77     }
78 
ControlCommand(Action action, String param)79     public ControlCommand(Action action, String param) {
80         this.action = action;
81         this.parameter = param;
82     }
83 
84     /**
85      * Create a REST command uri.
86      * @param action The 'verb' of the command.
87      * @param parameter The optional parameter.
88      * @return A string to send to the server as the end of the Uri.
89      */
createCommandUri(Action action, String parameter)90     public static String createCommandUri(Action action, String parameter) {
91         return ENDPOINT_PREFIX + action.toString() + (parameter != null && !parameter.isEmpty() ? "/" + parameter : "");
92     }
93 
94     /**
95      * Parse a Uri into the required Command action and parameter.
96      * @param commandUri the properly formatted Uri.
97      */
parseUri(String commandUri)98     public static ControlCommand parseUri(String commandUri) {
99         if (commandUri == null) {
100             throw new IllegalArgumentException("commandUri can't be null.");
101         }
102 
103         if (!commandUri.startsWith(ENDPOINT_PREFIX)) {
104             throw new IllegalArgumentException("Missing required prefix: " + ENDPOINT_PREFIX);
105         }
106 
107         String uri = commandUri.substring(ENDPOINT_PREFIX.length());
108         String name;
109         String param;
110 
111         int separatorIndex = uri.indexOf('/');
112         if (separatorIndex < 0) {
113             name = uri;
114             param = null;
115         } else {
116             name = uri.substring(0, separatorIndex);
117             param = uri.substring(separatorIndex + 1);
118         }
119 
120         return new ControlCommand(Action.valueOf(name.toUpperCase()), param);
121     }
122 }
123