<commit_before>/*
 * Copyright (C) 2014 EBay Software Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Authors : <NAME>
 */
package org.opendaylight.ovsdb.lib.schema;

import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.opendaylight.ovsdb.lib.message.TableUpdate;
import org.opendaylight.ovsdb.lib.notation.Column;
import org.opendaylight.ovsdb.lib.notation.Row;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.operations.Insert;
import org.opendaylight.ovsdb.lib.schema.BaseType.UuidBaseType;
import org.opendaylight.ovsdb.lib.schema.ColumnType.AtomicColumnType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;


public abstract class TableSchema<E extends TableSchema<E>> {


    protected static final Logger logger = LoggerFactory.getLogger(TableSchema.class);
    private String name;
    private Map<String, ColumnSchema> columns;

    public TableSchema() {
    }

    protected TableSchema(String name) {
        this.name = name;
    }

    public TableSchema(String name, Map<String, ColumnSchema> columns) {
        this.name = name;
        this.columns = columns;
    }

    public Set<String> getColumns() {
        return this.columns.keySet();
    }

    public Map<String, ColumnSchema> getColumnSchemas() {
        return columns;
    }

    public boolean hasColumn(String column) {
        return this.getColumns().contains(column);
    }


    public ColumnType getColumnType(String column) {
        return this.columns.get(column).getType();
    }

    public <E extends TableSchema<E>> E as(Class<E> clazz) {
        try {
            Constructor<E> e = clazz.getConstructor(TableSchema.class);
            return e.newInstance(this);
        } catch (Exception e) {
            throw new RuntimeException("exception constructing instance of clazz " + clazz, e);
        }
    }

    public Insert<E> insert() {
        return new Insert<>(this);
    }

    public <D> ColumnSchema<E, Set<D>> multiValuedColumn(String column, Class<D> type) {
        //todo exception handling

        ColumnSchema columnSchema = columns.get(column);
        columnSchema.validateType(type);
        return columnSchema;
    }

    public <K,V> ColumnSchema<E, Map<K,V>> multiValuedColumn(String column, Class<K> keyType, Class<V> valueType) {
        //todo exception handling

        ColumnSchema columnSchema = columns.get(column);
        columnSchema.validateType(valueType);
        return columnSchema;
    }

    public <D> ColumnSchema<E, D> column(String column, Class<D> type) {
        //todo exception handling

        ColumnSchema columnSchema = columns.get(column);
        columnSchema.validateType(type);
        return columnSchema;
    }

    public ColumnSchema column(String column) {
        return this.columns.get(column);
    }


    public String getName() {
        return name;
    }

    protected void setName(String name) {
        this.name = name;
    }

    protected void setColumns(Map<String, ColumnSchema> columns) {
        this.columns = columns;
    }

    public TableUpdate<E> updatesFromJson(JsonNode value) {

        Map.Entry<String, JsonNode> idOldNew = value.fields().next();
        String uuid = idOldNew.getKey();

        ObjectNode new_ = (ObjectNode) idOldNew.getValue().get("new");
        ObjectNode old = (ObjectNode) idOldNew.getValue().get("old");

        Row<E> newRow = new_ != null ? createRow(new_) : null;
        Row<E> oldRow = old != null ? createRow(old) : null;

        TableUpdate<E> tableUpdate = new TableUpdate<>(new UUID(uuid));
        tableUpdate.setNew(newRow);
        tableUpdate.setOld(oldRow);

        return tableUpdate;
    }

    protected Row<E> createRow(ObjectNode rowNode) {
        List<Column<E, ?>> columns = Lists.newArrayList();
        for (Iterator<Map.Entry<String, JsonNode>> iter = rowNode.fields(); iter.hasNext();) {
            Map.Entry<String, JsonNode> next = iter.next();
            ColumnSchema<E, Object> schema = column(next.getKey(), Object.class);
            Object o = schema.valueFromJson(next.getValue());
            columns.add(new Column<>(schema, o));
        }
        return new Row<>(columns);
    }

    /*
     * RFC 7047 Section 3.2 specifies 2 internally generated columns in each table
     * namely _uuid and _version which are not exposed in get_schema call.
     * Since these 2 columns are extremely useful for Mutate, update and select operations,
     * the ColumnSchema for these 2 columns are manually populated.
     *
     * It is to be noted that these 2 columns are specified as part of the RFC7047 and not
     * a specific Schema implementation detail & hence adding it by default in the Library
     * for better application experience using the library.
     */
    public void populateInternallyGeneratedColumns() {
        columns.put("_uuid", new ColumnSchema("_uuid", new AtomicColumnType(new UuidBaseType())));
        columns.put("_version", new ColumnSchema("_version", new AtomicColumnType(new UuidBaseType())));
    }
}<commit_msg>Added safety check for a case in which getSchema may not report a "hidden" Column, but Monitor respond with data for that "hidden" column.<commit_after>/*
 * Copyright (C) 2014 EBay Software Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Authors : <NAME>
 */
package org.opendaylight.ovsdb.lib.schema;

import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.opendaylight.ovsdb.lib.message.TableUpdate;
import org.opendaylight.ovsdb.lib.notation.Column;
import org.opendaylight.ovsdb.lib.notation.Row;
import org.opendaylight.ovsdb.lib.notation.UUID;
import org.opendaylight.ovsdb.lib.operations.Insert;
import org.opendaylight.ovsdb.lib.schema.BaseType.UuidBaseType;
import org.opendaylight.ovsdb.lib.schema.ColumnType.AtomicColumnType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;


public abstract class TableSchema<E extends TableSchema<E>> {


    protected static final Logger logger = LoggerFactory.getLogger(TableSchema.class);
    private String name;
    private Map<String, ColumnSchema> columns;

    public TableSchema() {
    }

    protected TableSchema(String name) {
        this.name = name;
    }

    public TableSchema(String name, Map<String, ColumnSchema> columns) {
        this.name = name;
        this.columns = columns;
    }

    public Set<String> getColumns() {
        return this.columns.keySet();
    }

    public Map<String, ColumnSchema> getColumnSchemas() {
        return columns;
    }

    public boolean hasColumn(String column) {
        return this.getColumns().contains(column);
    }


    public ColumnType getColumnType(String column) {
        return this.columns.get(column).getType();
    }

    public <E extends TableSchema<E>> E as(Class<E> clazz) {
        try {
            Constructor<E> e = clazz.getConstructor(TableSchema.class);
            return e.newInstance(this);
        } catch (Exception e) {
            throw new RuntimeException("exception constructing instance of clazz " + clazz, e);
        }
    }

    public Insert<E> insert() {
        return new Insert<>(this);
    }

    public <D> ColumnSchema<E, Set<D>> multiValuedColumn(String column, Class<D> type) {
        //todo exception handling

        ColumnSchema columnSchema = columns.get(column);
        columnSchema.validateType(type);
        return columnSchema;
    }

    public <K,V> ColumnSchema<E, Map<K,V>> multiValuedColumn(String column, Class<K> keyType, Class<V> valueType) {
        //todo exception handling

        ColumnSchema columnSchema = columns.get(column);
        columnSchema.validateType(valueType);
        return columnSchema;
    }

    public <D> ColumnSchema<E, D> column(String column, Class<D> type) {
        //todo exception handling

        ColumnSchema columnSchema = columns.get(column);
        if (columnSchema != null) {
            columnSchema.validateType(type);
        }
        return columnSchema;
    }

    public ColumnSchema column(String column) {
        return this.columns.get(column);
    }


    public String getName() {
        return name;
    }

    protected void setName(String name) {
        this.name = name;
    }

    protected void setColumns(Map<String, ColumnSchema> columns) {
        this.columns = columns;
    }

    public TableUpdate<E> updatesFromJson(JsonNode value) {

        Map.Entry<String, JsonNode> idOldNew = value.fields().next();
        String uuid = idOldNew.getKey();

        ObjectNode new_ = (ObjectNode) idOldNew.getValue().get("new");
        ObjectNode old = (ObjectNode) idOldNew.getValue().get("old");

        Row<E> newRow = new_ != null ? createRow(new_) : null;
        Row<E> oldRow = old != null ? createRow(old) : null;

        TableUpdate<E> tableUpdate = new TableUpdate<>(new UUID(uuid));
        tableUpdate.setNew(newRow);
        tableUpdate.setOld(oldRow);

        return tableUpdate;
    }

    protected Row<E> createRow(ObjectNode rowNode) {
        List<Column<E, ?>> columns = Lists.newArrayList();
        for (Iterator<Map.Entry<String, JsonNode>> iter = rowNode.fields(); iter.hasNext();) {
            Map.Entry<String, JsonNode> next = iter.next();
            ColumnSchema<E, Object> schema = column(next.getKey(), Object.class);
            /*
             * Ideally the ColumnSchema shouldn't be null at this stage. But there can be cases in which
             * the OVSDB manager Schema implementation might decide to include some "hidden" columns that
             * are NOT reported in getSchema, but decide to report it in unfiltered monitor.
             * Hence adding some safety checks around that.
             */
            if (schema != null) {
                Object o = schema.valueFromJson(next.getValue());
                columns.add(new Column<>(schema, o));
            }
        }
        return new Row<>(columns);
    }

    /*
     * RFC 7047 Section 3.2 specifies 2 internally generated columns in each table
     * namely _uuid and _version which are not exposed in get_schema call.
     * Since these 2 columns are extremely useful for Mutate, update and select operations,
     * the ColumnSchema for these 2 columns are manually populated.
     *
     * It is to be noted that these 2 columns are specified as part of the RFC7047 and not
     * a specific Schema implementation detail & hence adding it by default in the Library
     * for better application experience using the library.
     */
    public void populateInternallyGeneratedColumns() {
        columns.put("_uuid", new ColumnSchema("_uuid", new AtomicColumnType(new UuidBaseType())));
        columns.put("_version", new ColumnSchema("_version", new AtomicColumnType(new UuidBaseType())));
    }
}
{'fraction_non_alphanumeric': 0.10297423482621476, 'fraction_numerical': 0.004150095106346187, 'mean_word_length': 3.010748959778086, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '534909', 'n_tokens_mistral': 3335, 'n_tokens_neox': 3206, 'n_words': 894}