package org.xenei.jdbc4sparql.impl.rdf;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.xenei.jdbc4sparql.iface.ColumnDef;
import org.xenei.jdbc4sparql.iface.Key;
import org.xenei.jdbc4sparql.iface.TableDef;
import org.xenei.jena.entities.EntityManager;
import org.xenei.jena.entities.EntityManagerFactory;
import org.xenei.jena.entities.EntityManagerRequiredException;
import org.xenei.jena.entities.MissingAnnotation;
import org.xenei.jena.entities.ResourceWrapper;
import org.xenei.jena.entities.annotations.Predicate;
import org.xenei.jena.entities.annotations.Subject;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFList;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
@Subject(namespace = "http://org.xenei.jdbc4sparql/entity/TableDef#")
public class RdfTableDef extends RdfNamespacedObject implements TableDef,
ResourceWrapper {
public static class Builder implements TableDef {
private boolean distinct = false;
private final List<ColumnDef> columnDefs = new ArrayList<ColumnDef>();
private RdfKey primaryKey;
private RdfKey sortKey;
private RdfTableDef superTable;
private final Class<? extends RdfTableDef> typeClass = RdfTableDef.class;
private final Class<? extends RdfColumnDef> colDefClass = RdfColumnDef.class;
public Builder addColumnDef(final ColumnDef column) {
if (column instanceof ResourceWrapper) {
columnDefs.add(column);
return this;
}
throw new IllegalArgumentException(
"ColumnDef must implement ResourceWrapper");
}
public RdfTableDef build(final Model model) {
checkBuildState();
final String fqName = getFQName();
final ResourceBuilder builder = new ResourceBuilder(model);
final EntityManager entityManager = EntityManagerFactory
.getEntityManager();
Resource tableDef = null;
if (builder.hasResource(fqName)) {
tableDef = builder.getResource(fqName, typeClass);
}
else {
tableDef = builder.getResource(fqName, typeClass);
if (primaryKey != null) {
tableDef.addProperty(
builder.getProperty(typeClass, "primaryKey"),
primaryKey.getResource());
}
if (sortKey != null) {
tableDef.addProperty(
builder.getProperty(typeClass, "sortKey"),
sortKey.getResource());
}
if (superTable != null) {
tableDef.addProperty(
builder.getProperty(typeClass, "superTableDef"),
superTable.getResource());
}
tableDef.addLiteral(builder.getProperty(typeClass, "distinct"),
distinct);
RDFList lst = null;
for (final ColumnDef seg : columnDefs) {
final Resource s = ((ResourceWrapper) seg).getResource();
if (lst == null) {
lst = model.createList().with(s);
}
else {
lst.add(s);
}
}
final Property p = model.createProperty(ResourceBuilder
.getFQName(colDefClass));
tableDef.addProperty(p, lst);
}
try {
return entityManager.read(tableDef, typeClass);
} catch (final MissingAnnotation e) {
throw new RuntimeException(e);
}
}
protected void checkBuildState() {
if (columnDefs.size() == 0) {
throw new IllegalStateException(
"There must be at least one column defined");
}
}
@Override
public int getColumnCount() {
return columnDefs.size();
}
@Override
public ColumnDef getColumnDef(final int idx) {
return columnDefs.get(idx);
}
@Override
public List<ColumnDef> getColumnDefs() {
return columnDefs;
}
@Override
public int getColumnIndex(final ColumnDef column) {
return columnDefs.indexOf(column);
}
public String getFQName() {
final StringBuilder sb = new StringBuilder();
for (final ColumnDef cd : columnDefs) {
sb.append(((ResourceWrapper) cd).getResource().getURI())
.append(" ");
}
if (primaryKey != null) {
sb.append(primaryKey.getId()).append(" ");
}
if (sortKey != null) {
sb.append(sortKey.getId()).append(" ");
}
if (superTable != null) {
sb.append(superTable.getResource().getURI());
}
return String.format("%s/instance/UUID-%s",
ResourceBuilder.getFQName(RdfTableDef.class),
UUID.nameUUIDFromBytes(sb.toString().getBytes()));
}
@Override
public RdfKey getPrimaryKey() {
return primaryKey;
}
@Override
public Key getSortKey() {
return sortKey;
}
@Override
public TableDef getSuperTableDef() {
return superTable;
}
public void setDistinct(final boolean distinct) {
this.distinct = distinct;
}
public Builder setPrimaryKey(final RdfKey key) {
if (!key.isUnique()) {
throw new IllegalArgumentException(
"primary key must be a unique key");
}
this.primaryKey = key;
return this;
}
public Builder setSortKey(final RdfKey key) {
this.sortKey = key;
return this;
}
public Builder setSuperTableDef(final RdfTableDef tableDef) {
this.superTable = tableDef;
return this;
}
}
private List<ColumnDef> columns;
private final Class<? extends RdfColumnDef> colDefClass = RdfColumnDef.class;
@Override
public int getColumnCount() {
return getColumnDefs().size();
}
@Override
public ColumnDef getColumnDef(final int idx) {
return getColumnDefs().get(idx);
}
@Override
public List<ColumnDef> getColumnDefs() {
if (columns == null) {
final EntityManager entityManager = EntityManagerFactory
.getEntityManager();
columns = new ArrayList<ColumnDef>();
final Resource resource = getResource();
final Property p = resource.getModel().createProperty(
ResourceBuilder.getFQName(RdfColumnDef.class));
final List<RDFNode> resLst = resource.getRequiredProperty(p)
.getResource().as(RDFList.class).asJavaList();
for (final RDFNode n : resLst) {
try {
columns.add(entityManager.read(n.asResource(), colDefClass));
} catch (final MissingAnnotation e) {
throw new RuntimeException(e);
}
}
}
return columns;
}
@Override
public int getColumnIndex(final ColumnDef column) {
return getColumnDefs().indexOf(column);
}
/**
* get the primary key for the table
*
* @return
*/
@Override
@Predicate(impl = true)
public RdfKey getPrimaryKey() {
throw new EntityManagerRequiredException();
}
@Override
@Predicate(impl = true)
public Resource getResource() {
throw new EntityManagerRequiredException();
}
/**
* Get the table sort order key. returns null if the table is not sorted.
*
* @return
*/
@Override
@Predicate(impl = true)
public RdfKey getSortKey() {
throw new EntityManagerRequiredException();
}
@Override
@Predicate(impl = true)
public RdfTableDef getSuperTableDef() {
throw new EntityManagerRequiredException();
}
@Predicate(impl = true)
public boolean isDistinct() {
throw new EntityManagerRequiredException();
}
}