From 4a164f90a4bab55c79314343d6127570a8fbed10 Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 19 Sep 2016 09:18:00 +0000
Subject: [PATCH] OPENDJ-3250 Return the CREST descriptor over REST for config endpoint
---
opendj-server-legacy/src/test/java/org/forgerock/opendj/rest2ldap/AdminEndpointTestCase.java | 124 +++++++++++++++++++++++++++++++
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java | 47 ++++++++++-
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Resource.java | 27 ++++++
3 files changed, 192 insertions(+), 6 deletions(-)
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Resource.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Resource.java
index 07421a0..9aa6c0a 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Resource.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Resource.java
@@ -60,6 +60,7 @@
import org.forgerock.api.models.Services;
import org.forgerock.api.models.Update;
import org.forgerock.http.ApiProducer;
+import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.json.JsonPointer;
import org.forgerock.json.JsonValue;
@@ -128,12 +129,23 @@
private volatile Boolean hasSubTypesWithSubResources = null;
/** The set of actions supported by this resource and its sub-types. */
private final Set<Action> supportedActions = new HashSet<>();
+ private LocalizableMessage description;
Resource(final String id) {
this.id = id;
}
/**
+ * Sets the description of this resource.
+ *
+ * @param description
+ * the description of this resource
+ */
+ public void description(LocalizableMessage description) {
+ this.description = description;
+ }
+
+ /**
* Returns the resource ID of this resource.
*
* @return The resource ID of this resource.
@@ -507,6 +519,8 @@
org.forgerock.api.models.Resource.Builder resource = org.forgerock.api.models.Resource.
resource()
+ .title(id)
+ .description(toLS(description))
.resourceSchema(schemaRef("#/definitions/" + id))
.mvccSupported(isMvccSupported());
@@ -522,6 +536,7 @@
return ApiDescription.apiDescription()
.id("unused").version("unused")
.definitions(definitions())
+ .paths(getPaths())
.errors(errors())
.build();
}
@@ -536,6 +551,8 @@
ApiDescription collectionApi(boolean isReadOnly) {
org.forgerock.api.models.Resource.Builder resource = org.forgerock.api.models.Resource.
resource()
+ .title(id)
+ .description(toLS(description))
.resourceSchema(schemaRef("#/definitions/" + id))
.mvccSupported(isMvccSupported());
@@ -584,6 +601,16 @@
return definitions.build();
}
+ private LocalizableString toLS(LocalizableMessage msg) {
+ if (msg != null) {
+ if (msg.resourceName() != null) {
+ return new LocalizableString("i18n:" + msg.resourceName() + "#" /* TODO + msg.getKey() */);
+ }
+ return new LocalizableString(msg.toString());
+ }
+ return null;
+ }
+
/**
* Returns the api description that describes a resource with sub resources.
*
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java
index 7085ae5..2519aaa 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java
@@ -12,14 +12,12 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2016 ForgeRock AS.
- *
*/
package org.opends.server.protocols.http.rest2ldap;
import static org.forgerock.http.routing.RouteMatchers.newResourceApiVersionBehaviourManager;
import static org.forgerock.http.routing.Version.version;
import static org.forgerock.json.resource.RouteMatchers.resourceApiVersionContextFilter;
-import static org.forgerock.json.resource.http.CrestHttp.newHttpHandler;
import static org.forgerock.opendj.ldap.schema.CoreSchema.getBooleanSyntax;
import static org.forgerock.opendj.ldap.schema.CoreSchema.getIntegerSyntax;
import static org.forgerock.opendj.rest2ldap.Rest2Ldap.*;
@@ -43,11 +41,15 @@
import org.forgerock.http.routing.Version;
import org.forgerock.json.JsonPointer;
import org.forgerock.json.resource.BadRequestException;
+import org.forgerock.json.resource.ConnectionFactory;
+import org.forgerock.json.resource.CrestApplication;
import org.forgerock.json.resource.FilterChain;
import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
import org.forgerock.json.resource.ResourceException;
+import org.forgerock.json.resource.Resources;
import org.forgerock.json.resource.Router;
+import org.forgerock.json.resource.http.CrestHttp;
import org.forgerock.opendj.config.AbstractManagedObjectDefinition;
import org.forgerock.opendj.config.AggregationPropertyDefinition;
import org.forgerock.opendj.config.DefaultBehaviorProvider;
@@ -84,6 +86,7 @@
import org.opends.server.api.HttpEndpoint;
import org.opends.server.core.ServerContext;
import org.opends.server.types.InitializationException;
+import org.opends.server.util.BuildVersion;
/**
* An HTTP endpoint providing access to the server's monitoring backend (cn=monitor) and its configuration (cn=config).
@@ -115,9 +118,7 @@
return new AdminHttpApplication();
}
- /**
- * Specialized {@link HttpApplication} using internal connections to this local LDAP server.
- */
+ /** Specialized {@link HttpApplication} using internal connections to this local LDAP server. */
private final class AdminHttpApplication implements HttpApplication
{
private LDAPProfile ldapProfile = LDAPProfile.getInstance();
@@ -125,6 +126,11 @@
@Override
public Handler start() throws HttpApplicationException
{
+ return newHttpHandler(startRequestHandler());
+ }
+
+ FilterChain startRequestHandler() throws HttpApplicationException
+ {
final Map<String, Resource> resources = new HashMap<>();
// Define the entry point to the admin API.
@@ -196,12 +202,41 @@
// FIXME: Disable the warning header for now due to CREST-389 / CREST-390.
final ResourceApiVersionBehaviourManager behaviourManager = newResourceApiVersionBehaviourManager();
behaviourManager.setWarningEnabled(false);
- return newHttpHandler(new FilterChain(versionRouter, resourceApiVersionContextFilter(behaviourManager)));
+ return new FilterChain(versionRouter, resourceApiVersionContextFilter(behaviourManager));
+ }
+
+ private Handler newHttpHandler(RequestHandler handler)
+ {
+ final org.forgerock.json.resource.ConnectionFactory factory = Resources.newInternalConnectionFactory(handler);
+ return CrestHttp.newHttpHandler(new CrestApplication()
+ {
+ @Override
+ public ConnectionFactory getConnectionFactory()
+ {
+ return factory;
+ }
+
+ @Override
+ public String getApiId()
+ {
+ return "frapi:opendj:admin";
+ }
+
+ @Override
+ public String getApiVersion()
+ {
+ return BuildVersion.binaryVersion().toStringNoRevision();
+ }
+ });
}
private Resource buildResource(final AbstractManagedObjectDefinition<?, ?> mod)
{
final Resource resource = resource(mod.getName());
+ if (!mod.isTop())
+ {
+ resource.description(mod.getSynopsis());
+ }
configureResourceProperties(mod, resource);
configureResourceSubResources(mod, resource, false);
return resource;
diff --git a/opendj-server-legacy/src/test/java/org/forgerock/opendj/rest2ldap/AdminEndpointTestCase.java b/opendj-server-legacy/src/test/java/org/forgerock/opendj/rest2ldap/AdminEndpointTestCase.java
new file mode 100644
index 0000000..ee7d8c1
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/forgerock/opendj/rest2ldap/AdminEndpointTestCase.java
@@ -0,0 +1,124 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Portions Copyright 2016 ForgeRock AS.
+ */
+package org.forgerock.opendj.rest2ldap;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.forgerock.http.util.Json.*;
+import static org.forgerock.json.resource.Requests.*;
+import static org.forgerock.json.resource.ResourcePath.*;
+import static org.forgerock.opendj.rest2ldap.Rest2Ldap.*;
+import static org.forgerock.util.Options.*;
+
+import java.io.StringReader;
+import java.lang.reflect.Method;
+import java.util.Collections;
+
+import org.forgerock.api.CrestApiProducer;
+import org.forgerock.api.models.ApiDescription;
+import org.forgerock.http.HttpApplication;
+import org.forgerock.http.routing.UriRouterContext;
+import org.forgerock.http.util.Json;
+import org.forgerock.json.JsonValue;
+import org.forgerock.json.resource.FilterChain;
+import org.forgerock.json.resource.Request;
+import org.forgerock.services.context.Context;
+import org.forgerock.services.context.RootContext;
+import org.opends.server.DirectoryServerTestCase;
+import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.http.rest2ldap.AdminEndpoint;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+@SuppressWarnings("javadoc")
+public class AdminEndpointTestCase extends DirectoryServerTestCase
+{
+ private static final String ID = "frapi:opendj:admin";
+ private static final String VERSION = "4.0.0";
+
+ @BeforeClass
+ public void startServer() throws Exception
+ {
+ TestCaseUtils.startServer();
+ }
+
+ @Test
+ public void testApiDescriptionGeneration() throws Exception
+ {
+ FilterChain endpointHandler = configureEndpoint();
+ final ApiDescription api = requestApi(endpointHandler, "admin/config");
+ assertThat(api).isNotNull();
+
+ // Ensure we can can pretty print and parse back the generated api description
+ parseJson(prettyPrint(api));
+
+ assertThat(api.getId()).isEqualTo(ID + ":1.0");
+ assertThat(api.getVersion()).isEqualTo(VERSION);
+ assertThat(api.getPaths().getNames().size()).isGreaterThan(20);
+ assertThat(api.getDefinitions().getNames().size()).isGreaterThan(150);
+ }
+
+ private FilterChain configureEndpoint() throws Exception
+ {
+ AdminEndpoint adminEndpoint = new AdminEndpoint(null, DirectoryServer.getInstance().getServerContext());
+ HttpApplication httpApp = adminEndpoint.newHttpApplication();
+ FilterChain handler = startRequestHandler(httpApp);
+ handler.api(new CrestApiProducer(ID, VERSION));
+ return handler;
+ }
+
+ private FilterChain startRequestHandler(HttpApplication httpApp) throws Exception
+ {
+ Method m = httpApp.getClass().getDeclaredMethod("startRequestHandler");
+ m.setAccessible(true);
+ FilterChain handler = (FilterChain) m.invoke(httpApp);
+ return handler;
+ }
+
+ private ApiDescription requestApi(final FilterChain filterChain, String uriPath)
+ {
+ Context context = newRouterContext(uriPath);
+ Request request = newApiRequest(resourcePath(uriPath));
+ return filterChain.handleApiRequest(context, request);
+ }
+
+ private Context newRouterContext(final String uriPath)
+ {
+ Context ctx = new RootContext();
+ ctx = new Rest2LdapContext(ctx, rest2Ldap(defaultOptions()));
+ ctx = new UriRouterContext(ctx, null, uriPath, Collections.<String, String> emptyMap());
+ return ctx;
+ }
+
+ private String prettyPrint(Object o) throws Exception
+ {
+ final ObjectMapper objectMapper =
+ new ObjectMapper().registerModules(new Json.LocalizableStringModule(), new Json.JsonValueModule());
+ final ObjectWriter writer = objectMapper.writer().withDefaultPrettyPrinter();
+ return writer.writeValueAsString(o);
+ }
+
+ static JsonValue parseJson(final String json) throws Exception
+ {
+ try (StringReader r = new StringReader(json))
+ {
+ return new JsonValue(readJsonLenient(r));
+ }
+ }
+}
--
Gitblit v1.10.0