001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2013-2015 ForgeRock AS.
025 */
026package org.forgerock.opendj.adapter.server3x;
027
028import static com.forgerock.opendj.ldap.CoreMessages.*;
029import static com.forgerock.opendj.util.StaticUtils.*;
030
031import static org.forgerock.opendj.ldap.LdapException.*;
032import static org.opends.server.extensions.ExtensionsConstants.*;
033import static org.opends.server.util.CollectionUtils.*;
034
035import java.io.IOException;
036import java.util.ArrayList;
037import java.util.Collection;
038import java.util.List;
039import java.util.SortedSet;
040import java.util.TreeSet;
041
042import org.forgerock.i18n.LocalizableMessageBuilder;
043import org.forgerock.opendj.io.ASN1;
044import org.forgerock.opendj.io.ASN1Reader;
045import org.forgerock.opendj.io.ASN1Writer;
046import org.forgerock.opendj.ldap.Attribute;
047import org.forgerock.opendj.ldap.ByteString;
048import org.forgerock.opendj.ldap.ByteStringBuilder;
049import org.forgerock.opendj.ldap.DN;
050import org.forgerock.opendj.ldap.LdapException;
051import org.forgerock.opendj.ldap.LinkedAttribute;
052import org.forgerock.opendj.ldap.LinkedHashMapEntry;
053import org.forgerock.opendj.ldap.RDN;
054import org.forgerock.opendj.ldap.ResultCode;
055import org.forgerock.opendj.ldap.SearchScope;
056import org.forgerock.opendj.ldap.controls.Control;
057import org.forgerock.opendj.ldap.controls.GenericControl;
058import org.forgerock.opendj.ldap.responses.PasswordModifyExtendedResult;
059import org.forgerock.opendj.ldap.responses.Responses;
060import org.forgerock.opendj.ldap.responses.Result;
061import org.forgerock.opendj.ldap.responses.SearchResultEntry;
062import org.forgerock.opendj.server.config.meta.BackendVLVIndexCfgDefn;
063import org.forgerock.util.Reject;
064import org.opends.server.core.BindOperation;
065import org.opends.server.core.CompareOperation;
066import org.opends.server.core.ExtendedOperation;
067import org.opends.server.protocols.ldap.LDAPAttribute;
068import org.opends.server.protocols.ldap.LDAPControl;
069import org.opends.server.protocols.ldap.LDAPFilter;
070import org.opends.server.protocols.ldap.LDAPModification;
071import org.opends.server.types.AttributeBuilder;
072import org.opends.server.types.DirectoryException;
073import org.opends.server.types.LDAPException;
074import org.opends.server.types.Operation;
075import org.opends.server.types.SearchFilter;
076import org.opends.server.util.ServerConstants;
077
078/** Common utility methods. */
079public final class Converters {
080
081    /** Prevent instantiation. */
082    private Converters() {
083        throw new AssertionError();
084    }
085
086    /**
087     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Entry} to OpenDJ
088     * server {@link org.opends.server.types.Entry}.
089     *
090     * @param sdkEntry
091     *          SDK entry to convert
092     * @return the converted entry
093     */
094    public static org.opends.server.types.Entry to(
095            final org.forgerock.opendj.ldap.Entry sdkEntry) {
096        if (sdkEntry != null) {
097            org.opends.server.types.Entry entry =
098                new org.opends.server.types.Entry(to(sdkEntry.getName()), null, null, null);
099            List<ByteString> duplicateValues = new ArrayList<>();
100            for (org.opends.server.types.Attribute attribute : toAttributes(sdkEntry.getAllAttributes())) {
101                entry.addAttribute(attribute, duplicateValues);
102            }
103            return entry;
104        }
105        return null;
106    }
107
108    /**
109     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.responses.SearchResultEntry} to OpenDJ
110     * server {@link org.opends.server.types.SearchResultEntry}.
111     *
112     * @param value
113     *          value to convert
114     * @return the converted value
115     */
116    public static org.opends.server.types.SearchResultEntry to(
117            final org.forgerock.opendj.ldap.responses.SearchResultEntry value) {
118        if (value != null) {
119            org.opends.server.types.Entry entry =
120                new org.opends.server.types.Entry(to(value.getName()), null, null, null);
121            org.opends.server.types.SearchResultEntry searchResultEntry =
122                new org.opends.server.types.SearchResultEntry(entry, to(value.getControls()));
123            List<ByteString> duplicateValues = new ArrayList<>();
124            for (org.opends.server.types.Attribute attribute : toAttributes(value.getAllAttributes())) {
125                searchResultEntry.addAttribute(attribute, duplicateValues);
126            }
127            return searchResultEntry;
128        }
129        return null;
130    }
131
132    /**
133     * Converts from OpenDJ LDAP SDK {@link DN} to OpenDJ server
134     * {@link org.opends.server.types.DN}.
135     *
136     * @param dn
137     *          value to convert
138     * @return the converted value
139     */
140    public static org.opends.server.types.DN to(final DN dn) {
141        try {
142            return org.opends.server.types.DN.valueOf(dn.toString());
143        } catch (Exception e) {
144            throw new IllegalStateException(e.getMessage(), e);
145        }
146    }
147
148    /**
149     * Converts a set of OpenDJ LDAP SDK {@link DN} to a set of
150     * OpenDJ server {@link org.opends.server.types.DN}.
151     *
152     * @param dnSet
153     *          set to convert
154     * @return the converted set
155     */
156    public static SortedSet<org.opends.server.types.DN> to(final SortedSet<DN> dnSet) {
157        try {
158            SortedSet<org.opends.server.types.DN> newSet = new TreeSet<>();
159            for (DN dn : dnSet) {
160                newSet.add(org.opends.server.types.DN.valueOf(dn.toString()));
161            }
162            return newSet;
163        } catch (Exception e) {
164            throw new IllegalStateException(e.getMessage(), e);
165        }
166    }
167
168    /**
169     * Converts an array of OpenDJ LDAP SDK {@link DN} to an array of
170     * OpenDJ server {@link org.opends.server.types.DN}.
171     *
172     * @param dns
173     *          array of values to convert
174     * @return the converted array
175     */
176    public static org.opends.server.types.DN[] to(final DN[] dns) {
177        try {
178            org.opends.server.types.DN[] newDns = new org.opends.server.types.DN[dns.length];
179            for (int i = 0; i < dns.length; i++) {
180                newDns[i] = org.opends.server.types.DN.valueOf(dns[i].toString());
181            }
182            return newDns;
183        } catch (Exception e) {
184            throw new IllegalStateException(e.getMessage(), e);
185        }
186    }
187
188    /**
189     * Converts from OpenDJ LDAP SDK {@link RDN} to OpenDJ server
190     * {@link org.opends.server.types.RDN}.
191     *
192     * @param rdn
193     *          value to convert
194     * @return the converted value
195     */
196    public static org.opends.server.types.RDN to(final RDN rdn) {
197        try {
198            return org.opends.server.types.RDN.decode(rdn.toString());
199        } catch (Exception e) {
200            throw new IllegalStateException(e.getMessage(), e);
201        }
202    }
203
204    /**
205     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Filter} to
206     * OpenDJ server {@link org.opends.server.types.RawFilter}.
207     *
208     * @param filter
209     *          value to convert
210     * @return the converted value
211     */
212    public static org.opends.server.types.RawFilter to(final org.forgerock.opendj.ldap.Filter filter) {
213        org.opends.server.protocols.ldap.LDAPFilter ldapFilter = null;
214        try {
215            ldapFilter = LDAPFilter.decode(filter.toString());
216        } catch (LDAPException e) {
217            throw new IllegalStateException(e);
218        }
219        return ldapFilter;
220    }
221
222    /**
223     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Filter} to
224     * OpenDJ server {@link org.opends.server.types.RawFilter}.
225     *
226     * @param filter
227     *          value to convert
228     * @return the converted value
229     */
230    public static SearchFilter toSearchFilter(final org.forgerock.opendj.ldap.Filter filter) {
231        SearchFilter ldapFilter = null;
232        try {
233            ldapFilter = SearchFilter.createFilterFromString(filter.toString());
234        } catch (DirectoryException e) {
235            throw new IllegalStateException(e.getMessage(), e);
236        }
237        return ldapFilter;
238    }
239
240    /**
241     * Converts from OpenDJ LDAP SDK
242     * {@link org.forgerock.opendj.ldap.responses.SearchResultReference} to OpenDJ
243     * server {@link org.opends.server.types.SearchResultReference}.
244     *
245     * @param searchResultReference
246     *          value to convert
247     * @return the converted value
248     */
249    public static org.opends.server.types.SearchResultReference to(
250            final org.forgerock.opendj.ldap.responses.SearchResultReference searchResultReference) {
251        return new org.opends.server.types.SearchResultReference(
252                searchResultReference.getURIs(), to(searchResultReference.getControls()));
253    }
254
255    /**
256     * Converts from OpenDJ LDAP SDK {@link Control} to OpenDJ server
257     * {@link org.opends.server.protocols.ldap.LDAPControl}.
258     *
259     * @param control
260     *          value to convert
261     * @return the converted value
262     */
263    public static org.opends.server.protocols.ldap.LDAPControl to(final Control control) {
264        return new LDAPControl(control.getOID(), control.isCritical(), control.getValue());
265    }
266
267    /**
268     * Converts from a <code>List</code> of OpenDJ LDAP SDK
269     * {@link org.forgerock.opendj.ldap.controls.Control} to a <code>List</code>
270     * of OpenDJ server {@link org.opends.server.types.Control}.
271     *
272     * @param listOfControl
273     *          value to convert
274     * @return the converted value
275     */
276    public static List<org.opends.server.types.Control> to(
277            final List<org.forgerock.opendj.ldap.controls.Control> listOfControl) {
278        List<org.opends.server.types.Control> toListOfControl = new ArrayList<>(listOfControl.size());
279        for (org.forgerock.opendj.ldap.controls.Control c : listOfControl) {
280            toListOfControl.add(to(c));
281        }
282        return toListOfControl;
283    }
284
285    /**
286     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}
287     * to OpenDJ server {@link org.opends.server.types.RawAttribute}.
288     *
289     * @param attribute
290     *          value to convert
291     * @return the converted value
292     */
293    public static org.opends.server.types.RawAttribute to(
294            final org.forgerock.opendj.ldap.Attribute attribute) {
295        ArrayList<ByteString> listAttributeValues = newArrayList(attribute.toArray());
296        return new LDAPAttribute(attribute.getAttributeDescriptionAsString(), listAttributeValues);
297    }
298
299    /**
300     * Converts from an <code>Iterable</code> of OpenDJ LDAP SDK
301     * {@link org.forgerock.opendj.ldap.Attribute} to a <code>List</code> of
302     * OpenDJ server {@link org.opends.server.types.RawAttribute}.
303     *
304     * @param listOfAttributes
305     *          value to convert
306     * @return the converted value
307     */
308    public static List<org.opends.server.types.RawAttribute> to(
309            final Iterable<org.forgerock.opendj.ldap.Attribute> listOfAttributes) {
310        List<org.opends.server.types.RawAttribute> toListOfAttributes =
311                new ArrayList<>(((Collection<?>) listOfAttributes).size());
312        for (org.forgerock.opendj.ldap.Attribute a : listOfAttributes) {
313            toListOfAttributes.add(to(a));
314        }
315        return toListOfAttributes;
316    }
317
318    /**
319     * Converts from OpenDJ LDAP SDK
320     * {@link org.forgerock.opendj.ldap.Modification} to OpenDJ server
321     * {@link org.opends.server.types.RawModification}.
322     *
323     * @param modification
324     *          value to convert
325     * @return the converted value
326     */
327    public static org.opends.server.types.RawModification to(
328            final org.forgerock.opendj.ldap.Modification modification) {
329        return new LDAPModification(modification.getModificationType(), to(modification
330                .getAttribute()));
331    }
332
333    /**
334     * Converts from a <code>List</code> of OpenDJ LDAP SDK
335     * {@link org.forgerock.opendj.ldap.Modification} to a <code>List</code> of
336     * OpenDJ server {@link org.opends.server.types.RawModification}.
337     *
338     * @param listOfModifications
339     *          value to convert
340     * @return the converted value
341     */
342    public static List<org.opends.server.types.RawModification> toRawModifications(
343            final List<org.forgerock.opendj.ldap.Modification> listOfModifications) {
344        List<org.opends.server.types.RawModification> toListOfModifications =
345                new ArrayList<>(listOfModifications.size());
346        for (org.forgerock.opendj.ldap.Modification m : listOfModifications) {
347            toListOfModifications.add(to(m));
348        }
349        return toListOfModifications;
350    }
351
352    /**
353     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}
354     * to OpenDJ server {@link org.opends.server.types.Attribute}.
355     *
356     * @param attribute
357     *          value to convert
358     * @return the converted value
359     */
360    public static org.opends.server.types.Attribute toAttribute(
361            final org.forgerock.opendj.ldap.Attribute attribute) {
362        final AttributeBuilder attrBuilder =
363            new AttributeBuilder(attribute.getAttributeDescriptionAsString());
364        for (ByteString b : attribute.toArray()) {
365            attrBuilder.add(b);
366        }
367        return attrBuilder.toAttribute();
368    }
369
370    /**
371     * Converts from an <code>Iterable</code> of OpenDJ LDAP SDK
372     * {@link org.forgerock.opendj.ldap.Attribute} to a <code>List</code> of
373     * OpenDJ server {@link org.opends.server.types.RawAttribute}.
374     *
375     * @param listOfAttributes
376     *          value to convert
377     * @return the converted value
378     */
379    public static List<org.opends.server.types.Attribute> toAttributes(
380            final Iterable<org.forgerock.opendj.ldap.Attribute> listOfAttributes) {
381        List<org.opends.server.types.Attribute> toListOfAttributes =
382                new ArrayList<>(((Collection<?>) listOfAttributes).size());
383        for (org.forgerock.opendj.ldap.Attribute a : listOfAttributes) {
384            toListOfAttributes.add(toAttribute(a));
385        }
386        return toListOfAttributes;
387    }
388
389    /**
390     * Converts from OpenDJ LDAP SDK
391     * {@link org.forgerock.opendj.ldap.Modification} to OpenDJ server
392     * {@link org.opends.server.types.Modification}.
393     *
394     * @param modification
395     *          value to convert
396     * @return the converted value
397     */
398    public static org.opends.server.types.Modification toModification(
399            final org.forgerock.opendj.ldap.Modification modification) {
400        return new org.opends.server.types.Modification(modification.getModificationType(),
401            toAttribute(modification.getAttribute()));
402    }
403
404    /**
405     * Converts from a <code>List</code> of OpenDJ LDAP SDK
406     * {@link org.forgerock.opendj.ldap.Modification} to a <code>List</code> of
407     * OpenDJ server {@link org.opends.server.types.Modification}.
408     *
409     * @param listOfModifications
410     *          value to convert
411     * @return the converted value
412     */
413    public static List<org.opends.server.types.Modification> toModifications(
414            final List<org.forgerock.opendj.ldap.Modification> listOfModifications) {
415        List<org.opends.server.types.Modification> toListOfModifications = new ArrayList<>(listOfModifications.size());
416        for (org.forgerock.opendj.ldap.Modification m : listOfModifications) {
417            toListOfModifications.add(toModification(m));
418        }
419        return toListOfModifications;
420    }
421
422    /**
423     * Converts from OpenDJ server
424     * {@link org.opends.server.protocols.ldap.LDAPControl} to OpenDJ LDAP SDK
425     * {@link Control}.
426     *
427     * @param ldapControl
428     *          value to convert
429     * @return the converted value
430     */
431    public static Control from(final org.opends.server.protocols.ldap.LDAPControl ldapControl) {
432        return GenericControl.newControl(ldapControl.getOID(), ldapControl.isCritical(),
433                ldapControl.getValue());
434    }
435
436    /**
437     * Converts from OpenDJ server {@link org.opends.server.types.Control} to
438     * OpenDJ LDAP SDK {@link Control}.
439     *
440     * @param control
441     *          value to convert
442     * @return the converted value
443     */
444    public static Control from(final org.opends.server.types.Control control) {
445        String oid = null;
446        boolean isCritical = false;
447        ByteString value = null;
448        // The server control doesn't have a method for extracting directly the value so, we need to ASN1 it.
449        ByteStringBuilder builder = new ByteStringBuilder();
450        final ASN1Writer writer = ASN1.getWriter(builder);
451        try {
452            control.write(writer);
453        } catch (IOException e) {
454            // Nothing to do.
455        }
456
457        final ByteString sdkByteString = builder.toByteString();
458        final org.forgerock.opendj.io.ASN1Reader sdkReaderASN1 =
459                org.forgerock.opendj.io.ASN1.getReader(sdkByteString.toByteArray());
460
461        // Reads the ASN1 SDK byte string.
462        try {
463            sdkReaderASN1.readStartSequence();
464            oid = sdkReaderASN1.readOctetStringAsString();
465            if (sdkReaderASN1.hasNextElement()
466                    && sdkReaderASN1.peekType() == ASN1.UNIVERSAL_BOOLEAN_TYPE) {
467                isCritical = sdkReaderASN1.readBoolean();
468            }
469            if (sdkReaderASN1.hasNextElement()
470                    && sdkReaderASN1.peekType() == ASN1.UNIVERSAL_OCTET_STRING_TYPE) {
471                value = sdkReaderASN1.readOctetString();
472            }
473            sdkReaderASN1.readEndSequence();
474        } catch (IOException e) {
475            // Nothing to do.
476        }
477        // Creates the control
478        return GenericControl.newControl(oid, isCritical, value);
479    }
480
481    /**
482     * Converts from a <code>List</code> of OpenDJ server
483     * {@link org.opends.server.types.Control} to a <code>List</code> of OpenDJ
484     * LDAP SDK {@link org.forgerock.opendj.ldap.controls.Control}.
485     *
486     * @param listOfControl
487     *          value to convert
488     * @return the converted value
489     */
490    public static List<org.forgerock.opendj.ldap.controls.Control> from(
491            final List<org.opends.server.types.Control> listOfControl) {
492        List<org.forgerock.opendj.ldap.controls.Control> fromListofControl = new ArrayList<>(listOfControl.size());
493        for (org.opends.server.types.Control c : listOfControl) {
494            fromListofControl.add(from(c));
495        }
496        return fromListofControl;
497    }
498
499    /**
500     * Converts from OpenDJ server
501     * {@link org.opends.server.types.SearchResultReference} to OpenDJ LDAP SDK
502     * {@link org.forgerock.opendj.ldap.responses.SearchResultReference}.
503     *
504     * @param srvResultReference
505     *          value to convert
506     * @return the converted value
507     */
508    public static org.forgerock.opendj.ldap.responses.SearchResultReference from(
509            final org.opends.server.types.SearchResultReference srvResultReference) {
510        return Responses.newSearchResultReference(srvResultReference.getReferralURLString());
511    }
512
513    /**
514     * Converts from OpenDJ server {@link org.opends.server.types.Attribute} to
515     * OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}.
516     *
517     * @param attribute
518     *          value to convert
519     * @return the converted value
520     */
521    public static org.forgerock.opendj.ldap.Attribute from(
522            final org.opends.server.types.Attribute attribute) {
523        Attribute sdkAttribute = new LinkedAttribute(attribute.getNameWithOptions());
524        for (ByteString value : attribute) {
525            sdkAttribute.add(value);
526        }
527        return sdkAttribute;
528    }
529
530    /**
531     * Converts from an <code>Iterable</code> of OpenDJ server
532     * {@link org.opends.server.types.Attribute} to a <code>List</code> of OpenDJ
533     * LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}.
534     *
535     * @param listOfAttributes
536     *          value to convert
537     * @return the converted value
538     */
539    public static List<org.forgerock.opendj.ldap.Attribute> from(
540            final Iterable<org.opends.server.types.Attribute> listOfAttributes) {
541        List<org.forgerock.opendj.ldap.Attribute> fromListofAttributes =
542                new ArrayList<>(((Collection<?>) listOfAttributes).size());
543        for (org.opends.server.types.Attribute a : listOfAttributes) {
544            fromListofAttributes.add(from(a));
545        }
546        return fromListofAttributes;
547    }
548
549    /**
550     * Converts from OpenDJ server
551     * {@link org.opends.server.types.SearchResultEntry} to OpenDJ LDAP SDK
552     * {@link org.forgerock.opendj.ldap.responses.SearchResultEntry}.
553     *
554     * @param srvResultEntry
555     *          value to convert
556     * @return the converted value
557     */
558    public static org.forgerock.opendj.ldap.responses.SearchResultEntry from(
559            final org.opends.server.types.SearchResultEntry srvResultEntry) {
560
561        final SearchResultEntry searchResultEntry =
562                Responses.newSearchResultEntry(srvResultEntry.getName().toString());
563        if (srvResultEntry.getAttributes() != null) {
564            for (org.opends.server.types.Attribute a : srvResultEntry.getAttributes()) {
565                searchResultEntry.addAttribute(from(a));
566            }
567        }
568
569        if (srvResultEntry.getControls() != null) {
570            for (org.opends.server.types.Control c : srvResultEntry.getControls()) {
571                searchResultEntry.addControl(from(c));
572            }
573        }
574
575        return searchResultEntry;
576    }
577
578    /**
579     * Converts from OpenDJ server
580     * {@link org.opends.server.types.Entry} to OpenDJ LDAP SDK
581     * {@link org.forgerock.opendj.ldap.Entry}.
582     *
583     * @param srvResultEntry
584     *          value to convert
585     * @return the converted value
586     */
587    public static org.forgerock.opendj.ldap.Entry from(
588        final org.opends.server.types.Entry srvResultEntry) {
589
590        final org.forgerock.opendj.ldap.Entry entry = new LinkedHashMapEntry(srvResultEntry.getName().toString());
591        if (srvResultEntry.getAttributes() != null) {
592            for (org.opends.server.types.Attribute a : srvResultEntry.getAttributes()) {
593                entry.addAttribute(from(a));
594            }
595        }
596        return entry;
597    }
598
599    /**
600     * Converts from OpenDJ server
601     * {@link org.opends.server.admin.std.meta.VirtualAttributeCfgDefn.Scope} to OpenDJ LDAP SDK
602     * {@link org.forgerock.opendj.ldap.SearchScope}.
603     *
604     * @param srvScope
605     *          The server scope value.
606     * @return The SDK scope value.
607     */
608    public static SearchScope from(org.opends.server.admin.std.meta.VirtualAttributeCfgDefn.Scope srvScope) {
609        if (srvScope != null) {
610            switch (srvScope) {
611            case BASE_OBJECT:
612                return SearchScope.BASE_OBJECT;
613            case SINGLE_LEVEL:
614                return SearchScope.SINGLE_LEVEL;
615            case SUBORDINATE_SUBTREE:
616                return SearchScope.SUBORDINATES;
617            case WHOLE_SUBTREE:
618                return SearchScope.WHOLE_SUBTREE;
619            default:
620                return null;
621            }
622        }
623        return null;
624    }
625
626
627    /**
628     * Converts from OpenDJ server {@link org.opends.server.types.DN} to OpenDJ
629     * LDAP SDK {@link DN}.
630     *
631     * @param dn
632     *            value to convert
633     * @return the converted value
634     */
635    public static DN from(final org.opends.server.types.DN dn) {
636        try {
637            return DN.valueOf(dn.toString());
638        } catch (Exception e) {
639            throw new IllegalStateException(e.getMessage(), e);
640        }
641    }
642
643    /**
644     * Populates the result object with the operation details and return the
645     * result object if it was successful. Otherwise, it throws an
646     * {@link LdapException}.
647     *
648     * @param <T>
649     *          the type of the result object
650     * @param operation
651     *          used to populate the result
652     * @param result
653     *          the result object to populate from the Operation
654     * @return the result if successful, an {@link LdapException} is thrown
655     *         otherwise
656     * @throws LdapException
657     *           when an error occurs
658     */
659    public static <T extends Result> T getResponseResult(final Operation operation, final T result)
660            throws LdapException {
661        if (operation.getReferralURLs() != null) {
662            for (String ref : operation.getReferralURLs()) {
663                result.addReferralURI(ref);
664            }
665        }
666        if (operation.getResponseControls() != null) {
667            for (org.opends.server.types.Control c : operation.getResponseControls()) {
668                result.addControl(from(c));
669            }
670        }
671        final LocalizableMessageBuilder errorMsg = operation.getErrorMessage();
672        final org.opends.server.types.DN matchedDN = operation.getMatchedDN();
673        result.setDiagnosticMessage(errorMsg != null ? errorMsg.toString() : null);
674        result.setMatchedDN(matchedDN != null ? matchedDN.toString() : null);
675        if (result.isSuccess()) {
676            return result;
677        } else {
678            throw newLdapException(result);
679        }
680    }
681
682    /**
683     * Converts the OpenDJ server {@link Operation} object into an OpenDJ LDAP SDK
684     * {@link Result} object.
685     *
686     * @param operation
687     *          value to convert
688     * @return the converted value
689     * @throws LdapException
690     *           when an error occurs
691     */
692    public static Result getResponseResult(final Operation operation) throws LdapException {
693        return getResponseResult(operation, newSDKResult(operation));
694    }
695
696    private static Result newSDKResult(final Operation operation) throws LdapException {
697        ResultCode rc = operation.getResultCode();
698        if (operation instanceof BindOperation) {
699            return Responses.newBindResult(rc);
700        } else if (operation instanceof CompareOperation) {
701            return Responses.newCompareResult(rc);
702        } else if (operation instanceof ExtendedOperation) {
703            ExtendedOperation extendedOperation = (ExtendedOperation) operation;
704            switch (extendedOperation.getRequestOID()) {
705            case ServerConstants.OID_PASSWORD_MODIFY_REQUEST:
706                PasswordModifyExtendedResult result = Responses.newPasswordModifyExtendedResult(rc);
707                ByteString generatedPwd = getGeneratedPassword(extendedOperation);
708                if (generatedPwd != null) {
709                    result.setGeneratedPassword(generatedPwd.toByteArray());
710                }
711                return result;
712
713            default:
714                return Responses.newGenericExtendedResult(rc);
715            }
716        }
717        return Responses.newResult(rc);
718    }
719
720    private static ByteString getGeneratedPassword(ExtendedOperation op) throws LdapException {
721        // FIXME this code is duplicated with code in the SDK
722        // see PasswordModifyExtendedRequestImpl#ResultDecoder#decodeExtendedResult()
723        ByteString responseValue = op.getResponseValue();
724        if (responseValue != null) {
725            try {
726                ASN1Reader reader = ASN1.getReader(responseValue);
727                reader.readStartSequence();
728                return reader.readOctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD);
729            } catch (IOException e) {
730                throw LdapException.newLdapException(ResultCode.PROTOCOL_ERROR,
731                        ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST.get(getExceptionMessage(e)), e);
732            }
733        }
734        return null;
735    }
736
737    /**
738     * Converts from <code>byte[]</code> to OpenDJ server {@link ByteString}.
739     *
740     * @param authenticationValue
741     *          value to convert
742     * @return the converted value
743     */
744    public static ByteString getCredentials(final byte[] authenticationValue) {
745        final ASN1Reader reader = ASN1.getReader(authenticationValue);
746        ByteString saslCred = ByteString.empty();
747        try {
748            reader.readOctetStringAsString(); // Reads SASL Mechanism - RFC 4511 4.2
749            if (reader.hasNextElement()) {
750                saslCred = reader.readOctetString(); // Reads credentials.
751            }
752        } catch (IOException e) {
753            // Nothing to do.
754        }
755
756        return saslCred.toByteString();
757    }
758
759    /**
760     * Converts from OpenDJ server
761     * {@link org.opends.server.admin.std.meta.BackendVLVIndexCfgDefn.Scope} to
762     * {@link org.forgerock.opendj.server.config.meta.BackendVLVIndexCfgDefn.Scope}.
763     *
764     * @param scope
765     *          The scope value.
766     * @return The converted scope value.
767     */
768    public static BackendVLVIndexCfgDefn.Scope from(
769        final org.opends.server.admin.std.meta.BackendVLVIndexCfgDefn.Scope scope) {
770      Reject.ifNull(scope, "Provided scope to convert is null");
771      switch (scope) {
772      case BASE_OBJECT:
773        return BackendVLVIndexCfgDefn.Scope.BASE_OBJECT;
774      case SINGLE_LEVEL:
775        return BackendVLVIndexCfgDefn.Scope.SINGLE_LEVEL;
776      case SUBORDINATE_SUBTREE:
777        return BackendVLVIndexCfgDefn.Scope.SUBORDINATE_SUBTREE;
778      case WHOLE_SUBTREE:
779        return BackendVLVIndexCfgDefn.Scope.WHOLE_SUBTREE;
780      default:
781        throw new IllegalArgumentException("Impossible to convert the unknown scope: " + scope);
782      }
783    }
784}