/** * */ package meetup.beeno.util; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.TimeZone; import meetup.beeno.HDataTypes; import meetup.beeno.HDataTypes.DateTime; import meetup.beeno.HDataTypes.HField; import meetup.beeno.HDataTypes.JavaEnum; import meetup.beeno.HDataTypes.StringList; import meetup.beeno.HDataTypes.HField.Type; import org.apache.log4j.Logger; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; /** * Assorted utility methods for working with Google Protocol Buffers * * @author garyh * */ public class PBUtil { private static Logger log = Logger.getLogger(PBUtil.class); /* ********** Google Protocol Buffer versions for serialization *********** */ public static byte[] toBytes(Object val) { if (val == null) return null; Message pb = null; if (val.getClass().isArray() && val.getClass().getComponentType() == Byte.TYPE) { pb = toMessage( (byte[])val ); } else if (val instanceof Integer) { pb = toMessage( (Integer)val ); } else if (val instanceof Float) { pb = toMessage( (Float)val ); } else if (val instanceof Double) { pb = toMessage( (Double)val ); } else if (val instanceof Long) { pb = toMessage( (Long)val ); } else if (val instanceof String) { pb = toMessage( (String)val ); } else if (val instanceof Date) { pb = toMessage( (Date)val ); } else if (val instanceof Enum) { pb = toMessage( (Enum)val ); } else if (val instanceof Collection) { // assume it's a string collection for now! pb = toMessage( (Collection)val ); } else { // not handled log.warn(String.format("Unknown conversion to protobuf for property value type %s", val.getClass().getName())); return null; } if (pb != null) { // self describing message return pb.toByteArray(); } return null; } public static HDataTypes.HField readMessage(byte[] bytes) { if (bytes == null || bytes.length == 0) return null; // convert to the underlying message type HDataTypes.HField field = null; try { field = HDataTypes.HField.parseFrom(bytes); if (log.isDebugEnabled()) log.debug("Read field:\n"+field.toString()); } catch (InvalidProtocolBufferException e) { log.error("Invalid protocol buffer parsing bytes", e); } return field; } public static Object toValue(byte[] bytes) { HDataTypes.HField field = readMessage(bytes); if (field == null) return null; switch (field.getType()) { case TEXT: return field.getText(); case INTEGER: return field.getInteger(); case FLOAT: return field.getFloat(); case BOOLEAN: return field.getBoolean(); case BINARY: return field.getBinary().toByteArray(); case DATETIME: HDataTypes.DateTime dt = field.getDateTime(); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(dt.getTimestamp()); if (dt.hasTimezone()) cal.setTimeZone( TimeZone.getTimeZone(dt.getTimezone()) ); return cal.getTime(); case JAVAENUM: try { HDataTypes.JavaEnum en = field.getJavaEnum(); Class enumClass = Class.forName(en.getType()); return Enum.valueOf(enumClass, en.getValue()); } catch (Exception e) { log.error("Error instantiating field value for JavaEnum", e); } break; case STRINGLIST: return field.getStringList().getValuesList(); default: log.error("Unknown field type "+field.getType()); } return null; } public static HDataTypes.HField toMessage(String val) { return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.TEXT) .setText(val) .build(); } public static HDataTypes.HField toMessage(Integer val) { return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.INTEGER) .setInteger(val) .build(); } public static HDataTypes.HField toMessage(Long val) { return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.INTEGER) .setInteger(val) .build(); } public static HDataTypes.HField toMessage(Float val) { return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.FLOAT) .setFloat(val) .build(); } public static HDataTypes.HField toMessage(Double val) { return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.FLOAT) .setFloat(val) .build(); } public static HDataTypes.HField toMessage(Date val) { Calendar cal = Calendar.getInstance(); cal.setTime(val); HDataTypes.DateTime dt = HDataTypes.DateTime.newBuilder() .setTimestamp(cal.getTime().getTime()) .setTimezone(cal.getTimeZone().getID()) .build(); return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.DATETIME) .setDateTime(dt) .build(); } public static HDataTypes.HField toMessage(Boolean val) { return HDataTypes.HField.newBuilder() .setType(HDataTypes.HField.Type.BOOLEAN) .setBoolean(val) .build(); } public static HDataTypes.HField toMessage(byte[] val) { ByteString bytes = ByteString.copyFrom(val); return HDataTypes.HField.newBuilder() .setType( HDataTypes.HField.Type.BINARY ) .setBinary( bytes ) .build(); } public static HDataTypes.HField toMessage(Enum val) { HDataTypes.JavaEnum en = HDataTypes.JavaEnum.newBuilder() .setType( val.getClass().getName() ) .setValue( val.name() ) .build(); return HDataTypes.HField.newBuilder() .setType( HDataTypes.HField.Type.JAVAENUM ) .setJavaEnum( en ) .build(); } public static HDataTypes.HField toMessage(Collection<? extends String> vals) { HDataTypes.StringList list = HDataTypes.StringList.newBuilder() .addAllValues(vals) .build(); return HDataTypes.HField.newBuilder() .setType( HDataTypes.HField.Type.STRINGLIST ) .setStringList( list ) .build(); } }