X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.district.route%2Fsrc%2Forg%2Fsimantics%2Fdistrict%2Froute%2Finternal%2FRouteServiceImpl.java;fp=org.simantics.district.route%2Fsrc%2Forg%2Fsimantics%2Fdistrict%2Froute%2Finternal%2FRouteServiceImpl.java;h=e37a803b6fa76b96cb84cd8c48200b19d5b4f48b;hb=716ce6c9abe27be04635922ad437f242c4bd7dfc;hp=0000000000000000000000000000000000000000;hpb=cb14c9e0dfd0b7179c11f0a54af87e2b7fe16113;p=simantics%2Fdistrict.git diff --git a/org.simantics.district.route/src/org/simantics/district/route/internal/RouteServiceImpl.java b/org.simantics.district.route/src/org/simantics/district/route/internal/RouteServiceImpl.java new file mode 100644 index 00000000..e37a803b --- /dev/null +++ b/org.simantics.district.route/src/org/simantics/district/route/internal/RouteServiceImpl.java @@ -0,0 +1,195 @@ +package org.simantics.district.route.internal; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.eclipse.core.runtime.ListenerList; +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PossibleActiveModel; +import org.simantics.db.management.ISessionContext; +import org.simantics.db.management.ISessionContextChangedListener; +import org.simantics.db.management.SessionContextChangedEvent; +import org.simantics.db.procedure.SyncListener; +import org.simantics.district.route.Route; +import org.simantics.district.route.RouteEvent; +import org.simantics.district.route.RouteService; +import org.simantics.district.route.RouteServiceListener; +import org.simantics.district.route.Router; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + */ +public class RouteServiceImpl implements RouteService, ISessionContextChangedListener, Closeable { + + private final Logger LOGGER = LoggerFactory.getLogger(RouteServiceImpl.class); + + private ListenerList listeners = new ListenerList<>(); + private List routes = new ArrayList<>(); + private List unmodifiableRoutes = Collections.unmodifiableList(routes); + private List routers = new ArrayList<>(); + private List unmodifiableRouters = Collections.unmodifiableList(routers); + + private class StoreListener implements SyncListener { + private boolean disposed = false; + + @Override + public void execute(ReadGraph graph, Resource activeModel) { + try { + if (activeModel != null) { + resetRoutes(RoutePersistence.findRoutes(graph, activeModel)); + } else { + resetRoutes(Collections.emptyList()); + } + fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, this); + } catch (DatabaseException e) { + LOGGER.error("Failed to read routes from model {}", activeModel, e); + } + } + + @Override + public void exception(ReadGraph graph, Throwable t) { + LOGGER.error("Failed to listen to current route service storage", t); + } + + public void dispose() { + disposed = true; + } + + @Override + public boolean isDisposed() { + return disposed; + } + } + + private StoreListener storeListener; + + private synchronized void listenToActiveModels(Session s) { + StoreListener sl = storeListener; + if (sl != null) + sl.dispose(); + if (s != null) { + s.asyncRequest( + new PossibleActiveModel(Simantics.getProjectResource()), + storeListener = new StoreListener()); + } else { + resetRoutes(Collections.emptyList()); + } + } + + void resetRoutes(List newRoutes) { + routes.clear(); + newRoutes.forEach(r -> r.routeService(this)); + routes.addAll(newRoutes); + } + + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + ISessionContext ctx = event.getNewValue(); + Session s = ctx != null ? ctx.getSession() : null; + listenToActiveModels(s); + } + + public RouteServiceImpl() { + Session s = Simantics.peekSession(); + Simantics.getSessionContextProvider().addContextChangedListener(this); + if (s != null) + listenToActiveModels(s); + } + + @Override + public void close() { + Simantics.getSessionContextProvider().removeContextChangedListener(this); + } + + @Override + public void addListener(RouteServiceListener l) { + listeners.add(l); + } + + @Override + public void removeListener(RouteServiceListener l) { + listeners.remove(l); + } + + @Override + public Route createRoute(String name, Object backendModelEntity) { + Route r = new RouteImpl(name).modelEntity((Resource) backendModelEntity).routeService(this); + fireEvent(RouteEvent.TYPE_ROUTE_CREATED, r); + return r; + } + + @Override + public void registerRoute(Route route) { + routes.add(route); + fireEvent(RouteEvent.TYPE_ROUTE_REGISTERED, route); + } + + @Override + public CompletableFuture persistRoute(Route route) { + fireEvent(RouteEvent.TYPE_ROUTE_PERSISTING, route); + CompletableFuture future = new CompletableFuture<>(); + new RoutePersistenceJob((RouteImpl) route, RouteEvent.TYPE_ROUTE_PERSISTING, future).schedule(); + future.thenAccept(r -> fireEvent(RouteEvent.TYPE_ROUTE_PERSISTED, r)); + return future; + } + + @Override + public CompletableFuture discardRoute(Route route) { + fireEvent(RouteEvent.TYPE_ROUTE_DISCARDING, route); + CompletableFuture result = new CompletableFuture<>(); + RouteImpl ri = (RouteImpl) route; + result.thenAccept(r -> { + routes.remove(route); + fireEvent(RouteEvent.TYPE_ROUTE_DISCARDED, route); + }); + if (ri.backend() != null) { + new RoutePersistenceJob(ri, RouteEvent.TYPE_ROUTE_DISCARDING, result).schedule(); + } else { + result.complete(route); + } + return result; + } + + @Override + public List listRoutes() { + return unmodifiableRoutes; + } + + @Override + public void registerRouter(Router router) { + routers.add(router); + fireEvent(RouteEvent.TYPE_ROUTER_REGISTERED, router); + } + + @Override + public void unregisterRouter(Router router) { + routers.add(router); + fireEvent(RouteEvent.TYPE_ROUTER_UNREGISTERED, router); + } + + public List routers() { + return unmodifiableRouters; + } + + void fireEvent(int type, Object obj) { + RouteEvent e = new RouteEvent(this, type, obj); + LOGGER.info("firing route event {}", e); + listeners.forEach(l -> { + try { + l.handleEvent(e); + } catch (Exception | LinkageError | AssertionError ex) { + LOGGER.error("Failed to invoke RouteListener {}", l, ex); + } + }); + } + +}