/*
* Copyright (c) 2010 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.rdfbean.rdb;
import java.io.Closeable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.mysema.query.sql.Configuration;
import com.mysema.query.sql.RelationalPath;
import com.mysema.query.sql.SQLQuery;
import com.mysema.query.sql.SQLTemplates;
import com.mysema.query.sql.dml.SQLDeleteClause;
import com.mysema.query.sql.dml.SQLInsertClause;
import com.mysema.query.sql.dml.SQLMergeClause;
import com.mysema.rdfbean.model.BID;
import com.mysema.rdfbean.model.ID;
import com.mysema.rdfbean.model.IdSequence;
import com.mysema.rdfbean.model.LIT;
import com.mysema.rdfbean.model.NODE;
import com.mysema.rdfbean.model.RDFBeanTransaction;
import com.mysema.rdfbean.model.RepositoryException;
import com.mysema.rdfbean.model.UID;
import com.mysema.rdfbean.rdb.support.SortableQueryMetadata;
import com.mysema.rdfbean.xsd.ConverterRegistry;
/**
* RDBContext provides shared state and functionality for RDBCOnnection and
* RDBQuery
*
* @author tiwe
* @version $Id$
*/
public final class RDBContext implements Closeable {
private final ConverterRegistry converterRegistry;
private final Connection connection;
private final IdFactory idFactory;
private final IdSequence idSequence;
private final BiMap<Locale, Integer> langCache;
private final Map<Object, Long> idCache = new HashMap<Object, Long>(1000);
private final BiMap<NODE, Long> nodeCache;
private final BiMap<NODE, Long> localNodeCache = HashBiMap.create();
private final Configuration configuration;
public RDBContext(
ConverterRegistry converterRegistry,
IdFactory idFactory,
BiMap<NODE, Long> nodeCache,
BiMap<Locale, Integer> langCache,
IdSequence idSequence,
Connection connection,
SQLTemplates templates) {
this.converterRegistry = converterRegistry;
this.idFactory = idFactory;
this.idSequence = idSequence;
this.nodeCache = nodeCache;
this.langCache = langCache;
this.connection = connection;
this.configuration = new Configuration(templates);
}
public RDFBeanTransaction beginTransaction(boolean readOnly, int txTimeout, int isolationLevel) {
try {
connection.setAutoCommit(false);
connection.setReadOnly(readOnly);
if (isolationLevel != -1) {
connection.setTransactionIsolation(isolationLevel);
} else {
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
}
return new RDBTransaction(connection);
} catch (SQLException e) {
throw new RepositoryException(e);
}
}
public void clear() {
localNodeCache.clear();
}
@Override
public void close() {
try {
connection.close();
} catch (SQLException e) {
throw new RepositoryException(e.getMessage(), e);
}
}
public SQLDeleteClause createDelete(RelationalPath<?> entity) {
return new SQLDeleteClause(connection, configuration, entity);
}
public SQLInsertClause createInsert(RelationalPath<?> entity) {
return new SQLInsertClause(connection, configuration, entity);
}
public SQLMergeClause createMerge(RelationalPath<?> entity) {
return new SQLMergeClause(connection, configuration, entity);
}
public SQLQuery createQuery() {
return new SQLQuery(connection, configuration, new SortableQueryMetadata());
}
public Long getId(Object constant) {
Long id = idCache.get(constant);
if (id == null) {
UID type = converterRegistry.getDatatype(constant.getClass());
String lexical = converterRegistry.toString(constant);
id = getNodeId(new LIT(lexical, type));
// Date is not immutable, so it can't be cached safely
if (!java.util.Date.class.isAssignableFrom(constant.getClass())) {
idCache.put(constant, id);
}
}
return id;
}
public ID getID(String lex) {
if (lex.contains(":")) {
return new UID(lex);
} else {
return new BID(lex);
}
}
@Nullable
public Locale getLang(int id) {
return langCache.inverse().get(id);
}
public Integer getLangId(Locale locale) {
Integer id = langCache.get(locale);
if (id == null) {
id = idFactory.getId(locale);
langCache.put(locale, id);
}
return id;
}
public long getNextLocalId() {
return idSequence.getNextId();
}
@Nullable
public NODE getNode(long id, Function<Long, NODE> t) {
NODE node = nodeCache.inverse().get(id);
if (node == null) {
node = localNodeCache.inverse().get(id);
if (node == null) {
node = t.apply(id);
localNodeCache.put(node, id);
}
}
return node;
}
public Long getNodeId(NODE node) {
Long id = nodeCache.get(node);
if (id == null) {
id = localNodeCache.get(node);
if (id == null) {
id = idFactory.getId(node);
localNodeCache.put(node, id);
}
}
return id;
}
public Collection<NODE> getNodes() {
return nodeCache.keySet();
}
public <T> T convert(String value, Class<T> requiredType) {
return converterRegistry.fromString(value, requiredType);
}
public ConverterRegistry getConverters() {
return converterRegistry;
}
}