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