/**
* Copyright 2012 Impetus Infotech.
*
* 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 com.impetus.client.neo4j;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.impetus.client.neo4j.config.Neo4JPropertyReader;
import com.impetus.client.neo4j.config.Neo4JPropertyReader.Neo4JSchemaMetadata;
import com.impetus.kundera.PersistenceProperties;
import com.impetus.kundera.client.Client;
import com.impetus.kundera.configure.ClientProperties;
import com.impetus.kundera.configure.ClientProperties.DataStore;
import com.impetus.kundera.configure.PersistenceUnitConfigurationException;
import com.impetus.kundera.configure.schema.api.SchemaManager;
import com.impetus.kundera.loader.GenericClientFactory;
import com.impetus.kundera.metadata.model.PersistenceUnitMetadata;
/**
* Factory of Neo4J client(s)
*
* @author amresh.singh
*/
public class Neo4JClientFactory extends GenericClientFactory
{
/** The logger. */
private static Logger log = LoggerFactory.getLogger(Neo4JClientFactory.class);
@Override
public void initialize(Map<String, Object> puProperties)
{
initializePropertyReader();
setExternalProperties(puProperties);
}
/**
* Create Neo4J Embedded Graph DB instance, that acts as a Neo4J connection
* repository for Neo4J If a Neo4j specfic client properties file is
* specified in persistence.xml, it initializes DB instance with those
* properties. Other DB instance is initialized with default properties.
*/
@Override
protected Object createPoolOrConnection()
{
if (log.isInfoEnabled())
log.info("Initializing Neo4J database connection...");
PersistenceUnitMetadata puMetadata = kunderaMetadata.getApplicationMetadata().getPersistenceUnitMetadata(
getPersistenceUnit());
Properties props = puMetadata.getProperties();
String datastoreFilePath = null;
if (externalProperties != null)
{
datastoreFilePath = (String) externalProperties.get(PersistenceProperties.KUNDERA_DATASTORE_FILE_PATH);
}
if (StringUtils.isBlank(datastoreFilePath))
{
datastoreFilePath = (String) props.get(PersistenceProperties.KUNDERA_DATASTORE_FILE_PATH);
}
if (StringUtils.isBlank(datastoreFilePath))
{
throw new PersistenceUnitConfigurationException(
"For Neo4J, it's mandatory to specify kundera.datastore.file.path property in persistence.xml");
}
Neo4JSchemaMetadata nsmd = Neo4JPropertyReader.nsmd;
ClientProperties cp = nsmd != null ? nsmd.getClientProperties() : null;
GraphDatabaseService graphDb = (GraphDatabaseService) getConnectionPoolOrConnection();
if (cp != null && graphDb == null)
{
DataStore dataStore = nsmd != null ? nsmd.getDataStore() : null;
Properties properties = dataStore != null && dataStore.getConnection() != null ? dataStore.getConnection()
.getProperties() : null;
if (properties != null)
{
Map<String, String> config = new HashMap<String, String>((Map) properties);
GraphDatabaseBuilder builder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(datastoreFilePath);
builder.setConfig(config);
graphDb = builder.newGraphDatabase();
// registerShutdownHook(graphDb);
}
}
if (graphDb == null)
{
graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(datastoreFilePath);
// registerShutdownHook(graphDb);
}
return graphDb;
}
@Override
protected Client instantiateClient(String persistenceUnit)
{
return new Neo4JClient(this, externalProperties, persistenceUnit, kunderaMetadata);
}
@Override
public boolean isThreadSafe()
{
return true;
}
@Override
public SchemaManager getSchemaManager(Map<String, Object> puProperties)
{
log.info("No schema manager implementation available (required) for Neo4J.");
return null;
}
@Override
public void destroy()
{
this.externalProperties = null;
((GraphDatabaseService) getConnectionPoolOrConnection()).shutdown();
// Not required for multithreaded clients
}
/**
* Retrieves {@link GraphDatabaseService} instance
*
* @return
*/
GraphDatabaseService getConnection()
{
return (GraphDatabaseService) getConnectionPoolOrConnection();
}
void setConnection(GraphDatabaseService graphDb)
{
setConnectionPoolOrConnection(graphDb);
}
/**
*
*/
private void initializePropertyReader()
{
if (propertyReader == null)
{
propertyReader = new Neo4JPropertyReader(externalProperties, kunderaMetadata.getApplicationMetadata()
.getPersistenceUnitMetadata(getPersistenceUnit()));
propertyReader.read(getPersistenceUnit());
}
}
/**
* @param puProperties
*/
protected void setExternalProperties(Map<String, Object> puProperties)
{
if (puProperties != null)
{
this.externalProperties = puProperties;
}
}
/**
* Registers a shutdown hook for the Neo4j instance so that it shuts down
* nicely when the VM exits (even if you "Ctrl-C" the running example before
* it's completed) The EmbeddedGraphDatabase instance can be shared among
* multiple threads. Note however that you can’t create multiple instances
* pointing to the same database.
*
* @param graphDb
*/
/*
* private static void registerShutdownHook(final GraphDatabaseService
* graphDb) { Runtime.getRuntime().addShutdownHook(new Thread() {
*
* @Override public void run() { graphDb.shutdown(); } }); }
*/
@Override
protected void initializeLoadBalancer(String loadBalancingPolicyName)
{
throw new UnsupportedOperationException("Load balancing feature is not supported in "
+ this.getClass().getSimpleName());
}
}