001    /*
002     * Copyright 2010-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2010-2015 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.sdk.extensions;
022    
023    
024    
025    import com.unboundid.asn1.ASN1Boolean;
026    import com.unboundid.asn1.ASN1Element;
027    import com.unboundid.asn1.ASN1OctetString;
028    import com.unboundid.asn1.ASN1Sequence;
029    import com.unboundid.ldap.sdk.Control;
030    import com.unboundid.ldap.sdk.ExtendedRequest;
031    import com.unboundid.ldap.sdk.ExtendedResult;
032    import com.unboundid.ldap.sdk.LDAPConnection;
033    import com.unboundid.ldap.sdk.LDAPException;
034    import com.unboundid.ldap.sdk.ResultCode;
035    import com.unboundid.util.NotMutable;
036    import com.unboundid.util.ThreadSafety;
037    import com.unboundid.util.ThreadSafetyLevel;
038    
039    import static com.unboundid.ldap.sdk.extensions.ExtOpMessages.*;
040    import static com.unboundid.util.Debug.*;
041    import static com.unboundid.util.Validator.*;
042    
043    
044    
045    /**
046     * This class provides an implementation of the end transaction extended
047     * request as defined in
048     * <A HREF="http://www.ietf.org/rfc/rfc5805.txt">RFC 5805</A>.  It may be used
049     * to either commit or abort a transaction that was created using the start
050     * transaction request.  See the documentation for the
051     * {@link StartTransactionExtendedRequest} class for an example of processing an
052     * LDAP transaction.
053     */
054    @NotMutable()
055    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
056    public final class EndTransactionExtendedRequest
057           extends ExtendedRequest
058    {
059      /**
060       * The OID (1.3.6.1.1.21.3) for the end transaction extended request.
061       */
062      public static final String END_TRANSACTION_REQUEST_OID = "1.3.6.1.1.21.3";
063    
064    
065    
066      /**
067       * The serial version UID for this serializable class.
068       */
069      private static final long serialVersionUID = -7135468264026410702L;
070    
071    
072    
073      // The transaction ID for the associated transaction.
074      private final ASN1OctetString transactionID;
075    
076      // Indicates whether to commit or abort the associated transaction.
077      private final boolean commit;
078    
079    
080    
081      /**
082       * Creates a new end transaction extended request with the provided
083       * information.
084       *
085       * @param  transactionID  The transaction ID for the transaction to commit or
086       *                        abort.  It must not be {@code null}.
087       * @param  commit         {@code true} if the transaction should be committed,
088       *                        or {@code false} if the transaction should be
089       *                        aborted.
090       * @param  controls       The set of controls to include in the request.
091       */
092      public EndTransactionExtendedRequest(final ASN1OctetString transactionID,
093                                           final boolean commit,
094                                           final Control... controls)
095      {
096        super(END_TRANSACTION_REQUEST_OID, encodeValue(transactionID, commit),
097              controls);
098    
099        this.transactionID = transactionID;
100        this.commit        = commit;
101      }
102    
103    
104    
105      /**
106       * Creates a new end transaction extended request from the provided generic
107       * extended request.
108       *
109       * @param  extendedRequest  The generic extended request to use to create this
110       *                          end transaction extended request.
111       *
112       * @throws  LDAPException  If a problem occurs while decoding the request.
113       */
114      public EndTransactionExtendedRequest(final ExtendedRequest extendedRequest)
115             throws LDAPException
116      {
117        super(extendedRequest);
118    
119        final ASN1OctetString value = extendedRequest.getValue();
120        if (value == null)
121        {
122          throw new LDAPException(ResultCode.DECODING_ERROR,
123               ERR_END_TXN_REQUEST_NO_VALUE.get());
124        }
125    
126        try
127        {
128          final ASN1Element valueElement = ASN1Element.decode(value.getValue());
129          final ASN1Element[] elements =
130               ASN1Sequence.decodeAsSequence(valueElement).elements();
131          if (elements.length == 1)
132          {
133            commit        = true;
134            transactionID = ASN1OctetString.decodeAsOctetString(elements[0]);
135          }
136          else
137          {
138            commit        = ASN1Boolean.decodeAsBoolean(elements[0]).booleanValue();
139            transactionID = ASN1OctetString.decodeAsOctetString(elements[1]);
140          }
141        }
142        catch (Exception e)
143        {
144          debugException(e);
145          throw new LDAPException(ResultCode.DECODING_ERROR,
146               ERR_END_TXN_REQUEST_CANNOT_DECODE.get(e), e);
147        }
148      }
149    
150    
151    
152      /**
153       * Generates the value to include in this extended request.
154       *
155       * @param  transactionID  The transaction ID for the transaction to commit or
156       *                        abort.  It must not be {@code null}.
157       * @param  commit         {@code true} if the transaction should be committed,
158       *                        or {@code false} if the transaction should be
159       *                        aborted.
160       *
161       * @return  The ASN.1 octet string containing the encoded request value.
162       */
163      private static ASN1OctetString
164           encodeValue(final ASN1OctetString transactionID,
165                       final boolean commit)
166      {
167        ensureNotNull(transactionID);
168    
169        final ASN1Element[] valueElements;
170        if (commit)
171        {
172          valueElements = new ASN1Element[]
173          {
174            transactionID
175          };
176        }
177        else
178        {
179          valueElements = new ASN1Element[]
180          {
181            new ASN1Boolean(commit),
182            transactionID
183          };
184        }
185    
186        return new ASN1OctetString(new ASN1Sequence(valueElements).encode());
187      }
188    
189    
190    
191      /**
192       * Retrieves the transaction ID for the transaction to commit or abort.
193       *
194       * @return  The transaction ID for the transaction to commit or abort.
195       */
196      public ASN1OctetString getTransactionID()
197      {
198        return transactionID;
199      }
200    
201    
202    
203      /**
204       * Indicates whether the transaction should be committed or aborted.
205       *
206       * @return  {@code true} if the transaction should be committed, or
207       *          {@code false} if it should be aborted.
208       */
209      public boolean commit()
210      {
211        return commit;
212      }
213    
214    
215    
216      /**
217       * {@inheritDoc}
218       */
219      @Override()
220      public EndTransactionExtendedResult process(final LDAPConnection connection,
221                                                  final int depth)
222             throws LDAPException
223      {
224        final ExtendedResult extendedResponse = super.process(connection, depth);
225        return new EndTransactionExtendedResult(extendedResponse);
226      }
227    
228    
229    
230      /**
231       * {@inheritDoc}
232       */
233      @Override()
234      public EndTransactionExtendedRequest duplicate()
235      {
236        return duplicate(getControls());
237      }
238    
239    
240    
241      /**
242       * {@inheritDoc}
243       */
244      @Override()
245      public EndTransactionExtendedRequest duplicate(final Control[] controls)
246      {
247        final EndTransactionExtendedRequest r =
248             new EndTransactionExtendedRequest(transactionID, commit, controls);
249        r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
250        return r;
251      }
252    
253    
254    
255      /**
256       * {@inheritDoc}
257       */
258      @Override()
259      public String getExtendedRequestName()
260      {
261        return INFO_EXTENDED_REQUEST_NAME_END_TXN.get();
262      }
263    
264    
265    
266      /**
267       * {@inheritDoc}
268       */
269      @Override()
270      public void toString(final StringBuilder buffer)
271      {
272        buffer.append("EndTransactionExtendedRequest(transactionID='");
273        buffer.append(transactionID.stringValue());
274        buffer.append("', commit=");
275        buffer.append(commit);
276    
277        final Control[] controls = getControls();
278        if (controls.length > 0)
279        {
280          buffer.append("controls={");
281          for (int i=0; i < controls.length; i++)
282          {
283            if (i > 0)
284            {
285              buffer.append(", ");
286            }
287    
288            buffer.append(controls[i]);
289          }
290          buffer.append('}');
291        }
292    
293        buffer.append(')');
294      }
295    }