Finish RESTful Client API 13/57113/1
authorInstrumental <jonathan.gathman@att.com>
Sun, 22 Jul 2018 12:49:16 +0000 (07:49 -0500)
committerInstrumental <jonathan.gathman@att.com>
Sun, 22 Jul 2018 12:49:20 +0000 (07:49 -0500)
Issue-ID: AAF-361
Change-Id: I999cb419a79c5995baf3757fdbbe047528901597
Signed-off-by: Instrumental <jonathan.gathman@att.com>
auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/HMangrStub.java
auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Create.java
auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Delete.java
auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Describe.java
auth/auth-cmd/src/test/java/org/onap/aaf/auth/cmd/test/perm/JU_Grant.java
auth/auth-hello/src/main/java/org/onap/aaf/auth/hello/API_Hello.java
cadi/client/src/main/java/org/onap/aaf/cadi/client/Rcli.java
cadi/client/src/main/java/org/onap/aaf/cadi/locator/SingleEndpointLocator.java
cadi/oauth-enduser/src/main/java/org/onap/aaf/cadi/enduser/SimpleRESTClient.java
cadi/oauth-enduser/src/test/java/org/onap/aaf/cadi/enduser/test/SimpleRestClientExample.java

index 7ceb123..c1b8754 100644 (file)
@@ -49,6 +49,10 @@ public class HMangrStub extends HMangr {
                return null;
        }
        @Override public<RET> RET oneOf(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable, boolean notify, String host) {
+               try {
+                       return retryable.code(clientMock);
+               } catch (Exception e) {
+               }
                return null;
        }
 }
index 1fb2747..41295c7 100644 (file)
@@ -60,7 +60,7 @@ public class JU_Create {
        @Mock private Locator<URI> locMock;
        @Mock private Writer wrtMock;
        @Mock private Rcli<HttpURLConnection> clientMock;
-       @Mock private Future<Object> futureMock;
+       @Mock private Future<String> futureMock;
                
        private static Create create;
 
@@ -74,9 +74,9 @@ public class JU_Create {
        public void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException {
                MockitoAnnotations.initMocks(this);
                
-               when(clientMock.create(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.delete(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.update(any(), any(), any())).thenReturn(futureMock);
+               when(clientMock.create(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.delete(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.update(any(), any(), any(String.class))).thenReturn(futureMock);
 
                hman = new HMangrStub(access, locMock, clientMock);
                access = new PropAccess(new PrintStream(new ByteArrayOutputStream()), new String[0]);
index 4fd7892..19caced 100644 (file)
@@ -24,7 +24,7 @@ package org.onap.aaf.auth.cmd.test.perm;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.when;
 
-
+import org.hamcrest.core.AnyOf;
 import org.junit.Before;
 
 import org.onap.aaf.auth.cmd.test.HMangrStub;
@@ -62,7 +62,7 @@ public class JU_Delete {
        @Mock private Locator<URI> locMock;
        @Mock private Writer wrtMock;
        @Mock private Rcli<HttpURLConnection> clientMock;
-       @Mock private Future<Object> futureMock;
+       @Mock private Future<String> futureMock;
 
        private static Delete del;
        
@@ -75,9 +75,9 @@ public class JU_Delete {
        public void setUp() throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException {
                MockitoAnnotations.initMocks(this);
 
-               when(clientMock.create(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.delete(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.update(any(), any(), any())).thenReturn(futureMock);
+               when(clientMock.create(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.delete(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.update(any(), any(), any(String.class))).thenReturn(futureMock);
 
                hman = new HMangrStub(access, locMock, clientMock);
                access = new PropAccess(new PrintStream(new ByteArrayOutputStream()), new String[0]);
index 224b5c7..9a5fc73 100644 (file)
@@ -61,7 +61,7 @@ public class JU_Describe {
        @Mock private Locator<URI> locMock;
        @Mock private Writer wrtMock;
        @Mock private Rcli<HttpURLConnection> clientMock;
-       @Mock private Future<Object> futureMock;
+       @Mock private Future<String> futureMock;
 
        private PropAccess access;
        private HMangrStub hman;        
@@ -74,9 +74,9 @@ public class JU_Describe {
        public void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException {
                MockitoAnnotations.initMocks(this);
 
-               when(clientMock.create(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.delete(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.update(any(), any(), any())).thenReturn(futureMock);
+               when(clientMock.create(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.delete(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.update(any(), any(), any(String.class))).thenReturn(futureMock);
 
                hman = new HMangrStub(access, locMock, clientMock);
                access = new PropAccess(new PrintStream(new ByteArrayOutputStream()), new String[0]);
index 17280c6..975b83d 100644 (file)
@@ -63,7 +63,7 @@ public class JU_Grant {
        @Mock private Locator<URI> locMock;
        @Mock private Writer wrtMock;
        @Mock private Rcli<HttpURLConnection> clientMock;
-       @Mock private Future<Object> futureMock;
+       @Mock private Future<String> futureMock;
 
        private PropAccess access;
        private HMangrStub hman;        
@@ -74,9 +74,9 @@ public class JU_Grant {
        public void setUp () throws NoSuchFieldException, SecurityException, Exception, IllegalAccessException {
                MockitoAnnotations.initMocks(this);
 
-               when(clientMock.create(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.delete(any(), any(), any())).thenReturn(futureMock);
-               when(clientMock.update(any(), any(), any())).thenReturn(futureMock);
+               when(clientMock.create(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.delete(any(), any(), any(String.class))).thenReturn(futureMock);
+               when(clientMock.update(any(), any(), any(String.class))).thenReturn(futureMock);
 
                hman = new HMangrStub(access, locMock, clientMock);
                access = new PropAccess(new PrintStream(new ByteArrayOutputStream()), new String[0]);
index 2be162c..030073a 100644 (file)
@@ -21,6 +21,9 @@
 
 package org.onap.aaf.auth.hello;
 
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -40,6 +43,9 @@ import org.onap.aaf.misc.env.TimeTaken;
 public class API_Hello {
 
 
+       private static final String APPLICATION_JSON = "application/json";
+       protected static final byte[] NOT_JSON = "Data does not look like JSON".getBytes();
+
        // Hide Public Constructor
        private API_Hello() {}
        
@@ -85,10 +91,37 @@ public class API_Hello {
                        }
                }); 
 
-               ////////
-               // REST APIs
-               ///////
-               oauthHello.route(oauthHello.env,HttpMethods.GET,"/resthello/:perm*",new HttpCode<AuthzTrans, AAF_Hello>(oauthHello,"REST Hello OAuth") {
+////////////////
+// REST APIs
+////////////////
+
+               ////////////////
+               // CREATE/POST
+               ////////////////
+               oauthHello.route(oauthHello.env,HttpMethods.POST,"/resthello/:id",new HttpCode<AuthzTrans, AAF_Hello>(oauthHello,"REST Hello Create") {
+                       @Override
+                       public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+                               BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream()));
+                               StringBuilder sb = new StringBuilder();
+                               while(br.ready()) {
+                                       sb.append(br.readLine());
+                               }
+                               String content = sb.toString();
+                               trans.info().printf("Content from %s: %s\n", pathParam(req, ":id"),content);
+                               if(content.startsWith("{") && content.endsWith("}")) {
+                                       resp.setStatus(201 /* OK */);
+                               } else {
+                                       resp.getOutputStream().write(NOT_JSON);
+                                       resp.setStatus(406);
+                               }
+                       }
+               },APPLICATION_JSON); 
+
+
+               ////////////////
+               // READ/GET
+               ////////////////
+               oauthHello.route(oauthHello.env,HttpMethods.GET,"/resthello/:id/:perm*",new HttpCode<AuthzTrans, AAF_Hello>(oauthHello,"REST Hello Read") {
                        @Override
                        public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
                                resp.setStatus(200 /* OK */);
@@ -96,6 +129,7 @@ public class API_Hello {
                                sb.append(req.getUserPrincipal().getName());
                                sb.append('"');
                                String perm = pathParam(req, "perm");
+                               trans.info().printf("Read request from %s: %s\n", pathParam(req, ":id"),perm);
                                if(perm!=null && perm.length()>0) {
                                        TimeTaken tt = trans.start("Authorize perm", Env.REMOTE);
                                        try {
@@ -113,9 +147,42 @@ public class API_Hello {
                                os.println(sb.toString());
                                trans.info().printf("Said 'RESTful Hello' to %s, Authentication type: %s",trans.getUserPrincipal().getName(),trans.getUserPrincipal().getClass().getSimpleName());
                        }
-               },"application/json"); 
-               
-               
+               },APPLICATION_JSON); 
                
+               ////////////////
+               // UPDATE/PUT
+               ////////////////
+               oauthHello.route(oauthHello.env,HttpMethods.PUT,"/resthello/:id",new HttpCode<AuthzTrans, AAF_Hello>(oauthHello,"REST Hello Update") {
+                       @Override
+                       public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+                               BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream()));
+                               StringBuilder sb = new StringBuilder();
+                               while(br.ready()) {
+                                       sb.append(br.readLine());
+                               }
+                               String content = sb.toString();
+                               trans.info().printf("Content from %s: %s\n", pathParam(req, ":id"),content);
+                               if(content.startsWith("{") && content.endsWith("}")) {
+                                       resp.setStatus(200 /* OK */);
+                                       resp.getOutputStream().print(content);
+                               } else {
+                                       resp.getOutputStream().write(NOT_JSON);
+                                       resp.setStatus(406);
+                               }
+                       }
+               },APPLICATION_JSON); 
+
+
+               ////////////////
+               // DELETE
+               ////////////////
+               oauthHello.route(oauthHello.env,HttpMethods.DELETE,"/resthello/:id",new HttpCode<AuthzTrans, AAF_Hello>(oauthHello,"REST Hello Delete") {
+                       @Override
+                       public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+                               trans.info().printf("Delete requested on %s\n", pathParam(req, ":id"));
+                               resp.setStatus(200 /* OK */);
+                       }
+               },APPLICATION_JSON); 
+
        }
 }
index 058bbd3..04075f2 100644 (file)
@@ -217,6 +217,20 @@ public abstract class Rcli<CT> {
                return client.futureCreate(Void.class);
        }
 
+       public Future<Void> create(String pathinfo, String contentType, EClient.Transfer content) throws APIException, CadiException {
+               final ParsePath pp = new ParsePath(pathinfo);
+
+               EClient<CT> client = client();
+               client.setMethod(POST);
+               client.addHeader(CONTENT_TYPE,contentType);
+               client.setPathInfo(pp.path());
+               client.setQueryParams(pp.query());
+               client.setFragment(pp.frag());
+               client.setPayload(content);
+               client.send();
+               return client.futureCreate(Void.class);
+       }
+
 
        /**
         * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
@@ -462,6 +476,22 @@ public abstract class Rcli<CT> {
                client.send();
                return client.futureReadString();
        }
+       
+       public Future<String> update(String pathinfo, String contentType, EClient.Transfer content) throws APIException, CadiException {
+               final ParsePath pp = new ParsePath(pathinfo);
+
+               EClient<CT> client = client();
+               client.setMethod(PUT);
+               client.addHeader(CONTENT_TYPE,contentType);
+               client.setPathInfo(pp.path());
+               client.setQueryParams(pp.query());
+               client.setFragment(pp.frag());
+               client.setPayload(content);
+               client.send();
+               return client.futureReadString();
+       }
+
+
 
 
        public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
@@ -503,6 +533,8 @@ public abstract class Rcli<CT> {
                client.send();
                return client.future(t);
        }
+       
+
 
        /**
         * A method to update with a VOID
@@ -531,6 +563,7 @@ public abstract class Rcli<CT> {
                client.send();
                return client.future(null);
        }
+       
 
        public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
                final ParsePath pp = new ParsePath(pathinfo);
index b0c830f..23bcd4a 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.aaf.cadi.locator;
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.Date;
 
 import org.onap.aaf.cadi.Locator;
 import org.onap.aaf.cadi.LocatorException;
@@ -29,6 +30,7 @@ import org.onap.aaf.cadi.LocatorException;
 public class SingleEndpointLocator implements Locator<URI> {
        private final URI uri;
        private final static Item item = new Item() {};  
+       private Date noRetryUntil;
        
        public SingleEndpointLocator(final URI uri) {
                this.uri = uri;
@@ -45,12 +47,20 @@ public class SingleEndpointLocator implements Locator<URI> {
 
        @Override
        public boolean hasItems() {
+               if(noRetryUntil!=null) {
+                       if(new Date().after(noRetryUntil)) {
+                               noRetryUntil = null;
+                       } else {
+                               return false;
+                       }
+               }
                return true;
        }
 
        @Override
        public void invalidate(Item item) throws LocatorException {
-               // Endpoints cannot be invalidated
+               // one minute timeout, because there is no other item
+               noRetryUntil = new Date(System.currentTimeMillis()+60000); 
        }
 
        @Override
index 386d938..30344de 100644 (file)
 package org.onap.aaf.cadi.enduser;
 
 import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.net.ConnectException;
 import java.security.Principal;
 
 import org.onap.aaf.cadi.CadiException;
 import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.client.EClient;
 import org.onap.aaf.cadi.client.Future;
 import org.onap.aaf.cadi.client.Rcli;
 import org.onap.aaf.cadi.client.Result;
@@ -37,8 +40,10 @@ import org.onap.aaf.cadi.oauth.TokenClientFactory;
 import org.onap.aaf.cadi.oauth.TzClient;
 import org.onap.aaf.cadi.principal.TaggedPrincipal;
 import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.util.StringBuilderWriter;
 
 public class SimpleRESTClient {
+       private static final String APPLICATION_JSON = "application/json";
        private static final String[] EMPTY = new String[0];
        private final TokenClient tokenClient;
        private final TzClient restClient;
@@ -93,13 +98,116 @@ public class SimpleRESTClient {
                }
                return this;
        }
+       
+       /**
+        * Single Threaded Class for building up content
+        * @author jg1555
+        *
+        */
+       public static class Input {
+               private static final byte[] EMPTY_STREAM_BYTES = "".getBytes();
+
+               private String content;
+               private StringBuilder sb;
+               
+               public Input() {
+                       content = null;
+                       sb = null;
+               }
+               
+               public Input(final String content) {
+                       this.content = content;
+               }
+               
+               public void set(final String content) {
+                       this.content = content;
+               }
+               
+               public PrintWriter writer() {
+                       return new PrintWriter(new StringBuilderWriter(builder()));
+               }
+               
+               public StringBuilder builder() {
+                       if(sb==null) {
+                               sb = new StringBuilder();
+                               content = null;
+                       }
+                       return sb;
+               }
+               
+               /**
+                * Reuse StringBuilder object
+                */
+               public void clear() {
+                       content = null;
+                       if(sb!=null) {
+                               sb.setLength(0);
+                       }
+               }
+               
+               @Override
+               public String toString() {
+                       if(content!=null) {
+                               return content;
+                       } else if(sb!=null) {
+                               return sb.toString();
+                       } else {
+                               return "";
+                       }
+               }
+
+               public byte[] getBytes() {
+                       byte[] rv;
+                       if(content==null) {
+                               if(sb==null) {
+                                       rv = EMPTY_STREAM_BYTES;
+                               } else {
+                                       rv = sb.toString().getBytes();  
+                               }
+                       } else {
+                               rv = content.getBytes();
+                       }
+                       content = null;
+                       return rv;
+               }
+       }
+
+       /////////////////////////////////////////////////////////////
+       //  
+       // CREATE
+       //
+       /////////////////////////////////////////////////////////////
+       public void create(final String path, final Input input) throws RESTException, CadiException, LocatorException, APIException  {
+               post(path,APPLICATION_JSON, input);
+       }
+
+       public void post(final String path, final Input input) throws RESTException, CadiException, LocatorException, APIException  {
+               post(path,APPLICATION_JSON, input);
+       }
+
+       public void post(final String path, final String contentType, final Input input) throws RESTException, CadiException, LocatorException, APIException  {
+               Future<Void> future = restClient.best(new Retryable<Future<Void>>() {
+                       @Override
+                       public Future<Void> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+                               return client.create(path, contentType, new ETransfer(input));
+                       }
+               });
+               if(!future.get(callTimeout)) {
+                       throw new RESTException(future);
+               }                                       
+       }
 
+       /////////////////////////////////////////////////////////////
+       //  
+       // READ
+       //
+       /////////////////////////////////////////////////////////////
        public String read(final String path) throws RESTException, CadiException, LocatorException, APIException  {
-               return get(path,"application/json");
+               return get(path,APPLICATION_JSON);
        }
 
        public String get(final String path) throws RESTException, CadiException, LocatorException, APIException  {
-               return get(path,"application/json");
+               return get(path,APPLICATION_JSON);
        }
 
        public String get(final String path, final String accepts) throws RESTException, CadiException, LocatorException, APIException  {
@@ -116,6 +224,69 @@ public class SimpleRESTClient {
                }                                       
        }
        
+       /////////////////////////////////////////////////////////////
+       //  
+       // UPDATE
+       //
+       /////////////////////////////////////////////////////////////
+
+       public String update(final String path, final Input input) throws RESTException, CadiException, LocatorException, APIException  {
+               return put(path,APPLICATION_JSON, input);
+       }
+
+       public String put(final String path, final Input input) throws RESTException, CadiException, LocatorException, APIException  {
+               return put(path,APPLICATION_JSON, input);
+       }
+
+       public String put(final String path, final String contentType, final Input input) throws RESTException, CadiException, LocatorException, APIException  {
+               Future<String> future = restClient.best(new Retryable<Future<String>>() {
+                       @Override
+                       public Future<String> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+                               return client.update(path, contentType, new ETransfer(input));
+                       }
+               });
+               if(future.get(callTimeout)) {
+                       return future.value;
+               } else {
+                       throw new RESTException(future);
+               }                                       
+       }
+
+       /////////////////////////////////////////////////////////////
+       //  
+       // DELETE
+       //
+       /////////////////////////////////////////////////////////////
+       public void delete(final String path) throws RESTException, CadiException, LocatorException, APIException  {
+               delete(path,APPLICATION_JSON);
+       }
+               
+       public void delete(final String path, final String contentType) throws RESTException, CadiException, LocatorException, APIException  {
+               Future<Void> future = restClient.best(new Retryable<Future<Void>>() {
+                       @Override
+                       public Future<Void> code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+                               return client.delete(path, contentType);
+                       }
+               });
+               if(!future.get(callTimeout)) {
+                       throw new RESTException(future);
+               }                                       
+       }
+
+       /////////////////////////////////////////////////////////////
+       
+       private static class ETransfer implements EClient.Transfer {
+               private Input input;
+               public ETransfer(final Input input) {
+                       this.input = input;
+               }
+               
+               @Override
+               public void transfer(OutputStream os) throws IOException, APIException {
+                       os.write(input.getBytes());
+               }
+       }
+
        public interface Headers {
                String[] headers();
        }
index 7d251ba..6cabc65 100644 (file)
@@ -21,6 +21,7 @@
 
 package org.onap.aaf.cadi.enduser.test;
 
+import java.io.PrintWriter;
 import java.net.URISyntaxException;
 import java.security.Principal;
 
@@ -29,6 +30,7 @@ import org.onap.aaf.cadi.LocatorException;
 import org.onap.aaf.cadi.enduser.ClientFactory;
 import org.onap.aaf.cadi.enduser.RESTException;
 import org.onap.aaf.cadi.enduser.SimpleRESTClient;
+import org.onap.aaf.cadi.enduser.SimpleRESTClient.Input;
 import org.onap.aaf.misc.env.APIException;
 
 
@@ -46,32 +48,93 @@ public class SimpleRestClientExample {
                                                + " add -Dmyurl=https://<aaf hello machine>:8130 to VM Args\n\t"
                                                + "where \"aaf hello machine\" is an aaf Installation you know about.");
                        } else {
-                               SimpleRESTClient restClient = cf.simpleRESTClient(urlString,"org.osaaf.aaf");
-                               
-                               // Make some calls
                                
-                               // Call with no Queries
-                               String rv = restClient.get("resthello");
-                               System.out.println(rv);
-                               
-                               // Same call with "read" style
-                               rv = restClient.read("resthello");
-                               System.out.println(rv);
+                               SimpleRESTClient restClient = cf.simpleRESTClient(urlString,"org.osaaf.aaf");
+
+                               /////////////////////////////////////////////////////////////
+                               //  
+                               // Creating Content for CREATE/UPDATE
+                               //
+                               /////////////////////////////////////////////////////////////
+                               // Create an object that can be reusable IN THIS THREAD ONLY... Not Thread-safe on purpose
+                               Input input = new SimpleRESTClient.Input();
                                
+                               // Note: alternate use is to set the input object to an already created String
+                               // Input input = new SimpleRESTClient.Input(aString);
                                
-                               // Call with Queries
-                               rv = restClient.get("resthello?perm=org.osaaf.people|*|read");
-                               System.out.println(rv);
+                               PrintWriter pw = input.writer();
+                               pw.print("{\"something\": [");
+                               for(int i=0;i<4;++i) {
+                                       if(i>0) {
+                                               pw.print(',');
+                                       }
+                                       pw.print("{\"myint\":");
+                                       pw.print(i);
+                                       pw.print('}');
+                               }
+                               pw.println("]}");
                                
-                               // Call setting ID from principal coming from Trans
-                               // Pretend Transaction
-                               HRequest req = new HRequest("demo@people.osaaf.org"); // Pretend Trans has Jonathan as Identity
+                               // You can check or log the content
+                               String content = input.toString();
+                               System.out.println(content);
                                
-                               // Call with RESTException, which allows obtaining HTTPCode and any Error message sent
-                               rv = restClient.endUser(req.userPrincipal()).get("resthello?perm=org.osaaf.people|*|read");
-                               System.out.println(rv);
+                               // Good form for Writers is that you should close it... 
+                               pw.close();
+
+                               /////////////////////////////////////////////////////////////
+                               //  
+                               // CREATE/POST
+                               //
+                               /////////////////////////////////////////////////////////////
+                               System.out.println("-------- START REST CREATE/UPDATE --------");
+                               try {
+                                       restClient.create("resthello/rest_id", input);
+                                       // No Error code, it worked.
+                                       System.out.println("No Error Code, Create worked...");
+                               } catch (RESTException e) {
+                                       System.out.println(e.getCode());
+                                       System.out.println(e.getMsg());
+                               } finally {
+                                       System.out.println("-------- END REST CREATE/UPDATE --------");
+                               }
 
+
+                               /////////////////////////////////////////////////////////////
+                               //  
+                               // READ/GET
+                               //
+                               /////////////////////////////////////////////////////////////
+
+                               // Make some calls.  Note that RESTException is thrown if Call does not complete.
+                               // RESTException has HTTP Code and any Message sent from Server
+                               System.out.println("-------- START REST READ/GET --------");
+                               boolean expectException = false;
                                try {
+                                       
+                                       // Call with no Queries
+                                       String rv = restClient.get("resthello/rest_id");
+                                       System.out.println(rv);
+                                       
+                                       // Same call with "read" style
+                                       rv = restClient.read("resthello/rest_id");
+                                       System.out.println(rv);
+                                       
+                                       
+                                       // Call with Queries
+                                       rv = restClient.get("resthello/rest_id?perm=org.osaaf.people|*|read");
+                                       System.out.println(rv);
+                                       
+                                       // Call setting ID from principal coming from Trans
+                                       // Pretend Transaction
+                                       HRequest req = new HRequest("demo@people.osaaf.org"); // Pretend Trans has Jonathan as Identity
+                                       
+                                       // Call with RESTException, which allows obtaining HTTPCode and any Error message sent
+                                       rv = restClient.endUser(req.userPrincipal()).get("resthello/rest_id?perm=org.osaaf.people|*|read");
+                                       System.out.println(rv);
+
+                                       // Expect Exception here.
+                                       System.out.println("-------- START Expecting Exception starting here --------");
+                                       expectException = true;
                                        restClient.get("notAnAPI");
                                } catch(RESTException e) {
                                        System.out.println(e.getCode());
@@ -79,10 +142,57 @@ public class SimpleRestClientExample {
                                        System.out.println(e.getMessage());
                                        System.out.println(e.getLocalizedMessage());
                                        System.out.println(e);
+                               } finally {
+                                       if(expectException) {
+                                               System.out.println("-------- END Expecting Exception starting here --------");
+                                       }
+                                       System.out.println("-------- END REST READ/GET --------");
                                }
 
+                               /////////////////////////////////////////////////////////////
+                               //  
+                               // UPDATE/PUT
+                               //
+                               /////////////////////////////////////////////////////////////
+
+                               
+                               // If you use "input" object again as a writer, you can clear it on the same thread, and go again
+                               input.clear();
+                               // Here we just set to a String, instead of Writing
+                               input.set("{\"something\" : []}");
+                               
+                               System.out.println("-------- END REST UPDATE/PUT --------");
+                               try {
+                                       String rv = restClient.update("resthello/rest_id", input);
+                                       // No Error code, it worked.  REST Update will return the updated Data
+                                       System.out.println("Update worked");
+                                       System.out.println(rv);
+                               } catch (RESTException e) {
+                                       System.out.println(e.getCode());
+                                       System.out.println(e.getMsg());
+                               } finally {
+                                       System.out.println("-------- END REST UPDATE/PUT --------");
+                               }
+
+                               /////////////////////////////////////////////////////////////
+                               //  
+                               // DELETE
+                               //
+                               /////////////////////////////////////////////////////////////
+
+                               System.out.println("-------- START REST DELETE --------");
+                               try {
+                                       restClient.delete("resthello/rest_id");
+                                       // No Error code, it worked.  REST Update will return the updated Data
+                                       System.out.println("Delete worked");
+                               } catch (RESTException e) {
+                                       System.out.println(e.getCode());
+                                       System.out.println(e.getMsg());
+                               } finally {
+                                       System.out.println("-------- END REST DELETE --------");
+                               }
                        }                       
-               } catch (CadiException | APIException | RESTException e) {
+               } catch (CadiException | APIException e) {
                        e.printStackTrace();
                }
        }