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

org.cloudgraph.hbase.mutation.Update Maven / Gradle / Ivy

Go to download

CloudGraph(tm) is a suite of Service Data Object (SDO) 2.1 services designed for relational and big-table style "cloud" databases, such as HBase and others.

There is a newer version: 2.0.4
Show newest version
/**
 *        CloudGraph Community Edition (CE) License
 * 
 * This is a community release of CloudGraph, a dual-license suite of
 * Service Data Object (SDO) 2.1 services designed for relational and 
 * big-table style "cloud" databases, such as HBase and others. 
 * This particular copy of the software is released under the 
 * version 2 of the GNU General Public License. CloudGraph was developed by 
 * TerraMeta Software, Inc.
 * 
 * Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved.
 * 
 * General License information can be found below.
 * 
 * This distribution may include materials developed by third
 * parties. For license and attribution notices for these
 * materials, please refer to the documentation that accompanies
 * this distribution (see the "Licenses for Third-Party Components"
 * appendix) or view the online documentation at 
 * . 
 */
package org.cloudgraph.hbase.mutation;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudgraph.config.CloudGraphConfig;
import org.cloudgraph.hbase.io.DistributedWriter;
import org.cloudgraph.hbase.io.RowWriter;
import org.cloudgraph.hbase.io.TableWriter;
import org.cloudgraph.hbase.service.HBaseDataConverter;
import org.cloudgraph.hbase.service.ServiceContext;
import org.cloudgraph.state.GraphState;
import org.cloudgraph.state.GraphState.Edge;
import org.cloudgraph.store.service.GraphServiceException;
import org.plasma.sdo.PlasmaDataObject;
import org.plasma.sdo.PlasmaEdge;
import org.plasma.sdo.PlasmaNode;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaSetting;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.access.RequiredPropertyException;
import org.plasma.sdo.core.CoreConstants;
import org.plasma.sdo.core.CoreDataObject;
import org.plasma.sdo.core.NullValue;
import org.plasma.sdo.core.SnapshotMap;
import org.plasma.sdo.profile.KeyType;

import commonj.sdo.ChangeSummary.Setting;
import commonj.sdo.DataGraph;
import commonj.sdo.DataObject;
import commonj.sdo.Property;

public class Update extends DefaultMutation implements Collector {
	private static Log log = LogFactory.getLog(Update.class);
    public Update(ServiceContext context, SnapshotMap snapshotMap, String username) {
		super(context, snapshotMap, username);
	}

    @Override
    public void collect(DataGraph dataGraph, PlasmaDataObject dataObject, 
    		DistributedWriter graphWriter,
    		TableWriter tableWriter,
        	RowWriter rowWriter) 
        throws IllegalAccessException, IOException
    {   
        PlasmaType type = (PlasmaType)dataObject.getType();
                
        // FIXME: get rid of cast - define instance properties in 'base type'
        Timestamp snapshotDate = (Timestamp)((CoreDataObject)dataObject).getValue(CoreConstants.PROPERTY_NAME_SNAPSHOT_TIMESTAMP);                                     
        if (snapshotDate == null)                                                                    
            throw new RequiredPropertyException("instance property '" + CoreConstants.PROPERTY_NAME_SNAPSHOT_TIMESTAMP                
               + "' is required to update entity '" 
               + type.getURI() + "#" + type.getName() + "'"); 
        if (log.isDebugEnabled())
            log.debug(dataObject + " timestamp: " + String.valueOf(snapshotDate));
        
        checkLock(dataObject, type, snapshotDate);
        updateOptimistic(dataObject, type, rowWriter);
        
        List settings = dataGraph.getChangeSummary().getOldValues(dataObject);
        for (Setting setting: settings) // for every changed value
        {
        	PlasmaProperty property = (PlasmaProperty)setting.getProperty();
            if (property.isKey(KeyType.primary))
                continue; // cannot be modified on an update
            
            if (property.getConcurrent() != null)
                continue; // processed above           
    		
            if (property.isReadOnly())
    		    throw new IllegalAccessException("attempt to modify read-only property, "
        			+ property);

            Object dataValue = dataObject.get(property);
            if (dataValue != null) 
                if (log.isDebugEnabled())
                    log.debug("updating " + property.toString());
            else
                if (log.isDebugEnabled())
                    log.debug("removing " + property.toString());            	
       	
    		byte[] valueBytes = null;
        	if (!property.getType().isDataType()) {
        		if (!property.isMany()) {
            		valueBytes = this.collectSingular(graphWriter, tableWriter, rowWriter, 
            				dataObject, setting, property, dataValue);
        		}
        		else {
        			valueBytes = this.collectMulti(graphWriter, tableWriter, rowWriter, 
        					dataObject, setting, property, dataValue);
        		}
         	}
        	else {
        		// FIXME: research best way to encode multiple
        		// primitives as bytes
        		if (dataValue != null)
                    valueBytes = HBaseDataConverter.INSTANCE.toBytes(
                	    property, dataValue);
            }
        	
        	if (valueBytes != null) {
        	    this.updateCell(rowWriter, dataObject, 
                    property, valueBytes);
        	}
        	else {
        	    this.deleteCell(rowWriter, dataObject, 
                        property);
        	}
        }    
    } 

    private byte[] collectSingular(DistributedWriter graphWriter,
    		TableWriter tableWriter, RowWriter rowWriter, 
    		PlasmaDataObject dataObject,   
    		Setting setting, PlasmaProperty property, Object value) throws IOException
    {
    	byte[] valueBytes = null;
    	
		// get old value setting/value - can be List or single data-object
		Object oldValue = setting.getValue();
		
        PlasmaNode dataNode = (PlasmaNode)dataObject;
		List  edges = dataNode.getEdges(property);
		// remove old value if exists from graph state 
		if (!(oldValue instanceof NullValue)) {
			if (!(oldValue instanceof List)) {
    			DataObject oldOpposite = (DataObject)oldValue;
		    	rowWriter.getGraphState().removeSequence(oldOpposite);
			    boolean typeBound = CloudGraphConfig.getInstance().findTable(
			    		((PlasmaType)oldOpposite.getType()).getQualifiedName()) != null;
                // FIXME: if old opposite is a duplicate of current, new row key is removed
			    // and never re-added and graph assembly thinks its an internal edge
			    if (typeBound) 
		    	    rowWriter.getGraphState().removeRowKey(oldOpposite);
			}
    		else 
                throw new GraphServiceException("unexpected List as old value for property, "  
                	+ property.toString());
		}
		// if has a new value
		if (value != null) {
			// add the new value into graph state
    		this.addRowKeys(dataObject, dataNode, property, edges, graphWriter,
            		tableWriter, rowWriter);
    		List stateEdges = this.findUpdateEdges(dataNode, property, 
    				edges, graphWriter, rowWriter);            		
      		rowWriter.getGraphState().addEdges(dataNode,  stateEdges);        		
    		// Create a formatted column value
    		// for this edge. 
      		String valueString = rowWriter.getGraphState().marshalEdges(
    				dataNode, stateEdges);
    		valueBytes = valueString.getBytes(GraphState.charset);
	    	if (log.isDebugEnabled()) 
	    		log.debug("saving edges (singular): " + valueString);
		}
    	
		return valueBytes;
    }
    
    private byte[] collectMulti(DistributedWriter graphWriter,
    		TableWriter tableWriter, RowWriter rowWriter, 
    		PlasmaDataObject dataObject,  
    		Setting setting, PlasmaProperty property, Object value) throws IOException
    {
    	byte[] valueBytes = null;
			
		// get old value setting/value - can be List or single data-object
		Object oldValue = setting.getValue();
		
        PlasmaNode dataNode = (PlasmaNode)dataObject;
		List  edges = dataNode.getEdges(property);
		
		// get old edges from change summary
		HashMap oldEdgeMap = getOldEdgeMap(
			oldValue, property);
		
		// add the new plasma edge values into graph state
		this.addRowKeys(dataObject, dataNode, property, edges, graphWriter,
        		tableWriter, rowWriter);
		List updateEdges = this.findUpdateEdges(dataNode, property, 
				edges, graphWriter, rowWriter);            		
  		rowWriter.getGraphState().addEdges(dataNode,  updateEdges);  
  		
  		// convert to state edge map to compare w/existing
  		Edge[] updatedEdges = rowWriter.getGraphState().createEdges(dataNode, updateEdges);
		Map updatedEdgeMap = new HashMap();
		for (int i = 0; i < updatedEdges.length; i++)
			updatedEdgeMap.put(updatedEdges[i].getUuid(), updatedEdges[i]);
		
		// fetch the existing edges from data store and marshall as edges
	    byte[] existingValue = rowWriter.fetchColumnValue(dataObject, property);
	    Edge[] existingEdges = null;
	    if (existingValue != null && existingValue.length > 0)
	        existingEdges = rowWriter.getGraphState().unmarshalEdges(existingValue);
	    
	    // merge
	    if (log.isDebugEnabled()) {
	    	log.debug("merging existing: " + toString(existingEdges) 
	    	    + " updated:  " + toString(updatedEdges)
	    	    + " old: " + toString(oldEdgeMap));
	    }
	    List list = new ArrayList();
    	for (Edge updated : updatedEdges)
    		list.add(updated);
    	if (existingEdges != null)
		    for (Edge existing : existingEdges) {
		    	// Only add existing edge if NOT found in updated in graph and change summary
		    	if (!updatedEdgeMap.containsKey(existing.getUuid())) {	        		    		
		    		DataObject oldDataObject = oldEdgeMap.get(existing.getUuid());
		    		if (oldDataObject == null) {
		    			if (log.isDebugEnabled()) 
	        		    	log.debug("adding existing: " + existing);
		    			list.add(existing);
		    		}
		    		else { // edge is obsolete - move to history
		    			if (log.isDebugEnabled()) 
	        		    	log.debug("archiving existing: " + existing);
	    		    	rowWriter.getGraphState().removeSequence(oldDataObject);
	    			    boolean typeBound = CloudGraphConfig.getInstance().findTable(
	    			    		((PlasmaType)oldDataObject.getType()).getQualifiedName()) != null;
	    			    if (typeBound)
	    		    	    rowWriter.getGraphState().removeRowKey(oldDataObject);
		    		}
		    	} // else added it already above	        		    	
		    }
	    
	    Edge[] resultEdges = new Edge[list.size()];
	    list.toArray(resultEdges);
	    String valueString = rowWriter.getGraphState().marshalEdges(resultEdges);
	    valueBytes = valueString.getBytes(GraphState.charset);
    	if (log.isDebugEnabled()) {
    		log.debug("saving edges (multi): " + valueString);
	        for (Edge e : resultEdges) {
		    	log.debug("saving edge: " + e);
	    	    rowWriter.getGraphState().getUUID(e.getType(), e.getId()); // ensure it exists
	        }
    	} 
		return valueBytes;    	
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy