package mil.nga.giat.geowave.core.store.memory; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.store.adapter.DataAdapter; import mil.nga.giat.geowave.core.store.adapter.IndexedAdapterPersistenceEncoding; import mil.nga.giat.geowave.core.store.adapter.WritableDataAdapter; import mil.nga.giat.geowave.core.store.base.DataStoreEntryInfo; import mil.nga.giat.geowave.core.store.base.DataStoreEntryInfo.FieldInfo; import mil.nga.giat.geowave.core.store.callback.IngestCallback; import mil.nga.giat.geowave.core.store.data.PersistentDataset; import mil.nga.giat.geowave.core.store.data.PersistentValue; import mil.nga.giat.geowave.core.store.data.VisibilityWriter; import mil.nga.giat.geowave.core.store.data.field.FieldReader; import mil.nga.giat.geowave.core.store.index.CommonIndexModel; import mil.nga.giat.geowave.core.store.index.CommonIndexValue; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.util.DataStoreUtils; public class MemoryStoreUtils { private final static Logger LOGGER = LoggerFactory.getLogger(MemoryStoreUtils.class); protected static boolean isAuthorized( final byte[] visibility, final String[] authorizations ) { if ((visibility == null) || (visibility.length == 0)) { return true; } VisibilityExpression expr; try { expr = new VisibilityExpressionParser().parse(visibility); } catch (final IOException e) { LOGGER.error( "invalid visibility", e); return false; } return expr.ok(authorizations); } protected static IndexedAdapterPersistenceEncoding getEncoding( final CommonIndexModel model, final DataAdapter<?> adapter, final MemoryEntryRow row ) { final PersistentDataset<CommonIndexValue> commonData = new PersistentDataset<CommonIndexValue>(); final PersistentDataset<byte[]> unknownData = new PersistentDataset<byte[]>(); final PersistentDataset<Object> extendedData = new PersistentDataset<Object>(); for (final FieldInfo column : row.info.getFieldInfo()) { final FieldReader<? extends CommonIndexValue> reader = model.getReader(column.getDataValue().getId()); if (reader == null) { final FieldReader extendedReader = adapter.getReader(column.getDataValue().getId()); if (extendedReader != null) { extendedData.addValue(column.getDataValue()); } else { unknownData.addValue(new PersistentValue<byte[]>( column.getDataValue().getId(), column.getWrittenValue())); } } else { commonData.addValue(column.getDataValue()); } } return new IndexedAdapterPersistenceEncoding( new ByteArrayId( row.getTableRowId().getAdapterId()), new ByteArrayId( row.getTableRowId().getDataId()), new ByteArrayId( row.getTableRowId().getInsertionId()), row.getTableRowId().getNumberOfDuplicates(), commonData, unknownData, extendedData); } protected static <T> List<MemoryEntryRow> entryToRows( final WritableDataAdapter<T> dataWriter, final PrimaryIndex index, final T entry, final IngestCallback<T> ingestCallback, final VisibilityWriter<T> customFieldVisibilityWriter ) { final DataStoreEntryInfo ingestInfo = DataStoreUtils.getIngestInfo( dataWriter, index, entry, customFieldVisibilityWriter); ingestCallback.entryIngested( ingestInfo, entry); return buildRows( dataWriter.getAdapterId().getBytes(), entry, ingestInfo); } private static <T> List<MemoryEntryRow> buildRows( final byte[] adapterId, final T entry, final DataStoreEntryInfo ingestInfo ) { final List<MemoryEntryRow> rows = new ArrayList<MemoryEntryRow>(); for (final ByteArrayId rowId : ingestInfo.getRowIds()) { rows.add(new MemoryEntryRow( rowId, entry, ingestInfo)); } return rows; } private abstract static class VisibilityExpression { public abstract boolean ok( String[] auths ); public VisibilityExpression and() { final AndExpression exp = new AndExpression(); exp.add(this); return exp; } public VisibilityExpression or() { final OrExpression exp = new OrExpression(); exp.add(this); return exp; } public abstract List<VisibilityExpression> children(); public abstract VisibilityExpression add( VisibilityExpression expression ); } public static enum NodeType { TERM, OR, AND, } private static class VisibilityExpressionParser { private int index = 0; private int parens = 0; public VisibilityExpressionParser() {} VisibilityExpression parse( final byte[] expression ) throws IOException { if (expression.length > 0) { final VisibilityExpression expr = parse_(expression); if (expr == null) { badArgumentException( "operator or missing parens", expression, index - 1); } if (parens != 0) { badArgumentException( "parenthesis mis-match", expression, index - 1); } return expr; } return null; } VisibilityExpression processTerm( final int start, final int end, final VisibilityExpression expr, final byte[] expression ) throws UnsupportedEncodingException { if (start != end) { if (expr != null) { badArgumentException( "expression needs | or &", expression, start); } return new ChildExpression( new String( Arrays.copyOfRange( expression, start, end), "UTF-8")); } if (expr == null) { badArgumentException( "empty term", Arrays.copyOfRange( expression, start, end), start); } return expr; } VisibilityExpression parse_( final byte[] expression ) throws IOException { VisibilityExpression result = null; VisibilityExpression expr = null; int termStart = index; while (index < expression.length) { switch (expression[index++]) { case '&': { expr = processTerm( termStart, index - 1, expr, expression); if (result != null) { if (!(result instanceof AndExpression)) { badArgumentException( "cannot mix & and |", expression, index - 1); } } else { result = new AndExpression(); } result.add(expr); expr = null; termStart = index; break; } case '|': { expr = processTerm( termStart, index - 1, expr, expression); if (result != null) { if (!(result instanceof OrExpression)) { badArgumentException( "cannot mix | and &", expression, index - 1); } } else { result = new OrExpression(); } result.add(expr); expr = null; termStart = index; break; } case '(': { parens++; if ((termStart != (index - 1)) || (expr != null)) { badArgumentException( "expression needs & or |", expression, index - 1); } expr = parse_(expression); termStart = index; break; } case ')': { parens--; final VisibilityExpression child = processTerm( termStart, index - 1, expr, expression); if ((child == null) && (result == null)) { badArgumentException( "empty expression not allowed", expression, index); } if (result == null) { return child; } result.add(child); return result; } } } final VisibilityExpression child = processTerm( termStart, index, expr, expression); if (result != null) { result.add(child); } else { result = child; } if (!(result instanceof ChildExpression)) { if (result.children().size() < 2) { badArgumentException( "missing term", expression, index); } } return result; } } public abstract static class CompositeExpression extends VisibilityExpression { protected final List<VisibilityExpression> expressions = new ArrayList<VisibilityExpression>(); @Override public VisibilityExpression add( final VisibilityExpression expression ) { if (expression.getClass().equals( this.getClass())) { for (final VisibilityExpression child : expression.children()) { add(child); } } else { expressions.add(expression); } return this; } } public static class ChildExpression extends VisibilityExpression { private final String value; public ChildExpression( final String value ) { super(); this.value = value; } @Override public boolean ok( final String[] auths ) { if (auths != null) { for (final String auth : auths) { if (value.equals(auth)) { return true; } } } return false; } @Override public List<VisibilityExpression> children() { return Collections.emptyList(); } @Override public VisibilityExpression add( final VisibilityExpression expression ) { return this; } } public static class AndExpression extends CompositeExpression { @Override public List<VisibilityExpression> children() { return expressions; } @Override public boolean ok( final String[] auth ) { for (final VisibilityExpression expression : expressions) { if (!expression.ok(auth)) { return false; } } return true; } public VisibilityExpression and( final VisibilityExpression expression ) { return this; } } public static class OrExpression extends CompositeExpression { @Override public boolean ok( final String[] auths ) { for (final VisibilityExpression expression : expressions) { if (expression.ok(auths)) { return true; } } return false; } @Override public List<VisibilityExpression> children() { return expressions; } public VisibilityExpression or( final VisibilityExpression expression ) { return this; } } private static final void badArgumentException( final String msg, final byte[] expression, final int place ) { throw new IllegalArgumentException( msg + " for " + Arrays.toString(expression) + " at " + place); } }