Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2009-2022 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2009-2022 Ping Identity Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2009-2022 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk.unboundidds.controls;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.unboundid.asn1.ASN1Element;
import com.unboundid.asn1.ASN1Enumerated;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.asn1.ASN1Sequence;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DecodeableControl;
import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.util.Debug;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import com.unboundid.util.json.JSONArray;
import com.unboundid.util.json.JSONField;
import com.unboundid.util.json.JSONNumber;
import com.unboundid.util.json.JSONObject;
import com.unboundid.util.json.JSONString;
import com.unboundid.util.json.JSONValue;
import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
/**
* This class provides an implementation of a control that may be included in a
* search result entry in response to a join request control to provide a set of
* entries related to the search result entry. See the class-level
* documentation for the {@link JoinRequestControl} class for additional
* information and an example demonstrating its use.
*
*
* NOTE: This class, and other classes within the
* {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
* supported for use against Ping Identity, UnboundID, and
* Nokia/Alcatel-Lucent 8661 server products. These classes provide support
* for proprietary functionality or for external specifications that are not
* considered stable or mature enough to be guaranteed to work in an
* interoperable way with other types of LDAP servers.
*
*
* The value of the join result control is encoded as follows:
*
* JoinResult ::= SEQUENCE {
* COMPONENTS OF LDAPResult,
* entries [4] SEQUENCE OF JoinedEntry }
*
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class JoinResultControl
extends Control
implements DecodeableControl
{
/**
* The OID (1.3.6.1.4.1.30221.2.5.9) for the join result control.
*/
@NotNull public static final String JOIN_RESULT_OID =
"1.3.6.1.4.1.30221.2.5.9";
/**
* The BER type for the referral URLs element.
*/
private static final byte TYPE_REFERRAL_URLS = (byte) 0xA3;
/**
* The BER type for the join results element.
*/
private static final byte TYPE_JOIN_RESULTS = (byte) 0xA4;
/**
* The name of the field used to hold the diagnostic message in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_DIAGNOSTIC_MESSAGE =
"diagnostic-message";
/**
* The name of the field used to hold the DN of an entry in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_ENTRY_DN = "_dn";
/**
* The name of the field used to hold the set of joined entries in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_JOINED_ENTRIES =
"joined-entries";
/**
* The name of the field used to hold the matched DN in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_MATCHED_DN = "matched-dn";
/**
* The name of the field used to hold the nested join results in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_NESTED_JOIN_RESULTS =
"_nested-join-results";
/**
* The name of the field used to hold the referral URLs in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_REFERRAL_URLS =
"referral-urls";
/**
* The name of the field used to hold the join result code in the JSON
* representation of this control.
*/
@NotNull private static final String JSON_FIELD_RESULT_CODE = "result-code";
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 681831114773253358L;
// The set of entries which have been joined with the associated search result
// entry.
@NotNull private final List joinResults;
// The set of referral URLs for this join result.
@NotNull private final List referralURLs;
// The result code for this join result.
@NotNull private final ResultCode resultCode;
// The diagnostic message for this join result.
@Nullable private final String diagnosticMessage;
// The matched DN for this join result.
@Nullable private final String matchedDN;
/**
* Creates a new empty control instance that is intended to be used only for
* decoding controls via the {@code DecodeableControl} interface.
*/
JoinResultControl()
{
resultCode = null;
diagnosticMessage = null;
matchedDN = null;
referralURLs = null;
joinResults = null;
}
/**
* Creates a new join result control indicating a successful join.
*
* @param joinResults The set of entries that have been joined with the
* associated search result entry. It may be
* {@code null} or empty if no entries were joined with
* the search result entry.
*/
public JoinResultControl(@Nullable final List joinResults)
{
this(ResultCode.SUCCESS, null, null, null, joinResults);
}
/**
* Creates a new join result control with the provided information.
*
* @param resultCode The result code for the join processing. It
* must not be {@code null}.
* @param diagnosticMessage A message with additional information about the
* result of the join processing. It may be
* {@code null} if no message is needed.
* @param matchedDN The matched DN for the join processing. It may
* be {@code null} if no matched DN is needed.
* @param referralURLs The set of referral URLs for any referrals
* encountered while processing the join. It may
* be {@code null} or empty if no referral URLs
* are needed.
* @param joinResults The set of entries that have been joined with
* associated search result entry. It may be
* {@code null} or empty if no entries were joined
* with the search result entry.
*/
public JoinResultControl(@NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final List referralURLs,
@Nullable final List joinResults)
{
super(JOIN_RESULT_OID, false,
encodeValue(resultCode, diagnosticMessage, matchedDN, referralURLs,
joinResults));
this.resultCode = resultCode;
this.diagnosticMessage = diagnosticMessage;
this.matchedDN = matchedDN;
if (referralURLs == null)
{
this.referralURLs = Collections.emptyList();
}
else
{
this.referralURLs = Collections.unmodifiableList(referralURLs);
}
if (joinResults == null)
{
this.joinResults = Collections.emptyList();
}
else
{
this.joinResults = Collections.unmodifiableList(joinResults);
}
}
/**
* Creates a new join result control with the provided information.
*
* @param oid The OID for the control.
* @param isCritical Indicates whether the control should be marked
* critical.
* @param value The encoded value for the control. This may be
* {@code null} if no value was provided.
*
* @throws LDAPException If the provided control cannot be decoded as an
* account usable response control.
*/
public JoinResultControl(@NotNull final String oid, final boolean isCritical,
@Nullable final ASN1OctetString value)
throws LDAPException
{
super(oid, isCritical, value);
if (value == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_NO_VALUE.get());
}
try
{
final ASN1Element valueElement = ASN1Element.decode(value.getValue());
final ASN1Element[] elements =
ASN1Sequence.decodeAsSequence(valueElement).elements();
resultCode = ResultCode.valueOf(
ASN1Enumerated.decodeAsEnumerated(elements[0]).intValue());
final String matchedDNStr =
ASN1OctetString.decodeAsOctetString(elements[1]).stringValue();
if (matchedDNStr.isEmpty())
{
matchedDN = null;
}
else
{
matchedDN = matchedDNStr;
}
final String diagnosticMessageStr =
ASN1OctetString.decodeAsOctetString(elements[2]).stringValue();
if (diagnosticMessageStr.isEmpty())
{
diagnosticMessage = null;
}
else
{
diagnosticMessage = diagnosticMessageStr;
}
final ArrayList refs = new ArrayList<>(5);
final ArrayList entries = new ArrayList<>(20);
for (int i=3; i < elements.length; i++)
{
switch (elements[i].getType())
{
case TYPE_REFERRAL_URLS:
final ASN1Element[] refElements =
ASN1Sequence.decodeAsSequence(elements[i]).elements();
for (final ASN1Element e : refElements)
{
refs.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
}
break;
case TYPE_JOIN_RESULTS:
final ASN1Element[] entryElements =
ASN1Sequence.decodeAsSequence(elements[i]).elements();
for (final ASN1Element e : entryElements)
{
entries.add(JoinedEntry.decode(e));
}
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_INVALID_ELEMENT_TYPE.get(
StaticUtils.toHex(elements[i].getType())));
}
}
referralURLs = Collections.unmodifiableList(refs);
joinResults = Collections.unmodifiableList(entries);
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_CANNOT_DECODE.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
/**
* Encodes the provided information as appropriate for use as the value of
* this control.
*
* @param resultCode The result code for the join processing. It
* must not be {@code null}.
* @param diagnosticMessage A message with additional information about the
* result of the join processing. It may be
* {@code null} if no message is needed.
* @param matchedDN The matched DN for the join processing. It may
* be {@code null} if no matched DN is needed.
* @param referralURLs The set of referral URLs for any referrals
* encountered while processing the join. It may
* be {@code null} or empty if no referral URLs
* are needed.
* @param joinResults The set of entries that have been joined with
* associated search result entry. It may be
* {@code null} or empty if no entries were joined
* with the search result entry.
*
* @return An ASN.1 element containing an encoded representation of the
* value for this control.
*/
@NotNull()
private static ASN1OctetString encodeValue(
@NotNull final ResultCode resultCode,
@Nullable final String diagnosticMessage,
@Nullable final String matchedDN,
@Nullable final List referralURLs,
@Nullable final List joinResults)
{
Validator.ensureNotNull(resultCode);
final ArrayList elements = new ArrayList<>(5);
elements.add(new ASN1Enumerated(resultCode.intValue()));
if (matchedDN == null)
{
elements.add(new ASN1OctetString());
}
else
{
elements.add(new ASN1OctetString(matchedDN));
}
if (diagnosticMessage == null)
{
elements.add(new ASN1OctetString());
}
else
{
elements.add(new ASN1OctetString(diagnosticMessage));
}
if ((referralURLs != null) && (! referralURLs.isEmpty()))
{
final ArrayList refElements =
new ArrayList<>(referralURLs.size());
for (final String s : referralURLs)
{
refElements.add(new ASN1OctetString(s));
}
elements.add(new ASN1Sequence(TYPE_REFERRAL_URLS, refElements));
}
if ((joinResults == null) || joinResults.isEmpty())
{
elements.add(new ASN1Sequence(TYPE_JOIN_RESULTS));
}
else
{
final ArrayList entryElements =
new ArrayList<>(joinResults.size());
for (final JoinedEntry e : joinResults)
{
entryElements.add(e.encode());
}
elements.add(new ASN1Sequence(TYPE_JOIN_RESULTS, entryElements));
}
return new ASN1OctetString(new ASN1Sequence(elements).encode());
}
/**
* Retrieves the result code for this join result.
*
* @return The result code for this join result.
*/
@NotNull()
public ResultCode getResultCode()
{
return resultCode;
}
/**
* Retrieves the diagnostic message for this join result.
*
* @return The diagnostic message for this join result, or {@code null} if
* there is no diagnostic message.
*/
@Nullable()
public String getDiagnosticMessage()
{
return diagnosticMessage;
}
/**
* Retrieves the matched DN for this join result.
*
* @return The matched DN for this join result, or {@code null} if there is
* no matched DN.
*/
@Nullable()
public String getMatchedDN()
{
return matchedDN;
}
/**
* Retrieves the set of referral URLs for this join result.
*
* @return The set of referral URLs for this join result, or an empty list
* if there are no referral URLs.
*/
@NotNull()
public List getReferralURLs()
{
return referralURLs;
}
/**
* Retrieves the set of entries that have been joined with the associated
* search result entry.
*
* @return The set of entries that have been joined with the associated
* search result entry.
*/
@NotNull()
public List getJoinResults()
{
return joinResults;
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public JoinResultControl decodeControl(@NotNull final String oid,
final boolean isCritical,
@Nullable final ASN1OctetString value)
throws LDAPException
{
return new JoinResultControl(oid, isCritical, value);
}
/**
* Extracts a join result control from the provided search result entry.
*
* @param entry The search result entry from which to retrieve the join
* result control.
*
* @return The join result control contained in the provided search result
* entry, or {@code null} if the entry did not contain a join result
* control.
*
* @throws LDAPException If a problem is encountered while attempting to
* decode the join result control contained in the
* provided search result entry.
*/
@Nullable()
public static JoinResultControl get(@NotNull final SearchResultEntry entry)
throws LDAPException
{
final Control c = entry.getControl(JOIN_RESULT_OID);
if (c == null)
{
return null;
}
if (c instanceof JoinResultControl)
{
return (JoinResultControl) c;
}
else
{
return new JoinResultControl(c.getOID(), c.isCritical(), c.getValue());
}
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public String getControlName()
{
return INFO_CONTROL_NAME_JOIN_RESULT.get();
}
/**
* Retrieves a representation of this join result control as a JSON object.
* The JSON object uses the following fields:
*
*
* {@code oid} -- A mandatory string field whose value is the object
* identifier for this control. For the join result control, the OID is
* "1.3.6.1.4.1.30221.2.5.9".
*
*
* {@code control-name} -- An optional string field whose value is a
* human-readable name for this control. This field is only intended for
* descriptive purposes, and when decoding a control, the {@code oid}
* field should be used to identify the type of control.
*
*
* {@code criticality} -- A mandatory Boolean field used to indicate
* whether this control is considered critical.
*
*
* {@code value-base64} -- An optional string field whose value is a
* base64-encoded representation of the raw value for this join result
* control. Exactly one of the {@code value-base64} and
* {@code value-json} fields must be present.
*
*
* {@code value-json} -- An optional JSON object field whose value is a
* user-friendly representation of the value for this join result control.
* Exactly one of the {@code value-base64} and {@code value-json} fields
* must be present, and if the {@code value-json} field is used, then it
* will use the following fields:
*
*
* {@code result-code} -- An integer field whose value is the numeric
* representation of the LDAP result code for join processing.
*
*
* {@code matched-dn} -- An optional string field whose value is the
* matched DN for the join processing.
*
*
* {@code diagnostic-message} -- An optional string field whose value
* is a diagnostic message with additional information about the join
* processing.
*
*
* {@code referral-urls} -- An optional array field whose values are
* strings that represent referral URLs encountered while performing
* join processing.
*
*
* {@code joined-entries} -- An array field whose values are JSON
* objects that reference entries that were joined with the source
* entry. Each of these JSON objects will include a
* "{@code _dn}" string field whose value is the DN of the entry and
* an optional "{@code _nested-join-results}" array field whose values
* are JSON objects that represent nested join results. Any other
* fields in the JSON objects represent attributes in the joined
* entry, with the name of the field representing the name of the
* attribute, and the value of the field being an array of strings
* representing the values of that attribute.
*
*
*
*
*
* @return A JSON object that contains a representation of this control.
*/
@Override()
@NotNull()
public JSONObject toJSONControl()
{
final Map valueFields = new LinkedHashMap<>();
valueFields.put(JSON_FIELD_RESULT_CODE,
new JSONNumber(resultCode.intValue()));
if (matchedDN != null)
{
valueFields.put(JSON_FIELD_MATCHED_DN, new JSONString(matchedDN));
}
if (diagnosticMessage != null)
{
valueFields.put(JSON_FIELD_DIAGNOSTIC_MESSAGE,
new JSONString(diagnosticMessage));
}
if ((referralURLs != null) && (! referralURLs.isEmpty()))
{
final List referralValues =
new ArrayList<>(referralURLs.size());
for (final String referralURL : referralURLs)
{
referralValues.add(new JSONString(referralURL));
}
valueFields.put(JSON_FIELD_REFERRAL_URLS, new JSONArray(referralValues));
}
final List entryValues = new ArrayList<>(joinResults.size());
for (final JoinedEntry entry : joinResults)
{
entryValues.add(encodeEntryJSON(entry));
}
valueFields.put(JSON_FIELD_JOINED_ENTRIES, new JSONArray(entryValues));
return new JSONObject(
new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID, JOIN_RESULT_OID),
new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
INFO_CONTROL_NAME_JOIN_RESULT.get()),
new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
isCritical()),
new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
new JSONObject(valueFields)));
}
/**
* Encodes the provided joined entry to a JSON object.
*
* @param entry The entry to be encoded. It must not be {@code null}.
*
* @return The JSON object containing the encoded entry.
*/
@NotNull()
private static JSONObject encodeEntryJSON(@NotNull final JoinedEntry entry)
{
final Map fields = new LinkedHashMap<>();
fields.put(JSON_FIELD_ENTRY_DN, new JSONString(entry.getDN()));
for (final Attribute a : entry.getAttributes())
{
final List attrValueValues = new ArrayList<>(a.size());
for (final String value : a.getValues())
{
attrValueValues.add(new JSONString(value));
}
fields.put(a.getName(), new JSONArray(attrValueValues));
}
final List nestedEntries = entry.getNestedJoinResults();
if (! nestedEntries.isEmpty())
{
final List nestedEntryValues =
new ArrayList<>(nestedEntries.size());
for (final JoinedEntry nestedEntry : nestedEntries)
{
nestedEntryValues.add(encodeEntryJSON(nestedEntry));
}
fields.put(JSON_FIELD_NESTED_JOIN_RESULTS,
new JSONArray(nestedEntryValues));
}
return new JSONObject(fields);
}
/**
* Attempts to decode the provided object as a JSON representation of a join
* result control.
*
* @param controlObject The JSON object to be decoded. It must not be
* {@code null}.
* @param strict Indicates whether to use strict mode when decoding
* the provided JSON object. If this is {@code true},
* then this method will throw an exception if the
* provided JSON object contains any unrecognized
* fields. If this is {@code false}, then unrecognized
* fields will be ignored.
*
* @return The join result control that was decoded from the provided JSON
* object.
*
* @throws LDAPException If the provided JSON object cannot be parsed as a
* valid join result control.
*/
@NotNull()
public static JoinResultControl decodeJSONControl(
@NotNull final JSONObject controlObject,
final boolean strict)
throws LDAPException
{
final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
controlObject, strict, true, true);
final ASN1OctetString rawValue = jsonControl.getRawValue();
if (rawValue != null)
{
return new JoinResultControl(jsonControl.getOID(),
jsonControl.getCriticality(), rawValue);
}
final JSONObject valueObject = jsonControl.getValueObject();
final Integer resultCodeValue =
valueObject.getFieldAsInteger(JSON_FIELD_RESULT_CODE);
if (resultCodeValue == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_MISSING_VALUE_FIELD.get(
controlObject.toSingleLineString(), JSON_FIELD_RESULT_CODE));
}
final ResultCode resultCode = ResultCode.valueOf(resultCodeValue);
final String matchedDN =
valueObject.getFieldAsString(JSON_FIELD_MATCHED_DN);
final String diagnosticMessage =
valueObject.getFieldAsString(JSON_FIELD_DIAGNOSTIC_MESSAGE);
final List referralURLs;
final List referralURLValues =
valueObject.getFieldAsArray(JSON_FIELD_REFERRAL_URLS);
if (referralURLValues == null)
{
referralURLs = null;
}
else
{
referralURLs = new ArrayList<>(referralURLValues.size());
for (final JSONValue referralURLValue : referralURLValues)
{
if (referralURLValue instanceof JSONString)
{
referralURLs.add(((JSONString) referralURLValue).stringValue());
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_REFERRAL_URL_NOT_STRING.get(
controlObject.toSingleLineString(),
JSON_FIELD_REFERRAL_URLS));
}
}
}
final List joinedEntryValues =
valueObject.getFieldAsArray(JSON_FIELD_JOINED_ENTRIES);
if (joinedEntryValues == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_MISSING_VALUE_FIELD.get(
controlObject.toSingleLineString(), JSON_FIELD_JOINED_ENTRIES));
}
final List joinedEntries =
new ArrayList<>(joinedEntryValues.size());
for (final JSONValue joinedEntryValue : joinedEntryValues)
{
if (joinedEntryValue instanceof JSONObject)
{
joinedEntries.add(decodeEntryJSON(controlObject,
(JSONObject) joinedEntryValue));
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_ENTRY_NOT_OBJECT.get(
controlObject.toSingleLineString(),
JSON_FIELD_JOINED_ENTRIES));
}
}
if (strict)
{
final List unrecognizedFields =
JSONControlDecodeHelper.getControlObjectUnexpectedFields(
valueObject, JSON_FIELD_RESULT_CODE, JSON_FIELD_MATCHED_DN,
JSON_FIELD_DIAGNOSTIC_MESSAGE, JSON_FIELD_REFERRAL_URLS,
JSON_FIELD_JOINED_ENTRIES);
if (! unrecognizedFields.isEmpty())
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_UNRECOGNIZED_FIELD.get(
controlObject.toSingleLineString(),
unrecognizedFields.get(0)));
}
}
return new JoinResultControl(resultCode, diagnosticMessage, matchedDN,
referralURLs, joinedEntries);
}
/**
* Decodes the provided JSON object as a joined entry.
*
* @param controlObject The JSON object representing the entire control
* being decoded. It must not be {@code null}.
* @param entryObject The JSON object representing the entry to decode.
* It must not be {@code null}.
*
* @return The joined entry that was decoded.
*
* @throws LDAPException If the provided JSON object cannot be parsed as a
* valid joined entry.
*/
@NotNull()
private static JoinedEntry decodeEntryJSON(
@NotNull final JSONObject controlObject,
@NotNull final JSONObject entryObject)
throws LDAPException
{
String entryDN = null;
List nestedResults = null;
final List attributes =
new ArrayList<>(entryObject.getFields().size());
for (final Map.Entry e :
entryObject.getFields().entrySet())
{
final String fieldName = e.getKey();
final JSONValue fieldValue = e.getValue();
if (fieldName.equals(JSON_FIELD_ENTRY_DN))
{
if (fieldValue instanceof JSONString)
{
entryDN = ((JSONString) fieldValue).stringValue();
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_ENTRY_DN_NOT_STRING.get(
controlObject.toSingleLineString(),
JSON_FIELD_ENTRY_DN));
}
}
else if (fieldName.equals(JSON_FIELD_NESTED_JOIN_RESULTS))
{
if (fieldValue instanceof JSONArray)
{
final List nestedEntryValues =
((JSONArray) fieldValue).getValues();
nestedResults = new ArrayList<>(nestedEntryValues.size());
for (final JSONValue nestedEntryValue : nestedEntryValues)
{
if (nestedEntryValue instanceof JSONObject)
{
nestedResults.add(decodeEntryJSON(controlObject,
(JSONObject) nestedEntryValue));
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JON_RESULT_JSON_ENTRY_NESTED_ENTRY_NOT_OBJECT.get(
controlObject.toSingleLineString(),
JSON_FIELD_NESTED_JOIN_RESULTS));
}
}
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_ENTRY_NESTED_ENTRIES_NOT_ARRAY.get(
controlObject.toSingleLineString(),
JSON_FIELD_NESTED_JOIN_RESULTS));
}
}
else
{
if (fieldValue instanceof JSONArray)
{
final List attrValueValues =
((JSONArray) fieldValue).getValues();
final List attributeValues =
new ArrayList<>(attrValueValues.size());
for (final JSONValue v : attrValueValues)
{
if (v instanceof JSONString)
{
attributeValues.add(((JSONString) v).stringValue());
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_ENTRY_ATTR_VALUE_NOT_STRING.get(
controlObject.toSingleLineString(), fieldName));
}
}
attributes.add(new Attribute(fieldName, attributeValues));
}
else
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JOIN_RESULT_JSON_ENTRY_ATTR_VALUES_NOT_ARRAY.get(
controlObject.toSingleLineString(), fieldName));
}
}
}
if (entryDN == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_JON_RESULT_JSON_ENTRY_MISSING_DN.get(
controlObject.toSingleLineString(), JSON_FIELD_ENTRY_DN));
}
return new JoinedEntry(entryDN, attributes, nestedResults);
}
/**
* {@inheritDoc}
*/
@Override()
public void toString(@NotNull final StringBuilder buffer)
{
buffer.append("JoinResultControl(resultCode='");
buffer.append(resultCode.getName());
buffer.append("', diagnosticMessage='");
if (diagnosticMessage != null)
{
buffer.append(diagnosticMessage);
}
buffer.append("', matchedDN='");
if (matchedDN != null)
{
buffer.append(matchedDN);
}
buffer.append("', referralURLs={");
final Iterator refIterator = referralURLs.iterator();
while (refIterator.hasNext())
{
buffer.append(refIterator.next());
if (refIterator.hasNext())
{
buffer.append(", ");
}
}
buffer.append("}, joinResults={");
final Iterator entryIterator = joinResults.iterator();
while (entryIterator.hasNext())
{
entryIterator.next().toString(buffer);
if (entryIterator.hasNext())
{
buffer.append(", ");
}
}
buffer.append("})");
}
}