com.github.thorbenkuck.keller.mvp.AsynchronousViewController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of keller-mvp Show documentation
Show all versions of keller-mvp Show documentation
Keller is a universal base-package
The newest version!
package com.github.thorbenkuck.keller.mvp;
import com.github.thorbenkuck.keller.datatypes.interfaces.Factory;
import com.github.thorbenkuck.keller.datatypes.interfaces.Value;
import com.github.thorbenkuck.keller.sync.Awaiting;
import com.github.thorbenkuck.keller.sync.Synchronize;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public final class AsynchronousViewController implements ViewController {
private final Map, Factory> factoryMap = new HashMap<>();
private final Value> beforeShowConsumer = Value.of((presenter, view) -> {});
private final Value> onClose = Value.of(((presenter, view) -> {}));
private final Value> threadSimulator = Value.empty();
private final Value mainView = Value.empty();
private final List separateViews = new ArrayList<>();
public AsynchronousViewController() {
this(Executors.newCachedThreadPool());
}
public AsynchronousViewController(final ExecutorService executorService) {
this(executorService::execute);
}
public AsynchronousViewController(Consumer threadExtractor) {
this.threadSimulator.set(threadExtractor);
}
public void setBeforeShowConsumer(BiConsumer beforeShowConsumer) {
Objects.requireNonNull(beforeShowConsumer);
this.beforeShowConsumer.set(beforeShowConsumer);
}
public BiConsumer getBeforeShowConsumer() {
return beforeShowConsumer.get();
}
@Override
public void setViewFactoryMap(final Map, Factory> factoryMap) {
Objects.requireNonNull(factoryMap);
// Todo check all contents for non-null? ... Dunno...
synchronized (this.factoryMap) {
this.factoryMap.clear();
this.factoryMap.putAll(factoryMap);
}
}
@Override
public void addFactory(final Class extends View> clazz, final Factory viewFactory) {
Objects.requireNonNull(clazz);
Objects.requireNonNull(viewFactory);
synchronized (factoryMap) {
factoryMap.put(clazz, viewFactory);
}
}
@Override
public Awaiting openMainStage(final Class extends View> viewClass) {
Objects.requireNonNull(viewClass);
Synchronize synchronize = Synchronize.ofCountDownLatch();
final Factory viewFactory = safeGetViewFactory(viewClass);
runOnOtherThread(() -> runSynchronized(() -> {
closeStageOnCurrentThread(mainView.get());
View view = viewFactory.produce();
Presenter presenter = view.getPresenter();
beforeShowConsumer.get().accept(presenter, view);
showStage(view);
mainView.set(view);
view.notifyOpen();
}), synchronize);
return synchronize;
}
@Override
public Awaiting openSeparateStage(final Class extends View> viewClass) {
Objects.requireNonNull(viewClass);
Synchronize synchronize = Synchronize.ofCountDownLatch();
final Factory viewFactory = safeGetViewFactory(viewClass);
runOnOtherThread(() -> {
Optional extends View> oldStageOptional = getActiveSeparateStage(viewClass);
oldStageOptional.ifPresent(oldStage -> {
closeStageOnCurrentThread(oldStage);
separateViews.remove(oldStage);
});
View stage = viewFactory.produce();
separateViews.add(stage);
showStage(stage);
}, synchronize);
return synchronize;
}
// This is okay, because we check at runtime... Dam you type erasure!!!!
@SuppressWarnings ("unchecked")
@Override
public Optional getActiveSeparateStage(final Class viewClass) {
for (View customStage : separateViews) {
if (customStage.getClass().equals(viewClass)) {
return Optional.of((T) customStage);
}
}
return Optional.empty();
}
@Override
public Awaiting closeAll() {
Synchronize synchronize = Synchronize.ofCountDownLatch();
runOnOtherThread(() -> {
try {
closeAllSeparateStages().synchronize();
} catch (InterruptedException e) {
e.printStackTrace();
}
closeStageOnCurrentThread(getMainView());
}, synchronize);
return synchronize;
}
@Override
public Awaiting closeAllSeparateStages() {
Synchronize synchronize = Synchronize.ofCountDownLatch();
runOnOtherThread(() -> {
for (View stage : separateViews) {
getActiveSeparateStage(stage.getClass()).ifPresent(this::closeStageSynchronizedOnCurrentThread);
}
}, synchronize);
return synchronize;
}
@Override
public Awaiting closeSeparateActiveStage(final Class extends View> viewClass) {
Synchronize synchronize = Synchronize.ofCountDownLatch();
runOnOtherThread(() -> getActiveSeparateStage(viewClass).ifPresent(this::closeStageSynchronizedOnCurrentThread), synchronize);
return synchronize;
}
@Override
public Awaiting closeSeparateActiveStage(final View view) {
return closeSeparateActiveStage(view.getClass());
}
@Override
public View getMainView() {
return mainView.get();
}
@Override
public void setThreadExtractor(Consumer extractor) {
synchronized (threadSimulator) {
threadSimulator.set(extractor);
}
}
private Factory safeGetViewFactory(final Class extends View> clazz) {
final Factory viewFactory = getFactory(clazz);
if(viewFactory == null) {
throw new IllegalStateException("Factory for " + clazz + " is null! This is not acceptable!");
}
return viewFactory;
}
private void showStage(final View view) {
view.show();
}
private void runSynchronized(Runnable runnable) {
synchronized (this) {
runnable.run();
}
}
private void runOnOtherThread(Runnable runnable, Synchronize synchronize) {
Consumer extractor;
synchronized (threadSimulator) {
extractor = threadSimulator.get();
}
extractor.accept(() -> {
runnable.run();
synchronize.goOn();
});
}
private void closeStageOnCurrentThread(View view) {
if (view != null) {
closeStage(view);
}
}
private void closeStage(View view) {
Presenter presenter = view.getPresenter();
if (presenter != null) {
presenter.onClose();
}
view.close();
}
private void closeStageSynchronizedOnCurrentThread(final View view) {
runSynchronized(() -> closeStageOnCurrentThread(view));
}
private Factory getFactory(Class extends View> clazz) {
Factory result;
synchronized (factoryMap) {
result = factoryMap.get(clazz);
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy