All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.piax.common.attribs.AttributeTable Maven / Gradle / Ivy

The newest version!
/*
 * AttributeTable.java - A table of attributes.
 * 
 * Copyright (c) 2012-2015 National Institute of Information and 
 * Communications Technology
 *
 * You can redistribute it and/or modify it under either the terms of
 * the AGPLv3 or PIAX binary code license. See the file COPYING
 * included in the PIAX package for more in detail.
 *
 * $Id: AttributeTable.java 718 2013-07-07 23:49:08Z yos $
 */

package org.piax.common.attribs;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.piax.common.Destination;
import org.piax.common.Id;
import org.piax.common.Key;
import org.piax.common.ObjectId;
import org.piax.common.PeerId;
import org.piax.common.TransportIdPath;
import org.piax.gtrans.IdConflictException;
import org.piax.gtrans.dcl.VarDestinationPair;
import org.piax.gtrans.ov.NoSuchOverlayException;
import org.piax.gtrans.ov.Overlay;

/**
 * A class that corresponds to a table of attributes.
 */
public class AttributeTable {
    public final PeerId peerId;
    public final ObjectId tableId;
    
    /**
     * テーブルに一つ特別のrowの挿入を許す。
     * このrowの持つ属性値がマッチするとき、その属性がセットされていないすべてのrowがマッチの対象となる
     */
    public RowData superRow = null;
    public Object superRowLock = new Object();

    final Map attribs = new LinkedHashMap();
    final Map rows = new LinkedHashMap();

    public AttributeTable(PeerId peerId, ObjectId tableId) {
        this.peerId = peerId;
        this.tableId = tableId;
    }

    public void clear() {
        synchronized (rows) {
            rows.clear();
        }
        synchronized (attribs) {
            for (Attribute attrib : attribs.values()) {
                attrib.clear();
            }
            attribs.clear();
        }
    }
    
    /**
     * 指定された名前を持つAttributeを取得する。
     * もし、そのAttributeが存在しない場合は新規に作成する。
     * 
     * @param attribName 属性名
     * @return attribNameを持つAttribute
     */
    public Attribute newAttribIfAbsent(String attribName) {
        synchronized (attribs) {
            Attribute attrib = attribs.get(attribName);
            if (attrib == null) {
                attrib = new Attribute(this, attribName);
                attribs.put(attribName, attrib);
            }
            return attrib;
        }
    }

    /**
     * 指定された名前を持つAttributeを取得する。
     * newAttribIfAbsentと違って、Attributeの作成は行わない。
     * そのAttributeが存在しない場合はnullが返される。
     * 
     * @param attribName 属性名
     * @return attribNameを持つAttribute、存在しない場合はnull
     */
    public Attribute getAttrib(String attribName) {
        synchronized (attribs) {
            return attribs.get(attribName);
        }
    }
    
    public List getDeclaredAttribNames() {
        synchronized (attribs) {
            return new ArrayList(attribs.keySet());
        }
    }
    
    public void declareAttrib(String attribName)
            throws IllegalStateException {
        Attribute attrib = newAttribIfAbsent(attribName);
        if (attrib.isIndexable()) {
            throw new IllegalStateException("attrib already typed");
        }
    }

    public void declareAttrib(String attribName, Class type)
            throws IllegalStateException {
        Attribute attrib = newAttribIfAbsent(attribName);
        attrib.setType(type);
    }
    
    /**
     * 指定されたattribNameを持つAttributeに、
     * 指定されたTransportIdPathをsuffixとして持ち、型の互換性のあるOverlayをbindさせる。
     * 
     * @param attribName attribName
     * @param suffix suffixとして指定されたTransportIdPath
     * @throws IllegalArgumentException 該当するAttributeが存在しない場合
     * @throws NoSuchOverlayException 該当するOverlayが存在しない場合
     * @throws IncompatibleTypeException 型の互換性が原因で候補が得られない場合
     */
    public void bindOverlay(String attribName, TransportIdPath suffix)
            throws IllegalArgumentException, NoSuchOverlayException,
            IncompatibleTypeException {
        Attribute attrib = getAttrib(attribName);
        if (attrib == null) {
            throw new IllegalArgumentException("attrib not found");
        }
        attrib.bindOverlay(suffix);
    }
    
    public void unbindOverlay(String attribName)
            throws IllegalArgumentException, IllegalStateException {
        Attribute attrib = getAttrib(attribName);
        if (attrib == null) {
            throw new IllegalArgumentException("attrib not found");
        }
        attrib.unbindOverlay();
    }

    public Overlay getBindOverlay(String attribName)
            throws IllegalArgumentException {
        Attribute attrib = getAttrib(attribName);
        if (attrib == null) {
            throw new IllegalArgumentException("attrib not found");
        }
        return attrib.getBindOverlay();
    }
    
    public Set getMatchedRows(String attribName, Object value)
            throws IllegalArgumentException, IllegalStateException {
        Set mrows = new HashSet();
        synchronized (superRowLock) {
            /*
             * superRowがセットされている場合は、属性がセットされていないrowを一つ一つ調べて返す
             */
            if (superRow != null && value.equals(superRow.getAttribValue(attribName))) {
                for (RowData r : rows.values()) {
                    if (r == superRow) continue;
                    Object v = r.getAttribValue(attribName);
                    if (v == null || value.equals(v)) {
                        mrows.add(r);
                    }
                }
                return mrows;
            }
        }
        Attribute attrib = getAttrib(attribName);
        if (attrib == null) {
            throw new IllegalArgumentException("attrib not found");
        }
        mrows.addAll(attrib.getMatchedRows(value));
        return mrows;
    }
    
    public boolean satisfies(RowData row, List conds) {
        if (conds == null || conds.size() == 0) return true;
        return row.satisfies(conds);
    }

    /**
     * 指定されたrowIdを持つRowDataをsuperRowとしてセットする。
     * すでにRowDataが存在する場合はIdConflictExceptionがthrowされる。
     * 
     * @param rowId rowId
     * @return superRow
     * @throws IdConflictException すでにsuperRowが存在する場合
     */
    public RowData setSuperRow(Id rowId) throws IdConflictException {
        synchronized (superRowLock) {
            RowData srow = newRow(rowId);
            if (superRow != null) {
                throw new IdConflictException();
            }
            superRow = srow;
            return superRow;
        }
    }
    
    /**
     * superRowをunsetする。
     */
    public void unsetSuperRow() {
        synchronized (superRowLock) {
            superRow = null;
        }
    }
    
    /**
     * 指定されたrowIdを持つRowDataを新たに生成する。
     * すでにRowDataが存在する場合はIdConflictExceptionがthrowされる。
     * 
     * @param rowId rowId
     * @return rowIdを持つRowData
     * @throws IdConflictException すでにRowDataが存在する場合
     */
    public RowData newRow(Id rowId) throws IdConflictException {
        synchronized (rows) {
            if (rows.get(rowId) != null) {
                throw new IdConflictException();
            }
            RowData row = new RowData(this, rowId, true);
            rows.put(rowId, row);
            return row;
        }
    }
    
    /**
     * RowDataを挿入する。
     * すでに同じrowIdを持つRowDataが存在する場合はIdConflictExceptionがthrowされる。
     * 

* この挿入によって起こりうる不整合に注意する必要がある。 * 属性値を別に持つRowDataを新たにtableに挿入することで、属性名との不整合が起こりうる。 * このため、Attributeに対してunboundなRowDataでないと挿入は許されない。 * * @param row RowData * @throws IllegalStateException RowDataがAttributeに対してunboundでない場合 * @throws IdConflictException すでに同じrowIdを持つRowDataが存在する場合 */ public void insertRow(RowData row) throws IllegalStateException, IdConflictException { synchronized (rows) { if (row.isBoundToAttribute) { throw new IllegalStateException("row should be unbound"); } if (rows.get(row.rowId) != null) { throw new IdConflictException(); } rows.put(row.rowId, row); } } public RowData removeRow(Id rowId) { synchronized (rowId) { RowData row = rows.remove(rowId); row.unbindToAttribute(); return row; } } /** * 指定されたrowIdを持つRowDataを取得する。 * RowDataが存在しない場合はnullが返される。 * * @param rowId rowId * @return rowIdを持つRowData */ public RowData getRow(Id rowId) { synchronized (rows) { return rows.get(rowId); } } public List getRows() { synchronized (rows) { return new ArrayList(rows.values()); } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("AttributeTable [peerId=" + peerId + ", tableName=" + tableId + "]:\n"); sb.append("rowId"); for (String attrib : getDeclaredAttribNames()) { sb.append(", " + attrib); } sb.append("\n"); for (RowData row : getRows()) { sb.append(row.rowId); for (Object val : row.getAttribValues()) sb.append(", " + val); sb.append("\n"); } return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy