org.cloudgraph.hbase.io.TableWriterCollector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cloudgraph-hbase Show documentation
Show all versions of cloudgraph-hbase Show documentation
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.
/**
* 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