001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     * 
010     *      http://www.apache.org/licenses/LICENSE-2.0
011     * 
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.oozie.util;
019    
020    import org.apache.hadoop.io.Writable;
021    import org.apache.hadoop.util.ReflectionUtils;
022    
023    import java.io.ByteArrayInputStream;
024    import java.io.ByteArrayOutputStream;
025    import java.io.DataInputStream;
026    import java.io.DataOutputStream;
027    import java.io.IOException;
028    import java.io.DataOutput;
029    import java.io.DataInput;
030    
031    /**
032     * Utility class to write/read Hadoop writables to/from a byte array.
033     */
034    public class WritableUtils {
035    
036        /**
037         * Write a writable to a byte array.
038         *
039         * @param writable writable to write.
040         * @return array containing the serialized writable.
041         */
042        public static byte[] toByteArray(Writable writable) {
043            try {
044                ByteArrayOutputStream baos = new ByteArrayOutputStream();
045                DataOutputStream daos = new DataOutputStream(baos);
046                writable.write(daos);
047                daos.close();
048                return baos.toByteArray();
049            }
050            catch (IOException ex) {
051                throw new RuntimeException(ex);
052            }
053        }
054    
055        /**
056         * Read a writable from a byte array.
057         *
058         * @param array byte array with the serialized writable.
059         * @param clazz writable class.
060         * @return writable deserialized from the byte array.
061         */
062        @SuppressWarnings("unchecked")
063        public static <T extends Writable> T fromByteArray(byte[] array, Class<T> clazz) {
064            try {
065                T o = (T) ReflectionUtils.newInstance(clazz, null);
066                o.readFields(new DataInputStream(new ByteArrayInputStream(array)));
067                return o;
068            }
069            catch (IOException ex) {
070                throw new RuntimeException(ex);
071            }
072        }
073    
074        private static final String NULL = "||";
075    
076        /**
077         * Write a string to a data output supporting <code>null</code> values. <p/> It uses the '||' token to represent
078         * <code>null</code>.
079         *
080         * @param dataOutput data output.
081         * @param str string to write.
082         * @throws IOException thrown if the string could not be written.
083         */
084        public static void writeStr(DataOutput dataOutput, String str) throws IOException {
085            str = (str != null) ? str : NULL;
086            dataOutput.writeUTF(str);
087        }
088    
089        /**
090         * Read a string from a data input supporting <code>null</code> values. <p/> It uses the '||' token to represent
091         * <code>null</code>.
092         *
093         * @param dataInput data input.
094         * @return read string, <code>null</code> if the '||' token was read.
095         * @throws IOException thrown if the string could not be read.
096         */
097        public static String readStr(DataInput dataInput) throws IOException {
098            String str = dataInput.readUTF();
099            return (str.equals(NULL)) ? null : str;
100        }
101    }