source: java/main/src/main/java/com/framsticks/remote/RemoteTree.java @ 99

Last change on this file since 99 was 99, checked in by psniegowski, 11 years ago

HIGHLIGTS:

  • complete events implementation
  • add CLI in Java Framsticks server
  • add automatic registration for events in GUI
  • improve objects fetching (object are never overwritten with new instances)
  • properly react for ListChange? events
  • add ListPanel? with table view
    • columns to be shown may be statically specified in configuration
    • currently modyfying data through tables is not available
  • improve maven configuration
    • configuration file may be specified without touching pom.xml

CHANGELOG:
Extract constants from Flags into ParamFlags? and SetStateFlags?.

Extract flags I/O to FlagsUtils? class.

Configured maven to exec given resource configuration.

For example:
mvn exec:exec -Dframsticks.config=/configs/managed-console.xml

Cleanup pom.xml

Rename ObjectTree? to LocalTree? (also make LocalTree? and RemoteTree? final).

Minor change.

Add maximum number of columns in ListPanelProvider?.

Improve ColumnsConfig? interpretation.

Automatically fill FramsClass?.name if trying to construct empty.

Improve identitifer case mangling in XmlLoader?.

Introduce configurable ColumnsConfig?.

Draft working version of ListPanel?.

Table is being shown (although empty).

More improvements to table building.

Move some functionality from Frame to TreeModel?.

Move tree classes in gui to separate package.

Remove old table related classes.

Add draft implementation of TableModel?.

Redirect ParamBuilder?.forAccess to AccessInterface?.

Optimize ParamBuilder?.forAccess()

Do not clear list when loading.

Do not load fetched values directly.

Implement different AccessInterface? copying policy.

Optimize fetching values routine.

Remove Mode enum (work out get semantics).

Some improvements to ListChange? handling.

Improve UniqueListAccess?.

Add reaction for ListChanges? in the TreeNode?.

EventListeners? are being added in the TreeNode?.

Listeners for ListParams? are now very naive (they download
whole list).

Automatially register on events in GUI.

Events are working in RemoteTree? and Server.

Move listeners to the ClientSideManagedConnection?.

Remove old classes responsible for event subscriptions.

Improve event reading.

Improve events handling at server side.

Add register attribute in FramsClassAnnotation?
to automatically also register other classes.

Registering events works.

Setup for remote listeners registration.

More improvements.

Minor changes.

Add rootTree to the ClientAtServer?.

Moving CLI to the ClientAtServer?.

Fix bug: use Void.TYPE instead of Void.class

More development around CLI.

  • Improve Path resolving.

Add synthetic root to ObjectTree?.

It is needed to allow sybling for the original root
that would containg CLI.

Some work with registering events in RemoteTree?.

Draft implementation of listener registering in RemoteTree?.

Support events registration in the ObjectTree?.

Add events support to ReflectionAccess?.

EventParam? is recognized by ParamCandidate?.

Prepare interface for Events across project.

Add EventListener? and API for listeners in Tree.

File size: 10.0 KB
Line 
1package com.framsticks.remote;
2
3import com.framsticks.communication.*;
4import com.framsticks.communication.queries.CallRequest;
5import com.framsticks.communication.queries.GetRequest;
6import com.framsticks.communication.queries.InfoRequest;
7import com.framsticks.communication.queries.SetRequest;
8import com.framsticks.core.AbstractTree;
9import com.framsticks.core.Path;
10import com.framsticks.params.*;
11import com.framsticks.params.EventListener;
12import com.framsticks.params.annotations.AutoAppendAnnotation;
13import com.framsticks.params.annotations.FramsClassAnnotation;
14import com.framsticks.params.annotations.ParamAnnotation;
15import com.framsticks.params.types.EventParam;
16import com.framsticks.params.types.ProcedureParam;
17import com.framsticks.parsers.MultiParamLoader;
18import com.framsticks.core.Tree;
19import com.framsticks.util.*;
20import com.framsticks.util.dispatching.Dispatching;
21import com.framsticks.util.dispatching.Dispatching.DispatcherWaiter;
22import com.framsticks.util.dispatching.Future;
23import com.framsticks.util.dispatching.FutureHandler;
24import com.framsticks.util.dispatching.Joinable;
25import com.framsticks.util.dispatching.JoinableParent;
26import com.framsticks.util.dispatching.JoinableState;
27import com.framsticks.util.dispatching.ThrowExceptionHandler;
28import com.framsticks.util.lang.Casting;
29import com.framsticks.util.dispatching.RunAt;
30import static com.framsticks.core.TreeOperations.*;
31
32import java.util.*;
33
34import javax.annotation.Nonnull;
35
36import org.apache.log4j.Logger;
37
38/**
39 * @author Piotr Sniegowski
40 */
41@FramsClassAnnotation
42public final class RemoteTree extends AbstractTree implements JoinableParent {
43
44        private final static Logger log = Logger.getLogger(RemoteTree.class);
45
46        protected ClientSideManagedConnection connection;
47
48        public RemoteTree() {
49        }
50
51        @ParamAnnotation
52        public void setAddress(String address) {
53                setConnection(Connection.to(new ClientSideManagedConnection(), new Address(address)));
54        }
55
56        @ParamAnnotation
57        public String getAddress() {
58                return connection == null ? "<disconnected>" : connection.getAddress().toString();
59        }
60
61        @AutoAppendAnnotation
62        public void setConnection(final ClientSideManagedConnection connection) {
63                this.connection = connection;
64        }
65
66        public final ClientSideManagedConnection getConnection() {
67                return connection;
68        }
69
70        @Override
71        public String toString() {
72                assert Dispatching.isThreadSafe();
73                return "remote tree " + getName() + "(" + getAddress() + ")";
74        }
75
76        @Override
77        public void get(final Path path, final ValueParam param, final Future<Object> future) {
78                assert isActive();
79                assert param != null;
80                // assert path.isResolved();
81                //TODO only do that if needed
82                connection.send(new GetRequest().field(param.getId()).path(path.getTextual()), this, new ClientSideResponseFuture(future) {
83                        @Override
84                        protected void processOk(Response response) {
85                                assert isActive();
86                                processFetchedValues(path, response.getFiles());
87                                future.pass(bindAccess(path.tryResolveIfNeeded()).get(param, Object.class));
88                        }
89                });
90        }
91
92        protected final Map<String, Set<Future<FramsClass>>> infoRequests = new HashMap<String, Set<Future<FramsClass>>>();
93
94
95        @Override
96        public void info(final Path path, final Future<FramsClass> future) {
97
98                final String name = path.getTop().getParam().getContainedTypeName();
99
100                if (infoRequests.containsKey(name)) {
101                        infoRequests.get(name).add(future);
102                        return;
103                }
104
105                log.debug("issuing info request for " + name);
106                final Set<Future<FramsClass>> futures = new HashSet<Future<FramsClass>>();
107                futures.add(future);
108                infoRequests.put(name, futures);
109
110                final Future<FramsClass> compositeFuture = new Future<FramsClass>() {
111
112                        @Override
113                        public void handle(FramsticksException exception) {
114                                assert isActive();
115                                infoRequests.remove(name);
116                                for (Future<FramsClass> f : futures) {
117                                        f.handle(exception);
118                                }
119                        }
120
121                        @Override
122                        protected void result(FramsClass framsClass) {
123                                assert isActive();
124                                infoRequests.remove(name);
125                                for (Future<FramsClass> f : futures) {
126                                        f.pass(framsClass);
127                                }
128                        }
129                };
130
131                //TODO: if the info is in the cache, then don't communicate
132                connection.send(new InfoRequest().path(path.getTextual()), this, new ClientSideResponseFuture(compositeFuture) {
133                        @Override
134                        protected void processOk(Response response) {
135                                assert isActive();
136
137                                if (response.getFiles().size() != 1) {
138                                        throw new FramsticksException().msg("invalid number of files in response").arg("files", response.getFiles().size());
139                                }
140                                if (!path.isTheSame(response.getFiles().get(0).getPath())) {
141                                        throw new FramsticksException().msg("path mismatch").arg("returned path", response.getFiles().get(0).getPath());
142                                }
143                                FramsClass framsClass = processFetchedInfo(RemoteTree.this, response.getFiles().get(0));
144
145                                CompositeParam thisParam = path.getTop().getParam();
146                                if (!thisParam.isMatchingContainedName(framsClass.getId())) {
147                                        throw new FramsticksException().msg("framsclass id mismatch").arg("request", thisParam.getContainedTypeName()).arg("fetched", framsClass.getId());
148                                }
149                                compositeFuture.pass(framsClass);
150                        }
151                });
152        }
153
154        @Override
155        public void get(final Path path, final Future<Path> future) {
156                assert isActive();
157
158                log.trace("fetching values for " + path);
159                findInfo(path, new FutureHandler<FramsClass>(future) {
160                        @Override
161                        protected void result(FramsClass result) {
162
163                                connection.send(new GetRequest().path(path.getTextual()), RemoteTree.this, new ClientSideResponseFuture(future) {
164                                        @Override
165                                        protected void processOk(Response response) {
166                                                assert isActive();
167                                                Path p = path.tryResolveIfNeeded();
168                                                processFetchedValues(p, response.getFiles());
169                                                future.pass(p.tryResolveIfNeeded().assureResolved());
170                                        }
171                                });
172                        }
173                });
174        }
175
176        @Override
177        public void set(final Path path, final PrimitiveParam<?> param, final Object value, final Future<Integer> future) {
178                assert isActive();
179                final Integer flag = bindAccess(path).set(param, value);
180
181                log.trace("storing value " + param + " for " + path);
182                //TODO break in passing exception handler is here
183                connection.send(new SetRequest().value(value.toString()).field(param.getId()).path(path.getTextual()), this, new ClientSideResponseFuture(future) {
184                        @Override
185                        protected void processOk(Response response) {
186                                future.pass(flag);
187                        }
188                });
189        }
190
191        @Override
192        protected void joinableStart() {
193                Dispatching.use(connection, this);
194                super.joinableStart();
195
196                dispatch(new RunAt<RemoteTree>(ThrowExceptionHandler.getInstance()) {
197                        @Override
198                        protected void runAt() {
199                                final DispatcherWaiter<Tree, Tree> waiter = new DispatcherWaiter<Tree, Tree>(RemoteTree.this);
200
201                                connection.send(new InfoRequest().path("/"), waiter, new ClientSideResponseFuture(this) {
202                                        @Override
203                                        protected void processOk(Response response) {
204                                                FramsClass framsClass = processFetchedInfo(RemoteTree.this, response.getFiles().get(0));
205                                                assignRootParam(Param.build().name("Tree").id(RemoteTree.this.getName()).type("o " + framsClass.getId()).finish(CompositeParam.class));
206                                        }
207                                });
208
209                                waiter.waitFor();
210                        }
211                });
212        }
213
214        @Override
215        protected void joinableInterrupt() {
216                Dispatching.drop(connection, this);
217                super.joinableInterrupt();
218        }
219
220        @Override
221        protected void joinableFinish() {
222                super.joinableFinish();
223
224        }
225
226        @Override
227        public void joinableJoin() throws InterruptedException {
228                Dispatching.join(connection);
229                super.joinableJoin();
230        }
231
232        @Override
233        public void childChangedState(Joinable joinable, JoinableState state) {
234                proceedToState(state);
235        }
236
237        @Override
238        public void call(@Nonnull final Path path, @Nonnull final ProcedureParam procedure, @Nonnull Object[] arguments, final Future<Object> future) {
239                assert isActive();
240                assert path.isResolved();
241
242                //TODO validate arguments type using params
243                connection.send(new CallRequest().procedure(procedure.getId()).arguments(Arrays.asList(arguments)).path(path.getTextual()), this, new ClientSideResponseFuture(future) {
244                        @Override
245                        protected void processOk(Response response) {
246                                assert isActive();
247                                // InstanceUtils.processFetchedValues(path, response.getFiles());
248                                future.pass(null);
249                        }
250                });
251
252        }
253
254        protected final Map<EventListener<?>, EventListener<File>> proxyListeners = new IdentityHashMap<>();
255
256        public <A> void addListener(Path path, EventParam param, final EventListener<A> listener, final Class<A> argumentType, final Future<Void> future) {
257                assert isActive();
258                assert path.isResolved();
259                if ((!argumentType.equals(Object.class)) && (null == registry.getFramsClassForJavaClass(argumentType))) {
260                        registry.registerAndBuild(argumentType);
261                }
262
263                final EventListener<File> proxyListener = new EventListener<File>() {
264
265                        @Override
266                        public void action(final File file) {
267                                Dispatching.dispatchIfNotActive(RemoteTree.this, new RunAt<RemoteTree>(RemoteTree.this) {
268
269                                        @Override
270                                        protected void runAt() {
271                                                assert isActive();
272                                                if (argumentType.equals(Object.class)) {
273                                                        listener.action(Casting.tryCast(argumentType, file));
274                                                        return;
275                                                }
276                                                AccessInterface access = registry.createAccess(argumentType);
277                                                Object argument = access.createAccessee();
278                                                access.select(argument);
279                                                if (!argumentType.isInstance(argument)) {
280                                                        throw new FramsticksException().msg("created argument is of wrond type").arg("expected", argumentType).arg("created", argument.getClass());
281                                                }
282                                                A typedArgument = argumentType.cast(argument);
283
284                                                // log.info("executing event with argument " + argumentType);
285                                                MultiParamLoader loader = new MultiParamLoader();
286                                                loader.setNewSource(file.getContent());
287                                                loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
288                                                loader.addAccessInterface(access);
289                                                loader.go();
290
291                                                listener.action(typedArgument);
292                                        }
293                                });
294                        }
295                };
296
297                proxyListeners.put(listener, proxyListener);
298
299                connection.addListener(Path.appendString(path.getTextual(), param.getId()), proxyListener, this, future);
300        }
301
302        public void removeListener(Path path, EventParam param, EventListener<?> listener, Future<Void> future) {
303                assert isActive();
304                EventListener<File> proxyListener = proxyListeners.get(listener);
305                connection.removeListener(proxyListener, this, future);
306        }
307
308}
Note: See TracBrowser for help on using the repository browser.