001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2015 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.datamodel;
019
020import java.io.File;
021import java.text.ParseException;
022import java.util.Objects;
023
024import org.opends.server.util.Base64;
025
026/**
027 * Class used to represent Binary Values.  This is required in particular
028 * when the user wants to use the value in a file.  To be able to reflect
029 * this this object is used: it contains the binary itself, the base 64
030 * representation and the file that has been used.
031 *
032 */
033public class BinaryValue
034{
035  private Type type;
036  private String base64;
037  private byte[] bytes;
038  private File file;
039  private int hashCode;
040
041  /**
042   * The type of the binary value.
043   *
044   */
045  public enum Type
046  {
047    /**
048     * The binary value is provided as Base 64 string.
049     */
050    BASE64_STRING,
051    /**
052     * The binary value is provided as a byte array.
053     */
054    BYTE_ARRAY
055  }
056
057  /**
058   * This is done to force the use of the factory methods (createBase64 and
059   * createFromFile).
060   *
061   */
062  private BinaryValue()
063  {
064  }
065
066  /**
067   * Creates a binary value using a base64 string.
068   * @param base64 the base64 representation of the binary.
069   * @return the binary value.
070   * @throws ParseException if there is an error decoding the provided base64
071   * string.
072   */
073  public static BinaryValue createBase64(String base64) throws ParseException
074  {
075    BinaryValue value =  new BinaryValue();
076    value.type = Type.BASE64_STRING;
077    value.base64 = base64;
078    value.bytes = value.getBytes();
079    value.hashCode = base64.hashCode();
080    return value;
081  }
082
083  /**
084   * Creates a binary value using an array of bytes.
085   * @param bytes the byte array.
086   * @return the binary value.
087   */
088  public static BinaryValue createBase64(byte[] bytes)
089  {
090    BinaryValue value =  new BinaryValue();
091    value.type = Type.BASE64_STRING;
092    value.bytes = bytes;
093    value.base64 = value.getBase64();
094    value.hashCode = value.base64.hashCode();
095    return value;
096  }
097
098  /**
099   * Creates a binary value using an array of bytes and a file.
100   * @param bytes the bytes in the file.
101   * @param file the file the bytes were read from.
102   * @return the binary value.
103   */
104  public static BinaryValue createFromFile(byte[] bytes, File file)
105  {
106    BinaryValue value =  new BinaryValue();
107    value.type = Type.BYTE_ARRAY;
108    value.bytes = bytes;
109    value.base64 = value.getBase64();
110    value.hashCode = value.base64.hashCode();
111    value.file = file;
112    return value;
113  }
114
115  /**
116   * Returns the base64 representation of the binary value.
117   * @return the base64 representation of the binary value.
118   */
119  public String getBase64()
120  {
121    if (base64 == null && bytes != null)
122    {
123      base64 = Base64.encode(bytes);
124    }
125    return base64;
126  }
127
128  /**
129   * Returns the byte array of the binary value.
130   * @return the byte array of the binary value.
131   * @throws ParseException if this object was created using a base64 string
132   * and there was an error parsing it.
133   */
134  public byte[] getBytes() throws ParseException
135  {
136    if (bytes == null && base64 != null)
137    {
138      bytes = Base64.decode(base64);
139    }
140    return bytes;
141  }
142
143  /**
144   * Return the type of the binary value.
145   * @return the type of the binary value.
146   */
147  public Type getType()
148  {
149    return type;
150  }
151
152  /**
153   * Return the file that was used to read the binary value.
154   * @return the file that was used to read the binary value.
155   */
156  public File getFile()
157  {
158    return file;
159  }
160
161  /** {@inheritDoc} */
162  public boolean equals(Object o)
163  {
164    if (this == o)
165    {
166      return true;
167    }
168    if (o instanceof BinaryValue)
169    {
170      BinaryValue candidate = (BinaryValue)o;
171      return candidate.getType() == getType()
172          && Objects.equals(file, candidate.getFile())
173          && bytesEqual(candidate);
174    }
175    return false;
176  }
177
178  private boolean bytesEqual(BinaryValue candidate)
179  {
180    if (type == Type.BASE64_STRING)
181    {
182      return candidate.getBase64().equals(getBase64());
183    }
184
185    try
186    {
187      if (candidate.getBytes().length != getBytes().length) {
188        return false;
189      }
190      boolean equals = true;
191      for (int i=0; i<getBytes().length && equals; i++)
192      {
193        equals = bytes[i] == candidate.getBytes()[i];
194      }
195      return equals;
196    }
197    catch (ParseException pe)
198    {
199      throw new RuntimeException(
200          "Unexpected error getting bytes: "+pe, pe);
201    }
202  }
203
204  /** {@inheritDoc} */
205  public int hashCode()
206  {
207    return hashCode;
208  }
209}