001package com.nimbusds.common.ldap; 002 003 004import java.util.HashSet; 005import java.util.List; 006import java.util.Set; 007 008import com.thetransactioncompany.jsonrpc2.JSONRPC2Error; 009import com.thetransactioncompany.jsonrpc2.util.NamedParamsRetriever; 010 011 012/** 013 * Specifies a set of directory attributes for retrieval. They are grouped 014 * into two subsets: 015 * 016 * <ul> 017 * <li>Attributes treated as text and encoded as UTF-8. 018 * <li>Attributes treated as binary and encoded in Base64. 019 * </ul> 020 */ 021public class AttributesForRetrieval { 022 023 024 /** 025 * The retrieval specification, as required by the get entry or search 026 * LDAP SDK API. 027 */ 028 private String[] spec; 029 030 031 /** 032 * The set of all selected attribute names to retrieve (UTF-8 text and 033 * binary). The names are normalised to lower case. 034 */ 035 private final Set<String> allNames = new HashSet<>(); 036 037 038 /** 039 * The names of the binary attributes to retrieve. The names are 040 * normalised to lower case. 041 */ 042 private final Set<String> binaryNames = new HashSet<>(); 043 044 045 /** 046 * Creates a default specification of attributes for retrieval which is 047 * retrieve all user attributes as UTF-8 text. 048 */ 049 public AttributesForRetrieval() { 050 051 spec = null; 052 } 053 054 055 /** 056 * Gets the names of the attributes to retrieve as binary (Base64 057 * encoded). 058 * 059 * @return The names (normalised to lower case) of the attributes to 060 * retrieve as binary, empty set if none. 061 */ 062 public Set<String> getBinaryAttributes() { 063 064 return binaryNames; 065 } 066 067 068 /** 069 * Retrieves the specification of the attributes (UTF-8 text and binary) 070 * for retrieval for an LDAP get entry/search request. 071 * 072 * @return The attributes for retrieval, {@code null} for all. 073 */ 074 public String[] getSpec() { 075 076 return spec; 077 } 078 079 080 /** 081 * Parses a JSON-RPC 2.0 parameter representing a set of string values. 082 * This can be a space/comma delimited JSON string, a JSON array of 083 * strings or undefined to signify no specific parameters. 084 * 085 * @param paramName The parameter name. Must not be {@code null}. 086 * @param params The named parameters to parse. Must not be 087 * {@code null}. 088 * 089 * @return The values, empty array if none/undefined. 090 * 091 * @throws JSONRPC2Error If parsing failed (INVALID_PARAMS). 092 */ 093 public static String[] parseValues(final String paramName, 094 final NamedParamsRetriever params) 095 throws JSONRPC2Error { 096 097 // Return empty array if undefined 098 if (! params.hasParam(paramName)) 099 return new String[]{}; 100 101 Object v = params.get(paramName); 102 103 if (v instanceof String) { 104 105 // Values specified in a space/comma delimited string 106 String vString = ((String)v).trim(); 107 108 if (! vString.isEmpty()) 109 return vString.split("[\\s,]"); 110 else 111 return new String[]{}; // no values 112 } 113 else if (v instanceof List) { 114 115 // Values specified in a JSON string array 116 List vList = (List)v; 117 118 if (! vList.isEmpty()) 119 return params.getStringArray(paramName); 120 else 121 return new String[]{}; // no values 122 } 123 else { 124 // Unexpected value(s) 125 throw JSONRPC2Error.INVALID_PARAMS; 126 } 127 } 128 129 130 /** 131 * Parses an "attributes" and a "binaryAttributes" specification from 132 * the given named JSON-RPC parameters. 133 * 134 * @param params The named parameters to parse. Must not be 135 * {@code null}. 136 * 137 * @throws JSONRPC2Error If parsing failed (INVALID_PARAMS). 138 */ 139 public void parse(final NamedParamsRetriever params) 140 throws JSONRPC2Error { 141 142 // Initial state -> all user attributes 143 spec = null; 144 145 if (params.hasParam("attributes")) { 146 147 String[] names = parseValues("attributes", params); 148 149 for (String name: names) { 150 151 if (name.equals("*+") || name.equals("+*")) { 152 153 allNames.add("*"); 154 allNames.add("+"); 155 } 156 else { 157 // Includes '*', '+' and '1.1' 158 allNames.add(name.toLowerCase()); 159 } 160 } 161 } 162 163 164 if (params.hasParam("binaryAttributes")) { 165 166 for (String name: parseValues("binaryAttributes", params)) { 167 168 switch (name) { 169 case "*": 170 // Implies all, ignore 171 break; 172 case "1.1": 173 // Implies none, ignore 174 break; 175 case "+": 176 // Implies operational, ignore 177 break; 178 default: 179 allNames.add(name.toLowerCase()); 180 binaryNames.add(name.toLowerCase()); 181 break; 182 } 183 } 184 } 185 186 // Update spec? 187 188 if (allNames.size() > 0) 189 spec = allNames.toArray(new String[allNames.size()]); 190 191 else if (params.hasParam("attributes") && allNames.isEmpty()) 192 spec = new String[]{"1.1"}; 193 } 194}