package mil.nga.giat.geowave.datastore.accumulo.util; import java.text.DateFormat; import java.text.FieldPosition; import java.text.ParsePosition; import java.util.Date; import java.util.Iterator; import java.util.Map.Entry; import mil.nga.giat.geowave.core.index.Persistable; import mil.nga.giat.geowave.core.index.PersistenceUtils; import mil.nga.giat.geowave.core.index.StringUtils; import mil.nga.giat.geowave.core.store.base.EntryRowID; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.security.ColumnVisibility; import org.apache.accumulo.core.util.format.Formatter; import org.apache.hadoop.io.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PersistentDataFormatter implements Formatter { private static final Logger LOGGER = LoggerFactory.getLogger(PersistentDataFormatter.class); public PersistentDataFormatter() { super(); } private Iterator<Entry<Key, Value>> si; private boolean doTimestamps; private static final ThreadLocal<DateFormat> formatter = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new DefaultDateFormat(); } class DefaultDateFormat extends DateFormat { private static final long serialVersionUID = 1L; @Override public StringBuffer format( Date date, StringBuffer toAppendTo, FieldPosition fieldPosition ) { toAppendTo.append(Long.toString(date.getTime())); return toAppendTo; } @Override public Date parse( String source, ParsePosition pos ) { return new Date( Long.parseLong(source)); } } }; @Override public void initialize( Iterable<Entry<Key, Value>> scanner, boolean printTimestamps ) { checkState(false); si = scanner.iterator(); doTimestamps = printTimestamps; } public boolean hasNext() { checkState(true); return si.hasNext(); } public String next() { DateFormat timestampFormat = null; if (doTimestamps) { timestampFormat = formatter.get(); } return next(timestampFormat); } protected String next( DateFormat timestampFormat ) { checkState(true); return formatEntry( si.next(), timestampFormat); } public void remove() { checkState(true); si.remove(); } protected void checkState( boolean expectInitialized ) { if (expectInitialized && si == null) throw new IllegalStateException( "Not initialized"); if (!expectInitialized && si != null) throw new IllegalStateException( "Already initialized"); } // this should be replaced with something like Record.toString(); public String formatEntry( Entry<Key, Value> entry, boolean showTimestamps ) { DateFormat timestampFormat = null; if (showTimestamps) { timestampFormat = formatter.get(); } return formatEntry( entry, timestampFormat); } /* * so a new date object doesn't get created for every record in the scan * result */ private static ThreadLocal<Date> tmpDate = new ThreadLocal<Date>() { @Override protected Date initialValue() { return new Date(); } }; public String formatEntry( Entry<Key, Value> entry, DateFormat timestampFormat ) { StringBuilder sb = new StringBuilder(); StringBuilder sbInsertion = new StringBuilder(); Key key = entry.getKey(); EntryRowID rowId = new EntryRowID( key.getRow().getBytes()); byte[] insertionIdBytes; insertionIdBytes = rowId.getInsertionId(); for (byte b : insertionIdBytes) { sbInsertion.append(String.format( "%02x", b)); } Text insertionIdText = new Text( sbInsertion.toString()); Text adapterIdText = new Text( StringUtils.stringFromBinary(rowId.getAdapterId())); Text dataIdText = new Text( StringUtils.stringFromBinary(rowId.getDataId())); Text duplicatesText = new Text( Integer.toString(rowId.getNumberOfDuplicates())); // append insertion Id appendText( sb, insertionIdText).append( " "); // append adapterId appendText( sb, adapterIdText).append( " "); // append dataId appendText( sb, dataIdText).append( " "); // append numberOfDuplicates appendText( sb, duplicatesText).append( " "); // append column family appendText( sb, key.getColumnFamily()).append( ":"); // append column qualifier appendText( sb, key.getColumnQualifier()).append( " "); // append visibility expression sb.append(new ColumnVisibility( key.getColumnVisibility())); // append timestamp if (timestampFormat != null) { tmpDate.get().setTime( entry.getKey().getTimestamp()); sb.append( " ").append( timestampFormat.format(tmpDate.get())); } Value value = entry.getValue(); // append value if (value != null && value.getSize() > 0) { sb.append("\t"); appendValue( sb, value); } return sb.toString(); } private static StringBuilder appendText( StringBuilder sb, Text t ) { appendBytes( sb, t.getBytes(), 0, t.getLength()); return sb; } public void appendValue( StringBuilder sb, Value value ) { try { Persistable persistable = PersistenceUtils.fromBinary( value.get(), Persistable.class); sb.append(persistable.toString()); } catch (Exception ex) { LOGGER.info( "Exception caught", ex); appendBytes( sb, value.get(), 0, value.get().length); } } private static void appendBytes( StringBuilder sb, byte ba[], int offset, int len ) { for (int i = 0; i < len; i++) { int c = 0xff & ba[offset + i]; if (c == '\\') sb.append("\\\\"); else if (c >= 32 && c <= 126) sb.append((char) c); else sb.append( "\\x").append( String.format( "%02X", c)); } } public Iterator<Entry<Key, Value>> getScannerIterator() { return si; } protected boolean isDoTimestamps() { return doTimestamps; } }