1 package org.simantics.district.route.internal;
3 import java.io.Closeable;
4 import java.util.ArrayList;
5 import java.util.Collections;
7 import java.util.concurrent.CompletableFuture;
9 import org.eclipse.core.runtime.ListenerList;
10 import org.simantics.Simantics;
11 import org.simantics.db.ReadGraph;
12 import org.simantics.db.Resource;
13 import org.simantics.db.Session;
14 import org.simantics.db.common.procedure.adapter.DisposableListener;
15 import org.simantics.db.common.procedure.adapter.DisposableSyncListener;
16 import org.simantics.db.layer0.request.PossibleActiveModel;
17 import org.simantics.db.management.ISessionContext;
18 import org.simantics.db.management.ISessionContextChangedListener;
19 import org.simantics.db.management.SessionContextChangedEvent;
20 import org.simantics.district.route.Route;
21 import org.simantics.district.route.RouteEvent;
22 import org.simantics.district.route.RouteService;
23 import org.simantics.district.route.RouteServiceListener;
24 import org.simantics.district.route.Router;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * @author Tuukka Lehtonen
31 public class RouteServiceImpl implements RouteService, ISessionContextChangedListener, Closeable {
33 private final Logger LOGGER = LoggerFactory.getLogger(RouteServiceImpl.class);
35 private ListenerList<RouteServiceListener> listeners = new ListenerList<>();
36 private List<Route> routes = new ArrayList<>();
37 private List<Route> unmodifiableRoutes = Collections.unmodifiableList(routes);
38 private List<Router> routers = new ArrayList<>();
39 private List<Router> unmodifiableRouters = Collections.unmodifiableList(routers);
41 private class StoreRoutesListener extends DisposableListener<List<RouteImpl>> {
43 public void execute(List<RouteImpl> result) {
45 fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, RouteServiceImpl.this);
49 public void exception(Throwable t) {
50 LOGGER.error("Failed to listen to current route store routes", t);
54 private class StoreListener extends DisposableSyncListener<Resource> {
56 public void execute(ReadGraph graph, Resource activeModel) {
57 if (activeModel != null) {
58 StoreRoutesListener srl = storeRoutesListener;
61 Simantics.getSession().asyncRequest(
62 new RoutePersistence.ModelRoutesRequest(activeModel),
63 storeRoutesListener = new StoreRoutesListener());
65 resetRoutes(Collections.emptyList());
66 fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, RouteServiceImpl.this);
71 public void exception(ReadGraph graph, Throwable t) {
72 LOGGER.error("Failed to listen to current route service storage", t);
76 private StoreRoutesListener storeRoutesListener;
77 private StoreListener storeListener;
79 private synchronized void listenToActiveModels(Session s) {
80 StoreListener sl = storeListener;
85 new PossibleActiveModel(Simantics.getProjectResource()),
86 storeListener = new StoreListener());
88 resetRoutes(Collections.emptyList());
92 void resetRoutes(List<RouteImpl> newRoutes) {
94 newRoutes.forEach(r -> r.routeService(this));
95 routes.addAll(newRoutes);
99 public void sessionContextChanged(SessionContextChangedEvent event) {
100 ISessionContext ctx = event.getNewValue();
101 Session s = ctx != null ? ctx.getSession() : null;
102 listenToActiveModels(s);
105 public RouteServiceImpl() {
106 Session s = Simantics.peekSession();
107 Simantics.getSessionContextProvider().addContextChangedListener(this);
109 listenToActiveModels(s);
113 public void close() {
114 Simantics.getSessionContextProvider().removeContextChangedListener(this);
118 public void addListener(RouteServiceListener l) {
123 public void removeListener(RouteServiceListener l) {
128 public Route createRoute(String name, Object backendModelEntity) {
129 Route r = new RouteImpl(name).modelEntity((Resource) backendModelEntity).routeService(this);
130 fireEvent(RouteEvent.TYPE_ROUTE_CREATED, r);
135 public void registerRoute(Route route) {
137 fireEvent(RouteEvent.TYPE_ROUTE_REGISTERED, route);
141 public void refreshRoute(Route route) {
142 fireEvent(RouteEvent.TYPE_ROUTE_MODIFIED, route);
146 public CompletableFuture<Route> persistRoute(Route route) {
147 fireEvent(RouteEvent.TYPE_ROUTE_PERSISTING, route);
148 CompletableFuture<Route> future = new CompletableFuture<>();
149 new RoutePersistenceJob((RouteImpl) route, RouteEvent.TYPE_ROUTE_PERSISTING, future).schedule();
150 future.thenAccept(r -> fireEvent(RouteEvent.TYPE_ROUTE_PERSISTED, r));
155 public CompletableFuture<Route> discardRoute(Route route) {
156 fireEvent(RouteEvent.TYPE_ROUTE_DISCARDING, route);
157 CompletableFuture<Route> result = new CompletableFuture<>();
158 RouteImpl ri = (RouteImpl) route;
159 result.thenAccept(r -> {
160 routes.remove(route);
161 fireEvent(RouteEvent.TYPE_ROUTE_DISCARDED, route);
163 if (ri.backend() != null) {
164 new RoutePersistenceJob(ri, RouteEvent.TYPE_ROUTE_DISCARDING, result).schedule();
166 result.complete(route);
172 public List<Route> listRoutes() {
173 return unmodifiableRoutes;
177 public void registerRouter(Router router) {
179 fireEvent(RouteEvent.TYPE_ROUTER_REGISTERED, router);
183 public void unregisterRouter(Router router) {
185 fireEvent(RouteEvent.TYPE_ROUTER_UNREGISTERED, router);
188 public List<Router> routers() {
189 return unmodifiableRouters;
192 void fireEvent(int type, Object obj) {
193 RouteEvent e = new RouteEvent(this, type, obj);
194 LOGGER.info("firing route event {}", e);
195 listeners.forEach(l -> {
198 } catch (Exception | LinkageError | AssertionError ex) {
199 LOGGER.error("Failed to invoke RouteListener {}", l, ex);