001    /*
002     * Copyright 2009-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2016 UnboundID Corp.
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     */
021    package com.unboundid.ldap.protocol;
022    
023    
024    
025    import java.util.ArrayList;
026    import java.util.Collections;
027    import java.util.Iterator;
028    import java.util.List;
029    
030    import com.unboundid.asn1.ASN1Buffer;
031    import com.unboundid.asn1.ASN1BufferSequence;
032    import com.unboundid.asn1.ASN1Element;
033    import com.unboundid.asn1.ASN1OctetString;
034    import com.unboundid.asn1.ASN1Sequence;
035    import com.unboundid.asn1.ASN1StreamReader;
036    import com.unboundid.asn1.ASN1StreamReaderSequence;
037    import com.unboundid.ldap.sdk.Control;
038    import com.unboundid.ldap.sdk.LDAPException;
039    import com.unboundid.ldap.sdk.ResultCode;
040    import com.unboundid.ldap.sdk.SearchResultReference;
041    import com.unboundid.util.NotMutable;
042    import com.unboundid.util.InternalUseOnly;
043    import com.unboundid.util.ThreadSafety;
044    import com.unboundid.util.ThreadSafetyLevel;
045    
046    import static com.unboundid.ldap.protocol.ProtocolMessages.*;
047    import static com.unboundid.util.Debug.*;
048    import static com.unboundid.util.StaticUtils.*;
049    
050    
051    
052    /**
053     * This class provides an implementation of an LDAP search result reference
054     * protocol op.
055     */
056    @InternalUseOnly()
057    @NotMutable()
058    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
059    public final class SearchResultReferenceProtocolOp
060           implements ProtocolOp
061    {
062      /**
063       * The serial version UID for this serializable class.
064       */
065      private static final long serialVersionUID = -1526778443581862609L;
066    
067    
068    
069      // The list of referral URLs for this search result reference.
070      private final List<String> referralURLs;
071    
072    
073    
074      /**
075       * Creates a new search result reference protocol op with the provided
076       * information.
077       *
078       * @param  referralURLs  The list of referral URLs for this search result
079       *                       reference.
080       */
081      public SearchResultReferenceProtocolOp(final List<String> referralURLs)
082      {
083        this.referralURLs = Collections.unmodifiableList(referralURLs);
084      }
085    
086    
087    
088      /**
089       * Creates a new search result reference protocol op from the provided search
090       * result reference.
091       *
092       * @param  reference  The search result reference to use to create this
093       *                    protocol op.
094       */
095      public SearchResultReferenceProtocolOp(final SearchResultReference reference)
096      {
097        referralURLs = toList(reference.getReferralURLs());
098      }
099    
100    
101    
102      /**
103       * Creates a new search result reference protocol op read from the provided
104       * ASN.1 stream reader.
105       *
106       * @param  reader  The ASN.1 stream reader from which to read the search
107       *                 result reference protocol op.
108       *
109       * @throws  LDAPException  If a problem occurs while reading or parsing the
110       *                         search result reference.
111       */
112      SearchResultReferenceProtocolOp(final ASN1StreamReader reader)
113           throws LDAPException
114      {
115        try
116        {
117          final ArrayList<String> refs = new ArrayList<String>(5);
118          final ASN1StreamReaderSequence refSequence = reader.beginSequence();
119          while (refSequence.hasMoreElements())
120          {
121            refs.add(reader.readString());
122          }
123    
124          referralURLs = Collections.unmodifiableList(refs);
125        }
126        catch (Exception e)
127        {
128          debugException(e);
129    
130          throw new LDAPException(ResultCode.DECODING_ERROR,
131               ERR_SEARCH_REFERENCE_CANNOT_DECODE.get(getExceptionMessage(e)), e);
132        }
133      }
134    
135    
136    
137      /**
138       * Retrieves the list of referral URLs for this search result reference.
139       *
140       * @return  The list of referral URLs for this search result reference.
141       */
142      public List<String> getReferralURLs()
143      {
144        return referralURLs;
145      }
146    
147    
148    
149      /**
150       * {@inheritDoc}
151       */
152      public byte getProtocolOpType()
153      {
154        return LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE;
155      }
156    
157    
158    
159      /**
160       * {@inheritDoc}
161       */
162      public ASN1Element encodeProtocolOp()
163      {
164        final ArrayList<ASN1Element> urlElements =
165             new ArrayList<ASN1Element>(referralURLs.size());
166        for (final String url : referralURLs)
167        {
168          urlElements.add(new ASN1OctetString(url));
169        }
170    
171        return new ASN1Sequence(
172             LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE,
173             urlElements);
174      }
175    
176    
177    
178      /**
179       * Decodes the provided ASN.1 element as a search result reference protocol
180       * op.
181       *
182       * @param  element  The ASN.1 element to be decoded.
183       *
184       * @return  The decoded search result reference protocol op.
185       *
186       * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
187       *                         a search result reference protocol op.
188       */
189      public static SearchResultReferenceProtocolOp decodeProtocolOp(
190                                                         final ASN1Element element)
191             throws LDAPException
192      {
193        try
194        {
195          final ASN1Element[] urlElements =
196               ASN1Sequence.decodeAsSequence(element).elements();
197          final ArrayList<String> referralURLs =
198               new ArrayList<String>(urlElements.length);
199          for (final ASN1Element e : urlElements)
200          {
201            referralURLs.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
202          }
203    
204          return new SearchResultReferenceProtocolOp(referralURLs);
205        }
206        catch (final Exception e)
207        {
208          debugException(e);
209          throw new LDAPException(ResultCode.DECODING_ERROR,
210               ERR_SEARCH_REFERENCE_CANNOT_DECODE.get(getExceptionMessage(e)),
211               e);
212        }
213      }
214    
215    
216    
217      /**
218       * {@inheritDoc}
219       */
220      public void writeTo(final ASN1Buffer buffer)
221      {
222        final ASN1BufferSequence opSequence = buffer.beginSequence(
223             LDAPMessage.PROTOCOL_OP_TYPE_SEARCH_RESULT_REFERENCE);
224        for (final String s : referralURLs)
225        {
226          buffer.addOctetString(s);
227        }
228        opSequence.end();
229      }
230    
231    
232    
233      /**
234       * Creates a search result reference from this protocol op.
235       *
236       * @param  controls  The set of controls to include in the search result
237       *                   reference.  It may be empty or {@code null} if no
238       *                   controls should be included.
239       *
240       * @return  The search result reference that was created.
241       */
242      public SearchResultReference toSearchResultReference(
243                                        final Control... controls)
244      {
245        final String[] referralArray = new String[referralURLs.size()];
246        referralURLs.toArray(referralArray);
247    
248        return new SearchResultReference(referralArray, controls);
249      }
250    
251    
252    
253      /**
254       * Retrieves a string representation of this protocol op.
255       *
256       * @return  A string representation of this protocol op.
257       */
258      @Override()
259      public String toString()
260      {
261        final StringBuilder buffer = new StringBuilder();
262        toString(buffer);
263        return buffer.toString();
264      }
265    
266    
267    
268      /**
269       * {@inheritDoc}
270       */
271      public void toString(final StringBuilder buffer)
272      {
273        buffer.append("SearchResultReferenceProtocolOp(referralURLs={");
274    
275        final Iterator<String> iterator = referralURLs.iterator();
276        while (iterator.hasNext())
277        {
278          buffer.append('\'');
279          buffer.append(iterator.next());
280          buffer.append('\'');
281          if (iterator.hasNext())
282          {
283            buffer.append(',');
284          }
285        }
286    
287        buffer.append("})");
288      }
289    }