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

org.cloudgraph.hbase.io.TableWriterCollector 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.io;

import java.io.IOException;
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.config.Config;
import org.cloudgraph.config.TableConfig;
import org.plasma.sdo.PlasmaDataObject;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.access.provider.common.DeletedObjectCollector;
import org.plasma.sdo.access.provider.common.ModifiedObjectCollector;

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

/**
 * Traverses the change summary of the 
 * given Data Graph collecting
 * a list of {@link TableWriter} elements with nested {@link RowWriter}
 * elements. Each {@link RowWriter} represents the root of a new
 * or existing Data Graph within
 * the HBase table associated with the parent {@link TableWriter}.
 * 

* Graph nodes which are "unbound" (not assigned directly to a specific table) are assigned based on the * first parent node within the graph. Other parent nodes (if exist) are ignored. *

* @see org.cloudgraph.config.CloudGraphConfig * @see org.cloudgraph.config.TableConfig * @see org.cloudgraph.hbase.io.TableWriter * @see org.cloudgraph.hbase.io.RowWriter * @see commonj.sdo.ChangeSummary * * @author Scott Cinnamond * @since 0.5.1 */ public class TableWriterCollector extends WriterSupport { private static Log log = LogFactory.getLog(TableWriterCollector.class); private DataGraph dataGraph; private ChangeSummary changeSummary; private PlasmaDataObject root; private TableWriter rootTableWriter; private Map result = new HashMap(); private PlasmaDataObject[] created; private ModifiedObjectCollector modified; private DeletedObjectCollector deleted; private Config config = CloudGraphConfig.getInstance(); public TableWriterCollector(DataGraph dataGraph, PlasmaDataObject[] created, ModifiedObjectCollector modified, DeletedObjectCollector deleted) throws IOException { this.dataGraph = dataGraph; this.changeSummary = dataGraph.getChangeSummary(); this.root = (PlasmaDataObject)dataGraph.getRootObject(); this.created = created; this.modified = modified; this.deleted = deleted; collect(); } public List getTableWriters() { List list = new ArrayList(this.result.size()); for (TableWriter table : this.result.values()) list.add(table); return list; } public TableWriter getRootTableWriter() { return rootTableWriter; } public Map getRowWriterMap() { return this.rowWriterMap; } private void collect() throws IOException { // May need opposite writers just for sake of getting its // row writer and getting the row key to link into // modified graph. // FIXME: how do we detect this condition? Can we create // a row reader here instead of a writer?? // Collect all "bound" data objects up front // Note: The root may NOT be part of the change summary, but regardless // it must be associated with a table in order to // associate any linked un-bound types TableConfig rootTable = this.config.findTable(this.root.getType()); if (rootTable != null) associate(rootTable, this.root); // Collect all "bound" data objects associated w/the change summary for (DataObject dataObject : this.changeSummary.getChangedDataObjects()) { PlasmaType type = (PlasmaType)dataObject.getType(); TableConfig table = this.config.findTable(type); if (table != null) associate(table, dataObject); } if (result.size() == 0) throw new OperationException("no configured table(s) could be associated with root type " + this.root.getType().toString() + " - please add a configuration for this type"); for (PlasmaDataObject dataObject : this.created) { PlasmaType type = (PlasmaType)dataObject.getType(); TableConfig table = this.config.findTable(type); if (table == null) { if (log.isDebugEnabled()) log.debug("collecting unbound created: " + dataObject); associate(dataObject); } else { if (log.isDebugEnabled()) log.debug("collecting bound created: " + dataObject); } } for (PlasmaDataObject dataObject : this.modified.getResult()) { PlasmaType type = (PlasmaType)dataObject.getType(); TableConfig table = this.config.findTable(type); if (table == null) { if (log.isDebugEnabled()) log.debug("collecting unbound modified: " + dataObject); associate(dataObject); } else { if (log.isDebugEnabled()) log.debug("collecting bound modified: " + dataObject); } } List deletedResult = this.deleted.getResult(); for (int i = deletedResult.size()-1; i >= 0; i--) { PlasmaDataObject dataObject = deletedResult.get(i); PlasmaType type = (PlasmaType)dataObject.getType(); TableConfig table = this.config.findTable(type); if (table == null) { if (log.isDebugEnabled()) log.debug("collecting unbound deleted: " + dataObject); associate(dataObject); } else { if (log.isDebugEnabled()) log.debug("collecting bound deleted: " + dataObject); } } } /** * Links the given "unbound" data object to a {@link RowWriter row writer}. The containment * ancestry is searched and for the first container with a "bound" type, if an existing * associated {@link RowWriter row writer} exists for the bound type, that row writer * is returned. Otherwise the bound container data object is associated. Bound data * objects in the ancestry may not be associated if they are not part of the changed * object set within the change summary. *

* An unbound data object is not directly associated with a table but only * as part of a containment hierarchy within a graph. * @param target the data object * @throws IOException */ private void associate(DataObject target) throws IOException { TableConfig table = this.config.findTable((PlasmaType)target.getType()); if (table != null) throw new IllegalArgumentException("expected unbound data object - given data object " + target + " is bound to table, " + table.getQualifiedName()); RowWriter rowWriter = this.rowWriterMap.get(target); if (rowWriter == null) { RowWriter containerRowWriter = null; for (DataObject container : this.getContainerAncestry(target)) { TableConfig containerTable = this.config.findTable( (PlasmaType)container.getType()); if (containerTable == null) continue; // need a bound DO to associate to containerRowWriter = this.rowWriterMap.get(container); // Its container is a bound type but the container DO is not part of the // changed object set if (containerRowWriter == null) { containerRowWriter = associate(containerTable, container); } break; } if (containerRowWriter == null) throw new OperationException("no row writer could be associated with data object, " + target + ", or its containment ancestry"); rowWriter = containerRowWriter; if (log.isDebugEnabled()) log.debug("associating " + target + " with table '" + rowWriter.getTableWriter().getTableConfig().getName() + "'"); rowWriter.addDataObject(target); this.rowWriterMap.put(target, rowWriter); } else { if (log.isDebugEnabled()) log.debug("type " + target.getType() + " already associated with table '" + rowWriter.getTableWriter().getTableConfig().getName() + "' by means of another source/parent"); } } /** * Links the given "bound" data object to a row writer. A bound * data object is directly associated with a table * @param target the data object * @return the row writer. */ private RowWriter associate(TableConfig table, DataObject target) throws IOException { // a table is configured with this type as root TableWriter tableWriter = (TableWriter)result.get(table.getName()); RowWriter rowWriter = null; if (tableWriter == null) { tableWriter = new GraphTableWriter( table); rowWriter = createRowWriter(tableWriter, target); tableWriter = rowWriter.getTableWriter(); result.put(tableWriter.getTableConfig().getName(), tableWriter); } else { // just add a row writer to existing table writer rowWriter = this.addRowWriter( target, tableWriter); } if (log.isDebugEnabled()) log.debug("associating (root) " + target.getType().getURI() + "#" + target.getType().getName() + " with table '" + rowWriter.getTableWriter().getTableConfig().getName() + "'"); this.rowWriterMap.put(target, rowWriter); if (this.dataGraph.getRootObject().equals(target)) // root object this.rootTableWriter = tableWriter; return rowWriter; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy