001/* 002 * Copyright 2009-2022 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2009-2022 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2009-2022 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.controls; 037 038 039 040import com.unboundid.asn1.ASN1Element; 041import com.unboundid.asn1.ASN1OctetString; 042import com.unboundid.ldap.sdk.Control; 043import com.unboundid.ldap.sdk.LDAPException; 044import com.unboundid.ldap.sdk.ResultCode; 045import com.unboundid.util.Debug; 046import com.unboundid.util.NotMutable; 047import com.unboundid.util.NotNull; 048import com.unboundid.util.StaticUtils; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 053 054 055 056/** 057 * This class provides an implementation of an LDAP control which can be 058 * included in a search request to indicate that search result entries should be 059 * returned along with related entries based on a given set of criteria, much 060 * like an SQL join in a relational database. 061 * <BR> 062 * <BLOCKQUOTE> 063 * <B>NOTE:</B> This class, and other classes within the 064 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 065 * supported for use against Ping Identity, UnboundID, and 066 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 067 * for proprietary functionality or for external specifications that are not 068 * considered stable or mature enough to be guaranteed to work in an 069 * interoperable way with other types of LDAP servers. 070 * </BLOCKQUOTE> 071 * <BR> 072 * This request control has an OID of 1.3.6.1.4.1.30221.2.5.9, and the 073 * criticality is generally true. It must have a value, and the format of that 074 * value is described in the class-level documentation for the 075 * {@link JoinRequestValue} class. 076 * <BR> 077 * <H2>Example</H2> 078 * Consider the case in which user entries include an account number, but 079 * additional information about those accounts are available in separate 080 * entries. If you wish to retrieve both the user and account entries for a 081 * user given only a user ID, then you may accomplish that using the join 082 * request control as follows: 083 * <PRE> 084 * SearchRequest searchRequest = new SearchRequest( 085 * "ou=People,dc=example,dc=com", SearchScope.SUB, 086 * Filter.createEqualityFilter("uid", userID)); 087 * searchRequest.addControl(new JoinRequestControl(new JoinRequestValue( 088 * JoinRule.createEqualityJoin("accountNumber", "accountNumber", false), 089 * JoinBaseDN.createUseCustomBaseDN("ou=Accounts,dc=example,dc=com"), 090 * SearchScope.SUB, DereferencePolicy.NEVER, null, 091 * Filter.createEqualityFilter("objectClass", "accountEntry"), 092 * new String[0], false, null))); 093 * SearchResult searchResult = connection.search(searchRequest); 094 * 095 * for (SearchResultEntry userEntry : searchResult.getSearchEntries()) 096 * { 097 * JoinResultControl c = JoinResultControl.get(userEntry); 098 * for (JoinedEntry accountEntry : c.getJoinResults()) 099 * { 100 * // User userEntry was joined with account accountEntry 101 * } 102 * } 103 * </PRE> 104 */ 105@NotMutable() 106@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 107public final class JoinRequestControl 108 extends Control 109{ 110 /** 111 * The OID (1.3.6.1.4.1.30221.2.5.9) for the join request control. 112 */ 113 @NotNull public static final String JOIN_REQUEST_OID = 114 "1.3.6.1.4.1.30221.2.5.9"; 115 116 117 118 /** 119 * The serial version UID for this serializable class. 120 */ 121 private static final long serialVersionUID = -1321645105838145996L; 122 123 124 125 // The join request value for this control. 126 @NotNull private final JoinRequestValue joinRequestValue; 127 128 129 130 /** 131 * Creates a new join request control with the provided join request value. 132 * 133 * @param joinRequestValue The join request value to use for this control. 134 */ 135 public JoinRequestControl(@NotNull final JoinRequestValue joinRequestValue) 136 { 137 super(JOIN_REQUEST_OID, true, 138 new ASN1OctetString(joinRequestValue.encode().encode())); 139 140 this.joinRequestValue = joinRequestValue; 141 } 142 143 144 145 /** 146 * Creates a new join request control which is decoded from the provided 147 * generic control. 148 * 149 * @param control The generic control to be decoded as a join request 150 * control. 151 * 152 * @throws LDAPException If the provided control cannot be decoded as a 153 * virtual attributes only request control. 154 */ 155 public JoinRequestControl(@NotNull final Control control) 156 throws LDAPException 157 { 158 super(control); 159 160 final ASN1OctetString value = control.getValue(); 161 if (value == null) 162 { 163 throw new LDAPException(ResultCode.DECODING_ERROR, 164 ERR_JOIN_REQUEST_CONTROL_NO_VALUE.get()); 165 } 166 167 final ASN1Element valueElement; 168 try 169 { 170 valueElement = ASN1Element.decode(value.getValue()); 171 } 172 catch (final Exception e) 173 { 174 Debug.debugException(e); 175 176 throw new LDAPException(ResultCode.DECODING_ERROR, 177 ERR_JOIN_REQUEST_VALUE_CANNOT_DECODE.get( 178 StaticUtils.getExceptionMessage(e)), 179 e); 180 } 181 182 joinRequestValue = JoinRequestValue.decode(valueElement); 183 } 184 185 186 187 /** 188 * Retrieves the join request value for this join request control. 189 * 190 * @return The join request value for this join request control. 191 */ 192 @NotNull() 193 public JoinRequestValue getJoinRequestValue() 194 { 195 return joinRequestValue; 196 } 197 198 199 200 /** 201 * {@inheritDoc} 202 */ 203 @Override() 204 @NotNull() 205 public String getControlName() 206 { 207 return INFO_CONTROL_NAME_JOIN_REQUEST.get(); 208 } 209 210 211 212 /** 213 * {@inheritDoc} 214 */ 215 @Override() 216 public void toString(@NotNull final StringBuilder buffer) 217 { 218 buffer.append("JoinRequestControl(value="); 219 joinRequestValue.toString(buffer); 220 buffer.append(')'); 221 } 222}