/* Copyright 2008-2010 Gephi Authors : Martin Škurla Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.data.attributes.spi; import org.gephi.data.attributes.api.AttributeColumn; /** * <h3>General information</h3> * Provider for delegating attribute value. Using this interface it is possible to delegate the real * value of AttributeValue object to database (relational, graph, ...), index/search engine, ... * <br> * For every node/edge it is possible to add, get, set and remove every attribute value. * * <h3>Implementation details</h3> * As of implementation detail of AttributeValue immutability, both adding and setting the attribute value is done through the * set[Edge|Node]AttributeValue() method, so it is absolutely necessary to treat both cases in the method body. * <br> * Every method takes at least 2 arguments: * <ul> * <li>delegate id * <li>attribute column * </ul> * Delegate id is any type of object necessary to get the right node/edge. For instance for Neo4j it is of type Long, * which is directly used as Neo4j node/relationship id. For other storing engines which require indexing key and * value it could be crate (wrapper object) wrapping both values with proper types. * <br> * Attribute column is used usually for getting the column id which is used as property name. * * <h3>Automatic and manual type conversions</h3> * Important thing about the whole delegating process is type conversion. It is clear that there might exist type mismatch * between Gephi types and types which are supported in storing engine. During implementation it is necessary to fulfill * following requirements: * <ul> * <li>get[Edge|Node]AttributeValue() method must return any of primitive types, String or array of these types. The * conversion from array type into appropriate List type is done automatically using ListFactory method. * <li>set[Edge|Node]AttributeValue() can accept any of Gephi supported types described in AttributeType constructors * as class objects. It is up to the Provider to make appropriate conversion if this is needed, especially conversion * from List types. * </ul> * * <h3>Usage</h3> * Every AttributeColumn has direct link to its own AttributeValueDelegateProvider. This means that it is possible to * have more Providers in the same AttributeTable, each delegating from a subset of all columns. And because the fact * that every AttributeValue has link to its AttributeColumn, it has direct access to its Provider too. * <br> * Provider will be called for getting value for every AttributeValue which has column with AttributeOrigin.DELEGATE. * The first setValue() method call on Attributes/AttributeRow will set the delegate id and every other will change * data in storing engine. * * <h3>Best practises</h3> * Every implementing class should be implemented as singleton because of memory savings. This singleton should be * passed during populating AttributeTable / creating columns. * <br> * Any other necessary implementation information / resources (as concrete database instance) should be set using * static methods. * <br> * Any necessary convertor described in <b>Automatic and manual type conversions</b> should be implemented as static * inner class. * * @author Martin Škurla * * @param <T> type parameter used to restrict delegate id type */ public abstract class AttributeValueDelegateProvider<T> { /** * Returns the delegated node attribute value. * * @param delegateId delegate id * @param attributeColumn attribute column * * @return delegated node attribute value */ public abstract Object getNodeAttributeValue(T delegateId, AttributeColumn attributeColumn); /** * Adds or sets the delegated node attribute value. It is necessary to treat both cases in the method body! * * @param delegateId delegate id * @param attributeColumn attribute column * @param nodeValue new/changed delegated node attribute value */ public abstract void setNodeAttributeValue(T delegateId, AttributeColumn attributeColumn, Object nodeValue); /** * Deletes the delegated node attribute value. * * @param delegateId delegate id * @param attributeColumn attribute column */ public abstract void deleteNodeAttributeValue(T delegateId, AttributeColumn attributeColumn); /** * Returns the delegated edge attribute value. * * @param delegateId delegate id * @param attributeColumn attribute column * * @return delegated edge attribute value */ public abstract Object getEdgeAttributeValue(T delegateId, AttributeColumn attributeColumn); /** * Adds or sets the delegated edge attribute value. It is necessary to treat both cases in the method body! * * @param delegateId delegate id * @param attributeColumn attribute column * @param nodeValue new/changed delegated edge attribute value */ public abstract void setEdgeAttributeValue(T delegateId, AttributeColumn attributeColumn, Object edgeValue); /** * Deletes the delegated edge attribute value. * * @param delegateId delegate id * @param attributeColumn attribute column */ public abstract void deleteEdgeAttributeValue(T delegateId, AttributeColumn attributeColumn); /** * Returns name of storage engine. This is used when graph uses more storage engines and where must be an * option how to differ them in GUI. * * @return name of storage engine */ public abstract String storageEngineName();//TODO >>> add documentation for these two methods public abstract GraphItemDelegateFactoryProvider<T> graphItemDelegateFactoryProvider(); @Override//TODO >>> add documentation about this usage for hashing, ... public final boolean equals(Object obj) { if (!(obj instanceof AttributeValueDelegateProvider)) return false; return ((AttributeValueDelegateProvider) obj).storageEngineName().equals(this.storageEngineName()); } @Override public final int hashCode() { return storageEngineName().hashCode(); } }