org.cloudgraph.rdb.service.GraphDispatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cloudgraph-rdb Show documentation
Show all versions of cloudgraph-rdb 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.
The newest version!
/**
* Copyright 2017 TerraMeta Software, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cloudgraph.rdb.service;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudgraph.rdb.filter.RDBStatementExecutor;
import org.cloudgraph.rdb.filter.RDBStatementFactory;
import org.cloudgraph.store.lang.StatementExecutor;
import org.cloudgraph.store.lang.StatementFactory;
import org.cloudgraph.store.service.CreatedCommitComparator;
import org.cloudgraph.store.service.DeletedCommitComparator;
import org.cloudgraph.store.service.GraphServiceException;
import org.plasma.runtime.DataAccessProvider;
import org.plasma.runtime.DataAccessProviderName;
import org.plasma.runtime.PlasmaRuntime;
import org.plasma.sdo.DataFlavor;
import org.plasma.sdo.PlasmaChangeSummary;
import org.plasma.sdo.PlasmaDataGraph;
import org.plasma.sdo.PlasmaDataGraphVisitor;
import org.plasma.sdo.PlasmaDataObject;
import org.plasma.sdo.PlasmaNode;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.access.DataAccessException;
import org.plasma.sdo.access.DataGraphDispatcher;
import org.plasma.sdo.access.InvalidSnapshotException;
import org.plasma.sdo.access.LockedEntityException;
import org.plasma.sdo.access.RequiredPropertyException;
import org.plasma.sdo.access.SequenceGenerator;
import org.plasma.sdo.access.provider.common.ModifiedObjectCollector;
import org.plasma.sdo.access.provider.common.PropertyPair;
import org.plasma.sdo.core.CoreConstants;
import org.plasma.sdo.core.CoreDataObject;
import org.plasma.sdo.core.CoreHelper;
import org.plasma.sdo.core.NullValue;
import org.plasma.sdo.core.SnapshotMap;
import org.plasma.sdo.profile.ConcurrencyType;
import org.plasma.sdo.profile.ConcurrentDataFlavor;
import org.plasma.sdo.profile.KeyType;
import sorts.InsertionSort;
import commonj.sdo.ChangeSummary.Setting;
import commonj.sdo.DataGraph;
import commonj.sdo.DataObject;
import commonj.sdo.Property;
import commonj.sdo.Type;
public class GraphDispatcher implements DataGraphDispatcher {
private static Log log = LogFactory.getLog(GraphDispatcher.class);
private SnapshotMap snapshotMap;
private SequenceGenerator sequenceGenerator;
private String username;
private StatementFactory statementFactory;
private StatementExecutor statementExecutor;
@SuppressWarnings("unused")
private GraphDispatcher() {
}
public GraphDispatcher(SnapshotMap snapshotMap, String username, Connection con) {
this.snapshotMap = snapshotMap;
this.username = username;
this.statementFactory = new RDBStatementFactory();
this.statementExecutor = new RDBStatementExecutor(con);
}
public void close() {
if (sequenceGenerator != null)
sequenceGenerator.close();
}
@Override
public SnapshotMap commit(DataGraph[] dataGraphs) {
for (DataGraph dataGraph : dataGraphs)
commit(dataGraph);
return this.snapshotMap;
}
@Override
public SnapshotMap commit(DataGraph dataGraph) {
if (username == null || username.length() == 0)
throw new IllegalArgumentException("expected username param not, '"
+ String.valueOf(username) + "'");
else if (log.isDebugEnabled()) {
log.debug("current user is '" + username + "'");
}
if (log.isDebugEnabled()) {
log.debug(dataGraph.getChangeSummary().toString());
log.debug(((PlasmaDataGraph) dataGraph).dump());
}
PlasmaChangeSummary changeSummary = (PlasmaChangeSummary) dataGraph.getChangeSummary();
List list = changeSummary.getChangedDataObjects();
DataObject[] changed = new DataObject[list.size()];
list.toArray(changed);
if (log.isDebugEnabled()) {
StringBuffer buf = new StringBuffer();
buf.append('\n');
for (int i = 0; i < changed.length; i++) {
DataObject dataObject = changed[i];
if (changeSummary.isCreated(dataObject))
buf.append("created: ");
else if (changeSummary.isModified(dataObject))
buf.append("modified: ");
else if (changeSummary.isDeleted(dataObject))
buf.append("deleted: ");
buf.append(dataObject.getType().getName() + " (" + dataObject.toString() + ")");
buf.append(" depth: " + changeSummary.getPathDepth(dataObject));
buf.append('\n');
}
log.debug("commit list: " + buf.toString());
}
List createdList = new ArrayList();
for (int i = 0; i < changed.length; i++) {
DataObject dataObject = changed[i];
if (changeSummary.isCreated(dataObject))
createdList.add((CoreDataObject) dataObject);
}
CoreDataObject[] createdArray = new CoreDataObject[createdList.size()];
createdList.toArray(createdArray);
if (log.isDebugEnabled()) {
int createdIndex = 0;
for (DataObject dataObject : createdArray) {
log.debug("created before sort " + createdIndex + ": " + dataObject.toString());
createdIndex++;
}
}
Comparator comparator = new CreatedCommitComparator();
InsertionSort sort = new InsertionSort();
sort.sort(createdArray, comparator);
if (log.isDebugEnabled()) {
int createdIndex = 0;
for (DataObject dataObject : createdArray) {
log.debug("created after sort " + createdIndex + ": " + dataObject.toString());
createdIndex++;
}
}
List deletedList = new ArrayList();
for (int i = 0; i < changed.length; i++) {
DataObject dataObject = changed[i];
if (changeSummary.isDeleted(dataObject))
deletedList.add((CoreDataObject) dataObject);
}
CoreDataObject[] deletedArray = new CoreDataObject[deletedList.size()];
deletedList.toArray(deletedArray);
if (log.isDebugEnabled()) {
int deletedIndex = 0;
for (DataObject dataObject : deletedArray) {
log.debug("deleted before sort " + deletedIndex + ": " + dataObject.toString());
deletedIndex++;
}
}
comparator = new DeletedCommitComparator();
sort = new InsertionSort();
sort.sort(deletedArray, comparator);
if (log.isDebugEnabled()) {
int deletedIndex = 0;
for (int i = deletedArray.length - 1; i >= 0; i--) {
DataObject dataObject = deletedArray[i];
log.debug("deleted after sort " + deletedIndex + ": " + dataObject.toString());
deletedIndex++;
}
}
ModifiedObjectCollector modified = new ModifiedObjectCollector(dataGraph);
try {
for (PlasmaDataObject dataObject : createdArray)
create(dataGraph, dataObject);
for (PlasmaDataObject dataObject : modified.getResult())
update(dataGraph, dataObject);
// for (int i = deletedArray.length-1; i >= 0; i--) {
for (PlasmaDataObject dataObject : deletedArray) {
// DataObject dataObject = deletedArray[i];
delete(dataGraph, dataObject);
}
// FIXME: lock flags/values not found in change summary, must
// traverse non-changed
// nodes in graph to catch any concurrency flags
new UpdatePessimisticVisitor(dataGraph);
return snapshotMap;
} catch (IllegalAccessException e) {
throw new RDBServiceException(e);
} catch (IllegalArgumentException e) {
throw new RDBServiceException(e);
} catch (InvocationTargetException e) {
throw new RDBServiceException(e);
} catch (SQLException e) {
throw new RDBServiceException(e);
} catch (RuntimeException e) {
throw e;
}
}
private void create(DataGraph dataGraph, PlasmaDataObject dataObject)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
PlasmaType type = (PlasmaType) dataObject.getType();
UUID uuid = ((CoreDataObject) dataObject).getUUID();
if (uuid == null)
throw new DataAccessException("expected UUID for inserted entity '" + type.getName() + "'");
if (log.isDebugEnabled())
log.debug("creating " + type.getName() + " '"
+ ((PlasmaDataObject) dataObject).getUUIDAsString() + "'");
Map entity = new HashMap();
List pkList = type.findProperties(KeyType.primary);
if (pkList == null || pkList.size() == 0)
throw new DataAccessException("no pri-key properties found for type '"
+ dataObject.getType().getName() + "'");
for (Property pkp : pkList) {
PlasmaProperty priKeyProperty = (PlasmaProperty) pkp;
Object pk = dataObject.get(priKeyProperty.getName());
if (priKeyProperty.getType().isDataType()) {
if (pk == null) {
if (this.hasSequenceGenerator()) {
DataFlavor dataFlavor = priKeyProperty.getDataFlavor();
switch (dataFlavor) {
case integral:
if (sequenceGenerator == null) {
sequenceGenerator = this.newSequenceGenerator();
sequenceGenerator.initialize();
}
if (log.isDebugEnabled()) {
log.debug("getting seq-num for " + type.getName());
}
pk = sequenceGenerator.get(dataObject);
PropertyPair pair = new PropertyPair(priKeyProperty, pk);
entity.put(priKeyProperty.getName(), pair);
// entity.set(targetPriKeyProperty.getName(),
// pk);
((CoreDataObject) dataObject).setValue(priKeyProperty.getName(), pk); // FIXME:
// bypassing
// modification
// detection
// on
// pri-key
break;
default:
throw new DataAccessException("found null primary key property '"
+ priKeyProperty.getName() + "' for type, " + type.getURI() + "#"
+ type.getName());
}
}
} else {
PropertyPair pair = new PropertyPair(priKeyProperty, pk);
entity.put(priKeyProperty.getName(), pair);
}
} else // ref type
{
if (pk == null)
throw new DataAccessException("found null primary key value for property '"
+ priKeyProperty.toString() + " on property supplier chain");
PlasmaProperty priKeyValueProperty = priKeyProperty;
DataObject priKeyDataObject = dataObject;
// traverse to the datatype pk property for this reference
while (!priKeyValueProperty.getType().isDataType()) {
priKeyValueProperty = this.statementFactory
.getOppositePriKeyProperty(priKeyValueProperty);
priKeyDataObject = (DataObject) pk;
pk = priKeyDataObject.get(priKeyValueProperty.getName());
if (pk == null)
throw new DataAccessException("found null primary key value for property '"
+ priKeyValueProperty.toString() + " on property supplier chain");
}
PropertyPair pair = new PropertyPair(priKeyProperty, pk);
entity.put(priKeyProperty.getName(), pair);
pair.setValueProp(priKeyValueProperty);
}
if (pk != null) {
if (priKeyProperty.getType().isDataType()) {
if (log.isDebugEnabled()) {
log.debug("mapping UUID '" + uuid + "' to pk (" + String.valueOf(pk) + ")");
}
PropertyPair pkPair = new PropertyPair(priKeyProperty, pk);
snapshotMap.put(uuid, pkPair); // map new PK back to UUID
} else {
log.warn("ignoring FK pk property, " + priKeyProperty.toString());
}
}
}
// FIXME - could be a reference to a user
Property originationUserProperty = type.findProperty(ConcurrencyType.origination,
ConcurrentDataFlavor.user);
if (originationUserProperty != null)
entity.put(originationUserProperty.getName(), new PropertyPair(
(PlasmaProperty) originationUserProperty, username));
// entity.set(originationUserProperty.getName(), username);
else if (log.isDebugEnabled())
log.debug("could not find origination (username) property for type, " + type.getURI() + "#"
+ type.getName());
Property originationTimestampProperty = type.findProperty(ConcurrencyType.origination,
ConcurrentDataFlavor.time);
if (originationTimestampProperty != null)
entity.put(originationTimestampProperty.getName(), new PropertyPair(
(PlasmaProperty) originationTimestampProperty, this.snapshotMap.getSnapshotDate()));
// entity.set(originationTimestampProperty.getName(),
// this.snapshotMap.getSnapshotDate());
else if (log.isDebugEnabled())
log.debug("could not find origination date property for type, " + type + "#" + type.getName());
Property concurrencyUserProperty = type.findProperty(ConcurrencyType.optimistic,
ConcurrentDataFlavor.user);
if (concurrencyUserProperty != null)
entity.put(concurrencyUserProperty.getName(), new PropertyPair(
(PlasmaProperty) concurrencyUserProperty, username));
// entity.set(concurrencyUserProperty.getName(), username);
else if (log.isDebugEnabled())
log.debug("could not find optimistic concurrency (username) property for type, "
+ type.getURI() + "#" + dataObject.getType().getName());
Property concurrencyVersionProperty = type.findProperty(ConcurrencyType.optimistic,
ConcurrentDataFlavor.time);
if (concurrencyVersionProperty != null)
entity.put(concurrencyVersionProperty.getName(), new PropertyPair(
(PlasmaProperty) concurrencyVersionProperty, this.snapshotMap.getSnapshotDate()));
// entity.set(concurrencyVersionProperty.getName(),
// this.snapshotMap.getSnapshotDate());
else if (log.isDebugEnabled())
log.debug("could not find optimistic concurrency version property for type, " + type.getURI()
+ "#" + type.getName());
List properties = type.getProperties();
for (Property p : properties) {
PlasmaProperty property = (PlasmaProperty) p;
if (property.isMany())
continue;
if (property.isKey(KeyType.primary))
continue; // handled above
if (property.getConcurrent() != null)
continue;
Object value = dataObject.get(property);
if (value != null) {
PropertyPair pair = createValue(dataObject, value, property);
entity.put(property.getName(), pair);
}
}
StringBuilder insert = this.statementFactory.createInsert(type, entity);
if (log.isDebugEnabled()) {
log.debug("inserting " + dataObject.getType().getName());
}
if (!this.hasSequenceGenerator()) {
List keys = this.statementExecutor.executeInsertWithGeneratedKeys(type, insert,
entity);
for (Property pkp : pkList) {
PlasmaProperty targetPriKeyProperty = (PlasmaProperty) pkp;
for (PropertyPair key : keys) {
if (targetPriKeyProperty.getName().equals(key.getProp().getName())) {
if (log.isDebugEnabled()) {
log.debug("mapping UUID '" + uuid + "' to pk (" + String.valueOf(key.getValue())
+ ")");
}
snapshotMap.put(uuid, key); // map new PK back to UUID
}
}
}
} else {
this.statementExecutor.executeInsert(type, insert, entity);
}
}
private void update(DataGraph dataGraph, PlasmaDataObject dataObject)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException,
SQLException {
PlasmaType type = (PlasmaType) dataObject.getType();
if (log.isDebugEnabled())
log.debug("updating " + type.getName() + " '"
+ ((PlasmaDataObject) dataObject).getUUIDAsString() + "'");
List pkList = type.findProperties(KeyType.primary);
if (pkList == null || pkList.size() == 0)
throw new DataAccessException("no pri-key properties found for type '"
+ dataObject.getType().getName() + "'");
List pkPairs = new ArrayList();
for (Property pkp : pkList) {
PlasmaProperty pkProperty = (PlasmaProperty) pkp;
Object pk = dataObject.get(pkProperty);
if (pk == null)
throw new DataAccessException("found null primary key property '" + pkProperty.getName()
+ "' for type, " + type.getURI() + "#" + type.getName());
Setting setting = dataGraph.getChangeSummary().getOldValue(dataObject, pkProperty);
if (setting != null) { // it's been modified
// pk has been modified, yet we need it to lookup record, use
// the old value
if (!pkProperty.isReadOnly()) {
Object oldPk = setting.getValue();
PropertyPair pair = this.createValue(dataObject, pk, oldPk, pkProperty);
pkPairs.add(pair);
} else
throw new IllegalAccessException("attempt to modify read-only property, " + type.getURI()
+ "#" + type.getName() + "." + pkProperty.getName());
} else {
PropertyPair pair = this.createValue(dataObject, pk, pkProperty);
pkPairs.add(pair);
}
}
// 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() + "'");
else if (log.isDebugEnabled())
log.debug("snapshot date: " + String.valueOf(snapshotDate));
PlasmaProperty lockingUserProperty = (PlasmaProperty) type.findProperty(
ConcurrencyType.pessimistic, ConcurrentDataFlavor.user);
if (lockingUserProperty == null)
if (log.isDebugEnabled())
log.debug("could not find locking user property for type, " + type.getURI() + "#"
+ type.getName());
PlasmaProperty lockingTimestampProperty = (PlasmaProperty) type.findProperty(
ConcurrencyType.pessimistic, ConcurrentDataFlavor.time);
if (lockingTimestampProperty == null)
if (log.isDebugEnabled())
log.debug("could not find locking timestamp property for type, " + type.getURI() + "#"
+ type.getName());
PlasmaProperty concurrencyUserProperty = (PlasmaProperty) type.findProperty(
ConcurrencyType.optimistic, ConcurrentDataFlavor.user);
if (concurrencyUserProperty == null)
if (log.isDebugEnabled())
log.debug("could not find optimistic concurrency (username) property for type, "
+ type.getURI() + "#" + type.getName());
PlasmaProperty concurrencyTimestampProperty = (PlasmaProperty) type.findProperty(
ConcurrencyType.optimistic, ConcurrentDataFlavor.time);
if (concurrencyTimestampProperty == null)
if (log.isDebugEnabled())
log.debug("could not find optimistic concurrency timestamp property for type, "
+ type.getURI() + "#" + type.getName());
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy