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}