At somepoint in time, it may become necessary to add a new REST command to the CMO REST API. Here is a walk through of the basic components needed and some sample code....

A branch has been put together to illustrate how to get to an end to end REST command working.
see https://github.com/mhansonp/geode/tree/BlogCode

What you are going to need to get your REST command working?

OperationController this is what specifies the endpoints and the security to allow access to the thing you want to do. The main thing the OperationController does is map the REST commands to function calls. For this example our class name is BlogCodeOperationController. Using the endpoint and command type (POST or GET) it tells what command is being executed. There are three commands that necessary to be compliant the the ClusterManagementOperation POST, GET, and List. Please also note that the security settings are custom to the command type... Please see https://cwiki.apache.org/confluence/display/GEODE/Finer+grained+security to understand where your code might sit in terms of security.

OperationManager (literally named OperationManager) change to add your performer which will do the thing you ask it to do. There all that needs to happen is to register our operation  

registerOperation(BlogCodeRequest.class, new BlogCodePerformer());

A request class of some sort. This is going to be an object that is going to be serialized and desirialized across the REST interface to the locator. In our example we are using BlogCodeRequest

A response class of some sort. This is going to provide the server response. In this example, ours is BlogCodeResponse. It will be serialized then deserialized across the interface from the locator. Because of Jackson serialization, variables and methods must be consistently named. 

String statusMessage;
String getStatusMessage();
void setStatusMessage(String myString);

This allows for proper serialization. Any methods that don't match a variable should be @JSONIgnore'd

A performer class, for example BlogCodePerformer, takes the request, does the work and provides the response. Once the request reaches the performer, that is where your code has to interface with the rest of the system.

 

Please keep in mind that so much of this is just boiler plate to connect all the dots. The serialization support, in particular, is super picky.


Here is the unit test of this code


public class BlogCodeDUnitTest {

@Rule
public ClusterStartupRule cluster = new ClusterStartupRule();

private MemberVM locator;
private List<MemberVM> servers;
private static final int SERVERS_TO_START = 1;

private ClusterManagementService client1;

@Before
public void setup() {
     locator = cluster.startLocatorVM(0, MemberStarterRule::withHttpService);
     servers = new ArrayList<>();
     int locatorPort = locator.getPort();
     IntStream.range(0, SERVERS_TO_START)
       .forEach(i -> servers.add(cluster.startServerVM(i + 1, locatorPort)));

    client1 = new ClusterManagementServiceBuilder()
      .setHost("localhost")
      .setPort(locator.getHttpPort())
      .build();
  }

@After
public void tearDown() {
    client1.close();
  }

@Test
public void testBlogCode() throws ExecutionException, InterruptedException {

    BlogCodeRequest blogCodeRequest = new BlogCodeRequest();

    ClusterManagementOperationResult<BlogCodeRequest, BlogCodeResponse> startResult =
    client1.start(blogCodeRequest);

    assertThat(startResult.isSuccessful()).isTrue();

    ClusterManagementOperationResult<BlogCodeRequest, BlogCodeResponse> endResult =
    client1.getFuture(blogCodeRequest, startResult.getOperationId()).get();

    BlogCodeResponse blogCodeResponse = endResult.getOperationResult();

    assertThat(blogCodeResponse.getSuccess()).isTrue();

    assertThat(blogCodeResponse.getStatusMessage()).isEqualTo("Hello, World!");
  }

}



1 Comment

  1. Udo Kohlmeyer if you can add your comments about what specifically didn't make sense and I will add more documentation.