001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.util;
020
021import java.io.ByteArrayInputStream;
022import java.io.ByteArrayOutputStream;
023import java.io.DataInputStream;
024import java.io.DataOutputStream;
025import java.io.IOException;
026import java.util.ArrayList;
027import java.util.List;
028
029import org.apache.yetus.audience.InterfaceAudience;
030import org.apache.hadoop.io.DataInputBuffer;
031import org.apache.hadoop.io.Writable;
032
033/**
034 * Utility class with methods for manipulating Writable objects
035 */
036@InterfaceAudience.Private
037public class Writables {
038  /**
039   * @param w writable
040   * @return The bytes of <code>w</code> gotten by running its
041   * {@link Writable#write(java.io.DataOutput)} method.
042   * @throws IOException e
043   * @see #getWritable(byte[], Writable)
044   */
045  public static byte [] getBytes(final Writable w) throws IOException {
046    if (w == null) {
047      throw new IllegalArgumentException("Writable cannot be null");
048    }
049    ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
050    DataOutputStream out = new DataOutputStream(byteStream);
051    try {
052      w.write(out);
053      out.close();
054      out = null;
055      return byteStream.toByteArray();
056    } finally {
057      if (out != null) {
058        out.close();
059      }
060    }
061  }
062
063  /**
064   * Put a bunch of Writables as bytes all into the one byte array.
065   * @param ws writable
066   * @return The bytes of <code>w</code> gotten by running its
067   * {@link Writable#write(java.io.DataOutput)} method.
068   * @throws IOException e
069   */
070  public static byte [] getBytes(final Writable... ws) throws IOException {
071    List<byte []> bytes = new ArrayList<>(ws.length);
072    int size = 0;
073    for (Writable w: ws) {
074      byte [] b = getBytes(w);
075      size += b.length;
076      bytes.add(b);
077    }
078    byte [] result = new byte[size];
079    int offset = 0;
080    for (byte [] b: bytes) {
081      System.arraycopy(b, 0, result, offset, b.length);
082      offset += b.length;
083    }
084    return result;
085  }
086
087  /**
088   * Set bytes into the passed Writable by calling its
089   * {@link Writable#readFields(java.io.DataInput)}.
090   * @param bytes serialized bytes
091   * @param w An empty Writable (usually made by calling the null-arg
092   * constructor).
093   * @return The passed Writable after its readFields has been called fed
094   * by the passed <code>bytes</code> array or IllegalArgumentException
095   * if passed null or an empty <code>bytes</code> array.
096   * @throws IOException e
097   * @throws IllegalArgumentException
098   */
099  public static Writable getWritable(final byte [] bytes, final Writable w)
100  throws IOException {
101    return getWritable(bytes, 0, bytes.length, w);
102  }
103
104  /**
105   * Set bytes into the passed Writable by calling its
106   * {@link Writable#readFields(java.io.DataInput)}.
107   * @param bytes serialized bytes
108   * @param offset offset into array
109   * @param length length of data
110   * @param w An empty Writable (usually made by calling the null-arg
111   * constructor).
112   * @return The passed Writable after its readFields has been called fed
113   * by the passed <code>bytes</code> array or IllegalArgumentException
114   * if passed null or an empty <code>bytes</code> array.
115   * @throws IOException e
116   * @throws IllegalArgumentException
117   */
118  public static Writable getWritable(final byte [] bytes, final int offset,
119    final int length, final Writable w)
120  throws IOException {
121    if (bytes == null || length <=0) {
122      throw new IllegalArgumentException("Can't build a writable with empty " +
123        "bytes array");
124    }
125    if (w == null) {
126      throw new IllegalArgumentException("Writable cannot be null");
127    }
128    DataInputBuffer in = new DataInputBuffer();
129    try {
130      in.reset(bytes, offset, length);
131      w.readFields(in);
132      return w;
133    } finally {
134      in.close();
135    }
136  }
137
138  /**
139   * Copy one Writable to another.  Copies bytes using data streams.
140   * @param src Source Writable
141   * @param tgt Target Writable
142   * @return The target Writable.
143   * @throws IOException e
144   */
145  public static Writable copyWritable(final Writable src, final Writable tgt)
146  throws IOException {
147    return copyWritable(getBytes(src), tgt);
148  }
149
150  /**
151   * Copy one Writable to another.  Copies bytes using data streams.
152   * @param bytes Source Writable
153   * @param tgt Target Writable
154   * @return The target Writable.
155   * @throws IOException e
156   */
157  public static Writable copyWritable(final byte [] bytes, final Writable tgt)
158  throws IOException {
159    DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes));
160    try {
161      tgt.readFields(dis);
162    } finally {
163      dis.close();
164    }
165    return tgt;
166  }
167}