/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;
import org.obiba.magma.concurrent.LockManager;
import org.obiba.magma.support.Disposables;
import org.obiba.magma.support.Initialisables;
import org.obiba.magma.support.ValueTableReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@SuppressWarnings(
{ "AssignmentToStaticFieldFromInstanceMethod", "UnusedDeclaration", "StaticMethodOnlyUsedInOneClass" })
public class MagmaEngine implements DatasourceRegistry {
private final static Logger log = LoggerFactory.getLogger(MagmaEngine.class);
/**
* Keeps a reference on all singletons
*/
@SuppressWarnings("StaticNonFinalField")
private static Set<Object> singletons;
@Nullable
@SuppressWarnings("StaticNonFinalField")
private static MagmaEngine instance;
private final ValueTypeFactory valueTypeFactory;
private DatasourceRegistry datasourceRegistry = new DefaultDatasourceRegistry();
private final Set<MagmaEngineExtension> extensions = Sets.newHashSet();
private final LockManager lockManager = new LockManager();
public MagmaEngine() {
if(instance != null) {
throw new IllegalStateException(
"MagmaEngine already instantiated. Only one instance of MagmaEngine should be instantiated.");
}
instance = this;
singletons = new LinkedHashSet<>();
valueTypeFactory = new ValueTypeFactory();
}
@NotNull
public static MagmaEngine get() {
if(instance == null) {
log.debug("Instantiating a new MagmaEngine without any extensions.");
new MagmaEngine();
}
return instance;
}
public static boolean isInstantiated() {
return instance != null;
}
public MagmaEngine extend(@NotNull MagmaEngineExtension extension) {
//noinspection ConstantConditions
if(extension == null) throw new IllegalArgumentException("extension cannot be null");
if(!hasExtension(extension.getClass())) {
Initialisables.initialise(extension);
extensions.add(extension);
}
return this;
}
public boolean hasExtension(Class<? extends MagmaEngineExtension> extensionType) {
try {
Iterables.getOnlyElement(Iterables.filter(extensions, extensionType));
return true;
} catch(NoSuchElementException e) {
return false;
}
}
/**
* Returns true if the {@code MagmaEngine} has a instance of {@code MagmaEngineExtension} whose name equals the name
* provided.
*
* @param name
* @return
*/
public boolean hasExtension(String name) {
for(MagmaEngineExtension e : extensions) {
if(e.getName().equals(name)) return true;
}
return false;
}
public <T extends MagmaEngineExtension> T getExtension(Class<T> extensionType) {
try {
return Iterables.getOnlyElement(Iterables.filter(extensions, extensionType));
} catch(NoSuchElementException e) {
throw new MagmaRuntimeException("No extension of type '" + extensionType + "' was registered.");
}
}
public DatasourceRegistry getDatasourceRegistry() {
return datasourceRegistry;
}
public void decorate(Decorator<DatasourceRegistry> registryDecorator) {
datasourceRegistry = registryDecorator.decorate(datasourceRegistry);
}
@Override
public ValueTableReference createReference(String reference) {
return getDatasourceRegistry().createReference(reference);
}
@Override
public Datasource getDatasource(String name) {
return getDatasourceRegistry().getDatasource(name);
}
@Override
public Datasource addDatasource(Datasource datasource) {
return getDatasourceRegistry().addDatasource(datasource);
}
@Override
public Datasource addDatasource(DatasourceFactory factory) {
return getDatasourceRegistry().addDatasource(factory);
}
@Override
public void addDecorator(Decorator<Datasource> decorator) {
getDatasourceRegistry().addDecorator(decorator);
}
@Override
public String addTransientDatasource(DatasourceFactory factory) {
return getDatasourceRegistry().addTransientDatasource(factory);
}
@Override
public Set<Datasource> getDatasources() {
return getDatasourceRegistry().getDatasources();
}
@Override
public Datasource getTransientDatasourceInstance(String uid) {
return getDatasourceRegistry().getTransientDatasourceInstance(uid);
}
@Override
public boolean hasDatasource(String name) {
return getDatasourceRegistry().hasDatasource(name);
}
@Override
public boolean hasTransientDatasource(String uid) {
return getDatasourceRegistry().hasTransientDatasource(uid);
}
@Override
public void removeDatasource(Datasource datasource) {
getDatasourceRegistry().removeDatasource(datasource);
}
@Override
public void removeTransientDatasource(@Nullable String uid) {
getDatasourceRegistry().removeTransientDatasource(uid);
}
ValueTypeFactory getValueTypeFactory() {
return valueTypeFactory;
}
public void lock(Collection<String> lockNames) throws InterruptedException {
lockManager.lock(lockNames);
}
public void unlock(Iterable<String> lockNames) {
lockManager.unlock(lockNames, true);
}
public <T> WeakReference<T> registerInstance(T singleton) {
singletons.add(singleton);
return new WeakReference<>(singleton);
}
public void shutdown() {
for(Disposable d : Iterables.filter(extensions, Disposable.class)) {
Disposables.silentlyDispose(d);
}
Disposables.silentlyDispose(datasourceRegistry);
singletons = null;
instance = null;
}
}