]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.route/src/org/simantics/district/route/internal/RouteServiceImpl.java
Add a method for unpersisting individual routes into RouteService
[simantics/district.git] / org.simantics.district.route / src / org / simantics / district / route / internal / RouteServiceImpl.java
1 package org.simantics.district.route.internal;
2
3 import java.io.Closeable;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.List;
7 import java.util.concurrent.CompletableFuture;
8
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.exception.DatabaseException;
17 import org.simantics.db.layer0.request.PossibleActiveModel;
18 import org.simantics.db.management.ISessionContext;
19 import org.simantics.db.management.ISessionContextChangedListener;
20 import org.simantics.db.management.SessionContextChangedEvent;
21 import org.simantics.district.route.Route;
22 import org.simantics.district.route.RouteEvent;
23 import org.simantics.district.route.RouteService;
24 import org.simantics.district.route.RouteServiceListener;
25 import org.simantics.district.route.Router;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * @author Tuukka Lehtonen
31  */
32 public class RouteServiceImpl implements RouteService, ISessionContextChangedListener, Closeable {
33
34     private final Logger LOGGER = LoggerFactory.getLogger(RouteServiceImpl.class); 
35
36     private ListenerList<RouteServiceListener> listeners = new ListenerList<>();
37     private List<Route> routes = new ArrayList<>();
38     private List<Route> unmodifiableRoutes = Collections.unmodifiableList(routes);
39     private List<Router> routers = new ArrayList<>();
40     private List<Router> unmodifiableRouters = Collections.unmodifiableList(routers);
41
42     private class StoreRoutesListener extends DisposableListener<List<RouteImpl>> {
43         @Override
44         public void execute(List<RouteImpl> result) {
45             resetRoutes(result);
46             fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, RouteServiceImpl.this);
47         }
48
49         @Override
50         public void exception(Throwable t) {
51             LOGGER.error("Failed to listen to current route store routes", t);
52         }
53     }
54
55     private class StoreListener extends DisposableSyncListener<Resource> {
56         @Override
57         public void execute(ReadGraph graph, Resource activeModel) {
58             if (activeModel != null) {
59                 StoreRoutesListener srl = storeRoutesListener;
60                 if (srl != null)
61                     srl.dispose();
62                 Simantics.getSession().asyncRequest(
63                         new RoutePersistence.ModelRoutesRequest(activeModel),
64                         storeRoutesListener = new StoreRoutesListener());
65             } else {
66                 resetRoutes(Collections.emptyList());
67                 fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, RouteServiceImpl.this);
68             }
69         }
70
71         @Override
72         public void exception(ReadGraph graph, Throwable t) {
73             LOGGER.error("Failed to listen to current route service storage", t);
74         }
75     }
76
77     private StoreRoutesListener storeRoutesListener;
78     private StoreListener storeListener;
79
80     private synchronized void listenToActiveModels(Session s) {
81         StoreListener sl = storeListener;
82         if (sl != null)
83             sl.dispose();
84         if (s != null) {
85             s.asyncRequest(
86                     new PossibleActiveModel(Simantics.getProjectResource()),
87                     storeListener = new StoreListener());
88         } else {
89             resetRoutes(Collections.emptyList());
90         }
91     }
92
93     void resetRoutes(List<RouteImpl> newRoutes) {
94         routes.clear();
95         newRoutes.forEach(r -> r.routeService(this));
96         routes.addAll(newRoutes);
97     }
98
99     @Override
100     public void sessionContextChanged(SessionContextChangedEvent event) {
101         ISessionContext ctx = event.getNewValue();
102         Session s = ctx != null ? ctx.getSession() : null;
103         listenToActiveModels(s);
104     }
105
106     public RouteServiceImpl() {
107         Session s = Simantics.peekSession();
108         Simantics.getSessionContextProvider().addContextChangedListener(this);
109         if (s != null)
110             listenToActiveModels(s);
111     }
112
113     @Override
114     public void close() {
115         Simantics.getSessionContextProvider().removeContextChangedListener(this);
116     }
117
118     @Override
119     public void addListener(RouteServiceListener l) {
120         listeners.add(l);
121     }
122
123     @Override
124     public void removeListener(RouteServiceListener l) {
125         listeners.remove(l);
126     }
127
128     @Override
129     public Route createRoute(String name, Object backendModelEntity) {
130         Route r = new RouteImpl(name).modelEntity((Resource) backendModelEntity).routeService(this);
131         fireEvent(RouteEvent.TYPE_ROUTE_CREATED, r);
132         return r;
133     }
134
135     @Override
136     public void registerRoute(Route route) {
137         routes.add(route);
138         fireEvent(RouteEvent.TYPE_ROUTE_REGISTERED, route);
139     }
140
141     @Override
142     public void refreshRoute(Route route) {
143         fireEvent(RouteEvent.TYPE_ROUTE_MODIFIED, route);
144     }
145
146     @Override
147     public CompletableFuture<Route> persistRoute(Route route) {
148         fireEvent(RouteEvent.TYPE_ROUTE_PERSISTING, route);
149         CompletableFuture<Route> future = new CompletableFuture<>();
150         new RoutePersistenceJob((RouteImpl) route, RouteEvent.TYPE_ROUTE_PERSISTING, future).schedule();
151         future.thenAccept(r -> fireEvent(RouteEvent.TYPE_ROUTE_PERSISTED, r));
152         return future;
153     }
154
155     @Override
156     public CompletableFuture<Route> discardRoute(Route route) {
157         fireEvent(RouteEvent.TYPE_ROUTE_DISCARDING, route);
158         CompletableFuture<Route> result = new CompletableFuture<>();
159         RouteImpl ri = (RouteImpl) route;
160         result.thenAccept(r -> {
161             routes.remove(route);
162             fireEvent(RouteEvent.TYPE_ROUTE_DISCARDED, route);
163         });
164         if (ri.backend() != null) {
165             new RoutePersistenceJob(ri, RouteEvent.TYPE_ROUTE_DISCARDING, result).schedule();
166         } else {
167             result.complete(route);
168         }
169         return result;
170     }
171
172     @Override
173     public List<Route> listRoutes() {
174         return unmodifiableRoutes;
175     }
176
177     @Override
178     public void registerRouter(Router router) {
179         routers.add(router);
180         fireEvent(RouteEvent.TYPE_ROUTER_REGISTERED, router);
181     }
182
183     @Override
184     public void unregisterRouter(Router router) {
185         routers.add(router);
186         fireEvent(RouteEvent.TYPE_ROUTER_UNREGISTERED, router);
187     }
188
189     public List<Router> routers() {
190         return unmodifiableRouters;
191     }
192
193     void fireEvent(int type, Object obj) {
194         RouteEvent e = new RouteEvent(this, type, obj);
195         LOGGER.info("firing route event {}", e);
196         listeners.forEach(l -> {
197             try {
198                 l.handleEvent(e);
199             } catch (Exception | LinkageError | AssertionError ex) {
200                 LOGGER.error("Failed to invoke RouteListener {}", l, ex);
201             }
202         });
203     }
204
205     @Override
206     public Route readRoute(Object backendRouteObject) {
207         if (!(backendRouteObject instanceof Resource))
208             return null;
209         
210         try {
211             return Simantics.getSession().syncRequest(new RoutePersistence.RouteRequest((Resource)backendRouteObject));
212         } catch (DatabaseException e) {
213             LOGGER.error("Failed to read district route object for " + backendRouteObject, e);
214             return null;
215         }
216     }
217
218 }