Java tutorial
/* * Copyright (c) 2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.polygon.scim; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.common.exceptions.InvalidAttributeValueException; import org.identityconnectors.framework.common.objects.Attribute; import org.identityconnectors.framework.common.objects.AttributeUtil; import org.identityconnectors.framework.common.objects.OperationalAttributes; import org.json.JSONArray; import org.json.JSONObject; import com.evolveum.polygon.common.GuardedStringAccessor; /** * * @author Macik * * A class that contains the methods needed for construction of json * object representations of provided data sets. Attributes are * translated to json objects and arrays of json objects depending on * the attributes and dictionary. */ public class GenericDataBuilder implements ObjectTranslator { private static final String SEPPARATOR = "-"; private static final String FORBIDENSEPPARATOR = ":"; private static final Log LOGGER = Log.getLog(GenericDataBuilder.class); private String operation; /** * Constructor used to populate the local variable "operation". * * @param operation * String variable indicating that the "delete" operation * parameter should be added in the constructed json object. The * values which this parameter might acquire: * <li>"delete" * <li>"" - or empty string **/ public GenericDataBuilder(String operation) { this.operation = operation; } /** * Constructs a json object representation out of the provided data set and * schema dictionary. The json object representation will contain only * attributes which comply to the provided schema and operation attributes * as defined in the SCIM patch specification. * * @param imsAttributes * A set of attributes provided by the identity management * system. * @param injectedAttributes * A set of attributes which are injected into the provided set. * @return The complete json representation of the provided data set. */ public JSONObject translateSetToJson(Set<Attribute> imsAttributes, Set<Attribute> injectedAttributes, String resourceEndPoint) { LOGGER.info("Building account JsonObject"); JSONObject completeJsonObj = new JSONObject(); Set<Attribute> multiValueAttribute = new HashSet<Attribute>(); // e.g. // name.givenName Set<Attribute> multiLayerAttribute = new HashSet<Attribute>(); // e.g. // emails.work.value Set<Attribute> extensionAttribute = new HashSet<Attribute>(); // e.g. // urn|scim|schemas|extension|enterprise|1.0.division if (injectedAttributes != null) { for (Attribute injectedAttribute : injectedAttributes) { String attributeName = injectedAttribute.getName(); multiValueAttribute.add(injectedAttribute); if (attributeName.contains(DOT)) { String[] keyParts = attributeName.split(DELIMITER); // e.g. // schemas.default.blank if (keyParts.length == 2) { multiValueAttribute.add(injectedAttribute); } else { multiLayerAttribute.add(injectedAttribute); } } else { completeJsonObj.put(attributeName, AttributeUtil.getSingleValue(injectedAttribute)); } } } for (Attribute attribute : imsAttributes) { // LOGGER.info("Update or create set attribute: {0}", attribute); String attributeName = attribute.getName(); if (attributeName.contains(DOT)) { String[] keyParts = attributeName.split(DELIMITER); // e.g. // emails.work.value if (keyParts.length == 2) { multiValueAttribute.add(attribute); } else { multiLayerAttribute.add(attribute); } } else if (OperationalAttributes.ENABLE_NAME.equals(attributeName)) { completeJsonObj.put("active", AttributeUtil.getSingleValue(attribute)); } else if (OperationalAttributes.PASSWORD_NAME.equals(attributeName)) { GuardedString guardedString = (GuardedString) AttributeUtil.getSingleValue(attribute); GuardedStringAccessor accessor = new GuardedStringAccessor(); guardedString.access(accessor); completeJsonObj.put("password", accessor.getClearString()); } else if (attributeName.contains(SEPPARATOR)) { extensionAttribute.add(attribute); } else if ("__NAME__".equals(attributeName)) { if (resourceEndPoint.equals("Users")) { completeJsonObj.put("userName", AttributeUtil.getSingleValue(attribute)); } else { completeJsonObj.put("displayName", AttributeUtil.getSingleValue(attribute)); } } else { if (attributeName.contains(FORBIDENSEPPARATOR)) { attributeName = attributeName.replace(FORBIDENSEPPARATOR, SEPPARATOR); } completeJsonObj.put(attributeName, AttributeUtil.getSingleValue(attribute)); } } if (multiValueAttribute != null) { buildMultivalueAttribute(multiValueAttribute, completeJsonObj); } if (multiLayerAttribute != null) { buildLayeredAtrribute(multiLayerAttribute, completeJsonObj); } if (extensionAttribute != null) { buildExtensionAttribute(extensionAttribute, completeJsonObj); } // LOGGER.info("Json object returned from json data builder: {0}", // completeJsonObj); return completeJsonObj; } /** * Builds a json object representation out of a provided set of * "multi layered attributes". This type of attributes represent an array of * simple or complex json objects. * * @param multiLayerAttribute * A provided set of attributes. * @param json * A json object which may already contain data added in previous * methods. * @return A json representation of the provided data set. */ private JSONObject buildLayeredAtrribute(Set<Attribute> multiLayerAttribute, JSONObject json) { String mainAttributeName = ""; List<String> checkedNames = new ArrayList<String>(); for (Attribute i : multiLayerAttribute) { String attributeName = i.getName(); String[] attributeNameParts = attributeName.split(DELIMITER); // e.q. // email.work.value if (checkedNames.contains(attributeNameParts[0])) { } else { Set<Attribute> subAttributeLayerSet = new HashSet<Attribute>(); mainAttributeName = attributeNameParts[0]; checkedNames.add(mainAttributeName); for (Attribute j : multiLayerAttribute) { String secondLoopAttributeName = j.getName(); String[] secondLoopAttributeNameParts = secondLoopAttributeName.split(DELIMITER); // e.q. // email.work.value if (secondLoopAttributeNameParts[0].equals(mainAttributeName)) { subAttributeLayerSet.add(j); } } String canonicaltypeName = ""; boolean writeToArray = true; JSONArray jArray = new JSONArray(); List<String> checkedTypeNames = new ArrayList<String>(); for (Attribute k : subAttributeLayerSet) { String nameFromSubSet = k.getName(); String[] nameFromSubSetParts = nameFromSubSet.split(DELIMITER); // e.q. // email.work.value if (checkedTypeNames.contains(nameFromSubSetParts[1])) { } else { JSONObject multivalueObject = new JSONObject(); canonicaltypeName = nameFromSubSetParts[1]; checkedTypeNames.add(canonicaltypeName); for (Attribute subSetAttribute : subAttributeLayerSet) { String secondLoopNameFromSubSetParts = subSetAttribute.getName(); String[] finalSubAttributeNameParts = secondLoopNameFromSubSetParts.split(DELIMITER); // e.q. // email.work.value if (finalSubAttributeNameParts[1].equals(canonicaltypeName)) { if (subSetAttribute.getValue() != null && subSetAttribute.getValue().size() > 1) { writeToArray = false; List<Object> valueList = subSetAttribute.getValue(); for (Object attributeValue : valueList) { multivalueObject = new JSONObject(); multivalueObject.put(finalSubAttributeNameParts[2], attributeValue); if (!DEFAULT.equals(nameFromSubSetParts[1])) { multivalueObject.put(TYPE, nameFromSubSetParts[1]); } if (operation != null) { if (DELETE.equals(operation)) { multivalueObject.put(OPERATION, DELETE); } } jArray.put(multivalueObject); } } else { if (!BLANK.equals(finalSubAttributeNameParts[2])) { multivalueObject.put(finalSubAttributeNameParts[2], AttributeUtil.getSingleValue(subSetAttribute)); } else { jArray.put(AttributeUtil.getSingleValue(subSetAttribute)); writeToArray = false; } if (!DEFAULT.equals(nameFromSubSetParts[1])) { multivalueObject.put(TYPE, nameFromSubSetParts[1]); } if (operation != null) { if (DELETE.equals(operation)) { multivalueObject.put(OPERATION, DELETE); } } } } } if (writeToArray) { jArray.put(multivalueObject); } } String attrame = nameFromSubSetParts[0]; if (attrame.contains(SEPPARATOR)) { attrame = attrame.replace(SEPPARATOR, FORBIDENSEPPARATOR); } json.put(attrame, jArray); } } } return json; } /** * Builds a json object representation out of a provided set of * "multi value attributes". This type of attributes represent a complex * json object containing other key value pairs. * * @param multiValueAttribute * A provided set of attributes. * @param json * A json representation of the provided data set. * * @return A json representation of the provided data set. */ public JSONObject buildMultivalueAttribute(Set<Attribute> multiValueAttribute, JSONObject json) { String mainAttributeName = ""; List<String> checkedNames = new ArrayList<String>(); Set<Attribute> specialMlAttributes = new HashSet<Attribute>(); for (Attribute i : multiValueAttribute) { String attributeName = i.getName(); String[] attributeNameParts = attributeName.split(DELIMITER); // e.g. // name.givenName if (checkedNames.contains(attributeNameParts[0])) { } else { JSONObject jObject = new JSONObject(); mainAttributeName = attributeNameParts[0]; checkedNames.add(mainAttributeName); for (Attribute j : multiValueAttribute) { String secondLoopAttributeName = j.getName(); String[] secondLoopAttributeNameParts = secondLoopAttributeName.split(DELIMITER); // e.g. // name.givenName if (secondLoopAttributeNameParts[0].equals(mainAttributeName) && !mainAttributeName.equals(SCHEMA)) { jObject.put(secondLoopAttributeNameParts[1], AttributeUtil.getSingleValue(j)); } else if (secondLoopAttributeNameParts[0].equals(mainAttributeName) && mainAttributeName.equals(SCHEMA)) { specialMlAttributes.add(j); } } if (specialMlAttributes.isEmpty()) { json.put(attributeNameParts[0], jObject); } // else { String sMlAttributeName = "No schema type"; Boolean nameWasSet = false; for (Attribute specialAttribute : specialMlAttributes) { String innerName = specialAttribute.getName(); String[] innerKeyParts = innerName.split(DELIMITER); // e.g. // name.givenName if (innerKeyParts[1].equals(TYPE) && !nameWasSet) { sMlAttributeName = AttributeUtil.getAsStringValue(specialAttribute); nameWasSet = true; } else if (!innerKeyParts[1].equals(TYPE)) { jObject.put(innerKeyParts[1], AttributeUtil.getSingleValue(specialAttribute)); } } if (nameWasSet) { json.put(sMlAttributeName, jObject); specialMlAttributes.removeAll(specialMlAttributes); } else { LOGGER.error( "Schema type not specified {0}. Error occurrence while translating user object attribute set: {0}", sMlAttributeName); throw new InvalidAttributeValueException( "Schema type not specified. Error occurrence while translating user object attribute set"); } } } } return json; } /** * Builds a json object representation out of a provided set of * "attributes belonging to an extension". This type of attributes represent * a complex json object containing other key value pairs. * * @param extensionAttribute * A provided set of attributes. * @param json * A json representation of the provided data set. * * @return A json representation of the provided data set. */ public JSONObject buildExtensionAttribute(Set<Attribute> extensionAttribute, JSONObject json) { boolean isPartOfName = false; String mainAttributeName = ""; Map<String, Map<String, Object>> processedGoods = new HashMap<String, Map<String, Object>>(); for (Attribute i : extensionAttribute) { String attributeName = i.getName(); attributeName = attributeName.replace(SEPPARATOR, FORBIDENSEPPARATOR); String[] attributeNameParts = attributeName.split(DELIMITER); // e.q. // urn:scim:schemas:extension:enterprise:1.0.division for (int position = 1; position < attributeNameParts.length; position++) { String namePart = attributeNameParts[position]; for (int charPossition = 0; charPossition < namePart.length(); charPossition++) { char c = namePart.charAt(charPossition); if (Character.isDigit(c)) { if (charPossition == 0 && charPossition + 1 == namePart.length()) { isPartOfName = true; } else if (charPossition + 1 == namePart.length() && !isPartOfName) { isPartOfName = false; } else { isPartOfName = true; } } else { isPartOfName = false; } } if (!isPartOfName) { if (mainAttributeName.isEmpty()) { mainAttributeName = attributeNameParts[0]; } if (!processedGoods.containsKey(mainAttributeName)) { Map<String, Object> processedAttribute = new HashMap<String, Object>(); processedAttribute.put(namePart, AttributeUtil.getSingleValue(i)); processedGoods.put(mainAttributeName, processedAttribute); mainAttributeName = ""; break; } else { Map<String, Object> processedAttribute = processedGoods.get(mainAttributeName); processedAttribute.put(namePart, AttributeUtil.getSingleValue(i)); processedGoods.put(mainAttributeName, processedAttribute); mainAttributeName = ""; break; } } else { StringBuilder buildName; if (mainAttributeName.isEmpty()) { buildName = new StringBuilder(attributeNameParts[0]).append(DOT).append(namePart); mainAttributeName = buildName.toString(); } else { buildName = new StringBuilder(mainAttributeName).append(DOT).append(namePart); mainAttributeName = buildName.toString(); } } } } if (!processedGoods.isEmpty()) { for (String attributeName : processedGoods.keySet()) { JSONObject subAttributes = new JSONObject(); Map<String, Object> sAttribute = processedGoods.get(attributeName); for (String sAttributeName : sAttribute.keySet()) { subAttributes.put(sAttributeName, sAttribute.get(sAttributeName)); } json.put(attributeName, subAttributes); } } return json; } }