/*
* Copyright (c) 2007, 2010, James Leigh All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the openrdf.org nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package net.enilink.komma.em;
import java.util.Locale;
import java.util.Set;
import net.enilink.komma.core.IDialect;
import net.enilink.komma.core.IEntityManager;
import net.enilink.komma.core.IEntityManagerFactory;
import net.enilink.komma.core.IProvider;
import net.enilink.komma.core.IUnitOfWork;
import net.enilink.komma.core.KommaModule;
import net.enilink.komma.core.SparqlStandardDialect;
import net.enilink.komma.core.URI;
import net.enilink.komma.dm.IDataManagerFactory;
import net.enilink.komma.em.util.IClosable;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
/**
* Creates {@link IEntityManager}s.
*
*/
class EntityManagerFactory implements IEntityManagerFactory {
@Inject(optional = true)
Set<IClosable> closables;
@Inject(optional = true)
IDataManagerFactory dmFactory;
private IEntityManagerFactory parent = null;
IProvider<Locale> locale;
Injector injector;
Module managerModule;
KommaModule module;
private volatile boolean open = true;
@Inject
IUnitOfWork unitOfWork;
volatile IEntityManager sharedManager;
EntityManagerFactory(KommaModule module, IProvider<Locale> locale,
Module managerModule) {
this.module = module;
this.locale = locale;
this.managerModule = managerModule;
}
public synchronized void close() {
if (open) {
if (parent == null) {
if (dmFactory != null) {
dmFactory.close();
}
if (closables != null) {
for (IClosable closable : closables) {
closable.close();
}
closables = null;
}
}
open = false;
}
}
private void ensureFactoryIsOpened() {
if (!open) {
throw new RuntimeException("EntityManagerFactory is closed!");
}
}
@Override
public IEntityManager create() {
ensureFactoryIsOpened();
return getManagerInjector(new AbstractModule() {
@Override
protected void configure() {
bind(IEntityManager.class)
.to(Key.get(IEntityManager.class,
Names.named("unmanaged"))).in(Singleton.class);
}
}).getInstance(IEntityManager.class);
}
@Override
public IEntityManager create(final IEntityManager scope) {
ensureFactoryIsOpened();
return getManagerInjector(new AbstractModule() {
@Override
protected void configure() {
bind(IEntityManager.class).toInstance(scope);
}
}).getInstance(Key.get(IEntityManager.class, Names.named("unmanaged")));
}
@Override
public IEntityManagerFactory createChildFactory(KommaModule... modules) {
return createChildFactory(null, modules);
}
@Override
public IEntityManagerFactory createChildFactory(IProvider<Locale> locale,
KommaModule... modules) {
KommaModule childModule = new KommaModule(module.getClassLoader());
childModule.includeModule(module);
for (KommaModule include : modules) {
childModule.includeModule(include);
for (URI writable : include.getWritableGraphs()) {
childModule.addWritableGraph(writable);
}
}
EntityManagerFactory childFactory = new EntityManagerFactory(
childModule, locale == null ? this.locale : locale,
managerModule);
childFactory.parent = this;
injector.injectMembers(childFactory);
return childFactory;
}
@Override
public IEntityManager get() {
if (sharedManager == null) {
synchronized (this) {
if (sharedManager == null) {
sharedManager = getManagerInjector(new AbstractModule() {
@Override
protected void configure() {
final Provider<IEntityManager> provider = getProvider(Key
.get(IEntityManager.class,
Names.named("unmanaged")));
ThreadLocalEntityManager manager = new ThreadLocalEntityManager() {
@Override
protected IEntityManager initialValue() {
return provider.get();
}
};
bind(IEntityManager.class).toInstance(manager);
requestInjection(manager);
}
}).getInstance(IEntityManager.class);
}
}
}
return sharedManager;
}
@Override
public IDialect getDialect() {
if (dmFactory != null) {
return dmFactory.getDialect();
}
return new SparqlStandardDialect();
}
@Override
public IEntityManagerFactory getParent() {
return parent;
}
protected synchronized Injector getManagerInjector(
AbstractModule customModule) {
return injector.createChildInjector(customModule,
new ManagerCompositionModule(module), new AbstractModule() {
@Override
protected void configure() {
bind(IEntityManagerFactory.class).annotatedWith(
Names.named("currentFactory")).toInstance(
EntityManagerFactory.this);
bind(new TypeLiteral<Set<URI>>() {
}).annotatedWith(Names.named("readContexts"))
.toInstance(module.getReadableGraphs());
bind(new TypeLiteral<Set<URI>>() {
}).annotatedWith(Names.named("modifyContexts"))
.toInstance(module.getWritableGraphs());
bind(Locale.class).toProvider(new Provider<Locale>() {
@Override
public Locale get() {
return locale == null ? Locale.getDefault()
: locale.get();
}
});
}
}, managerModule);
}
@Override
public KommaModule getModule() {
return module;
}
@Override
public IUnitOfWork getUnitOfWork() {
return unitOfWork;
}
public boolean isOpen() {
return open;
}
@Inject
public void setInjector(Injector injector) {
// do not re-inject injector for currentFactory
if (this.injector == null) {
this.injector = injector;
}
}
}