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-2016 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 */
032public class BinaryValue
033{
034  private Type type;
035  private String base64;
036  private byte[] bytes;
037  private File file;
038  private int hashCode;
039
040  /** The type of the binary value. */
041  public enum Type
042  {
043    /** The binary value is provided as Base 64 string. */
044    BASE64_STRING,
045    /** The binary value is provided as a byte array. */
046    BYTE_ARRAY
047  }
048
049  /** This is done to force the use of the factory methods (createBase64 and createFromFile). */
050  private BinaryValue()
051  {
052  }
053
054  /**
055   * Creates a binary value using a base64 string.
056   * @param base64 the base64 representation of the binary.
057   * @return the binary value.
058   * @throws ParseException if there is an error decoding the provided base64
059   * string.
060   */
061  public static BinaryValue createBase64(String base64) throws ParseException
062  {
063    BinaryValue value =  new BinaryValue();
064    value.type = Type.BASE64_STRING;
065    value.base64 = base64;
066    value.bytes = value.getBytes();
067    value.hashCode = base64.hashCode();
068    return value;
069  }
070
071  /**
072   * Creates a binary value using an array of bytes.
073   * @param bytes the byte array.
074   * @return the binary value.
075   */
076  public static BinaryValue createBase64(byte[] bytes)
077  {
078    BinaryValue value =  new BinaryValue();
079    value.type = Type.BASE64_STRING;
080    value.bytes = bytes;
081    value.base64 = value.getBase64();
082    value.hashCode = value.base64.hashCode();
083    return value;
084  }
085
086  /**
087   * Creates a binary value using an array of bytes and a file.
088   * @param bytes the bytes in the file.
089   * @param file the file the bytes were read from.
090   * @return the binary value.
091   */
092  public static BinaryValue createFromFile(byte[] bytes, File file)
093  {
094    BinaryValue value =  new BinaryValue();
095    value.type = Type.BYTE_ARRAY;
096    value.bytes = bytes;
097    value.base64 = value.getBase64();
098    value.hashCode = value.base64.hashCode();
099    value.file = file;
100    return value;
101  }
102
103  /**
104   * Returns the base64 representation of the binary value.
105   * @return the base64 representation of the binary value.
106   */
107  public String getBase64()
108  {
109    if (base64 == null && bytes != null)
110    {
111      base64 = Base64.encode(bytes);
112    }
113    return base64;
114  }
115
116  /**
117   * Returns the byte array of the binary value.
118   * @return the byte array of the binary value.
119   * @throws ParseException if this object was created using a base64 string
120   * and there was an error parsing it.
121   */
122  public byte[] getBytes() throws ParseException
123  {
124    if (bytes == null && base64 != null)
125    {
126      bytes = Base64.decode(base64);
127    }
128    return bytes;
129  }
130
131  /**
132   * Return the type of the binary value.
133   * @return the type of the binary value.
134   */
135  public Type getType()
136  {
137    return type;
138  }
139
140  /**
141   * Return the file that was used to read the binary value.
142   * @return the file that was used to read the binary value.
143   */
144  public File getFile()
145  {
146    return file;
147  }
148
149  @Override
150  public boolean equals(Object o)
151  {
152    if (this == o)
153    {
154      return true;
155    }
156    if (o instanceof BinaryValue)
157    {
158      BinaryValue candidate = (BinaryValue)o;
159      return candidate.getType() == getType()
160          && Objects.equals(file, candidate.getFile())
161          && bytesEqual(candidate);
162    }
163    return false;
164  }
165
166  private boolean bytesEqual(BinaryValue candidate)
167  {
168    if (type == Type.BASE64_STRING)
169    {
170      return candidate.getBase64().equals(getBase64());
171    }
172
173    try
174    {
175      if (candidate.getBytes().length != getBytes().length) {
176        return false;
177      }
178      boolean equals = true;
179      for (int i=0; i<getBytes().length && equals; i++)
180      {
181        equals = bytes[i] == candidate.getBytes()[i];
182      }
183      return equals;
184    }
185    catch (ParseException pe)
186    {
187      throw new RuntimeException(
188          "Unexpected error getting bytes: "+pe, pe);
189    }
190  }
191
192  @Override
193  public int hashCode()
194  {
195    return hashCode;
196  }
197}