Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * * Copyright 2013 Near Infinity Corporation. */ package com.nearinfinity.honeycomb.mysql; import com.google.common.collect.*; import com.nearinfinity.honeycomb.exceptions.RuntimeIOException; import com.nearinfinity.honeycomb.mysql.schema.IndexSchema; import org.apache.avro.io.*; import org.apache.log4j.Logger; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.UUID; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * Utility class containing helper functions. */ public class Util { public static final int UUID_WIDTH = 16; private static final Logger logger = Logger.getLogger(Util.class); /** * Returns a byte wide buffer from a {@link UUID}. * * @param uuid The {@link UUID} to convert * @return A byte array representation that is {@value #UUID_WIDTH} bytes wide */ public static byte[] UUIDToBytes(UUID uuid) { checkNotNull(uuid, "uuid must not be null."); return ByteBuffer.allocate(UUID_WIDTH).putLong(uuid.getMostSignificantBits()) .putLong(uuid.getLeastSignificantBits()).array(); } /** * Create a {@link UUID} from the provided byte array. * * @param bytes A byte array that must be {@value #UUID_WIDTH} bytes wide, not null * @return A {@link UUID} representation */ public static UUID bytesToUUID(byte[] bytes) { checkNotNull(bytes, "bytes must not be null."); checkArgument(bytes.length == UUID_WIDTH, "bytes must be of length " + UUID_WIDTH + "."); ByteBuffer buffer = ByteBuffer.wrap(bytes); return new UUID(buffer.getLong(), buffer.getLong()); } /** * Serialize an object to a byte array * * @param obj The object to serialize * @param writer The datum writer for the class * @return Serialized row */ public static <T> byte[] serializeAvroObject(T obj, DatumWriter<T> writer) { ByteArrayOutputStream out = new ByteArrayOutputStream(); Encoder encoder = EncoderFactory.get().binaryEncoder(out, null); try { writer.write(obj, encoder); encoder.flush(); } catch (IOException e) { throw serializationError(obj, e); } return out.toByteArray(); } /** * Deserialize the provided serialized data into an instance of the specified class type * * @param serializedData a buffer containing the serialized data * @param reader the datum reader for the class * @return A new instance of the specified class representing the deserialized data */ public static <T> T deserializeAvroObject(byte[] serializedData, DatumReader<T> reader) { checkNotNull(serializedData); checkNotNull(reader); Decoder binaryDecoder = DecoderFactory.get().binaryDecoder(serializedData, null); try { return reader.read(null, binaryDecoder); } catch (IOException e) { throw deserializationError(serializedData, e, null); } } /** * Create a hex string for a byte string. The string will be formatted {@code "A2BE"} * * @param bytes Byte string * @return Hex string */ public static String generateHexString(final byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } /** * Quietly close a {@link Closeable} suppressing the IOException thrown * * @param closeable Closeable */ public static void closeQuietly(Closeable closeable) { try { closeable.close(); } catch (IOException e) { logger.error(String.format("IOException thrown while closing resource of type %s", closeable.getClass().getName()), e); throw new RuntimeIOException(e); } } /** * Retrieve from a list of indices which ones have been changed. * * @param indices Table indices * @param oldRecords Old MySQL row * @param newRecords New MySQL row * @return List of changed indices */ public static ImmutableList<IndexSchema> getChangedIndices(Collection<IndexSchema> indices, Map<String, ByteBuffer> oldRecords, Map<String, ByteBuffer> newRecords) { if (indices.isEmpty()) { return ImmutableList.of(); } MapDifference<String, ByteBuffer> diff = Maps.difference(oldRecords, newRecords); Set<String> changedColumns = Sets.difference(Sets.union(newRecords.keySet(), oldRecords.keySet()), diff.entriesInCommon().keySet()); ImmutableList.Builder<IndexSchema> changedIndices = ImmutableList.builder(); for (IndexSchema index : indices) { Set<String> indexColumns = ImmutableSet.copyOf(index.getColumns()); if (!Sets.intersection(changedColumns, indexColumns).isEmpty()) { changedIndices.add(index); } } return changedIndices.build(); } private static <T> RuntimeException deserializationError(byte[] serializedData, IOException e, Class<T> clazz) { String clazzMessage = clazz == null ? "" : "of class type " + clazz.getName(); String format = String.format("Deserialization failed for data (%s) " + clazzMessage, Util.generateHexString(serializedData)); logger.error(format, e); return new RuntimeException(format, e); } private static <T> RuntimeException serializationError(T obj, IOException e) { String format = String.format("Serialization failed for data (%s) of class type %s", obj.toString(), obj.getClass().getName()); logger.error(format, e); return new RuntimeException(format, e); } }