View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2014-2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.json.resource.examples;
18  
19  import static org.forgerock.http.routing.Version.version;
20  import static org.forgerock.json.resource.Requests.newCreateRequest;
21  import static org.forgerock.json.resource.Resources.newInternalConnection;
22  import static org.forgerock.json.resource.RouteMatchers.requestResourceApiVersionMatcher;
23  import static org.forgerock.json.resource.RouteMatchers.requestUriMatcher;
24  import static org.forgerock.json.resource.Router.uriTemplate;
25  import static org.forgerock.json.resource.examples.DemoUtils.*;
26  
27  import org.forgerock.services.context.Context;
28  import org.forgerock.http.routing.RoutingMode;
29  import org.forgerock.json.resource.ActionRequest;
30  import org.forgerock.json.resource.ActionResponse;
31  import org.forgerock.json.resource.Connection;
32  import org.forgerock.json.resource.ConnectionFactory;
33  import org.forgerock.json.resource.CreateRequest;
34  import org.forgerock.json.resource.DeleteRequest;
35  import org.forgerock.json.resource.MemoryBackend;
36  import org.forgerock.json.resource.PatchRequest;
37  import org.forgerock.json.resource.QueryRequest;
38  import org.forgerock.json.resource.QueryResourceHandler;
39  import org.forgerock.json.resource.QueryResponse;
40  import org.forgerock.json.resource.ReadRequest;
41  import org.forgerock.json.resource.RequestHandler;
42  import org.forgerock.json.resource.Requests;
43  import org.forgerock.json.resource.ResourceException;
44  import org.forgerock.json.resource.ResourceResponse;
45  import org.forgerock.json.resource.Resources;
46  import org.forgerock.json.resource.Router;
47  import org.forgerock.json.resource.SingletonResourceProvider;
48  import org.forgerock.json.resource.UpdateRequest;
49  import org.forgerock.util.promise.Promise;
50  
51  /**
52   * An example client application which performs asynchronous reads against different versions of the same resource.
53   *
54   * @since 2.4.0
55   */
56  public final class VersionedResourcesDemo {
57  
58      private VersionedResourcesDemo() {
59          // No implementation.
60      }
61  
62      /**
63       * Main application.
64       *
65       * @param args
66       *            CLI arguments.
67       * @throws ResourceException
68       *             If an unexpected error occurs.
69       */
70      public static void main(String... args) throws ResourceException {
71          try (ConnectionFactory server = getConnectionFactory();
72               Connection connection = server.getConnection()) {
73              log("Reading version 1.0 of resource");
74              ResourceResponse response = connection.read(ctx(), Requests.newReadRequest("users/1")
75                      .setResourceVersion(version(1)));
76              log("Retrieved resource with revision: " + response.getRevision());
77  
78  
79              log("Reading version 1.5 of resource");
80              response = connection.read(ctx(), Requests.newReadRequest("users/1")
81                      .setResourceVersion(version(1, 5)));
82              log("Retrieved resource with revision: " + response.getRevision());
83  
84              log("Reading version 2.0 of resource");
85              response = connection.read(ctx(), Requests.newReadRequest("users/1")
86                      .setResourceVersion(version(2)));
87              log("Retrieved resource with revision: " + response.getRevision());
88          }
89      }
90  
91      private static ConnectionFactory getConnectionFactory() throws ResourceException {
92          MemoryBackend usersV1Dot0 = new MemoryBackend();
93          MemoryBackend usersV1Dot5 = new MemoryBackend();
94          MemoryBackend usersV2Dot0 = new MemoryBackend();
95  
96          RequestHandler rolesV1Dot0 = handler(new MemoryBackend());
97          RequestHandler rolesV1Dot5 = handler(new MemoryBackend());
98          RequestHandler rolesV2Dot0 = handler(new MemoryBackend());
99  
100         SingletonResourceProvider configV1Dot0 = singleton(new MemoryBackend());
101         SingletonResourceProvider configV1Dot5 = singleton(new MemoryBackend());
102         SingletonResourceProvider configV2Dot0 = singleton(new MemoryBackend());
103 
104         MemoryBackend groups = new MemoryBackend();
105 
106         Router router = new Router();
107         Router usersRouter = new Router();
108         router.addRoute(requestUriMatcher(RoutingMode.STARTS_WITH, "/users"), usersRouter);
109         usersRouter.addRoute(version(1), usersV1Dot0);
110         usersRouter.addRoute(version(1, 5), usersV1Dot5);
111         usersRouter.addRoute(version(2), usersV2Dot0);
112 
113         Router rolesRouter = new Router();
114         router.addRoute(requestUriMatcher(RoutingMode.EQUALS, "/roles"), rolesRouter);
115         rolesRouter.addRoute(requestResourceApiVersionMatcher(version(1)), rolesV1Dot0);
116         rolesRouter.addRoute(requestResourceApiVersionMatcher(version(1, 5)), rolesV1Dot5);
117         rolesRouter.addRoute(requestResourceApiVersionMatcher(version(2)), rolesV2Dot0);
118 
119         Router configRouter = new Router();
120         router.addRoute(requestUriMatcher(RoutingMode.STARTS_WITH, "/config"), configRouter);
121         configRouter.addRoute(version(1), configV1Dot0);
122         configRouter.addRoute(version(1, 5), configV1Dot5);
123         configRouter.addRoute(version(2), configV2Dot0);
124 
125         // Ignores any version information.
126         router.addRoute(uriTemplate("groups"), groups);
127 
128         final Connection connection = newInternalConnection(router);
129         connection.create(ctx(), newCreateRequest("users", "1", userAliceWithIdAndRev(1, 0))
130                 .setResourceVersion(version(1)));
131         connection.create(ctx(), newCreateRequest("users", "1", userAliceWithIdAndRev(1, 1))
132                 .setResourceVersion(version(1, 5)));
133         connection.create(ctx(), newCreateRequest("users", "1", userAliceWithIdAndRev(1, 2))
134                 .setResourceVersion(version(2)));
135 
136         return Resources.newInternalConnectionFactory(router);
137     }
138 
139     private static SingletonResourceProvider singleton(final MemoryBackend backend) {
140         return new SingletonResourceProvider() {
141 
142             @Override
143             public Promise<ActionResponse, ResourceException> actionInstance(Context context, ActionRequest request) {
144                 return backend.actionInstance(context, "INSTANCE", request);
145             }
146 
147             @Override
148             public Promise<ResourceResponse, ResourceException> patchInstance(Context context, PatchRequest request) {
149                 return backend.patchInstance(context, "INSTANCE", request);
150             }
151 
152             @Override
153             public Promise<ResourceResponse, ResourceException> readInstance(Context context, ReadRequest request) {
154                 return backend.readInstance(context, "INSTANCE", request);
155             }
156 
157             @Override
158             public Promise<ResourceResponse, ResourceException> updateInstance(Context context, UpdateRequest request) {
159                 return backend.updateInstance(context, "INSTANCE", request);
160             }
161         };
162     }
163 
164     private static RequestHandler handler(final MemoryBackend backend) {
165         return new RequestHandler() {
166             @Override
167             public Promise<ActionResponse, ResourceException> handleAction(Context context, ActionRequest request) {
168                 return backend.actionInstance(context, "INSTANCE", request);
169             }
170 
171             @Override
172             public Promise<ResourceResponse, ResourceException> handleCreate(Context context, CreateRequest request) {
173                 return backend.createInstance(context, request);
174             }
175 
176             @Override
177             public Promise<ResourceResponse, ResourceException> handleDelete(Context context, DeleteRequest request) {
178                 return backend.deleteInstance(context, "INSTANCE", request);
179             }
180 
181             @Override
182             public Promise<ResourceResponse, ResourceException> handlePatch(Context context, PatchRequest request) {
183                 return backend.patchInstance(context, "INSTANCE", request);
184             }
185 
186             @Override
187             public Promise<QueryResponse, ResourceException> handleQuery(Context context, QueryRequest request,
188                     QueryResourceHandler handler) {
189                 return backend.queryCollection(context, request, handler);
190             }
191 
192             @Override
193             public Promise<ResourceResponse, ResourceException> handleRead(Context context, ReadRequest request) {
194                 return backend.readInstance(context, "INSTANCE", request);
195             }
196 
197             @Override
198             public Promise<ResourceResponse, ResourceException> handleUpdate(Context context, UpdateRequest request) {
199                 return backend.updateInstance(context, "INSTANCE", request);
200             }
201         };
202     }
203 }