From 7c8ad397660416252204e0a4c0232471534efcc6 Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 23 Sep 2016 21:41:17 +0000
Subject: [PATCH] OPENDJ-3246 Better JSON schema: set type, format and description for properties
---
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimplePropertyMapper.java | 103 ++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 80 insertions(+), 23 deletions(-)
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimplePropertyMapper.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimplePropertyMapper.java
index c78d863..c705ca7 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimplePropertyMapper.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimplePropertyMapper.java
@@ -31,16 +31,15 @@
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.Filter;
import org.forgerock.opendj.ldap.schema.AttributeType;
-import org.forgerock.opendj.ldap.schema.CoreSchema;
+import org.forgerock.opendj.ldap.schema.Syntax;
import org.forgerock.services.context.Context;
import org.forgerock.util.Function;
import org.forgerock.util.promise.Promise;
import static java.util.Collections.*;
-
import static org.forgerock.json.JsonValue.*;
import static org.forgerock.opendj.ldap.Filter.*;
-import static org.forgerock.opendj.rest2ldap.Rest2Ldap.asResourceException;
+import static org.forgerock.opendj.ldap.schema.CoreSchema.*;
import static org.forgerock.opendj.rest2ldap.Utils.*;
import static org.forgerock.util.promise.Promises.newResultPromise;
@@ -48,6 +47,7 @@
public final class SimplePropertyMapper extends AbstractLdapPropertyMapper<SimplePropertyMapper> {
private Function<ByteString, ?, ? extends Exception> decoder;
private Function<Object, ByteString, ? extends Exception> encoder;
+ private JsonValue jsonSchema;
SimplePropertyMapper(final AttributeDescription ldapAttributeName) {
super(ldapAttributeName);
@@ -129,6 +129,20 @@
return this;
}
+ /**
+ * Sets the JSON schema corresponding to this simple property mapper. If not {@code null},
+ * it will be returned by {@link #toJsonSchema()}, otherwise a default JSON schema will be
+ * automatically generated with the information available in this property mapper.
+ *
+ * @param jsonSchema
+ * the JSON schema corresponding to this simple property mapper. Can be {@code null}
+ * @return This property mapper.
+ */
+ public SimplePropertyMapper jsonSchema(JsonValue jsonSchema) {
+ this.jsonSchema = jsonSchema;
+ return this;
+ }
+
@Override
public String toString() {
return "simple(" + ldapAttributeName + ")";
@@ -188,7 +202,7 @@
}
} catch (final Exception ex) {
// The LDAP attribute could not be decoded.
- return asResourceException(ex).asPromise();
+ return Rest2Ldap.asResourceException(ex).asPromise();
}
}
@@ -202,37 +216,80 @@
@Override
JsonValue toJsonSchema() {
+ return this.jsonSchema != null ? this.jsonSchema : toJsonSchema0();
+ }
+
+ private JsonValue toJsonSchema0() {
final AttributeType attrType = ldapAttributeName.getAttributeType();
- final JsonValue jsonSchema = json(object(field("type", toJsonSchemaType(attrType))));
+ final JsonValue jsonSchema;
+ if (isMultiValued()) {
+ jsonSchema = json(object(
+ field("type", "array"),
+ // LDAP has set semantics => all items are unique
+ field("uniqueItems", true),
+ field("items", itemsSchema(attrType))));
+ } else {
+ jsonSchema = itemsSchema(attrType);
+ }
+
final String description = attrType.getDescription();
if (description != null && !"".equals(description)) {
jsonSchema.put("title", description);
}
-
putWritabilityProperties(jsonSchema);
return jsonSchema;
}
- private static String toJsonSchemaType(AttributeType attrType) {
+ private JsonValue itemsSchema(final AttributeType attrType) {
+ final JsonValue itemsSchema = json(object());
+ putTypeAndFormat(itemsSchema, attrType);
+ return itemsSchema;
+ }
+
+ /**
+ * Puts the type and format corresponding to the provided attribute type on the provided JSON
+ * schema.
+ *
+ * @param jsonSchema
+ * the JSON schema where to put the type and format
+ * @param attrType
+ * the attribute type for which to infer JSON the type and format
+ * @see <a href=
+ * "https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types">
+ * OpenAPI Specification 2.0</a>
+ * @see <a href="https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-7.3">
+ * draft-fge-json-schema-validation-00 - Semantic validation with "format" - Defined
+ * attributes</a>
+ */
+ public static void putTypeAndFormat(JsonValue jsonSchema, AttributeType attrType) {
if (attrType.isPlaceHolder()) {
- return "string";
+ jsonSchema.put("type", "string");
+ return;
}
- // TODO JNR cannot use switch + SchemaConstants.SYNTAX_DIRECTORY_STRING_OID
- // because the class is not public
- // this is not nice :(
- // TODO JNR not so sure about these mappings
- final String oid = attrType.getSyntax().getOID();
- if (CoreSchema.getDirectoryStringSyntax().getOID().equals(oid)
- || CoreSchema.getOctetStringSyntax().getOID().equals(oid)) {
- return "string";
- } else if (CoreSchema.getBooleanSyntax().getOID().equals(oid)) {
- return "boolean";
- } else if (CoreSchema.getIntegerSyntax().getOID().equals(oid)) {
- return "integer";
- } else if (CoreSchema.getNumericStringSyntax().getOID().equals(oid)) {
- return "number";
+
+ final Syntax syntax = attrType.getSyntax();
+ if (attrType.hasName("userPassword")) {
+ jsonSchema.put("type", "string");
+ jsonSchema.put("format", "password");
+ } else if (attrType.hasName("mail")) {
+ jsonSchema.put("type", "string");
+ jsonSchema.put("format", "email");
+ } else if (syntax.equals(getBooleanSyntax())) {
+ jsonSchema.put("type", "boolean");
+ } else if (syntax.equals(getNumericStringSyntax())) {
+ // credit card numbers are numeric strings whose leading zeros are significant
+ jsonSchema.put("type", "string");
+ } else if (syntax.equals(getIntegerSyntax())) {
+ jsonSchema.put("type", "integer");
+ } else if (syntax.equals(getGeneralizedTimeSyntax())) {
+ jsonSchema.put("type", "string");
+ jsonSchema.put("format", "date-time");
+ } else if (!syntax.isHumanReadable()) {
+ jsonSchema.put("type", "string");
+ jsonSchema.put("format", "byte");
+ } else {
+ jsonSchema.put("type", "string");
}
- return "string";
}
}
--
Gitblit v1.10.0