package org.xenei.jdbc4sparql.impl.rdf; import java.util.HashSet; import java.util.Set; import java.util.UUID; import org.xenei.jdbc4sparql.iface.Catalog; import org.xenei.jdbc4sparql.iface.NameFilter; import org.xenei.jdbc4sparql.iface.Schema; import org.xenei.jdbc4sparql.iface.Table; import org.xenei.jdbc4sparql.iface.name.SchemaName; 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.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.vocabulary.RDFS; @Subject(namespace = "http://org.xenei.jdbc4sparql/entity/Schema#") public class RdfSchema extends RdfNamespacedObject implements Schema, ResourceWrapper { public static class Builder implements Schema { public static RdfSchema fixupCatalog(final RdfCatalog catalog, final RdfSchema schema) { schema.catalog = catalog; final Property p = ResourceFactory.createProperty( ResourceBuilder.getNamespace(RdfCatalog.class), "schemas"); catalog.getResource().addProperty(p, schema.getResource()); return schema; } private String name; private RdfCatalog catalog; private final Set<Table> tables = new HashSet<Table>(); public RdfSchema build(final Model model) { checkBuildState(); final Class<?> typeClass = RdfSchema.class; final String fqName = getFQName(); final ResourceBuilder builder = new ResourceBuilder(model); final EntityManager entityManager = EntityManagerFactory .getEntityManager(); Resource schema = null; if (builder.hasResource(fqName)) { schema = builder.getResource(fqName, typeClass); } else { schema = builder.getResource(fqName, typeClass); schema.addLiteral(RDFS.label, name); for (final Table tbl : tables) { if (tbl instanceof ResourceWrapper) { schema.addProperty( builder.getProperty(typeClass, "table"), ((ResourceWrapper) tbl).getResource()); } } } try { RdfSchema retval = entityManager.read(schema, RdfSchema.class); retval = Builder.fixupCatalog(catalog, retval); model.register(retval.new ChangeListener()); return retval; } catch (final MissingAnnotation e) { throw new RuntimeException(e); } } private void checkBuildState() { if (name == null) { throw new IllegalStateException("Name must be set"); } if (catalog == null) { throw new IllegalStateException("catalog must be set"); } } @Override public NameFilter<Table> findTables(final String tableNamePattern) { return new NameFilter<Table>(tableNamePattern, tables); } @Override public Catalog getCatalog() { return catalog; } private String getFQName() { final StringBuilder sb = new StringBuilder() .append(catalog.getResource().getURI()).append(" ") .append(name); return String .format("%s/instance/N%s", ResourceBuilder .getFQName(RdfSchema.class), UUID.nameUUIDFromBytes(sb.toString().getBytes()).toString()); } @Override public SchemaName getName() { return new SchemaName(catalog.getShortName(), name); } @Override public Table getTable(final String tableName) { final NameFilter<Table> nf = findTables(tableName); return nf.hasNext() ? nf.next() : null; } @Override public Set<Table> getTables() { return tables; } public Builder setCatalog(final RdfCatalog catalog) { this.catalog = catalog; return this; } public Builder setName(final String name) { this.name = name; return this; } } public class ChangeListener extends AbstractChangeListener<Schema, RdfTable> { public ChangeListener() { super(RdfSchema.this.getResource(), RdfSchema.class, "tables", RdfTable.class); } @Override protected void addObject(final RdfTable t) { tableList.add(t); } @Override protected void clearObjects() { tableList = null; } @Override protected boolean isListening() { return tableList != null; } @Override protected void removeObject(final RdfTable t) { tableList.remove(t); } } private RdfCatalog catalog; private SchemaName schemaName = null; private Set<Table> tableList; @Predicate(impl = true) public void addTables(final RdfTable table) { throw new EntityManagerRequiredException(); } public void delete() { for (final Table tbl : readTables()) { tbl.delete(); } final Model model = getResource().getModel(); model.enterCriticalSection(Lock.WRITE); try { getResource().getModel().remove(null, null, getResource()); getResource().getModel().remove(getResource(), null, null); } finally { model.leaveCriticalSection(); } } @Override public NameFilter<Table> findTables(final String tableNamePattern) { return new NameFilter<Table>(tableNamePattern, readTables()); } public Set<Table> fixupTables(final Set<Table> tables) { final Set<Table> tableList = new HashSet<Table>(); for (final Table table : tables) { tableList.add(RdfTable.Builder.fixupSchema(this, (RdfTable) table)); } this.tableList = tableList; return tableList; } @Override public RdfCatalog getCatalog() { if (catalog == null) { final Property p = ResourceFactory.createProperty( ResourceBuilder.getNamespace(RdfCatalog.class), "schemas"); Resource r = this.getResource(); r = r.getModel().listSubjectsWithProperty(p, r).next(); final EntityManager entityManager = EntityManagerFactory .getEntityManager(); try { catalog = entityManager.read(r, RdfCatalog.class); } catch (final MissingAnnotation e) { throw new RuntimeException(e.getMessage(), e); } } return catalog; } @Predicate(impl = true, namespace = "http://www.w3.org/2000/01/rdf-schema#", name = "label") public String getLocalSchemaName() { throw new EntityManagerRequiredException(); } @Override public SchemaName getName() { if (schemaName == null) { schemaName = new SchemaName(getCatalog().getShortName(), getLocalSchemaName()); } return schemaName; } @Override @Predicate(impl = true) public Resource getResource() { throw new EntityManagerRequiredException(); } @Override public Table getTable(final String tableName) { final NameFilter<Table> nf = findTables(tableName); return nf.hasNext() ? nf.next() : null; } @Override @Predicate(impl = true, type = RdfTable.class, postExec = "fixupTables") public Set<Table> getTables() { throw new EntityManagerRequiredException(); } private Set<Table> readTables() { if (tableList == null) { tableList = getTables(); } return tableList; } @Override public String toString() { return getName().toString(); } }