Package net.floodlightcontroller.storage.nosql

Source Code of net.floodlightcontroller.storage.nosql.NoSqlStorageSource

/**
*    Copyright 2011, Big Switch Networks, Inc.
*    Originally created by David Erickson, Stanford University
*
*    Licensed 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.
**/

package net.floodlightcontroller.storage.nosql;

import java.lang.Class;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.floodlightcontroller.storage.AbstractStorageSource;
import net.floodlightcontroller.storage.CompoundPredicate;
import net.floodlightcontroller.storage.IPredicate;
import net.floodlightcontroller.storage.IQuery;
import net.floodlightcontroller.storage.IResultSet;
import net.floodlightcontroller.storage.OperatorPredicate;
import net.floodlightcontroller.storage.RowOrdering;
import net.floodlightcontroller.storage.StorageException;
import net.floodlightcontroller.storage.StorageSourceNotification;
import net.floodlightcontroller.storage.TypeMismatchStorageException;

public abstract class NoSqlStorageSource extends AbstractStorageSource {
    protected static Logger log = LoggerFactory.getLogger(NoSqlStorageSource.class);

    public enum ColumnIndexMode { NOT_INDEXED, RANGE_INDEXED, EQUALITY_INDEXED };
   
    protected static final String DEFAULT_PRIMARY_KEY_NAME = "id";
   
    private Map<String,String> tablePrimaryKeyMap = new HashMap<String,String>();
    private Map<String, Map<String,ColumnIndexMode>> tableIndexedColumnMap =
        new HashMap<String,Map<String,ColumnIndexMode>>();
   
    abstract static class NoSqlPredicate {

        public boolean incorporateComparison(String columnName,
                OperatorPredicate.Operator operator, Comparable<?> value,
                CompoundPredicate.Operator parentOperator) {
            return false;
        }
       
        public boolean canExecuteEfficiently() {
            return false;
        }
       
        public List<Map<String,Object>> execute(String[] columnNames) {
            assert(false);
            return null;
        }
       
        abstract public boolean matchesRow(Map<String,Object> row);
    }
   
    @SuppressWarnings({ "unchecked", "rawtypes" })
    static class NoSqlRangePredicate extends NoSqlPredicate {
        NoSqlStorageSource storageSource;
        String tableName;
        String columnName;
        Comparable<?> startValue;
        boolean startInclusive;
        Comparable<?> endValue;
        boolean endInclusive;
       
        NoSqlRangePredicate(NoSqlStorageSource storageSource, String tableName,
                String columnName, Comparable<?> startValue, boolean startInclusive,
                Comparable<?> endValue, boolean endInclusive) {
            this.storageSource = storageSource;
            this.tableName = tableName;
            this.columnName = columnName;
            this.startValue = startValue;
            this.startInclusive = startInclusive;
            this.endValue = endValue;
            this.endInclusive = endInclusive;
        }
       
        public boolean incorporateComparison(String columnName,
                OperatorPredicate.Operator operator, Comparable<?> value,
                CompoundPredicate.Operator parentOperator) {
           
            assert(operator != null);
            assert(parentOperator != null);
           
            // Must be the same column to incorporate
            if (!this.columnName.equals(columnName))
                return false;
           
            // The only time we allow a null value is if it's an EQ operator.
            // In that case we can only incorporate if this predicate is also
            // a null equality predicate.
            if (value == null) {
                return ((operator == OperatorPredicate.Operator.EQ) &&
                        (startValue == null) && (endValue == null) &&
                        startInclusive && endInclusive);
            }
           
            // Don't incorporate parameterized values
            if (value instanceof String) {
                String s = (String)value;
                if (s.startsWith("?") && s.endsWith("?")) {
                    return false;
                }
            }
           
            if (parentOperator == CompoundPredicate.Operator.AND) {
                switch (operator) {
                case EQ:
                    if (matchesValue(value)) {
                        startValue = endValue = value;
                        startInclusive = endInclusive = true;
                        return true;
                    }
                    break;
                case LT:
                    if ((endValue == null) || (((Comparable)value).compareTo(endValue) <= 0)) {
                        endValue = value;
                        endInclusive = false;
                        return true;
                    }
                    break;
                case LTE:
                    if ((endValue == null) || (((Comparable)value).compareTo(endValue) < 0)) {
                        endValue = value;
                        endInclusive = true;
                        return true;
                    }
                    break;
                case GT:
                    if ((startValue == null) || (((Comparable)value).compareTo(startValue) >= 0)) {
                        startValue = value;
                        startInclusive = false;
                        return true;
                    }
                    break;
                case GTE:
                    if ((startValue == null) || (((Comparable)value).compareTo(startValue) > 0)) {
                        startValue = value;
                        startInclusive = true;
                        return true;
                    }
                    break;
                }
            } else {
                switch (operator) {
                case EQ:
                    if (matchesValue(value))
                        return true;
                    break;
                case LT:
                    if ((endValue == null) || (((Comparable)value).compareTo(endValue) > 0)) {
                        endValue = value;
                        endInclusive = false;
                        return true;
                    }
                    break;
                case LTE:
                    if ((endValue == null) || (((Comparable)value).compareTo(endValue) >= 0)) {
                        endValue = value;
                        endInclusive = true;
                        return true;
                    }
                    break;
                case GT:
                    if ((startValue == null) || (((Comparable)value).compareTo(startValue) < 0)) {
                        startValue = value;
                        startInclusive = false;
                        return true;
                    }
                    break;
                case GTE:
                    if ((startValue == null) || (((Comparable)value).compareTo(startValue) <= 0)) {
                        startValue = value;
                        startInclusive = true;
                        return true;
                    }
                    break;
                }
            }
           
            return false;
        }

        private boolean isEqualityRange() {
            return (startValue == endValue) && startInclusive && endInclusive;
        }
       
        public boolean canExecuteEfficiently() {
            ColumnIndexMode indexMode = storageSource.getColumnIndexMode(tableName, columnName);
            switch (indexMode) {
            case NOT_INDEXED:
                return false;
            case RANGE_INDEXED:
                return true;
            case EQUALITY_INDEXED:
                return isEqualityRange();
            }
            return true;
        }

        public List<Map<String,Object>> execute(String columnNameList[]) {
            List<Map<String,Object>> rowList;
            if (isEqualityRange())
                rowList = storageSource.executeEqualityQuery(tableName, columnNameList, columnName, startValue);
            else
                rowList = storageSource.executeRangeQuery(tableName, columnNameList, columnName,
                        startValue, startInclusive, endValue, endInclusive);
               
            return rowList;
        }
       
        Comparable<?> coerceValue(Comparable<?> value, Class targetClass) {
           
            if (value == null)
                return null;
           
            if (value.getClass() == targetClass)
                return value;
           
            // FIXME: For now we convert by first converting the source value to a
            // string and then converting to the target type. This logic probably needs
            // another pass to make it more robust/optimized.
           
            String s = value.toString();
            Comparable<?> obj = null;
           
            try {
                if (targetClass == Integer.class) {
                    obj = new Integer(s);
                } else if (targetClass == Long.class) {
                    obj = new Long(s);
                } else if (targetClass == Short.class) {
                    obj = new Short(s);
                } else if (targetClass == Boolean.class) {
                    obj = new Boolean(s);
                } else if (targetClass == Float.class) {
                    obj = new Float(s);
                } else if (targetClass == Double.class) {
                    obj = new Double(s);
                } else if (targetClass == Byte.class) {
                    obj = new Byte(s);
                } else if (targetClass == String.class) {
                    obj = s;
                } else if (targetClass == Date.class) {
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                    dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
                    try {
                        obj = dateFormat.parse(s);
                    }
                    catch (ParseException exc) {
                        throw new TypeMismatchStorageException(Date.class.getName(), value.getClass().getName(), "???");
                    }
                }
            }
            catch (Exception exc) {
                // Ignore the exception here. In this case obj will not be set, so we'll
                // throw the StorageException below when we check for a null obj.
            }
           
            if (obj == null)
                throw new StorageException("Column value could not be coerced to the correct type");
           
            return obj;
        }
       
        boolean matchesValue(Comparable<?> value) {
            boolean isNullEqPredicate = (startValue == null) && (endValue == null) && startInclusive && endInclusive;
            if (value == null)
                return isNullEqPredicate;

            if (isNullEqPredicate)
                return false;
           
            int result;
            Comparable<?> coercedValue;
            if (startValue != null) {
                coercedValue = coerceValue(value, startValue.getClass());
                result = ((Comparable)coercedValue).compareTo(startValue);
                if ((result < 0) || (!startInclusive && (result == 0)))
                    return false;
            }
            if (endValue != null) {
                coercedValue = coerceValue(value, endValue.getClass());
                result = ((Comparable)coercedValue).compareTo(endValue);
                if ((result > 0) || (!endInclusive && (result == 0)))
                    return false;
            }
            return true;
        }
       
        public boolean matchesRow(Map<String,Object> row) {
            Comparable value = (Comparable)row.get(columnName);
            return matchesValue(value);
        }
    }
   
    static class NoSqlOperatorPredicate extends NoSqlPredicate {
       
        NoSqlStorageSource storageSource;
        String columnName;
        OperatorPredicate.Operator operator;
        Object value;
       
        NoSqlOperatorPredicate(NoSqlStorageSource storageSource, String columnName,
                OperatorPredicate.Operator operator, Object value) {
            this.storageSource = storageSource;
            this.columnName = columnName;
            this.operator = operator;
            this.value = value;
        }

        public boolean incorporateComparison(String columnName,
                OperatorPredicate.Operator operator, Comparable<?> value,
                CompoundPredicate.Operator parentOperator) {
            return false;
        }

        public boolean canExecuteEfficiently() {
            return false;
        }

        public List<Map<String,Object>> execute(String columnNames[]) {
            throw new StorageException("Unimplemented predicate.");
        }
       
        public boolean matchesRow(Map<String,Object> row) {
            return false;
        }
    }
   
    static class NoSqlCompoundPredicate extends NoSqlPredicate {
       
        NoSqlStorageSource storageSource;
        CompoundPredicate.Operator operator;
        boolean negated;
        String tableName;
        List<NoSqlPredicate> predicateList;
       
        NoSqlCompoundPredicate(NoSqlStorageSource storageSource, String tableName,
                CompoundPredicate.Operator operator, boolean negated,
                List<NoSqlPredicate> predicateList) {
            this.storageSource = storageSource;
            this.tableName = tableName;
            this.operator = operator;
            this.negated = negated;
            this.predicateList = predicateList;
        }

        public boolean incorporateComparison(String columnName,
                OperatorPredicate.Operator operator, Comparable<?> value,
                CompoundPredicate.Operator parentOperator) {
            // It may be possible to incorporate other operator predicate into this one,
            // but it would need to take into account the negated attribute and I'd need
            // to think about it some more to make sure it was correct, so for now we just
            // disallow incorporation
            //if (parentOperator == this.operator) {
            //    for (NoSqlPredicate predicate: predicateList) {
            //        if (predicate.incorporateComparison(columnName, operator, value, parentOperator))
            //            return true;
            //    }
            //}
            return false;
        }

        public boolean canExecuteEfficiently() {
            if (operator == CompoundPredicate.Operator.AND) {
                for (NoSqlPredicate predicate: predicateList) {
                    if (predicate.canExecuteEfficiently()) {
                        return true;
                    }
                }
                return false;
            } else {
                for (NoSqlPredicate predicate: predicateList) {
                    if (!predicate.canExecuteEfficiently()) {
                        return false;
                    }
                }
                return true;
            }
        }

        @SuppressWarnings({ "unchecked", "rawtypes" })
        static class RowComparator implements Comparator<Map<String,Object>> {
            private String primaryKeyName;
           
            public RowComparator(String primaryKeyName) {
                this.primaryKeyName = primaryKeyName;
            }
           
            public int compare(Map<String,Object> row1, Map<String,Object> row2) {
                Comparable key1 = (Comparable)row1.get(primaryKeyName);
                Comparable key2 = (Comparable)row2.get(primaryKeyName);
                return key1.compareTo(key2);
            }
           
            public boolean equals(Object obj) {
                if (!(obj instanceof RowComparator))
                    return false;
                RowComparator rc = (RowComparator)obj;
                if (rc.primaryKeyName == null)
                    return this.primaryKeyName == null;
                return rc.primaryKeyName.equals(this.primaryKeyName);
            }
        }

        @SuppressWarnings({ "unchecked", "rawtypes" })
        private List<Map<String,Object>> combineRowLists(String primaryKeyName,
                List<Map<String,Object>> list1, List<Map<String,Object>> list2,
                CompoundPredicate.Operator operator) {
            ArrayList<Map<String,Object>> combinedRowList = new ArrayList<Map<String,Object>>();
            RowComparator rc = new RowComparator(primaryKeyName);
            Collections.sort(list1, rc);
            Collections.sort(list2,rc);
           
            Iterator<Map<String,Object>> iterator1 = list1.iterator();
            Iterator<Map<String,Object>> iterator2 = list2.iterator();
            boolean update1 = true;
            boolean update2 = true;
            Map<String,Object> row1 = null;
            Map<String,Object> row2 = null;
            Comparable<?> key1 = null;
            Comparable<?> key2 = null;
           
            while (true) {
                if (update1) {
                    if (iterator1.hasNext()) {
                        row1 = iterator1.next();
                        key1 = (Comparable<?>)row1.get(primaryKeyName);
                    } else {
                        row1 = null;
                    }
                }
                if (update2) {
                    if (iterator2.hasNext()) {
                        row2 = iterator2.next();
                        key2 = (Comparable<?>)row2.get(primaryKeyName);
                    } else {
                        row2 = null;
                    }
                }
                update1 = update2 = false;
                if (operator == CompoundPredicate.Operator.AND) {
                    if ((row1 == null) || (row2 == null))
                        break;
                    int result = ((Comparable)key1).compareTo(key2);
                    if (result == 0) {
                        combinedRowList.add(row1);
                        update1 = update2 = true;
                    } else if (result < 0) {
                        update1 = true;
                    } else {
                        update2 = true;
                    }
                } else {
                    if (row1 != null) {
                        if (row2 != null) {
                            int result = ((Comparable)key1).compareTo(key2);
                            if (result <= 0) {
                                combinedRowList.add(row1);
                                update1 = true;
                                update2 = (result == 0);
                            } else {
                                combinedRowList.add(row2);
                                update2 = true;
                            }
                        } else {
                            combinedRowList.add(row1);
                            update1 = true;
                        }
                    } else if (row2 != null) {
                        combinedRowList.add(row2);
                        update2 = true;
                    } else {
                        break;
                    }
                }
            }
           
            return combinedRowList;
        }
       
        public List<Map<String,Object>> execute(String columnNames[]) {
            List<Map<String,Object>> combinedRowList = null;
            Set<NoSqlPredicate> inefficientPredicates = new HashSet<NoSqlPredicate>();
            for (NoSqlPredicate predicate: predicateList) {
                if (predicate.canExecuteEfficiently()) {
                    List<Map<String,Object>> rowList = predicate.execute(columnNames);
                    if (combinedRowList != null) {
                        String primaryKeyName = storageSource.getTablePrimaryKeyName(tableName);
                        combinedRowList = combineRowLists(primaryKeyName,
                                combinedRowList, rowList, operator);
                    } else {
                        combinedRowList = rowList;
                    }
                } else {
                    inefficientPredicates.add(predicate);
                }
            }

            if (inefficientPredicates.isEmpty())
                return combinedRowList;

            List<Map<String,Object>> filteredRowList = new ArrayList<Map<String,Object>>();
            for (Map<String,Object> row: combinedRowList) {
                for (NoSqlPredicate predicate: inefficientPredicates) {
                    if (predicate.matchesRow(row)) {
                        filteredRowList.add(row);
                    }
                }
            }

            return filteredRowList;
        }

        public boolean matchesRow(Map<String,Object> row) {
            if (operator == CompoundPredicate.Operator.AND) {
                for (NoSqlPredicate predicate : predicateList) {
                    if (!predicate.matchesRow(row))  {
                        return false;
                    }
                }
                return true;
            } else {
                for (NoSqlPredicate predicate : predicateList) {
                    if (predicate.matchesRow(row))  {
                        return true;
                    }
                }
                return false;
               
            }
        }
    }
   
    public NoSqlStorageSource() {
        super();
    }
   
    @Override
    public void createTable(String tableName, Set<String> indexedColumns) {
        super.createTable(tableName, indexedColumns);
        if (indexedColumns == null) return;
        for (String columnName : indexedColumns) {
            setColumnIndexMode(tableName, columnName,
                               ColumnIndexMode.EQUALITY_INDEXED);
        }
    }

    public void setTablePrimaryKeyName(String tableName, String primaryKeyName) {
        if ((tableName == null) || (primaryKeyName == null))
            throw new NullPointerException();
        tablePrimaryKeyMap.put(tableName, primaryKeyName);
    }
   
    protected String getTablePrimaryKeyName(String tableName) {
        String primaryKeyName = tablePrimaryKeyMap.get(tableName);
        if (primaryKeyName == null)
            primaryKeyName = DEFAULT_PRIMARY_KEY_NAME;
        return primaryKeyName;
    }
   
    protected ColumnIndexMode getColumnIndexMode(String tableName, String columnName) {
        ColumnIndexMode columnIndexMode = null;
        Map<String, ColumnIndexMode> indexedColumnMap = tableIndexedColumnMap.get(tableName);
        if (indexedColumnMap != null)
            columnIndexMode = indexedColumnMap.get(columnName);
        if (columnIndexMode == null)
            return ColumnIndexMode.NOT_INDEXED;
        return columnIndexMode;
    }
   
    public void setColumnIndexMode(String tableName, String columnName, ColumnIndexMode indexMode) {
        Map<String, ColumnIndexMode> indexedColumnMap = tableIndexedColumnMap.get(tableName);
        if (indexedColumnMap == null) {
            indexedColumnMap = new HashMap<String,ColumnIndexMode>();
            tableIndexedColumnMap.put(tableName, indexedColumnMap);
        }
        indexedColumnMap.put(columnName, indexMode);
    }
   
    Comparable<?> getOperatorPredicateValue(OperatorPredicate predicate, Map<String,Comparable<?>> parameterMap) {
        Comparable<?> value = predicate.getValue();
        if (value instanceof String) {
            String stringValue = (String) value;
            if ((stringValue.charAt(0) == '?') && (stringValue.charAt(stringValue.length()-1) == '?')) {
                String parameterName = stringValue.substring(1,stringValue.length()-1);
                value = parameterMap.get(parameterName);
            }
        }
        return value;
    }
   
    NoSqlPredicate convertPredicate(IPredicate predicate, String tableName, Map<String,Comparable<?>> parameterMap) {
        if (predicate == null)
            return null;
        NoSqlPredicate convertedPredicate = null;
        if (predicate instanceof CompoundPredicate) {
            CompoundPredicate compoundPredicate = (CompoundPredicate)predicate;
            ArrayList<NoSqlPredicate> noSqlPredicateList = new ArrayList<NoSqlPredicate>();
            for (IPredicate childPredicate: compoundPredicate.getPredicateList()) {
                boolean incorporated = false;
                if (childPredicate instanceof OperatorPredicate) {
                    OperatorPredicate childOperatorPredicate = (OperatorPredicate)childPredicate;
                    for (NoSqlPredicate childNoSqlPredicate: noSqlPredicateList) {
                        incorporated = childNoSqlPredicate.incorporateComparison(
                                childOperatorPredicate.getColumnName(), childOperatorPredicate.getOperator(),
                                getOperatorPredicateValue(childOperatorPredicate, parameterMap),
                                compoundPredicate.getOperator());
                        if (incorporated)
                            break;
                    }
                }
                if (!incorporated) {
                    NoSqlPredicate noSqlPredicate = convertPredicate(childPredicate, tableName, parameterMap);
                    noSqlPredicateList.add(noSqlPredicate);
                }
            }
            convertedPredicate = new NoSqlCompoundPredicate(this, tableName,
                    compoundPredicate.getOperator(),
                    compoundPredicate.isNegated(), noSqlPredicateList);
        } else if (predicate instanceof OperatorPredicate) {
            OperatorPredicate operatorPredicate = (OperatorPredicate) predicate;
            Comparable<?> value = getOperatorPredicateValue(operatorPredicate, parameterMap);
            switch (operatorPredicate.getOperator()) {
            case EQ:
                convertedPredicate = new NoSqlRangePredicate(this, tableName,
                        operatorPredicate.getColumnName(), value, true, value, true);
                break;
            case LT:
                convertedPredicate = new NoSqlRangePredicate(this, tableName,
                        operatorPredicate.getColumnName(), null, false, value, false);
                break;
            case LTE:
                convertedPredicate = new NoSqlRangePredicate(this, tableName,
                        operatorPredicate.getColumnName(), null, false, value, true);
                break;
            case GT:
                convertedPredicate = new NoSqlRangePredicate(this, tableName,
                        operatorPredicate.getColumnName(), value, false, null, false);
                break;
            case GTE:
                convertedPredicate = new NoSqlRangePredicate(this, tableName,
                        operatorPredicate.getColumnName(), value, true, null, false);
                break;
            default:
                convertedPredicate = new NoSqlOperatorPredicate(this, operatorPredicate.getColumnName(),
                        operatorPredicate.getOperator(), value);
            }
        } else {
            throw new StorageException("Unknown predicate type");
        }
       
        return convertedPredicate;
    }
   
    @SuppressWarnings({ "unchecked", "rawtypes" })
    class RowComparator implements Comparator<Map<String,Object>> {
        private RowOrdering rowOrdering;
       
        public RowComparator(RowOrdering rowOrdering) {
            this.rowOrdering = rowOrdering;
        }
       
        public int compare(Map<String,Object> row1, Map<String,Object> row2) {
            if (rowOrdering == null)
                return 0;
           
            for (RowOrdering.Item item: rowOrdering.getItemList()) {
                Comparable key1 = (Comparable)row1.get(item.getColumn());
                Comparable key2 = (Comparable)row2.get(item.getColumn());
                int result = key1.compareTo(key2);
                if (result != 0) {
                    if (item.getDirection() == RowOrdering.Direction.DESCENDING)
                        result = -result;
                    return result;
                }
            }
           
            return 0;
        }
       
        public boolean equals(Object obj) {
            if (!(obj instanceof RowComparator))
                return false;
            RowComparator rc = (RowComparator)obj;
            if (rc.rowOrdering == null)
                return this.rowOrdering == null;
            return rc.rowOrdering.equals(this.rowOrdering);
        }
    }
   
    private NoSqlResultSet executeParameterizedQuery(String tableName, String[] columnNameList,
            IPredicate predicate, RowOrdering rowOrdering, Map<String,Comparable<?>> parameterMap) {
        NoSqlPredicate noSqlPredicate = convertPredicate(predicate, tableName, parameterMap);
        List<Map<String,Object>> rowList;
        if ((noSqlPredicate != null) && noSqlPredicate.canExecuteEfficiently()) {
            rowList = noSqlPredicate.execute(columnNameList);
        } else {
            rowList = new ArrayList<Map<String,Object>>();
            Collection<Map<String,Object>> allRowList = getAllRows(tableName, columnNameList);
            for (Map<String,Object> row: allRowList) {
                if ((noSqlPredicate == null) || noSqlPredicate.matchesRow(row)) {
                    rowList.add(row);
                }
            }
        }
        if (rowOrdering != null)
            Collections.sort(rowList, new RowComparator(rowOrdering));
           
        return new NoSqlResultSet(this, tableName, rowList);
    }
   
    @Override
    public IQuery createQuery(String tableName, String[] columnNameList,
            IPredicate predicate, RowOrdering rowOrdering) {
        return new NoSqlQuery(tableName, columnNameList, predicate, rowOrdering);
    }

    @Override
    public IResultSet executeQueryImpl(IQuery query) {
        NoSqlQuery noSqlQuery = (NoSqlQuery) query;
        return executeParameterizedQuery(noSqlQuery.getTableName(),
                noSqlQuery.getColumnNameList(), noSqlQuery.getPredicate(),
                noSqlQuery.getRowOrdering(), noSqlQuery.getParameterMap());
    }

    protected void sendNotification(String tableName, StorageSourceNotification.Action action,
            List<Map<String,Object>> rows) {
        Set<Object> rowKeys = new HashSet<Object>();
        String primaryKeyName = getTablePrimaryKeyName(tableName);
        for (Map<String,Object> row : rows) {
            Object rowKey = row.get(primaryKeyName);
            rowKeys.add(rowKey);
        }
        StorageSourceNotification notification =
            new StorageSourceNotification(tableName, action, rowKeys);
        notifyListeners(notification);
    }
   
    protected void sendNotification(String tableName,
            StorageSourceNotification.Action action, Set<Object> rowKeys) {
        StorageSourceNotification notification =
            new StorageSourceNotification(tableName, action, rowKeys);
        notifyListeners(notification);
    }
   
    protected void insertRowsAndNotify(String tableName, List<Map<String,Object>> insertRowList) {
        insertRows(tableName, insertRowList);
        sendNotification(tableName, StorageSourceNotification.Action.MODIFY, insertRowList);
    }

    @Override
    public void insertRowImpl(String tableName, Map<String, Object> values) {
        ArrayList<Map<String,Object>> rowList = new ArrayList<Map<String,Object>>();
        rowList.add(values);
        insertRowsAndNotify(tableName, rowList);
    }

    protected void updateRowsAndNotify(String tableName, Set<Object> rowKeys, Map<String,Object> updateRowList) {
        updateRows(tableName, rowKeys, updateRowList);
        sendNotification(tableName, StorageSourceNotification.Action.MODIFY, rowKeys);
    }

    protected void updateRowsAndNotify(String tableName, List<Map<String,Object>> updateRowList) {
        updateRows(tableName, updateRowList);
        sendNotification(tableName, StorageSourceNotification.Action.MODIFY, updateRowList);
    }

    @Override
    public void updateMatchingRowsImpl(String tableName, IPredicate predicate, Map<String,Object> values) {
        String primaryKeyName = getTablePrimaryKeyName(tableName);
        String[] columnNameList = {primaryKeyName};
        IResultSet resultSet = executeQuery(tableName, columnNameList, predicate, null);
        Set<Object> rowKeys = new HashSet<Object>();
        while (resultSet.next()) {
            String rowKey = resultSet.getString(primaryKeyName);
            rowKeys.add(rowKey);
        }
        updateRowsAndNotify(tableName, rowKeys, values);
    }
   
    @Override
    public void updateRowImpl(String tableName, Object rowKey, Map<String,Object> values) {
        Map<String,Object> valuesWithKey = new HashMap<String,Object>(values);
        String primaryKeyName = getTablePrimaryKeyName(tableName);
        valuesWithKey.put(primaryKeyName, rowKey);
        List<Map<String,Object>> rowList = new ArrayList<Map<String,Object>>();
        rowList.add(valuesWithKey);
        updateRowsAndNotify(tableName, rowList);
    }

   @Override
    public void updateRowImpl(String tableName, Map<String,Object> values) {
        List<Map<String,Object>> rowKeys = new ArrayList<Map<String,Object>>();
        rowKeys.add(values);
        updateRowsAndNotify(tableName, rowKeys);
    }

   protected void deleteRowsAndNotify(String tableName, Set<Object> rowKeyList) {
       deleteRows(tableName, rowKeyList);
       sendNotification(tableName, StorageSourceNotification.Action.DELETE, rowKeyList);
   }

    @Override
    public void deleteRowImpl(String tableName, Object key) {
        HashSet<Object> keys = new HashSet<Object>();
        keys.add(key);
        deleteRowsAndNotify(tableName, keys);
    }

    @Override
    public IResultSet getRowImpl(String tableName, Object rowKey) {
        List<Map<String,Object>> rowList = new ArrayList<Map<String,Object>>();
        Map<String,Object> row = getRow(tableName, null, rowKey);
        if (row != null)
            rowList.add(row);
        NoSqlResultSet resultSet = new NoSqlResultSet(this, tableName, rowList);
        return resultSet;
    }
  
    // Below are the methods that must be implemented by the subclasses
   
    protected abstract Collection<Map<String,Object>> getAllRows(String tableName, String[] columnNameList);
   
    protected abstract Map<String,Object> getRow(String tableName, String[] columnNameList, Object rowKey);
   
    protected abstract List<Map<String,Object>> executeEqualityQuery(String tableName,
            String[] columnNameList, String predicateColumnName, Comparable<?> value);
   
    protected abstract List<Map<String,Object>> executeRangeQuery(String tableName,
            String[] columnNameList, String predicateColumnName,
            Comparable<?> startValue, boolean startInclusive, Comparable<?> endValue, boolean endInclusive);
   
    protected abstract void insertRows(String tableName, List<Map<String,Object>> insertRowList);
   
    protected abstract void updateRows(String tableName, Set<Object> rowKeys, Map<String,Object> updateColumnMap);
}
TOP

Related Classes of net.floodlightcontroller.storage.nosql.NoSqlStorageSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.