SchemaSlurper.groovy revision 3b9de50fdf0980762d6930a49e1a0f20b61a6f6b
af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (c) 2014 ForgeRock AS. All Rights Reserved
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * The contents of this file are subject to the terms
af062818b47340eef15700d2f0211576ba3506eevboxsync * of the Common Development and Distribution License
af062818b47340eef15700d2f0211576ba3506eevboxsync * (the License). You may not use this file except in
af062818b47340eef15700d2f0211576ba3506eevboxsync * compliance with the License.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * You can obtain a copy of the License at
af062818b47340eef15700d2f0211576ba3506eevboxsync * http://forgerock.org/license/CDDLv1.0.html
af062818b47340eef15700d2f0211576ba3506eevboxsync * See the License for the specific language governing
af062818b47340eef15700d2f0211576ba3506eevboxsync * permission and limitations under the License.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * When distributing Covered Code, include this CDDL
af062818b47340eef15700d2f0211576ba3506eevboxsync * Header Notice in each file and include the License file
af062818b47340eef15700d2f0211576ba3506eevboxsync * at http://forgerock.org/license/CDDLv1.0.html
af062818b47340eef15700d2f0211576ba3506eevboxsync * If applicable, add the following below the CDDL Header,
af062818b47340eef15700d2f0211576ba3506eevboxsync * with the fields enclosed by brackets [] replaced by
af062818b47340eef15700d2f0211576ba3506eevboxsync * your own identifying information:
af062818b47340eef15700d2f0211576ba3506eevboxsync * "Portions Copyrighted [year] [name of copyright owner]"
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport groovy.json.JsonOutput
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport groovy.json.JsonSlurper
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.forgerock.json.fluent.JsonPointer
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.forgerock.openicf.misc.crest.VisitorParameter
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.common.CollectionUtil
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.common.Pair
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.common.security.GuardedByteArray
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.common.security.GuardedString
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.exceptions.ConfigurationException
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.Attribute
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.AttributeInfo
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.AttributeInfoBuilder
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.AttributeUtil
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.Name
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.ObjectClass
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.QualifiedUid
af062818b47340eef15700d2f0211576ba3506eevboxsyncimport org.identityconnectors.framework.common.objects.Uid
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/**
af062818b47340eef15700d2f0211576ba3506eevboxsync * A CRESTSchema parses the OpenIDM configuration and builds the schema from.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @author Laszlo Hordos
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncclass SchemaSlurper {
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_STRING = "string";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_NUMBER = "number";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_INTEGER = "integer";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_BOOLEAN = "boolean";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_OBJECT = "object";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_ARRAY = "array";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String TYPE_NULL = "null";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String JAVA_TYPE_BIGDECIMAL = "JAVA_TYPE_BIGDECIMAL";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String JAVA_TYPE_BIGINTEGER = "JAVA_TYPE_BIGINTEGER";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String JAVA_TYPE_PRIMITIVE_BOOLEAN = "JAVA_TYPE_PRIMITIVE_BOOLEAN";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String JAVA_TYPE_BYTE_ARRAY = "JAVA_TYPE_BYTE_ARRAY";
af062818b47340eef15700d2f0211576ba3506eevboxsync public static final String JAVA_TYPE_CHAR = "JAVA_TYPE_CHAR";
public static final String JAVA_TYPE_CHARACTER = "JAVA_TYPE_CHARACTER";
public static final String JAVA_TYPE_DATE = "JAVA_TYPE_DATE";
public static final String JAVA_TYPE_PRIMITIVE_DOUBLE = "JAVA_TYPE_PRIMITIVE_DOUBLE";
public static final String JAVA_TYPE_DOUBLE = "JAVA_TYPE_DOUBLE";
public static final String JAVA_TYPE_FILE = "JAVA_TYPE_FILE";
public static final String JAVA_TYPE_PRIMITIVE_FLOAT = "JAVA_TYPE_PRIMITIVE_FLOAT";
public static final String JAVA_TYPE_FLOAT = "JAVA_TYPE_FLOAT";
public static final String JAVA_TYPE_GUARDEDBYTEARRAY = "JAVA_TYPE_GUARDEDBYTEARRAY";
public static final String JAVA_TYPE_GUARDEDSTRING = "JAVA_TYPE_GUARDEDSTRING";
public static final String JAVA_TYPE_INT = "JAVA_TYPE_INT";
public static final String JAVA_TYPE_PRIMITIVE_LONG = "JAVA_TYPE_PRIMITIVE_LONG";
public static final String JAVA_TYPE_LONG = "JAVA_TYPE_LONG";
public static final String JAVA_TYPE_NAME = "JAVA_TYPE_NAME";
public static final String JAVA_TYPE_OBJECTCLASS = "JAVA_TYPE_OBJECTCLASS";
public static final String JAVA_TYPE_QUALIFIEDUID = "JAVA_TYPE_QUALIFIEDUID";
public static final String JAVA_TYPE_SCRIPT = "JAVA_TYPE_SCRIPT";
public static final String JAVA_TYPE_UID = "JAVA_TYPE_UID";
public static final String JAVA_TYPE_URI = "JAVA_TYPE_URI";
public static final String JAVA_TYPE_BYTE = "JAVA_TYPE_BYTE";
public static final String JAVA_TYPE_PRIMITIVE_BYTE = "JAVA_TYPE_PRIMITIVE_BYTE";
static Map<String, Object> parse(URL jsonConfig) {
assert null != jsonConfig;
new SchemaSlurper(jsonConfig).validate()
}
private def schema = [:]
Map<String, Object> validate() {
schema.each { key, Map value ->
if (!value.attributes.containsKey(Name.NAME)) {
throw new ConfigurationException("Schema of ${key} does not contain '__NAME__'")
}
}
}
private SchemaSlurper(URL url) {
Map<String, Class> typeMap = new HashMap<String, Class>(43);
typeMap.put(TYPE_ARRAY, List.class);
typeMap.put(TYPE_BOOLEAN, Boolean.class);
typeMap.put(TYPE_INTEGER, Integer.class);
typeMap.put(TYPE_NUMBER, Number.class);
typeMap.put(TYPE_OBJECT, Map.class);
typeMap.put(TYPE_STRING, String.class);
typeMap.put(JAVA_TYPE_BIGDECIMAL, BigDecimal.class);
typeMap.put(JAVA_TYPE_BIGINTEGER, BigInteger.class);
typeMap.put(JAVA_TYPE_PRIMITIVE_BOOLEAN, boolean.class);
typeMap.put(JAVA_TYPE_BYTE_ARRAY, byte[].class);
typeMap.put(JAVA_TYPE_CHAR, char.class);
typeMap.put(JAVA_TYPE_CHARACTER, Character.class);
typeMap.put(JAVA_TYPE_DATE, Date.class);
typeMap.put(JAVA_TYPE_PRIMITIVE_DOUBLE, double.class);
typeMap.put(JAVA_TYPE_DOUBLE, Double.class);
typeMap.put(JAVA_TYPE_FILE, File.class);
typeMap.put(JAVA_TYPE_PRIMITIVE_FLOAT, float.class);
typeMap.put(JAVA_TYPE_FLOAT, Float.class);
typeMap.put(JAVA_TYPE_GUARDEDBYTEARRAY, GuardedByteArray.class);
typeMap.put(JAVA_TYPE_GUARDEDSTRING, GuardedString.class);
typeMap.put(JAVA_TYPE_INT, int.class);
typeMap.put(JAVA_TYPE_PRIMITIVE_LONG, long.class);
typeMap.put(JAVA_TYPE_LONG, Long.class);
typeMap.put(JAVA_TYPE_NAME, Name.class);
typeMap.put(JAVA_TYPE_OBJECTCLASS, ObjectClass.class);
typeMap.put(JAVA_TYPE_QUALIFIEDUID, QualifiedUid.class);
typeMap.put(JAVA_TYPE_SCRIPT, org.identityconnectors.common.script.Script.class);
typeMap.put(JAVA_TYPE_UID, Uid.class);
typeMap.put(JAVA_TYPE_URI, URI.class);
typeMap.put(JAVA_TYPE_BYTE, Byte.class);
typeMap.put(JAVA_TYPE_PRIMITIVE_BYTE, Byte.TYPE);
def slurper = new JsonSlurper()
//def url = getClass().getClassLoader().getResource("schema.json")
def result = slurper.parse(url)
result.objectTypes.collectEntries(schema) { objectName, objectDefinition ->
[objectDefinition.nativeType,
[resourceContainer: objectName,
attributes :
objectDefinition.properties.collectEntries {String propertyName, Map propertyDefinition ->
if (AttributeUtil.namesEqual(Uid.NAME, propertyDefinition.nativeName)) {
//Ignore it
return null
} else {
def jsonType = propertyDefinition.type
AttributeInfoBuilder builder = new AttributeInfoBuilder(propertyDefinition.nativeName);
if (propertyDefinition?.required) {
builder.setRequired(true)
}
propertyDefinition?.flags?.each {
if ("NOT_CREATABLE".equalsIgnoreCase(it)) {
builder.setCreateable(false)
} else if ("NOT_UPDATEABLE".equalsIgnoreCase(it)) {
builder.setUpdateable(false)
} else if ("NOT_READABLE".equalsIgnoreCase(it)) {
builder.setReadable(false)
} else if ("NOT_RETURNED_BY_DEFAULT".equalsIgnoreCase(it)) {
builder.setReturnedByDefault(false)
}
}
if (TYPE_ARRAY.equals(jsonType)) {
builder.setMultiValued(true)
jsonType = propertyDefinition.items.type
}
if (null != propertyDefinition.nativeType) {
builder.setType(typeMap[propertyDefinition.nativeType])
}
return [propertyDefinition.nativeName,
[attributeInfo: builder.build(),
jsonType : jsonType,
jsonName : new JsonPointer(propertyName),
]]
}
}]]
}
}
String getResourceContainer(ObjectClass objectClass) {
for (Pair<String, String> pair : cache.keySet()) {
if (objectClass.is(pair.second)) {
return pair.first
}
}
throw new UnsupportedOperationException("Unsupported ObjectClass: " + objectClass.objectClassValue)
}
Map<String, Set<AttributeInfo>> getAttributeInfo() {
return cache.collectEntries { key, value ->
[key.second, value*.value.attributeInfo]
}
}
private Map<String, VisitorParameter> visitorCache;
VisitorParameter getVisitorParameter(ObjectClass objectClass) {
if (visitorCache == null) {
visitorCache = CollectionUtil.newCaseInsensitiveMap();
cache.each { key, value ->
final
def parameter = visitorCache[key.second] = new org.forgerock.openicf.misc.crest.VisitorParameter() {
def params = value
String translateName(String filter) {
def a = params[filter]
if (null != a) {
return a.attributeInfo.name
} else {
filter
}
}
String convertValue(Attribute filter) {
def a = params[filter]
if (null != a) {
if (TYPE_ARRAY.equals(a.jsonType)) {
JsonOutput.toJson(filter.value.each {
CRESTHelper.setAttributeValue(a.attributeInfo, it)
})
} else if (TYPE_BOOLEAN.equals(a.jsonType)) {
AttributeUtil.getBooleanValue(filter)
} else {
CRESTHelper.setAttributeValue(a.attributeInfo, AttributeUtil.getSingleValue(filter))
}
} else {
AttributeUtil.getAsStringValue(filter)
}
}
}
parameter
}
}
VisitorParameter p = visitorCache[objectClass.objectClassValue]
if (null != p) {
return p
} else {
throw new UnsupportedOperationException("Unsupported ObjectClass: " + objectClass.objectClassValue)
}
}
}