001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2010-2015 ForgeRock AS.
026 */
027package org.opends.server.replication.server.changelog.je;
028
029import static org.opends.server.util.StaticUtils.*;
030
031import java.io.UnsupportedEncodingException;
032
033import org.forgerock.i18n.LocalizableMessage;
034import org.opends.server.replication.common.CSN;
035import org.opends.server.replication.server.changelog.api.ChangeNumberIndexRecord;
036import org.opends.server.replication.server.changelog.api.ChangelogException;
037import org.opends.server.types.DN;
038import org.opends.server.types.DirectoryException;
039
040import com.sleepycat.je.DatabaseEntry;
041
042/**
043 * Subclass of DatabaseEntry used for data stored in the DraftCNDB.
044 */
045public class DraftCNData extends DatabaseEntry
046{
047  private static final String FIELD_SEPARATOR = "!";
048  private static final String EMPTY_STRING_PREVIOUS_COOKIE = "";
049  private static final long serialVersionUID = 1L;
050
051  private long changeNumber;
052  private ChangeNumberIndexRecord record;
053
054  /**
055   * Creates a record to be stored in the DraftCNDB.
056   *
057   * @param changeNumber
058   *          the change number
059   * @param baseDN
060   *          The baseDN (domain DN)
061   * @param csn
062   *          The replication CSN
063   */
064  public DraftCNData(long changeNumber, DN baseDN, CSN csn)
065  {
066    this.changeNumber = changeNumber;
067    // Although the previous cookie is not used any more, we need
068    // to keep it in database for compatibility with previous versions
069    String record = EMPTY_STRING_PREVIOUS_COOKIE + FIELD_SEPARATOR + baseDN + FIELD_SEPARATOR + csn;
070    setData(getBytes(record));
071  }
072
073  /**
074   * Creates a record to be stored in the DraftCNDB from the provided byte[].
075   *
076   * @param changeNumber
077   *          the change number
078   * @param data
079   *          the provided byte[]
080   * @throws ChangelogException
081   *           if a database problem occurred
082   */
083  public DraftCNData(long changeNumber, byte[] data) throws ChangelogException
084  {
085    this.changeNumber = changeNumber;
086    this.record = decodeData(changeNumber, data);
087  }
088
089  /**
090   * Decode and returns a {@link ChangeNumberIndexRecord}.
091   *
092   * @param changeNumber
093   * @param data
094   *          the provided byte array.
095   * @return the decoded {@link ChangeNumberIndexRecord}
096   * @throws ChangelogException
097   *           when a problem occurs.
098   */
099  private ChangeNumberIndexRecord decodeData(long changeNumber, byte[] data)
100      throws ChangelogException
101  {
102    try
103    {
104      // Although the previous cookie is not used any more, we need
105      // to keep it in database for compatibility with previous versions
106      String stringData = new String(data, "UTF-8");
107      String[] str = stringData.split(FIELD_SEPARATOR, 3);
108      // str[0] contains previous cookie and is ignored
109      final DN baseDN = DN.valueOf(str[1]);
110      final CSN csn = new CSN(str[2]);
111      return new ChangeNumberIndexRecord(changeNumber, baseDN, csn);
112    }
113    catch (UnsupportedEncodingException e)
114    {
115      // should never happens
116      // TODO: i18n
117      throw new ChangelogException(LocalizableMessage.raw("need UTF-8 support"));
118    }
119    catch (DirectoryException e)
120    {
121      throw new ChangelogException(e);
122    }
123  }
124
125  /**
126   * Getter for the decoded record.
127   *
128   * @return the {@link ChangeNumberIndexRecord} record.
129   * @throws ChangelogException
130   *           when a problem occurs.
131   */
132  public ChangeNumberIndexRecord getRecord() throws ChangelogException
133  {
134    if (record == null)
135    {
136      record = decodeData(changeNumber, getData());
137    }
138    return record;
139  }
140
141  /**
142   * Provide a string representation of these data.
143   * @return the string representation of these data.
144   */
145  @Override
146  public String toString()
147  {
148    return "DraftCNData : [" + record + "]";
149  }
150
151}