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

org.cloudgraph.hbase.scan.CompleteRowKeyAssembler 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.scan;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.util.Hash;
import org.cloudgraph.config.CloudGraphConfig;
import org.cloudgraph.config.DataGraphConfig;
import org.cloudgraph.config.KeyFieldConfig;
import org.cloudgraph.config.PreDefinedKeyFieldConfig;
import org.cloudgraph.config.TableConfig;
import org.cloudgraph.config.UserDefinedRowKeyFieldConfig;
import org.cloudgraph.hbase.key.Hashing;
import org.cloudgraph.hbase.key.KeySupport;
import org.cloudgraph.hbase.key.Padding;
import org.plasma.query.model.Where;
import org.plasma.sdo.DataFlavor;
import org.plasma.sdo.PlasmaType;


/**
 * Assembles a row key where each
 * field within the composite row key is constructed 
 * based a set of given query predicates.  
 * 
 * @see org.cloudgraph.config.DataGraphConfig
 * @see org.cloudgraph.config.TableConfig
 * @see org.cloudgraph.config.UserDefinedField 
 * @see org.cloudgraph.config.PredefinedField 
 * @see org.cloudgraph.config.PreDefinedFieldName 
 * @author Scott Cinnamond
 * @since 0.5.5
 */
public class CompleteRowKeyAssembler  
    implements RowKeyScanAssembler, CompleteRowKey
{
    private static Log log = LogFactory.getLog(CompleteRowKeyAssembler.class);
	protected int bufsize = 4000;
	protected ByteBuffer startKey = ByteBuffer.allocate(bufsize);
	protected PlasmaType rootType;
	protected DataGraphConfig graph;
	protected TableConfig table;
	protected KeySupport keySupport = new KeySupport();
	protected Charset charset;
	protected ScanLiterals scanLiterals;
	protected int startRowFieldCount;
    protected String rootUUID;
	protected Hashing hashing;
	protected Padding padding;
	
	@SuppressWarnings("unused")
	private CompleteRowKeyAssembler() {}

	/**
	 * Constructor
	 * @param rootType the root type
	 */
	public CompleteRowKeyAssembler(PlasmaType rootType)
	{
    	this.rootType = rootType;
		QName rootTypeQname = this.rootType.getQualifiedName();
		this.graph = CloudGraphConfig.getInstance().getDataGraph(
				rootTypeQname);
		this.table = CloudGraphConfig.getInstance().getTable(rootTypeQname);
		Hash hash = this.keySupport.getHashAlgorithm(this.table);
		this.charset = CloudGraphConfig.getInstance().getCharset();
		this.hashing = new Hashing(hash, this.charset);
		this.padding = new Padding(this.charset);
	}
	
	/**
	 * Constructor which enables the use of data object UUID as
	 * a pre-defined row key field. Only applicable for graph
	 * predicate "slice" queries. 
	 * @param rootType the root type
	 * @param rootUUID the root UUID.
	 */
	public CompleteRowKeyAssembler(PlasmaType rootType, String rootUUID)
	{
		this(rootType);
		this.rootUUID = rootUUID;
	}
	
    /**
     * Assemble row key scan information based only on any
     * pre-defined row-key fields such as the
     * data graph root type or URI.
     * @see org.cloudgraph.config.PredefinedField 
     * @see org.cloudgraph.config.PreDefinedFieldName 
     */
	@Override
	public void assemble() {    	
		this.startKey = ByteBuffer.allocate(bufsize);
      	assemblePredefinedFields();
	}
	
	/**
	 * Assemble row key scan information based on the given
	 * scan literals as well as pre-defined row-key fields such as the
     * data graph root type or URI.
	 * @param literalList the scan literals
     * @see org.cloudgraph.config.PredefinedField 
     * @see org.cloudgraph.config.PreDefinedFieldName 
	 */
	@Override
	public void assemble(ScanLiterals literals) {
		this.scanLiterals = literals;
		this.startKey = ByteBuffer.allocate(bufsize);
    	assembleLiterals();
	}
	
    /**
     * Assemble row key scan information based on one or more
     * given query predicates.
     * @param where the row predicate hierarchy
     * @param contextType the context type which may be the root type or another
     * type linked by one or more relations to the root
     */
	@Override
	public void assemble(Where where, PlasmaType contextType) {
		this.startKey = ByteBuffer.allocate(bufsize);
		
		if (log.isDebugEnabled())
    		log.debug("begin traverse");
    	
		ScanLiteralAssembler literalAssembler = 
				new ScanLiteralAssembler(this.rootType);
    	where.accept(literalAssembler); // traverse
    	
    	this.scanLiterals = literalAssembler.getPartialKeyScanResult();
    	
    	if (log.isDebugEnabled())
    		log.debug("end traverse");      	

    	assembleLiterals();
    }
	
	private void assemblePredefinedFields()
	{
    	List resultFields = new ArrayList();
        
    	for (PreDefinedKeyFieldConfig field : this.graph.getPreDefinedRowKeyFields()) {
    		switch (field.getName()) {
    		case URI: 
    		case TYPE:
    			resultFields.add(field);
    			break;
    		case UUID:
    			break; // not applicable
    		default:
    		}
        }    	
    	
    	int fieldCount = resultFields.size();
    	for (int i = 0; i < fieldCount; i++) {
        	PreDefinedKeyFieldConfig preDefinedField = resultFields.get(i);
    		if (startRowFieldCount > 0) {
        	    this.startKey.put(graph.getRowKeyFieldDelimiterBytes());
    		}
    		
    		byte[] startValue = this.keySupport.getPredefinedFieldValueStartBytes(this.rootType, 
       	    		hashing, preDefinedField);
       	    byte[] paddedStartValue = null;
       	    if (preDefinedField.isHash()) {
       	    	paddedStartValue = this.padding.pad(startValue, preDefinedField.getMaxLength(), 
    				DataFlavor.integral);
       	    }
       	    else {
       	    	paddedStartValue = this.padding.pad(startValue, preDefinedField.getMaxLength(), 
       	    			preDefinedField.getDataFlavor());
       	    }
    		
    		this.startKey.put(paddedStartValue);
        }				
	}
	
	private void assembleLiterals()
	{		
		for (KeyFieldConfig fieldConfig : this.graph.getRowKeyFields()) {
    		if (fieldConfig instanceof PreDefinedKeyFieldConfig) {
    			PreDefinedKeyFieldConfig predefinedConfig = (PreDefinedKeyFieldConfig)fieldConfig;
        		
        		byte[] tokenValue = null;
        		switch (predefinedConfig.getName()) {
        		case UUID:
        			if (this.rootUUID != null) {
        				tokenValue = this.rootUUID.getBytes(this.charset);
        				break;
        			}
        			else
        				continue;        			
        		default:	
        		    tokenValue = predefinedConfig.getKeyBytes(this.rootType);
        			break;
        		}        		
        		//FIXME: if predefined field is last, need stop bytes
        		
        		byte[] paddedTokenValue = null;
        		if (fieldConfig.isHash()) {
        			tokenValue = hashing.toStringBytes(tokenValue);
            		paddedTokenValue = this.padding.pad(tokenValue, predefinedConfig.getMaxLength(), 
            				DataFlavor.integral);
    			} 
        		else {
        			paddedTokenValue = this.padding.pad(tokenValue, predefinedConfig.getMaxLength(), 
            				predefinedConfig.getDataFlavor());
        		}
        		
        		if (startRowFieldCount > 0) 
            	    this.startKey.put(graph.getRowKeyFieldDelimiterBytes());
           	    this.startKey.put(paddedTokenValue);
           	    this.startRowFieldCount++;
    		}
    		else if (fieldConfig instanceof UserDefinedRowKeyFieldConfig) {
    			UserDefinedRowKeyFieldConfig userFieldConfig = (UserDefinedRowKeyFieldConfig)fieldConfig;
    			List scanLiterals = this.scanLiterals.getLiterals(userFieldConfig);    				 
    			if (scanLiterals == null)
    				continue;
    			for (ScanLiteral scanLiteral : scanLiterals) {
    				byte[] startBytes = scanLiteral.getStartBytes();
    				if (startBytes.length > 0) {
    					if (this.startRowFieldCount > 0) {
    						this.startKey.put(graph.getRowKeyFieldDelimiterBytes());		
    					}
    					this.startKey.put(startBytes);
    					this.startRowFieldCount++;
    				}
    			}
    		}
		}			
	}
	
	/**
	 * Returns the row key as a byte array.
	 * @return the row key
	 * @throws IllegalStateException if the row key is not yet assembled
	 */
	@Override
	public byte[] getKey() {
		if (this.startKey == null)
			throw new IllegalStateException("row keys not assembled - first call assemble(...)");
		// ByteBuffer.array() returns unsized array so don't sent that back to clients
		// to misuse. 
		// Use native arraycopy() method as it uses native memcopy to create result array
		// and because 
		// ByteBuffer.get(byte[] dst,int offset, int length) is not native
	    byte [] result = new byte[this.startKey.position()];
	    System.arraycopy(this.startKey.array(), this.startKey.arrayOffset(), result, 0, this.startKey.position()); 
		return result;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy