001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2010 Sun Microsystems, Inc.
015 * Portions Copyright 2016 ForgeRock AS.
016 */
017package org.forgerock.opendj.ldap.controls;
018
019import static com.forgerock.opendj.ldap.CoreMessages.ERR_MANAGEDSAIT_CONTROL_BAD_OID;
020import static com.forgerock.opendj.ldap.CoreMessages.ERR_MANAGEDSAIT_INVALID_CONTROL_VALUE;
021
022import org.forgerock.i18n.LocalizableMessage;
023import org.forgerock.opendj.ldap.ByteString;
024import org.forgerock.opendj.ldap.DecodeException;
025import org.forgerock.opendj.ldap.DecodeOptions;
026
027import org.forgerock.util.Reject;
028
029/**
030 * The ManageDsaIT request control as defined in RFC 3296. This control allows
031 * manipulation of referral and other special objects as normal objects.
032 * <p>
033 * When this control is present in the request, the server will not generate a
034 * referral or continuation reference based upon information held in referral
035 * objects and instead will treat the referral object as a normal entry. The
036 * server, however, is still free to return referrals for other reasons.
037 *
038 * <pre>
039 * // &quot;dc=ref,dc=com&quot; holds a referral to something else.
040 *
041 * // Referral without the ManageDsaIT control:
042 * SearchRequest request = Requests.newSearchRequest(
043 *          &quot;dc=ref,dc=com&quot;,
044 *          SearchScope.SUBORDINATES,
045 *          &quot;(objectclass=*)&quot;,
046 *          &quot;&quot;);
047 *
048 * ConnectionEntryReader reader = connection.search(request);
049 * while (reader.hasNext()) {
050 *     if (reader.isReference()) {
051 *         SearchResultReference ref = reader.readReference();
052 *         // References: ref.getURIs()
053 *     }
054 * }
055 *
056 * // Referral with the ManageDsaIT control:
057 * request.addControl(ManageDsaITRequestControl.newControl(true));
058 * SearchResultEntry entry = connection.searchSingleEntry(request);
059 * // ...
060 * </pre>
061 *
062 * @see <a href="http://tools.ietf.org/html/rfc3296">RFC 3296 - Named
063 *      Subordinate References in Lightweight Directory Access Protocol (LDAP)
064 *      Directories </a>
065 */
066public final class ManageDsaITRequestControl implements Control {
067    /** The OID for the ManageDsaIT request control. */
068    public static final String OID = "2.16.840.1.113730.3.4.2";
069
070    private static final ManageDsaITRequestControl CRITICAL_INSTANCE =
071            new ManageDsaITRequestControl(true);
072    private static final ManageDsaITRequestControl NONCRITICAL_INSTANCE =
073            new ManageDsaITRequestControl(false);
074
075    /** A decoder which can be used for decoding the Manage DsaIT request control. */
076    public static final ControlDecoder<ManageDsaITRequestControl> DECODER =
077            new ControlDecoder<ManageDsaITRequestControl>() {
078
079                @Override
080                public ManageDsaITRequestControl decodeControl(final Control control,
081                        final DecodeOptions options) throws DecodeException {
082                    Reject.ifNull(control);
083
084                    if (control instanceof ManageDsaITRequestControl) {
085                        return (ManageDsaITRequestControl) control;
086                    }
087
088                    if (!control.getOID().equals(OID)) {
089                        final LocalizableMessage message =
090                                ERR_MANAGEDSAIT_CONTROL_BAD_OID.get(control.getOID(), OID);
091                        throw DecodeException.error(message);
092                    }
093
094                    if (control.hasValue()) {
095                        final LocalizableMessage message =
096                                ERR_MANAGEDSAIT_INVALID_CONTROL_VALUE.get();
097                        throw DecodeException.error(message);
098                    }
099
100                    return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
101                }
102
103                @Override
104                public String getOID() {
105                    return OID;
106                }
107            };
108
109    /**
110     * Creates a new ManageDsaIT request control having the provided
111     * criticality.
112     *
113     * @param isCritical
114     *            {@code true} if it is unacceptable to perform the operation
115     *            without applying the semantics of this control, or
116     *            {@code false} if it can be ignored.
117     * @return The new control.
118     */
119    public static ManageDsaITRequestControl newControl(final boolean isCritical) {
120        return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE;
121    }
122
123    private final boolean isCritical;
124
125    private ManageDsaITRequestControl(final boolean isCritical) {
126        this.isCritical = isCritical;
127    }
128
129    @Override
130    public String getOID() {
131        return OID;
132    }
133
134    @Override
135    public ByteString getValue() {
136        return null;
137    }
138
139    @Override
140    public boolean hasValue() {
141        return false;
142    }
143
144    @Override
145    public boolean isCritical() {
146        return isCritical;
147    }
148
149    @Override
150    public String toString() {
151        final StringBuilder builder = new StringBuilder();
152        builder.append("ManageDsaITRequestControl(oid=");
153        builder.append(getOID());
154        builder.append(", criticality=");
155        builder.append(isCritical());
156        builder.append(")");
157        return builder.toString();
158    }
159
160}