Changeset 99 for java/main/src


Ignore:
Timestamp:
07/10/13 22:41:02 (11 years ago)
Author:
psniegowski
Message:

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.

Location:
java/main/src
Files:
27 added
20 deleted
70 edited

Legend:

Unmodified
Added
Removed
  • java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java

    r98 r99  
    22
    33import com.framsticks.communication.queries.ApplicationRequest;
     4import com.framsticks.communication.queries.CallRequest;
    45import com.framsticks.communication.queries.ProtocolRequest;
    5 import com.framsticks.communication.queries.RegistrationRequest;
     6import com.framsticks.communication.queries.RegisterRequest;
    67import com.framsticks.communication.queries.UseRequest;
    78import com.framsticks.communication.queries.VersionRequest;
    8 import com.framsticks.communication.util.LoggingStateCallback;
     9import com.framsticks.core.Path;
    910import com.framsticks.params.ListSource;
    1011import com.framsticks.util.*;
     
    1819import com.framsticks.util.lang.Pair;
    1920import com.framsticks.util.lang.Strings;
     21import com.framsticks.params.EventListener;
    2022
    2123import org.apache.log4j.Logger;
     
    3234        private final static Logger log = Logger.getLogger(ClientSideManagedConnection.class);
    3335
    34         protected final Map<String, Subscription<?>> subscriptions = new HashMap<>();
    35 
    3636        private final List<Runnable> applicationRequestsBuffer = new LinkedList<>();
    3737        private boolean isHandshakeDone = false;
     38
    3839
    3940        /**
     
    9394        }
    9495
    95         private static class EventFire extends InboundMessage {
    96                 public final Subscription<?> subscription;
    97 
    98                 private EventFire(Subscription<?> subscription) {
    99                         this.subscription = subscription;
    100                 }
    101 
    102                 public void startFile(String path) {
    103                         assert path == null;
    104                         initCurrentFile(null);
    105                 }
    106 
    107                 @Override
    108                 public void eof() {
    109                         finishCurrentFile();
    110 
    111                         subscription.dispatchCall(getFiles());
    112                 }
     96        protected List<String> readFileContent() {
     97                List<String> content = new LinkedList<String>();
     98                String line;
     99                while (!(line = getLine()).startsWith("eof")) {
     100                        content.add(line);
     101                }
     102                return content;
    113103        }
    114104
     
    239229        }
    240230
    241         public <C> void subscribe(final String path, final Dispatcher<C> dispatcher, final SubscriptionCallback<? extends C> callback) {
    242                 send(new RegistrationRequest().path(path), AtOnceDispatcher.getInstance(), new ClientSideResponseFuture(callback) {
    243                         @Override
    244                         protected void processOk(Response response) {
    245                                 assert response.getFiles().isEmpty();
    246                                 Subscription<C> subscription = new Subscription<C>(ClientSideManagedConnection.this, path, response.getComment(), dispatcher);
    247                                 log.debug("registered on event: " + subscription);
    248                                 synchronized (subscriptions) {
    249                                         subscriptions.put(subscription.getRegisteredPath(), subscription);
    250                                 }
    251                                 subscription.setEventCallback(callback.subscribed(subscription));
    252                                 if (subscription.getEventCallback() == null) {
    253                                         log.info("subscription for " + path + " aborted");
    254                                         subscription.unsubscribe(new LoggingStateCallback(log, "abort subscription"));
    255                                 }
    256                         }
    257                 });
    258         }
    259231
    260232        private void sendQueryVersion(final int version, final Future<Void> future) {
     
    322294                Matcher matcher = Request.EVENT_PATTERN.matcher(rest);
    323295                if (!matcher.matches()) {
    324                         log.error("invalid event line: " + rest);
    325                         return;
    326                 }
    327                 Subscription<?> subscription = subscriptions.get(matcher.group(1));
    328                 if (subscription == null) {
    329                         log.error("non subscribed event: " + matcher.group(1));
    330                         return;
    331                 }
    332                 EventFire event = new EventFire(subscription);
    333                 event.startFile(null);
    334                 processMessage(event);
     296                        throw new FramsticksException().msg("invalid event line").arg("rest", rest);
     297                }
     298                String fileLine = getLine();
     299                if (!fileLine.equals("file")) {
     300                        throw new FramsticksException().msg("expected file line").arg("got", fileLine);
     301                }
     302                String eventObjectPath = Request.takeGroup(rest, matcher, 1).toString();
     303                String eventCalleePath = Request.takeGroup(rest, matcher, 2).toString();
     304                final File file = new File("", new ListSource(readFileContent()));
     305                log.debug("firing event " + eventObjectPath);
     306                EventListener<File> listener;
     307                synchronized (registeredListeners) {
     308                        listener = registeredListeners.get(eventObjectPath);
     309                }
     310                if (listener  == null) {
     311                        throw new FramsticksException().msg("failed to find registered event").arg("event path", eventObjectPath).arg("object", eventCalleePath);
     312                }
     313                listener.action(file);
    335314        }
    336315
     
    397376        }
    398377
     378        protected final Map<String, EventListener<File>> registeredListeners = new HashMap<>();
     379
     380        public <C> void addListener(String path, final EventListener<File> listener, final Dispatcher<C> dispatcher, final Future<Void> future) {
     381                send(new RegisterRequest().path(path), dispatcher, new ClientSideResponseFuture(future) {
     382                        @Override
     383                        protected void processOk(Response response) {
     384                                synchronized (registeredListeners) {
     385                                        registeredListeners.put(Path.validateString(response.getComment()), listener);
     386                                }
     387                                future.pass(null);
     388                        }
     389                });
     390        }
     391
     392        public <C> void removeListener(EventListener<File> listener, final Dispatcher<C> dispatcher, final Future<Void> future) {
     393                String eventPath = null;
     394                synchronized (registeredListeners) {
     395                        for (Map.Entry<String, EventListener<File>> e : registeredListeners.entrySet()) {
     396                                if (e.getValue() == listener) {
     397                                        eventPath = e.getKey();
     398                                        break;
     399                                }
     400                        }
     401                }
     402                if (eventPath == null) {
     403                        future.handle(new FramsticksException().msg("listener is not registered").arg("listener", listener));
     404                        return;
     405                }
     406
     407                final String finalEventPath = eventPath;
     408                                //TODO add arguments to the exception
     409                send(new CallRequest().procedure("remove").path(eventPath), dispatcher, new ClientSideResponseFuture(future) {
     410
     411                        @Override
     412                        protected void processOk(Response response) {
     413                                synchronized (registeredListeners) {
     414                                        registeredListeners.remove(finalEventPath);
     415                                }
     416                                future.pass(null);
     417                        }
     418                });
     419        }
    399420}
  • java/main/src/main/java/com/framsticks/communication/Request.java

    r98 r99  
    3737                        case "info": return new InfoRequest();
    3838                        case "call": return new CallRequest();
    39                         case "reg": return new RegistrationRequest();
     39                        case "reg": return new RegisterRequest();
    4040                        case "use": return new UseRequest();
    4141                        case "version": return new VersionRequest();
  • java/main/src/main/java/com/framsticks/communication/ServerSideManagedConnection.java

    r98 r99  
    6868        }
    6969
     70        protected final void putFile(File file, String outId) {
     71                putLine("file" + outId/* + " " + f.getPath()*/);
     72                SourceInterface content = file.getContent();
     73                String line;
     74                while ((line = content.readLine()) != null) {
     75                        putLine(line);
     76                }
     77                putLine("eof");
     78        }
     79
     80        public final void sendFile(final String header, final File file) {
     81                senderThread.dispatch(new RunAt<Connection>(requestHandler) {
     82                        @Override
     83                        protected void runAt() {
     84                                putLine(header);
     85                                putFile(file, "");
     86                                flushOut();
     87                        }
     88                });
     89        }
     90
    7091        protected final void respond(final Response response, final Integer id) {
    7192                senderThread.dispatch(new RunAt<Connection>(requestHandler) {
     
    7596                                if (response.getFiles() != null) {
    7697                                        for (File f : response.getFiles()) {
    77                                                 putLine("file" + outId/* + " " + f.getPath()*/);
    78                                                 SourceInterface content = f.getContent();
    79                                                 String line;
    80                                                 while ((line = content.readLine()) != null) {
    81                                                         putLine(line);
    82                                                 }
    83                                                 putLine("eof");
     98                                                putFile(f, outId);
    8499                                        }
    85100                                }
     
    87102                                statusLine.append(response.getOk() ? "ok" : "error").append(outId);
    88103                                if (Strings.notEmpty(response.getComment())) {
    89                                         statusLine.append(" \"").append(response.getComment()).append('"');
     104                                        Request.quoteValue(statusLine.append(" "), response.getComment());
    90105                                }
    91106                                putLine(statusLine.toString());
  • java/main/src/main/java/com/framsticks/communication/ServerSideResponseFuture.java

    r97 r99  
    1111        @Override
    1212        public final void handle(FramsticksException e) {
    13                 result(new Response(false, e.getClass().getCanonicalName() + ": " + e.getMsg(), null));
     13                result(new Response(false, e.getClass().getCanonicalName() + ": " + e.getMessage(), null));
    1414        }
    1515
  • java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java

    r96 r99  
    2323        }
    2424
     25        public String getActualPath() {
     26                return path;
     27        }
     28
    2529
    2630        @Override
  • java/main/src/main/java/com/framsticks/core/AbstractTree.java

    r98 r99  
    3232public abstract class AbstractTree extends AbstractJoinable implements Dispatcher<Tree>, Tree, JoinableParent {
    3333
    34         private static final Logger log = Logger.getLogger(Tree.class);
     34        private static final Logger log = Logger.getLogger(AbstractTree.class);
    3535
    3636        private Node root = null;
     
    4545                }
    4646                root = new Node(this, param, null);
    47                 log.info("assigned root type: " + root);
     47                log.debug("assigned root type: " + root);
    4848        }
    4949
     
    5757                }
    5858                root = new Node(this, root.getParam(), object);
    59                 log.info("assigned root object: " + root);
     59                log.debug("assigned root object: " + root);
    6060        }
    6161
     
    177177        }
    178178
     179        /**
     180         * @return the registry
     181         */
     182        @Override
     183        public Registry getRegistry() {
     184                return registry;
     185        }
     186
    179187        @Override
    180188        protected void joinableStart() {
  • java/main/src/main/java/com/framsticks/core/Framsticks.java

    r97 r99  
    2121        public Framsticks() {
    2222                PropertyConfigurator.configure(getClass().getResource("/configs/log4j.properties"));
     23
     24                // log.info("config is: " + System.getProperties().getProperty("framsticks.config", "/configs/framsticks.xml"));
    2325        }
    2426
  • java/main/src/main/java/com/framsticks/core/Path.java

    r98 r99  
    66import com.framsticks.util.FramsticksException;
    77import com.framsticks.util.dispatching.Dispatching;
     8import com.framsticks.util.dispatching.ExceptionResultHandler;
     9import com.framsticks.util.dispatching.IgnoreExceptionHandler;
     10import com.framsticks.util.lang.Pair;
    811
    912import java.util.Iterator;
    1013import java.util.LinkedList;
    1114import java.util.List;
     15import java.util.regex.Pattern;
    1216
    1317import javax.annotation.Nonnull;
     
    2731        final LinkedList<Node> nodes;
    2832
    29         protected static Object getKnownChild(Tree tree, AccessInterface access, CompositeParam param) {
     33        protected static Object getKnownChild(Tree tree, AccessInterface access, CompositeParam param, ExceptionResultHandler handler) {
    3034                Object child = access.get(param, Object.class);
    3135                if (child == null) {
     
    3640                        return child;
    3741                } catch (FramsticksException e) {
     42                        handler.handle(e);
    3843                }
    3944                return null;
     
    130135                }
    131136
    132 
    133137                public PathBuilder resolve(@Nonnull Tree tree, String textual) {
     138                        return resolve(tree, textual, IgnoreExceptionHandler.getInstance());
     139                }
     140
     141                public PathBuilder resolve(@Nonnull Tree tree, String textual, ExceptionResultHandler handler) {
    134142
    135143                        assert nodes.isEmpty();
     
    146154                                String e = i.next();
    147155                                Param p = access.getParam(e);
     156                                if (p == null) {
     157                                        break;
     158                                }
    148159                                if (!(p instanceof CompositeParam)) {
    149                                         //entries.add(new Entry());
    150                                         break;
    151                                 }
    152                                 CompositeParam c = (CompositeParam)p;
     160                                        throw new FramsticksException().msg("param is not a composite").arg("param", p).arg("tree", tree).arg("textual", textual).arg("access", access);
     161                                }
     162                                CompositeParam c = (CompositeParam) p;
    153163                                b.append("/").append(e);
    154164                                access.select(current.getObject());
    155                                 current = new Node(current.getTree(), c, getKnownChild(tree, access, c));
     165                                current = new Node(current.getTree(), c, getKnownChild(tree, access, c, handler));
    156166                                nodes.add(current);
    157167                        }
     
    245255                        return Path.build().resolve(tree, "/").finish();
    246256                }
    247                 Object child = getKnownChild(tree, TreeOperations.bindAccess(getUnder()), getTop().getParam());
     257                Object child = getKnownChild(tree, TreeOperations.bindAccess(getUnder()), getTop().getParam(), IgnoreExceptionHandler.getInstance());
    248258                if (child == null) {
    249259                        return this;
     
    274284        }
    275285
     286        public static Path tryTo(@Nonnull Tree tree, String textual) {
     287                return Path.build().resolve(tree, textual).finish();
     288        }
     289
    276290        public static Path to(@Nonnull Tree tree, String textual) {
    277                 return Path.build().resolve(tree, textual).finish();
     291                Path path = tryTo(tree, textual);
     292                if (path.getTextual().equals(textual)) {
     293                        return path;
     294                }
     295                throw new FramsticksException().msg("failed to create path").arg("textual", textual).arg("result", path).arg("tree", tree);
    278296        }
    279297
     
    299317        }
    300318
     319        public static final Pattern pathPattern = Pattern.compile("(\\/)|((\\/[^/]+)+)");
     320
     321        public static boolean isValidString(String path) {
     322                return pathPattern.matcher(path).matches();
     323        }
     324
     325        public static String appendString(String path, String element) {
     326                if (path.equals("/")) {
     327                        return path + element;
     328                }
     329                return path + "/" + element;
     330        }
     331
     332        public static Pair<String, String> removeLastElement(String path) {
     333                assert isValidString(path);
     334                if (path.equals("/")) {
     335                        throw new FramsticksException().msg("cannot remove last element from root path");
     336                }
     337                int index = path.lastIndexOf('/');
     338                assert index != -1;
     339                if (index == 0) {
     340                        return new Pair<String, String>("/", path.substring(1));
     341                }
     342                return new Pair<String, String>(path.substring(0, index), path.substring(index + 1));
     343        }
     344
     345        public static String validateString(String path) {
     346                if (!isValidString(path)) {
     347                        throw new FramsticksException().msg("path string validation failured").arg("path", path);
     348                }
     349                return path;
     350        }
     351
    301352
    302353        // public boolean isEmpty() {
  • java/main/src/main/java/com/framsticks/core/Tree.java

    r98 r99  
    55import com.framsticks.params.AccessInterface;
    66import com.framsticks.params.CompositeParam;
     7import com.framsticks.params.EventListener;
    78import com.framsticks.params.FramsClass;
    89import com.framsticks.params.PrimitiveParam;
    910import com.framsticks.params.Registry;
    1011import com.framsticks.params.ValueParam;
     12import com.framsticks.params.types.EventParam;
    1113import com.framsticks.params.types.ProcedureParam;
    1214import com.framsticks.util.dispatching.Dispatcher;
     
    3436         *
    3537         */
    36         public void get(Path path, ValueParam param, Mode mode, Future<Object> future);
     38        public void get(Path path, ValueParam param, Future<Object> future);
    3739
    38         public void get(Path path, Mode mode, Future<Path> future);
     40        public void get(Path path, Future<Path> future);
    3941
    4042        public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future);
     
    5759        public JoinableDispatcher<Tree> getDispatcher();
    5860
     61        public <A> void addListener(Path path, EventParam param, EventListener<A> listener, Class<A> argumentType, Future<Void> future);
     62
     63        public void removeListener(Path path, EventParam param, EventListener<?> listener, Future<Void> future);
     64
     65        public Registry getRegistry();
     66
    5967}
  • java/main/src/main/java/com/framsticks/core/TreeOperations.java

    r98 r99  
    22
    33
     4import java.util.HashSet;
    45import java.util.List;
     6import java.util.Set;
    57
    68import javax.annotation.Nonnull;
     
    1012import com.framsticks.communication.File;
    1113import com.framsticks.params.AccessInterface;
    12 import com.framsticks.params.CompositeParam;
     14import com.framsticks.params.EventListener;
    1315import com.framsticks.params.FramsClass;
    1416import com.framsticks.params.ListAccess;
    1517import com.framsticks.params.Param;
    1618import com.framsticks.params.PrimitiveParam;
     19import com.framsticks.params.UniqueListAccess;
     20import com.framsticks.params.Util;
     21import com.framsticks.params.types.EventParam;
    1722import com.framsticks.params.types.ObjectParam;
    1823import com.framsticks.params.types.ProcedureParam;
     
    7378
    7479                        ListAccess listAccess = (ListAccess) bindAccess(node);
    75                         listAccess.clearValues();
     80
     81                        Set<String> oldValuesIds = new HashSet<>();
     82                        for (Param p : listAccess.getParams()) {
     83                                oldValuesIds.add(p.getId());
     84                        }
     85
     86                        // listAccess.clearValues();
    7687
    7788                        AccessInterface elementAccess = listAccess.getElementAccess();
     89                        AccessInterface clonerInterface = elementAccess.cloneAccess();
     90
    7891                        loader.addAccessInterface(elementAccess);
    7992                        MultiParamLoader.Status status;
     93                        int number = 0;
    8094                        while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
    8195                                if (status == MultiParamLoader.Status.AfterObject) {
    8296                                        AccessInterface accessInterface = loader.getLastAccessInterface();
    8397
    84                                         String id = listAccess.computeIdentifierFor(accessInterface.getSelected());
    85                                         //TODO listAccessParam
    86                                         CompositeParam param = Param.build().forAccess(accessInterface).id(id).finish(CompositeParam.class);
    87                                         Object child = accessInterface.getSelected();
     98                                        String id;
     99                                        if (listAccess instanceof UniqueListAccess) {
     100                                                id = ((UniqueListAccess) listAccess).computeIdentifierFor(accessInterface.getSelected());
     101                                        } else {
     102                                                id = Integer.toString(number);
     103                                        }
     104                                        ++number;
     105
     106                                        Object childTo = listAccess.get(id, Object.class);
     107                                        boolean newOne;
     108                                        if (childTo == null) {
     109                                                childTo = clonerInterface.createAccessee();
     110                                                newOne = true;
     111                                        } else {
     112                                                assert oldValuesIds.contains(id);
     113                                                newOne = false;
     114                                        }
     115                                        oldValuesIds.remove(id);
     116                                        clonerInterface.select(childTo);
     117                                        Util.takeAllNonNullValues(clonerInterface, accessInterface);
     118                                        if (newOne) {
     119                                                listAccess.set(id, childTo);
     120                                        }
     121
     122                                        // listAccess.set(id, accessInterface.getSelected());
    88123                                        accessInterface.select(null);
    89                                         assert child != null;
    90                                         bindAccess(node).set(param, child);
     124
    91125                                }
     126                        }
     127                        /** It looks tricky for ArrayListAccess but should also work.
     128                         *
     129                         * They should be sorted.
     130                         */
     131                        for (String id : oldValuesIds) {
     132                                listAccess.set(id, null);
    92133                        }
    93134
     
    170211        }
    171212
    172 
    173         /** This might not be correct. */
     213        public static <A> void addListener(final Path path, final EventParam param, final EventListener<A> listener, final Class<A> argument, final Future<Void> future) {
     214                final Tree tree = path.getTree();
     215
     216                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
     217                        @Override
     218                        protected void runAt() {
     219                                tree.addListener(path, param, listener, argument, future);
     220                        }
     221                });
     222        }
     223
     224        public static void removeListener(final Path path, final EventParam param, final EventListener<?> listener, final Future<Void> future) {
     225                final Tree tree = path.getTree();
     226
     227                dispatchIfNotActive(tree, new RunAt<Tree>(future) {
     228                        @Override
     229                        protected void runAt() {
     230                                tree.removeListener(path, param, listener, future);
     231                        }
     232                });
     233        }
     234
     235
     236        /**
     237         *
     238         * If StackOverflow occurs in that loop in LocalTree it is probably caused
     239         * the by the fact, that get operation may find the object, but Path resolution
     240         * cannot.
     241         * */
    174242        public static void tryGet(final Tree tree, final String targetPath, final Future<Path> future) {
    175243                log.debug("resolve textual: " + targetPath + " for " + tree);
     
    178246                        @Override
    179247                        protected void runAt() {
    180                                 final Path path = Path.to(tree, targetPath);
     248                                final Path path = Path.tryTo(tree, targetPath).tryResolveIfNeeded();
     249                                log.debug("found: " + path);
    181250                                if (path.isResolved()) {
    182251                                        future.pass(path);
     
    184253                                }
    185254
    186                                 tree.get(path, Mode.FETCH, new FutureHandler<Path>(future) {
     255                                tree.get(path, new FutureHandler<Path>(future) {
    187256                                        @Override
    188257                                        protected void result(Path result) {
     258                                                // if (result.isResolved(targetPath)) {
     259                                                //      future.pass(result);
     260                                                //      return;
     261                                                // }
     262                                                log.debug("retrying resolve textual: " + targetPath + " for " + tree + " with " + result);
    189263                                                tryGet(tree, targetPath, future);
    190264                                        }
     
    198272                return path.getTree().getInfoFromCache(path.getTop().getParam().getContainedTypeName());
    199273        }
     274
    200275}
  • java/main/src/main/java/com/framsticks/gui/Browser.java

    r98 r99  
    44import com.framsticks.gui.console.Console;
    55import com.framsticks.gui.console.TrackConsole;
     6import com.framsticks.gui.table.ColumnsConfig;
     7import com.framsticks.gui.table.ListPanelProvider;
    68import com.framsticks.params.annotations.AutoAppendAnnotation;
    79import com.framsticks.params.annotations.FramsClassAnnotation;
     
    5759        }
    5860
     61        protected final StandardPanelProvider standardPanelProvider;
     62        protected final ListPanelProvider listPanelProvider;
     63
    5964        public Browser() {
    6065                setName("browser");
    6166                JPopupMenu.setDefaultLightWeightPopupEnabled(false);
    62                 addPanelProvider(new StandardPanelProvider());
     67                addPanelProvider(standardPanelProvider = new StandardPanelProvider());
     68                addPanelProvider(listPanelProvider = new ListPanelProvider());
    6369
    6470                mainFrame = new MainFrame(Browser.this);
     
    116122
    117123        @AutoAppendAnnotation
     124        public void addColumnsConfig(ColumnsConfig columnsConfig) {
     125                listPanelProvider.addColumnsConfig(columnsConfig);
     126        }
     127
     128        @AutoAppendAnnotation
    118129        public void addPopupMenuEntryProvider(PopupMenuEntryProvider popupMenuEntryProvider) {
    119130                popupMenuEntryProviders.add(popupMenuEntryProvider);
     
    122133        @AutoAppendAnnotation
    123134        public void addTree(Tree tree) {
    124                 log.info("adding tree: " + tree);
     135                log.debug("adding tree: " + tree);
    125136                tree.setDispatcher(new SwingDispatcher<Tree>());
    126137                trees.add(tree);
     
    155166        }
    156167
    157         public void createTreeNodeForChild(final Path path) {
    158                 assert !isActive();
    159                 //assert tree.isActive();
    160 
    161                 /*
    162                  final TreeNode parentTreeNode = (TreeNode) child.getParent().getUserObject();
    163                  if (parentTreeNode == null) {
    164                  Dispatching.invokeDispatch(this, manager, new Runnable() {
    165                  @Override
    166                  public void run() {
    167                  createTreeNodeForChild(child);
    168                  }
    169                  });
    170                  return;
    171                  }
    172                  log.debug(child.getClass().getSimpleName() + " created: " + child);
    173 
    174 
    175                  invokeLater(new Runnable() {
    176                  @Override
    177                  public void run() {
    178                  parentTreeNode.getOrCreateChildTreeNodeFor(child);
    179                  }
    180                  });
    181                  */
    182         }
    183 
    184168        @Override
    185169        protected void joinableStart() {
     
    288272        }
    289273
    290         // final protected Map<EventParam, Subscription<?>> userSubscriptions = new HashMap<>();
    291         // public boolean hasSubscribed(EventParam param) {
    292         //      assert frame.isActive();
    293         //      return userSubscriptions.containsKey(param);
    294         // }
    295 
    296         // public void unsubscribe(EventParam eventParam) {
    297         //      assert frame.isActive();
    298         //      if (!hasSubscribed(eventParam)) {
    299         //              log.error("could not unsubscribe from " + eventParam);
    300         //              return;
    301         //      }
    302         //      userSubscriptions.get(eventParam).unsubscribe(new LoggingStateCallback(log, "unsubscribed " + eventParam));
    303         //      userSubscriptions.remove(eventParam);
    304         // }
    305 
    306 
    307 
    308 
    309274}
  • java/main/src/main/java/com/framsticks/gui/Frame.java

    r98 r99  
    3838import org.apache.log4j.Logger;
    3939
    40 import com.framsticks.core.Mode;
    4140import com.framsticks.core.Path;
    4241import com.framsticks.core.Tree;
    43 import com.framsticks.core.TreeOperations;
    44 import com.framsticks.gui.view.TreeCellRenderer;
    45 import com.framsticks.params.AccessInterface;
     42import com.framsticks.gui.tree.MetaNode;
     43import com.framsticks.gui.tree.TreeCellRenderer;
     44import com.framsticks.gui.tree.TreeModel;
     45import com.framsticks.gui.tree.TreeNode;
    4646import com.framsticks.util.dispatching.Dispatching;
    4747import com.framsticks.util.dispatching.FutureHandler;
     
    126126                        @Override
    127127                        public void valueChanged(TreeSelectionEvent e) {
    128                                 chooseTreeNode(e.getNewLeadSelectionPath());
     128                                treeModel.chooseTreeNode(e.getNewLeadSelectionPath());
    129129                        }
    130130                });
     
    139139                        @Override
    140140                        public void treeExpanded(TreeExpansionEvent e) {
    141                                 loadChildren(treeModel.convertToPath(e.getPath()), false);
     141                                // loadChildren(treeModel.convertToPath(e.getPath()), false);
    142142                        }
    143143                });
     
    243243                        public void actionPerformed(ActionEvent actionEvent) {
    244244
    245                                 loadPath(treeModel.convertToPath(jtree.getSelectionPath()), true);
     245                                treeModel.loadPath(treeModel.convertToPath(jtree.getSelectionPath()), true);
    246246                        }
    247247                });
     
    258258                Tree tree = path.getTree();
    259259
    260                 log.info("trying mount: " + path);
     260                log.debug("trying mount: " + path);
    261261                if (!tree.getAssignedRoot().isResolved()) {
    262                         tree.get(path, Mode.FETCH, new FutureHandler<Path>(this) {
     262                        tree.get(path, new FutureHandler<Path>(this) {
    263263
    264264                                @Override
     
    275275                treeAtFrames.put(tree, e);
    276276
    277                 rootNode.getChildren().add(new TreeNode(tree.getAssignedRoot()));
     277                rootNode.getChildren().add(new TreeNode(e, Path.to(tree, "/")));
    278278                e.rootNode = tree.getAssignedRoot();
    279279                treeModel.nodeStructureChanged(new TreePath(rootNode));
     
    311311        }
    312312
    313         public void loadChildren(Path path, boolean reload) {
    314                 if (path == null) {
    315                         return;
     313        public void updatePanelIfIsLeadSelection(TreePath treePath, Path path) {
     314                assert isActive();
     315                if (treePath.equals(jtree.getSelectionPath())) {
     316                        treeAtFrames.get(path.getTree()).useOrCreatePanel(treePath);
    316317                }
    317                 AccessInterface access = TreeOperations.bindAccess(path);
    318 
    319                 int count = access.getCompositeParamCount();
    320                 for (int i = 0; i < count; ++i) {
    321                         Path childPath = path.appendParam(access.getCompositeParam(i)).tryFindResolution();
    322                         loadPath(childPath, reload);
    323                 }
    324 
    325         }
    326 
    327         public void loadPath(Path path, boolean reload) {
    328                 if (path == null) {
    329                         return;
    330                 }
    331                 if (path.isResolved() && !reload) {
    332                         return;
    333                 }
    334                 path.getTree().get(path, Mode.FETCH, new FutureHandler<Path>(this) {
    335                         @Override
    336                         protected void result(Path result) {
    337                                 final TreePath treePath = treeModel.convertToTreePath(result);
    338 
    339                                 treeModel.nodeStructureChanged(treePath);
    340                                 if (treePath.equals(jtree.getSelectionPath())) {
    341                                         treeAtFrames.get(result.getTree()).useOrCreatePanel(treePath);
    342                                 }
    343                         }
    344                 });
    345         }
    346 
    347         public void chooseTreeNode(final TreePath treePath) {
    348                 assert isActive();
    349                 if (treePath == null) {
    350                         return;
    351                 }
    352                 if (treeModel.isChanging()) {
    353                         return;
    354                 }
    355 
    356                 Path path = treeModel.convertToPath(treePath);
    357                 if (path == null) {
    358                         return;
    359                 }
    360                 path = path.assureResolved();
    361                 final Tree tree = path.getTree();
    362 
    363                 treeAtFrames.get(tree).useOrCreatePanel(treePath);
    364                 loadChildren(path, false);
    365 
    366         }
     318        }
     319
    367320
    368321
     
    420373
    421374        /**
     375         * @return the jtree
     376         */
     377        public JTree getJtree() {
     378                return jtree;
     379        }
     380
     381        /**
    422382         * @return the treeModel
    423383         */
     
    426386        }
    427387
     388        /**
     389         * @return the rootNode
     390         */
     391        public MetaNode getRootNode() {
     392                return rootNode;
     393        }
     394
     395        /**
     396         * @return the treeAtFrames
     397         */
     398        public Map<Tree, TreeAtFrame> getTreeAtFrames() {
     399                return treeAtFrames;
     400        }
     401
    428402}
  • java/main/src/main/java/com/framsticks/gui/Gui.java

    r97 r99  
    101101
    102102        public static <P extends Param, C extends Control> void fillWithControls(ControlOwner owner, Collection<P> params, Map<P, C> components, Class<C> controlType) {
    103                 JPanel panel = owner.getPanel();
     103                JPanel panel = owner.getPanelForControls();
    104104                for (P param : params) {
    105105                        if (param.isUserHidden()) {
  • java/main/src/main/java/com/framsticks/gui/ModifiablePanel.java

    r98 r99  
    2020         * Pane to which components will be added.
    2121         */
    22         protected JPanel contentPanel;
    2322
    24         final protected JLabel label;
    25         final protected JButton applyButton;
     23        protected final JLabel label;
     24        protected final JButton applyButton;
     25        protected final JPanel centerPanel;
     26
     27        protected Component contentComponent;
    2628
    2729        public ModifiablePanel(Panel.Parameters parameters) {
     
    3032
    3133
    32                 contentPanel = new JPanel();
    33                 contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
    34                 JScrollPane scroll = new JScrollPane(contentPanel);
    35                 //scroll.setBorder(BorderFactory.createEtchedBorder());
    3634
    3735                JPanel pageEndPanel = new JPanel();
     
    5351
    5452                label = new JLabel();
    55                 JPanel centerPanel = new JPanel();
     53                centerPanel = new JPanel();
    5654                centerPanel.setLayout(new BorderLayout());
    5755                centerPanel.add(Box.createHorizontalStrut(10), BorderLayout.LINE_START);
    5856                centerPanel.add(Box.createHorizontalStrut(10), BorderLayout.LINE_END);
    5957                centerPanel.add(label, BorderLayout.PAGE_START);
    60                 centerPanel.add(scroll, BorderLayout.CENTER);
     58
     59
    6160                centerPanel.add(pageEndPanel, BorderLayout.PAGE_END);
    6261
     
    6867        protected abstract void applyChanges();
    6968
     69        protected void setupContentComponent(Component contentComponent) {
     70                this.contentComponent = contentComponent;
     71                centerPanel.add(contentComponent, BorderLayout.CENTER);
     72        }
     73
    7074}
  • java/main/src/main/java/com/framsticks/gui/ObjectPanel.java

    r98 r99  
    2929        final protected Map<ValueParam, ValueControl> valueControls = new IdentityHashMap<ValueParam, ValueControl>();
    3030
     31        protected final JPanel contentPanel;
     32        protected final JScrollPane scrollPane;
     33
    3134        public ObjectPanel(Panel.Parameters parameters, Collection<Param> params) {
    3235                super(parameters);
     36
     37                contentPanel = new JPanel();
     38                scrollPane = new JScrollPane(contentPanel);
     39                contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
     40                setupContentComponent(scrollPane);
    3341
    3442                Gui.fillWithControls(this, params, components, Control.class);
     
    102110
    103111        @Override
    104         public JPanel getPanel() {
     112        public JPanel getPanelForControls() {
    105113                return contentPanel;
    106114        }
  • java/main/src/main/java/com/framsticks/gui/Panel.java

    r98 r99  
    2222                public final TreeAtFrame treeAtFrame;
    2323                public final CompositeParam param;
     24
     25                /** Contained type FramsClass. */
    2426                public final FramsClass framsClass;
    2527
  • java/main/src/main/java/com/framsticks/gui/TreeAtFrame.java

    r98 r99  
    88import com.framsticks.core.TreeOperations;
    99import com.framsticks.gui.controls.ValueControl;
     10import com.framsticks.gui.tree.TreeNode;
    1011import com.framsticks.params.CompositeParam;
    1112import com.framsticks.params.FramsClass;
  • java/main/src/main/java/com/framsticks/gui/console/ManagedConsole.java

    r98 r99  
    1010import com.framsticks.communication.Response;
    1111import com.framsticks.communication.queries.ApplicationRequest;
    12 import com.framsticks.core.Mode;
    1312import com.framsticks.core.Path;
    1413import static com.framsticks.core.TreeOperations.*;
     
    143142
    144143                                if (path.getTop().getParam() instanceof ListParam) {
    145                                         tree.get(path, Mode.FETCH, new FutureHandler<Path>(ManagedConsole.this) {
     144                                        tree.get(path, new FutureHandler<Path>(ManagedConsole.this) {
    146145                                                @Override
    147146                                                protected void result(Path result) {
  • java/main/src/main/java/com/framsticks/gui/controls/Control.java

    r98 r99  
    66import javax.swing.JPanel;
    77
    8 import com.framsticks.params.Flags;
     8import com.framsticks.params.ParamFlags;
    99import com.framsticks.params.Param;
    1010import com.framsticks.util.FramsticksException;
     
    5757
    5858        public final boolean isReadonly() {
    59                 return !userEnabled || param.hasFlag(Flags.READONLY);
     59                return !userEnabled || param.hasFlag(ParamFlags.READONLY);
    6060        }
    6161
  • java/main/src/main/java/com/framsticks/gui/controls/ControlOwner.java

    r98 r99  
    99public interface ControlOwner extends ExceptionResultHandler {
    1010
    11         public JPanel getPanel();
     11        public JPanel getPanelForControls();
    1212        public TreePath getCurrentTreePath();
    1313        public Frame getFrame();
  • java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java

    r98 r99  
    8686
    8787        @Override
    88         public JPanel getPanel() {
     88        public JPanel getPanelForControls() {
    8989                return this;
    9090        }
  • java/main/src/main/java/com/framsticks/gui/controls/ValueControl.java

    r98 r99  
    44
    55import com.framsticks.params.CastFailure;
    6 import com.framsticks.params.Flags;
     6import com.framsticks.params.ParamFlags;
    77import com.framsticks.params.PrimitiveParam;
    88import com.framsticks.params.ReassignResult;
     9import com.framsticks.params.SetStateFlags;
    910import com.framsticks.util.FramsticksException;
     11import com.framsticks.util.lang.FlagsUtil;
    1012import com.framsticks.util.swing.TooltipConstructor;
    1113
     
    3335                        .append("min", primitiveParam.getMin(Object.class))
    3436                        .append("max", primitiveParam.getMax(Object.class))
    35                         .append("flags", Flags.write(primitiveParam.getFlags(), null))
     37                        .append("flags", FlagsUtil.write(ParamFlags.class, primitiveParam.getFlags(), null))
    3638                        .append("group", primitiveParam.getGroup())
    3739                        .append("extra", primitiveParam.getExtra())
     
    7072                        ReassignResult<?> res = getParam().reassign(candidate, oldValue);
    7173                        if (res.getFlags() != 0) {
    72                                 log.warn("filter of param " + param + " failed: " + Flags.write(res.getFlags(), "0"));
     74                                log.warn("filter of param " + param + " failed: " + FlagsUtil.write(SetStateFlags.class, res.getFlags(), "0"));
    7375                        }
    7476                        return res.getValue();
  • java/main/src/main/java/com/framsticks/hosting/ClientAtServer.java

    r98 r99  
    88import com.framsticks.communication.queries.GetRequest;
    99import com.framsticks.communication.queries.InfoRequest;
     10import com.framsticks.communication.queries.RegisterRequest;
    1011import com.framsticks.communication.queries.SetRequest;
     12import com.framsticks.core.LocalTree;
    1113import com.framsticks.core.Tree;
    1214import com.framsticks.core.Path;
    1315import com.framsticks.params.*;
     16import com.framsticks.params.types.EventParam;
    1417import com.framsticks.params.types.ProcedureParam;
    1518import com.framsticks.parsers.Savers;
    1619import com.framsticks.util.FramsticksException;
     20import com.framsticks.util.Misc;
    1721import com.framsticks.util.dispatching.AbstractJoinable;
    1822import com.framsticks.util.dispatching.Dispatching;
     
    2226import com.framsticks.util.dispatching.JoinableParent;
    2327import com.framsticks.util.dispatching.JoinableState;
     28import com.framsticks.util.lang.FlagsUtil;
     29import com.framsticks.util.lang.Strings;
     30
    2431import static com.framsticks.core.TreeOperations.*;
    2532
    2633import java.net.Socket;
    27 import java.util.LinkedList;
    28 import java.util.List;
    2934
    3035/**
     
    3439
    3540        protected final Server server;
    36         protected final Tree tree;
     41        protected final Tree contentTree;
     42        protected final Object treeRootObject;
    3743        protected final ServerSideManagedConnection connection;
     44
     45        protected final Cli cliObject;
     46        protected final LocalTree rootTree;
     47
     48
     49        protected final FramsClass rootFramsClass;
     50        protected final Object root;
     51        protected final String contentPrefix;
    3852
    3953        public ClientAtServer(Server server, Socket socket) {
    4054                this.server = server;
    41                 this.tree = server.hosted;
     55                this.contentTree = server.hosted;
    4256                this.connection = new ServerSideManagedConnection(socket, this);
     57
     58                treeRootObject = contentTree.getAssignedRoot().getObject();
     59                Misc.throwIfNull(treeRootObject);
     60
     61                cliObject = new Cli(this);
     62                rootTree = new LocalTree();
     63                // rootTree.setDispatcher(new AtOnceDispatcher<Tree>());
     64                rootTree.setDispatcher(server.getHosted().getDispatcher());
     65                assert rootTree.getDispatcher() != null;
     66
     67                final FramsClass framsClass = bindAccess(contentTree.getAssignedRoot()).getFramsClass();
     68                final String id = Strings.uncapitalize(framsClass.getName());
     69                contentPrefix = "/" + id;
     70                final String rootFramsClassId = id + "Root";
     71
     72                rootFramsClass = FramsClass.build()
     73                        .idAndName(rootFramsClassId)
     74                        .param(Param.build().id(id).name(framsClass.getName()).type("o " + framsClass.getId()))
     75                        .param(Param.build().id("cli").name("CLI").type("o Cli"))
     76                        .finish();
     77
     78                // rootTree.putInfoIntoCache(rootFramsClass);
     79                rootTree.getRegistry().putFramsClass(rootFramsClass);
     80                rootTree.getRegistry().registerAndBuild(Cli.class);
     81                rootTree.getRegistry().registerAndBuild(CliEvent.class);
     82
     83                AccessInterface access = new PropertiesAccess(rootFramsClass);
     84
     85                root = access.createAccessee();
     86                access.select(root);
     87                access.set(id, treeRootObject);
     88                access.set("cli", cliObject);
     89
     90                rootTree.assignRootParam(access.buildParam(new ParamBuilder()).name(rootFramsClassId).finish(CompositeParam.class));
     91                rootTree.assignRootObject(root);
     92
    4393        }
    4494
     
    52102                assureNotEmpty(request.getPath());
    53103
    54                 tryGet(tree, request.getPath(), new FutureHandler<Path>(responseCallback) {
     104                if (request.getPath().startsWith(contentPrefix)) {
     105                        String p = request.getPath().substring(contentPrefix.length());
     106                        request.path(p.equals("") ? "/" : p);
     107                        handleInTree(contentTree, request, responseCallback, contentPrefix);
     108                        return;
     109                }
     110
     111                handleInTree(rootTree, request, responseCallback, "");
     112        }
     113
     114        public static File printToFile(String path, AccessInterface access) {
     115                ListSink sink = new ListSink();
     116                access.save(sink);
     117                return new File(path, new ListSource(sink.getOut()));
     118        }
     119
     120        protected void handleInTree(final Tree tree, final ApplicationRequest request, final ServerSideResponseFuture responseCallback, final String usedPrefix) {
     121
     122                tryGet(tree, request.getActualPath(), new FutureHandler<Path>(responseCallback) {
    55123                        @Override
    56124                        protected void result(final Path path) {
    57125
    58                                 if (!path.getTextual().equals(request.getPath())) {
    59                                         throw new FramsticksException().msg("invalid path").arg("path", request.getPath());
     126                                if (!path.getTextual().equals(request.getActualPath())) {
     127                                        throw new FramsticksException().msg("invalid path").arg("path", request.getActualPath());
    60128                                }
    61129
    62130                                // final AccessInterface access = tree.prepareAccess(path);
    63131                                final AccessInterface access = bindAccess(path);
     132
     133                                if (request instanceof GetRequest) {
     134                                        Object result = path.getTopObject();
     135                                        if (result != access.getSelected()) {
     136                                                throw new FramsticksException().msg("mismatch objects during fetch").arg("path", path);
     137                                        }
     138                                        responseCallback.pass(new Response(true, "", File.single(printToFile(path.getTextual(), access))));
     139
     140                                        return;
     141                                }
    64142
    65143                                if (request instanceof SetRequest) {
     
    69147                                                @Override
    70148                                                protected void result(Integer flag) {
    71                                                         responseCallback.pass(new Response(true, Flags.write(flag, null), null));
     149                                                        responseCallback.pass(new Response(true, FlagsUtil.write(SetStateFlags.class, flag, null), null));
    72150
    73151                                                }
     
    76154                                }
    77155
    78                                 if (request instanceof GetRequest) {
    79                                         Object result = path.getTopObject();
    80                                         if (result != access.getSelected()) {
    81                                                 throw new FramsticksException().msg("mismatch objects during fetch").arg("path", path);
    82                                         }
    83                                         List<File> files = new LinkedList<File>();
    84                                         ListSink sink = new ListSink();
    85                                         access.save(sink);
    86                                         files.add(new File(path.getTextual(), new ListSource(sink.getOut())));
    87                                         responseCallback.pass(new Response(true, "", files));
    88 
    89                                         return;
    90                                 }
    91156                                if (request instanceof CallRequest) {
    92157                                        final CallRequest callRequest = (CallRequest) request;
     
    107172                                        return;
    108173                                }
     174
    109175                                if (request instanceof InfoRequest) {
    110176                                        FramsClass framsClass = getInfo(path);
     
    116182                                }
    117183
     184                                if (request instanceof RegisterRequest) {
     185                                        RegisterRequest register = (RegisterRequest) request;
     186
     187                                        cliObject.addListener(path, access.getFramsClass().getParamEntry(register.getEventName(), EventParam.class), usedPrefix, responseCallback);
     188                                        return;
     189                                }
     190
    118191                                throw new FramsticksException().msg("invalid request type: " + request.getCommand());
    119192                        }
     
    148221        @Override
    149222        public void handle(FramsticksException exception) {
    150                 tree.handle(exception);
     223                contentTree.handle(exception);
     224        }
     225
     226        /**
     227         * @return the tree
     228         */
     229        public Tree getTree() {
     230                return contentTree;
    151231        }
    152232
  • java/main/src/main/java/com/framsticks/model/Model.java

    r90 r99  
    5959        public List<NeuroConnection> getNeuroConnections() { return neuroConnections; }
    6060
     61        @Override
     62        public String toString() {
     63                return "Model{" + parts.size() + ":" + joints.size() + ":" + neuroDefinitions.size() + ":" + neuroConnections.size() + "}";
     64
     65        }
     66
    6167}
  • java/main/src/main/java/com/framsticks/params/AccessInterface.java

    r98 r99  
    22
    33
     4import com.framsticks.params.types.EventParam;
    45import com.framsticks.params.types.ProcedureParam;
    56
     
    3940        <T> int set(ValueParam param, T value);
    4041
     42        void reg(EventParam param, EventListener<?> listener);
     43
     44        void regRemove(EventParam param, EventListener<?> listener);
     45
    4146        void setDefault(boolean numericOnly);
    4247
     
    5055
    5156        void setMax(int i);
    52 
    53         void copyFrom(AccessInterface src);
    5457
    5558        void save(SinkInterface sink);
     
    8083        CompositeParam getCompositeParam(int number);
    8184
     85        ParamBuilder buildParam(ParamBuilder builder);
     86
    8287
    8388}
  • java/main/src/main/java/com/framsticks/params/ArrayListAccess.java

    r98 r99  
    11package com.framsticks.params;
    22
     3import com.framsticks.params.types.ArrayListParam;
    34import com.framsticks.util.UnimplementedException;
    45import com.framsticks.util.lang.Numbers;
     
    1516
    1617        List<Object> list;
     18
    1719
    1820        public ArrayListAccess(AccessInterface elementAccess) {
     
    3537                        return null;
    3638                }
    37                 return Param.build().id(Integer.toString(i)).forAccess(elementAccess).finish(CompositeParam.class);
     39                return paramBuilder.id(Integer.toString(i)).finish(CompositeParam.class);
    3840        }
    3941
     
    109111        }
    110112
    111         @Override
    112         public String computeIdentifierFor(Object selected) {
    113                 return Integer.toString(list.size());
    114         }
    115113
    116114        @Override
     
    131129                                        @Override
    132130                                        public Param next() {
    133                                                 Param param = Param.build().id(Integer.toString(internal.nextIndex())).forAccess(elementAccess).finish();
     131                                                Param param = paramBuilder.id(Integer.toString(internal.nextIndex())).finish(CompositeParam.class);
    134132                                                internal.next();
    135133                                                return param;
     
    156154        }
    157155
     156        @Override
     157        public ParamBuilder buildParam(ParamBuilder builder) {
     158                return builder.name(containedTypeName + " list").type(ArrayListParam.class).containedTypeName(containedTypeName);
     159        }
    158160
    159161}
  • java/main/src/main/java/com/framsticks/params/FramsClass.java

    r98 r99  
    55import com.framsticks.util.FramsticksException;
    66import com.framsticks.util.lang.Containers;
     7import com.framsticks.util.lang.Strings;
    78// import com.framsticks.util.FramsticksException;
    89
     
    6061
    6162                this.id = builder.getId();
    62                 this.name = builder.getName();
     63                this.name = Strings.toStringEmptyProof(builder.getName(), this.id);
    6364                this.description = builder.getDescription();
    6465                this.groups = Containers.build(builder.groupBuilders);
  • java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java

    r98 r99  
    4040
    4141        public static ParamBuilder induceParamType(ParamBuilder builder, Type type) {
     42                // if (type.equals(Void.TYPE)) {
     43                //      throw new ConstructionException().msg("void is not a valid type");
     44                // }
    4245
    4346                if (type instanceof ParameterizedType) {
     
    4750                        //TODO make implementation here
    4851                        boolean map = false;
     52                        StringBuilder b = new StringBuilder();
    4953                        if (rawType.equals(Map.class)) {
    5054                                containedType = p.getActualTypeArguments()[1];
    5155                                map = true;
     56                                b.append("l");
    5257                        } else if (rawType.equals(List.class)) {
    5358                                containedType = p.getActualTypeArguments()[0];
     59                                b.append("l");
     60                        } else if (rawType.equals(EventListener.class)) {
     61                                containedType = p.getActualTypeArguments()[0];
     62                                b.append("e");
    5463                        }
    5564                        if (!(containedType instanceof Class)) {
    5665                                return builder;
    5766                        }
     67                        b.append(" ");
     68
    5869                        Class<?> containedClass = (Class<?>) containedType;
    59                         StringBuilder b = new StringBuilder();
    60                         b.append("l ");
    6170                        FramsClassAnnotation fca = containedClass.getAnnotation(FramsClassAnnotation.class);
    6271                        if (fca == null) {
    63                                 log.error("the class is not annotated: " + containedClass);
    64                                 return builder;
     72                                throw new ConstructionException().msg("the contained class is not annotated").arg("class", containedClass);
    6573                        }
    6674                        b.append(getName(fca, containedClass));
     75                        //TODO parametrize this
    6776                        if (map) {
    6877                                b.append(" name");
     
    109118                                return builder;
    110119                        }
     120
    111121
    112122                        // builder.type("o " + (cl).getCanonicalName());
     
    174184                        }
    175185                        if (argsNum == 1) {
    176                                 return n.startsWith("set") ? Strings.uncapitalize(n.substring(3)) : n;
     186                                if (n.startsWith("set")) {
     187                                        return Strings.uncapitalize(n.substring(3));
     188                                }
     189                                if (n.startsWith("add")) {
     190                                        return Strings.uncapitalize(n.substring(3));
     191                                }
     192                                if (n.startsWith("remove")) {
     193                                        return Strings.uncapitalize(n.substring(6));
     194                                }
     195                                return n;
    177196                        }
    178197                        log.error("invalid number of arguments");
  • java/main/src/main/java/com/framsticks/params/InvalidOperationException.java

    r90 r99  
    11package com.framsticks.params;
    22
    3 import com.framsticks.util.FramsticksException;
     3import com.framsticks.util.UnsupportedOperationException;
    44
    55@SuppressWarnings("serial")
    6 public class InvalidOperationException extends FramsticksException {
     6public class InvalidOperationException extends UnsupportedOperationException {
    77
    88}
  • java/main/src/main/java/com/framsticks/params/ListAccess.java

    r97 r99  
    55import static com.framsticks.util.lang.Containers.filterInstanceof;
    66
     7import com.framsticks.params.types.EventParam;
    78import com.framsticks.params.types.ProcedureParam;
    89
     
    1314
    1415        final AccessInterface elementAccess;
     16        final String containedTypeName;
     17
     18        protected final ParamBuilder paramBuilder;
    1519
    1620        public ListAccess(AccessInterface elementAccess) {
    1721                this.elementAccess = elementAccess;
     22                this.containedTypeName = elementAccess.getId();
     23                paramBuilder = elementAccess.buildParam(new ParamBuilder());
    1824        }
    1925
     
    4854
    4955        @Override
    50         public void copyFrom(AccessInterface src) {
    51         }
    52 
    53         @Override
    5456        public void save(SinkInterface sink) {
    5557                for (CompositeParam p : filterInstanceof(getParams(), CompositeParam.class)) {
     
    7072        }
    7173
    72         public abstract String computeIdentifierFor(Object selected);
     74        /**
     75         * @return the containedTypeName
     76         */
     77        public String getContainedTypeName() {
     78                return containedTypeName;
     79        }
    7380
    7481        @Override
     
    8592        @Override
    8693        public Object call(String id, Object[] arguments) {
    87                 throw new InvalidOperationException().msg("list access does not support calling methods").arg("id", id);
     94                throw new InvalidOperationException().msg("list access does not support calling methods").arg("id", id).arg("access", this);
    8895        }
    8996
    9097        @Override
    9198        public Object call(ProcedureParam param, Object[] arguments) {
    92                 throw new InvalidOperationException().msg("list access does not support calling methods").arg("param", param);
     99                throw new InvalidOperationException().msg("list access does not support calling methods").arg("param", param).arg("access", this);
    93100        }
    94101
     102        @Override
     103        public void reg(EventParam param, EventListener<?> listener) {
     104                throw new InvalidOperationException().msg("list access does not support registering events").arg("param", param).arg("access", this);
     105        }
     106
     107        @Override
     108        public void regRemove(EventParam param, EventListener<?> listener) {
     109                throw new InvalidOperationException().msg("list access does not support registering events").arg("param", param).arg("access", this);
     110        }
     111
     112
     113        @Override
     114        public String toString() {
     115                StringBuilder b = new StringBuilder();
     116                b.append("list of ").append(containedTypeName);
     117                if (getSelected() != null) {
     118                        b.append("[").append(getParamCount()).append("]");
     119                }
     120                return b.toString();
     121        }
    95122};
  • java/main/src/main/java/com/framsticks/params/Param.java

    r96 r99  
    9797
    9898        public boolean isUserHidden() {
    99                 return (flags & Flags.USERHIDDEN) != 0;
     99                return (flags & ParamFlags.USERHIDDEN) != 0;
    100100        }
    101101
  • java/main/src/main/java/com/framsticks/params/ParamBuilder.java

    r97 r99  
    77import com.framsticks.util.FramsticksException;
    88import com.framsticks.util.Misc;
     9import com.framsticks.util.lang.FlagsUtil;
    910import com.framsticks.util.lang.Strings;
    1011
     
    6667        private int extra = 0;
    6768
    68         String containedTypeName;
     69        protected String containedTypeName;
     70
     71        protected String eventArgumentTypeName;
    6972
    7073        protected Class<?> storageType;
     
    116119        }
    117120
     121        public ParamBuilder containedTypeName(String containedTypeName) {
     122                this.containedTypeName = containedTypeName;
     123                return this;
     124        }
     125
    118126        /**
    119127         * @return the resultType
     
    160168        public String getUid() {
    161169                return uid;
     170        }
     171
     172        public ParamBuilder uid(String uid) {
     173                this.uid = uid;
     174                return this;
    162175        }
    163176
     
    322335                        case 'e': {
    323336                                type(EventParam.class);
    324                                 break;
    325                         }
    326                         case 'l': {
    327                                 containedTypeName = second;
    328                                 if (third != null) {
    329                                         type(UniqueListParam.class);
    330                                         uid = third;
    331                                 } else {
    332                                         type(ArrayListParam.class);
    333                                 }
    334                                 break;
    335                         }
    336                         default:{
    337                                 log.error("unknown type: " + first);
    338                                 return this;
    339                         }
    340                 }
     337                        eventArgumentTypeName(second);
     338                        break;
     339                }
     340                case 'l': {
     341                        containedTypeName = second;
     342                        if (third != null) {
     343                                type(UniqueListParam.class);
     344                                uid = third;
     345                        } else {
     346                                type(ArrayListParam.class);
     347                        }
     348                        break;
     349                }
     350                default: {
     351                        log.error("unknown type: " + first);
     352                        return this;
     353                }
     354                }
     355                return this;
     356        }
     357
     358        public ParamBuilder eventArgumentTypeName(String eventArgumentTypeName) {
     359                this.eventArgumentTypeName = eventArgumentTypeName;
    341360                return this;
    342361        }
     
    438457                        id(paramEntryValues[0]);
    439458                        group(Integer.valueOf(paramEntryValues[1]));
    440                         flags(Flags.read(paramEntryValues[2]));
     459                        flags(FlagsUtil.read(ParamFlags.class, paramEntryValues[2]));
    441460                        name(paramEntryValues[3]);
    442461                        type(paramEntryValues[4]);
     
    464483                                break;
    465484                        case FLAGS_FIELD:
    466                                 flags(Flags.read(value));
     485                                flags(FlagsUtil.read(ParamFlags.class, value));
    467486                                break;
    468487                        case HELP_FIELD:
     
    492511        }
    493512
     513        /**
     514         * @return the eventArgumentTypeName
     515         */
     516        public String getEventArgumentTypeName() {
     517                return eventArgumentTypeName;
     518        }
     519
    494520        public Class<?> getStorageType() {
    495521                return storageType;
    496         }
    497 
    498         public ParamBuilder forAccess(AccessInterface access) {
    499                 return name(access.getId()).type("o " + access.getId());
    500522        }
    501523
  • java/main/src/main/java/com/framsticks/params/ParamCandidate.java

    r90 r99  
    7373        protected final OneTime<Method> getter = new OneTime<>("getter");
    7474        protected final OneTime<Method> caller = new OneTime<>("caller");
     75        protected final OneTime<Method> adder = new OneTime<>("adder");
     76        protected final OneTime<Method> remover = new OneTime<>("remover");
    7577
    7678        protected final List<ParamAnnotation> annotations = new LinkedList<>();
     
    142144
    143145        /**
     146         * @return the getter
     147         */
     148        public Method getAdder() {
     149                return adder.get();
     150        }
     151
     152        /**
     153         * @return the getter
     154         */
     155        public Method getRemover() {
     156                return remover.get();
     157        }
     158
     159        /**
    144160         * @return the annotations
    145161         */
     
    150166        void validate() throws ConstructionException {
    151167                try {
     168                        if (adder.has() != remover.has()) {
     169                                throw new ConstructionException().msg("only one of event manipulator methods is defined");
     170                        }
     171                        if (adder.has() && remover.has()) {
     172                                return;
     173                        }
    152174                        if (caller.has()) {
    153175                                if (!isPublic(caller)) {
     
    174196                                throw new ConstructionException().msg("missing getter or field");
    175197                        }
     198                        if (getter.has() || field.has() || setter.has()) {
     199                                if (type.get().equals(Void.TYPE)) {
     200                                        throw new ConstructionException().msg("type of field is void");
     201                                }
     202                        }
    176203                } catch (ConstructionException e) {
    177204                        throw e.arg("in", this);
     
    183210                        return false;
    184211                }
     212                if (adder.has() || remover.has()) {
     213                        return false;
     214                }
    185215                if (Collection.class.isAssignableFrom(getRawType())) {
    186216                        return false;
     
    197227        boolean isReadOnly() {
    198228                if (caller.has()) {
     229                        return false;
     230                }
     231                if (adder.has() || remover.has()) {
    199232                        return false;
    200233                }
     
    229262                        }
    230263                        Type[] ps = m.getGenericParameterTypes();
     264                        Class<?>[] pts = m.getParameterTypes();
    231265                        if (ps.length == 0) {
     266                                if (m.getReturnType().equals(Void.TYPE)) {
     267                                        throw new ConstructionException().msg("failed to add getter of void return type");
     268                                }
    232269                                getter.set(m);
    233270                                setType(m.getGenericReturnType());
     
    235272                        }
    236273                        if (ps.length == 1) {
     274                                if (pts[0].equals(EventListener.class)) {
     275                                        if (member.getName().startsWith("add")) {
     276                                                adder.set(m);
     277                                                setType(ps[0]);
     278                                                return;
     279                                        }
     280                                        if (member.getName().startsWith("remove")) {
     281                                                remover.set(m);
     282                                                setType(ps[0]);
     283                                                return;
     284                                        }
     285                                        throw new ConstructionException().msg("invalid name of event manipulator").arg("method", m).arg("in", this);
     286                                }
    237287                                setter.set(m);
    238288                                setType(ps[0]);
     
    251301                int f = 0;
    252302                if (isReadOnly()) {
    253                         f |= Flags.READONLY;
     303                        f |= ParamFlags.READONLY;
    254304                }
    255305                return f;
  • java/main/src/main/java/com/framsticks/params/PropertiesAccess.java

    r96 r99  
    44import java.util.Map;
    55
     6import com.framsticks.params.types.EventParam;
    67import com.framsticks.params.types.ProcedureParam;
    78
     
    9798        @Override
    9899        public Object call(String id, Object[] arguments) {
    99                 throw new InvalidOperationException().msg("list access does not support calling methods").arg("id", id);
     100                throw new InvalidOperationException().msg("properties access does not support calling methods").arg("id", id);
    100101        }
    101102
    102103        @Override
    103104        public Object call(ProcedureParam param, Object[] arguments) {
    104                 throw new InvalidOperationException().msg("list access does not support calling methods").arg("param", param);
     105                throw new InvalidOperationException().msg("properties access does not support calling methods").arg("param", param);
     106        }
     107
     108        @Override
     109        public void reg(EventParam param, EventListener<?> listener) {
     110                throw new InvalidOperationException().msg("properties access does not support registering events").arg("param", param).arg("access", this);
     111        }
     112
     113        @Override
     114        public void regRemove(EventParam param, EventListener<?> listener) {
     115                throw new InvalidOperationException().msg("properties access does not support registering events").arg("param", param).arg("access", this);
    105116        }
    106117
  • java/main/src/main/java/com/framsticks/params/ReflectionAccess.java

    r98 r99  
    1717
    1818import com.framsticks.params.annotations.AutoAppendAnnotation;
     19import com.framsticks.params.types.EventParam;
    1920import com.framsticks.params.types.ProcedureParam;
    2021import com.framsticks.util.FramsticksException;
     
    5758                }
    5859
     60                public interface ReflectedAdder{
     61                        public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
     62                }
     63
     64                public interface ReflectedRemover{
     65                        public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
     66                }
     67
    5968                protected final Map<ValueParam, ReflectedSetter> setters = new IdentityHashMap<>();
    6069                protected final Map<ValueParam, ReflectedGetter> getters = new IdentityHashMap<>();
    6170                protected final Map<ProcedureParam, ReflectedCaller> callers = new IdentityHashMap<>();
     71                protected final Map<EventParam, ReflectedAdder> adders = new IdentityHashMap<>();
     72                protected final Map<EventParam, ReflectedRemover> removers = new IdentityHashMap<>();
     73
    6274                protected final List<Method> autoAppendMethods = new ArrayList<>();
    6375
     
    100112                                }
    101113
     114                                for (final EventParam ep : filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
     115                                        if (!candidates.containsKey(ep.getId())) {
     116                                                log.trace("java class does not implement the event param " + ep);
     117                                                continue;
     118                                        }
     119                                        ParamCandidate ec = candidates.get(ep.getId());
     120                                        final Method adder = ec.getAdder();
     121                                        final Method remover = ec.getRemover();
     122
     123                                        backend.adders.put(ep, new ReflectedAdder() {
     124
     125                                                @Override
     126                                                public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
     127                                                        adder.invoke(object, listener);
     128                                                }
     129                                        });
     130
     131                                        backend.removers.put(ep, new ReflectedRemover() {
     132
     133                                                @Override
     134                                                public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
     135                                                        remover.invoke(object, listener);
     136                                                }
     137                                        });
     138                                }
     139
    102140                                for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
    103141                                        if (!candidates.containsKey(vp.getId())) {
     
    105143                                        }
    106144                                        ParamCandidate pc = candidates.get(vp.getId());
    107                                         if (pc.isReadOnly() && !vp.hasFlag(Flags.READONLY)) {
     145                                        if (pc.isReadOnly() && !vp.hasFlag(ParamFlags.READONLY)) {
    108146                                                throw new ConstructionException().msg("readonly state conflict").arg("param", vp);
    109147                                        }
     
    200238        }
    201239
    202         public ReflectionAccess(Class<?> reflectedClass) throws ConstructionException {
    203                 this(reflectedClass, FramsClass.build().forClass(reflectedClass));
    204         }
    205 
    206240        public static boolean typeMatch(Class<?> a, Class<?> b) {
    207                 assert !b.isPrimitive();
     241                if (b.isPrimitive()) {
     242                        throw new FramsticksException().msg("failed to match type, right argument is primitive").arg("left", a).arg("right", b);
     243                }
    208244                if (!a.isPrimitive()) {
    209245                        return a.equals(b);
     
    219255                        return b.equals(Boolean.class);
    220256                }
    221                 assert false;
    222                 return false;
    223         }
    224 
    225         public ReflectionAccess(Class<?> reflectedClass, FramsClass framsClass) throws ConstructionException {
     257                throw new FramsticksException().msg("failed to match types").arg("left", a).arg("right", b);
     258        }
     259
     260
     261
     262
     263        public ReflectionAccess(Class<?> javaClass) throws ConstructionException {
     264                this(javaClass, FramsClass.build().forClass(javaClass));
     265        }
     266
     267
     268        public ReflectionAccess(Class<?> javaClass, FramsClass framsClass) throws ConstructionException {
     269                this(javaClass, framsClass, Backend.getOrCreateFor(javaClass, framsClass));
     270        }
     271
     272        protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, Backend backend) throws ConstructionException {
    226273                super(framsClass);
    227                 this.javaClass = reflectedClass;
    228                 this.backend = Backend.getOrCreateFor(reflectedClass, framsClass);
    229         }
    230 
     274                this.javaClass = javaClass;
     275                this.backend = backend;
     276        }
     277
     278        @Override
     279        public ReflectionAccess cloneAccess() throws ConstructionException {
     280                return new ReflectionAccess(javaClass, framsClass, backend);
     281        }
    231282
    232283        @Override
     
    268319                } catch (FramsticksException e) {
    269320                        throw e.arg("param", param).arg("value", value).arg("access", this);
     321                }
     322        }
     323
     324        @Override
     325        public void reg(EventParam param, EventListener<?> listener) {
     326                try {
     327                        try {
     328                                if (object == null) {
     329                                        throw new FramsticksException().msg("no object set");
     330                                }
     331
     332                                backend.adders.get(param).reg(object, listener);
     333                                return;
     334                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     335                                throw new FramsticksException().msg("failed to add listener").cause(e);
     336                        }
     337                } catch (FramsticksException e) {
     338                        throw e.arg("param", param).arg("access", this);
     339                }
     340        }
     341
     342        @Override
     343        public void regRemove(EventParam param, EventListener<?> listener) {
     344                try {
     345                        try {
     346                                if (object == null) {
     347                                        throw new FramsticksException().msg("no object set");
     348                                }
     349
     350                                backend.removers.get(param).regRemove(object, listener);
     351                                return;
     352                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     353                                throw new FramsticksException().msg("failed to remove listener").cause(e);
     354                        }
     355                } catch (FramsticksException e) {
     356                        throw e.arg("param", param).arg("access", this);
    270357                }
    271358        }
     
    352439        }
    353440
    354         @Override
    355         public ReflectionAccess cloneAccess() throws ConstructionException {
    356                 return new ReflectionAccess(javaClass, framsClass);
    357         }
    358441
    359442        @Override
     
    368451        }
    369452
    370         @Override
    371         public String toString() {
    372                 StringBuilder b = new StringBuilder();
    373                 b.append(framsClass);
    374                 if (object != null) {
    375                         b.append("(").append(object).append(")");
    376                 }
    377                 return b.toString();
    378         }
    379453
    380454        @Override
  • java/main/src/main/java/com/framsticks/params/Registry.java

    r98 r99  
    4646                register(javaClass);
    4747                associate(javaClass, putFramsClass(FramsClass.build().forClass(javaClass)));
     48                for (Class<?> r : javaClass.getAnnotation(FramsClassAnnotation.class).register()) {
     49                        registerAndBuild(r);
     50                }
    4851                return this;
    4952        }
     
    122125        }
    123126
     127        public FramsClass getFramsClassForJavaClass(Class<?> javaClass) {
     128                return javaToFramsAssociation.get(javaClass);
     129        }
     130
    124131        public Set<Class<?>> getReflectedClasses() {
    125132                return javaClasses.getValues();
  • java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java

    r98 r99  
    66import org.apache.log4j.Logger;
    77
    8 import com.framsticks.util.UnimplementedException;
     8import com.framsticks.params.types.ObjectParam;
     9import com.framsticks.util.FramsticksException;
     10import static com.framsticks.params.SetStateFlags.*;
    911
    1012/**
     
    105107        @Override
    106108        public <T> int set(ValueParam param, T value) {
    107                 int flags = 0;
    108109
    109110                //String id = param.getEffectiveId();
     
    115116                                internalSet(param, casted);
    116117                        }
    117                         flags = result.getFlags();
     118                        return result.getFlags();
    118119                } catch (CastFailure e) {
    119                         log.error("casting failure while set: ", e);
    120                 }
    121                 return flags;
     120                        throw new FramsticksException()
     121                                .msg("casting failure while set")
     122                                .arg("param", param)
     123                                .arg("value", value)
     124                                .arg("value's type", (value == null ? "<null>" : value.getClass().getCanonicalName()))
     125                                .arg("in", this).cause(e);
     126                }
    122127        }
    123128
     
    167172                        set(i, max);
    168173                }
    169         }
    170 
    171         @Override
    172         public void copyFrom(AccessInterface src) {
    173                 throw new UnimplementedException();
    174                 // clearValues();
    175                 //TODO: iterate over self, and pull from src
    176                 /*
    177                 for (int i = 0; i < src.getFramsClass().size(); i++) {
    178                         this.set(i, src.get(i, Object.class));
    179                 }
    180                 */
    181174        }
    182175
     
    257250                                continue;
    258251                        }
    259                         if ((param.getFlags() & Flags.DONTLOAD) != 0) {
     252                        if ((param.getFlags() & ParamFlags.DONTLOAD) != 0) {
    260253                                log.debug("DontLoad flag was set - not loading...");
    261254                        } else {
    262255                                int retFlags = this.set((ValueParam) param, entry.value);
    263                                 if ((retFlags & (Flags.PSET_HITMIN | Flags.PSET_HITMAX)) != 0) {
    264                                         String which = ((retFlags & Flags.PSET_HITMIN) != 0) ? "small" : "big";
     256                                if ((retFlags & (PSET_HITMIN | PSET_HITMAX)) != 0) {
     257                                        String which = ((retFlags & PSET_HITMIN) != 0) ? "small" : "big";
    265258                                        log.warn("value of key '" + entry.key + "' was too " + which + ", adjusted");
    266259                                }
     
    304297        }*/
    305298
     299        @Override
     300        public String toString() {
     301                StringBuilder b = new StringBuilder();
     302                b.append(framsClass);
     303                if (getSelected() != null) {
     304                        b.append("(").append(getSelected()).append(")");
     305                }
     306                return b.toString();
     307        }
     308
     309        @Override
     310        public ParamBuilder buildParam(ParamBuilder builder) {
     311                return builder.name(getId()).type(ObjectParam.class).containedTypeName(getId());
     312        }
    306313
    307314}
  • java/main/src/main/java/com/framsticks/params/UniqueListAccess.java

    r98 r99  
    11package com.framsticks.params;
    22
     3import com.framsticks.params.types.UniqueListParam;
    34import com.framsticks.util.FramsticksException;
    45import com.framsticks.util.UnimplementedException;
     
    8081                        return null;
    8182                }
    82                 return Param.build().id(Integer.toString(i)).forAccess(elementAccess).finish(CompositeParam.class);
     83                Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
     84                while (i > 0 && iterator.hasNext()) {
     85                        iterator.next();
     86                        --i;
     87                }
     88                if (i > 0) {
     89                        return null;
     90                }
     91                if (!iterator.hasNext()) {
     92                        return null;
     93                }
     94                return paramBuilder.id(getUidOf(iterator.next().getValue())).finish(CompositeParam.class);
    8395        }
    8496
     
    96108                        return null;
    97109                }
    98                 return Param.build().id(id).forAccess(elementAccess).finish(CompositeParam.class);
     110                return paramBuilder.id(id).finish(CompositeParam.class);
    99111        }
    100112
     
    148160                String uid = elementAccess.get(uidName, String.class);
    149161                elementAccess.select(tmp);
    150                 if (uid == null) {
    151                         return null;
    152                 }
    153162                return uid;
    154163        }
     
    233242        }
    234243
    235         @Override
    236244        public String computeIdentifierFor(Object selected) {
    237245                String uid = getUidOf(selected);
     
    260268                                        @Override
    261269                                        public Param next() {
    262                                                 return Param.build().id(internal.next().getKey()).forAccess(elementAccess).finish();
     270                                                return paramBuilder.id(internal.next().getKey()).finish();
    263271                                        }
    264272
     
    282290                return getParam(number);
    283291        }
     292
     293        @Override
     294        public ParamBuilder buildParam(ParamBuilder builder) {
     295                return builder.name(containedTypeName + " list").type(UniqueListParam.class).containedTypeName(containedTypeName).uid(uidName);
     296        }
     297
    284298}
  • java/main/src/main/java/com/framsticks/params/Util.java

    r90 r99  
    3636        }
    3737
    38         public static int copyParams(AccessInterface to, AccessInterface from) {
     38        public static int takeAllNonNullValues(AccessInterface to, AccessInterface from) {
     39                int copied = 0;
     40                for (ValueParam f : filterInstanceof(from.getParams(), ValueParam.class)) {
     41                        Object v = from.get(f, Object.class);
     42                        if (v == null) {
     43                                continue;
     44                        }
     45                        to.set(f, v);
     46                        ++copied;
     47                }
     48                return copied;
     49        }
     50
     51        public static int copyExistingParamsTypeSafe(AccessInterface to, AccessInterface from) {
    3952                int copied = 0;
    4053                for (ValueParam f : filterInstanceof(from.getParams(), ValueParam.class)) {
  • java/main/src/main/java/com/framsticks/params/annotations/FramsClassAnnotation.java

    r90 r99  
    1313
    1414        String[] order() default {};
     15        Class<?>[] register() default {};
    1516}
  • java/main/src/main/java/com/framsticks/params/types/EventParam.java

    r87 r99  
    1212public class EventParam extends Param {
    1313
     14        protected final String eventArgumentTypeName;
    1415
    1516
     
    1920        public EventParam(ParamBuilder builder) {
    2021                super(builder);
     22                eventArgumentTypeName = builder.getEventArgumentTypeName();
    2123        }
    2224
    2325        @Override
    2426        public Class<?> getStorageType() {
    25                 return Void.class;
     27                return Void.TYPE;
    2628        }
    2729
    2830        @Override
    2931        public String getFramsTypeName() {
    30                 return "e";
     32                return eventArgumentTypeName != null ? "e " + eventArgumentTypeName : "e";
    3133        }
    3234}
  • java/main/src/main/java/com/framsticks/params/types/NumberParam.java

    r87 r99  
    22
    33import com.framsticks.params.CastFailure;
    4 import com.framsticks.params.Flags;
    54import com.framsticks.params.ParamBuilder;
    65import com.framsticks.params.PrimitiveParam;
     
    109
    1110import javax.annotation.concurrent.Immutable;
     11import static com.framsticks.params.SetStateFlags.*;
    1212
    1313/**
     
    4040                }
    4141                if (min != null && v.compareTo(getMin(type)) < 0) {
    42                         return new ReassignResult<T>(getMin(type), Flags.PSET_HITMIN);
     42                        return new ReassignResult<T>(getMin(type), PSET_HITMIN);
    4343                }
    4444                if (max != null && v.compareTo(getMax(type)) > 0) {
    45                         return new ReassignResult<T>(getMax(type), Flags.PSET_HITMAX);
     45                        return new ReassignResult<T>(getMax(type), PSET_HITMAX);
    4646                }
    4747                return ReassignResult.create(v);
  • java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java

    r97 r99  
    5454        @Override
    5555        public Class<?> getStorageType() {
    56                 return Void.class;
     56                return Void.TYPE;
    5757        }
    5858
  • java/main/src/main/java/com/framsticks/parsers/F0Parser.java

    r98 r99  
    1414import static com.framsticks.params.SimpleAbstractAccess.*;
    1515
    16 import com.framsticks.params.Flags;
    1716import com.framsticks.params.Param;
    1817import com.framsticks.params.PrimitiveParam;
     
    2625import com.framsticks.params.FramsClass;
    2726import com.framsticks.params.AccessInterface;
     27import static com.framsticks.params.ParamFlags.*;
     28import static com.framsticks.params.SetStateFlags.*;
    2829
    2930/**
     
    205206                                        }
    206207                                } else {
    207                                         if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & Flags.CANOMITNAME) == 0)) {
     208                                        if (nextParamNumber == null || ((params[nextParamNumber].getFlags() & CANOMITNAME) == 0)) {
    208209                                                nextParamNumber = null;
    209210                                                throw new Exception(
     
    220221                                                PrimitiveParam<?> vp = (PrimitiveParam<?>) currentParam;
    221222                                                int setFlag = access.set(vp, pair.value);
    222                                                 if ((setFlag & Flags.PSET_HITMIN) != 0) {
    223                                                         exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMIN));
    224                                                 }
    225 
    226                                                 if ((setFlag & Flags.PSET_HITMAX) != 0) {
    227                                                         exceptions.add(createBoundaryHitException(access, vp, pair.value, Flags.PSET_HITMAX));
    228                                                 }
    229 
    230                                                 if ((setFlag & Flags.PSET_RONLY) != 0) {
     223                                                if ((setFlag & PSET_HITMIN) != 0) {
     224                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, PSET_HITMIN));
     225                                                }
     226
     227                                                if ((setFlag & PSET_HITMAX) != 0) {
     228                                                        exceptions.add(createBoundaryHitException(access, vp, pair.value, PSET_HITMAX));
     229                                                }
     230
     231                                                if ((setFlag & PSET_RONLY) != 0) {
    231232                                                        throw (new Exception("tried to set a read-only attribute \""
    232233                                                                + currentParam.getId()
     
    250251
    251252        private static Exception createBoundaryHitException(AccessInterface access, PrimitiveParam<?> param, String value, int flag) {
    252                 boolean minimum = (flag & Flags.PSET_HITMIN) != 0;
     253                boolean minimum = (flag & PSET_HITMIN) != 0;
    253254                String boundary = (minimum ? param.getMin(Object.class) : param.getMax(Object.class)).toString();
    254255                String name =  (minimum ? "minimum" : "maximum");
  • java/main/src/main/java/com/framsticks/parsers/F0Writer.java

    r90 r99  
    77import com.framsticks.util.lang.Containers;
    88import static com.framsticks.util.lang.Containers.filterInstanceof;
     9import static com.framsticks.params.ParamFlags.*;
    910
    1011/**
     
    6566                        }
    6667
    67                         if ((!contiguous) || ((param.getFlags() & Flags.CANOMITNAME) == 0)) {
     68                        if ((!contiguous) || ((param.getFlags() & CANOMITNAME) == 0)) {
    6869                                line.append(param.getId()).append("=");
    6970                                contiguous = true;
  • java/main/src/main/java/com/framsticks/parsers/GenotypeLoader.java

    r87 r99  
    66
    77import org.apache.log4j.Logger;
     8import static com.framsticks.params.ParamFlags.*;
    89
    910public class GenotypeLoader extends MultiParamLoader {
     
    2425                        .param(Param.build().id("genotype").group(0).name("Genotype").type(StringParam.class).min(1))
    2526                        .param(Param.build().id("info").group(0).name("Info").type(StringParam.class).min(1).help("Additional information or comments"))
    26                         .param(Param.build().id("simi").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Similarity").type(FloatParam.class))
    27                         .param(Param.build().id("energ0").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Starting energy").type(FloatParam.class))
    28                         .param(Param.build().id("strsiz").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Body parts (deprecated; use numparts)").type(FloatParam.class))
    29                         .param(Param.build().id("strjoints").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Body joints (deprecated; use numjoints)").type(FloatParam.class))
    30                         .param(Param.build().id("nnsiz").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Brain size (deprecated; use numneurons)").type(FloatParam.class))
    31                         .param(Param.build().id("nncon").group(1).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Brain connections (deprecated; use numconnections)").type(FloatParam.class))
    32                         .param(Param.build().id("numparts").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Body parts").type(FloatParam.class))
    33                         .param(Param.build().id("numjoints").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Body joints").type(FloatParam.class))
    34                         .param(Param.build().id("numneurons").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Brain size").type(FloatParam.class))
    35                         .param(Param.build().id("numconnections").group(1).flags(Flags.READONLY | Flags.DONTSAVE).name("Brain connections").type(FloatParam.class))
     27                        .param(Param.build().id("simi").group(1).flags(READONLY | DONTSAVE).name("Similarity").type(FloatParam.class))
     28                        .param(Param.build().id("energ0").group(1).flags(READONLY | DONTSAVE).name("Starting energy").type(FloatParam.class))
     29                        .param(Param.build().id("strsiz").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Body parts (deprecated; use numparts)").type(FloatParam.class))
     30                        .param(Param.build().id("strjoints").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Body joints (deprecated; use numjoints)").type(FloatParam.class))
     31                        .param(Param.build().id("nnsiz").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Brain size (deprecated; use numneurons)").type(FloatParam.class))
     32                        .param(Param.build().id("nncon").group(1).flags(READONLY | DONTSAVE | USERHIDDEN).name("Brain connections (deprecated; use numconnections)").type(FloatParam.class))
     33                        .param(Param.build().id("numparts").group(1).flags(READONLY | DONTSAVE).name("Body parts").type(FloatParam.class))
     34                        .param(Param.build().id("numjoints").group(1).flags(READONLY | DONTSAVE).name("Body joints").type(FloatParam.class))
     35                        .param(Param.build().id("numneurons").group(1).flags(READONLY | DONTSAVE).name("Brain size").type(FloatParam.class))
     36                        .param(Param.build().id("numconnections").group(1).flags(READONLY | DONTSAVE).name("Brain connections").type(FloatParam.class))
    3637                        .param(Param.build().id("num").group(2).name("Ordinal number").type(DecimalParam.class))
    3738                        .param(Param.build().id("gnum").group(2).name("Generation").type(DecimalParam.class))
    38                         .param(Param.build().id("popsiz").group(2).flags(Flags.USERHIDDEN).name("Deprecated; use entities").type(DecimalParam.class))
    39                         .param(Param.build().id("entities").group(2).flags(Flags.DONTSAVE).name("Instances").type(DecimalParam.class).help("Copies of this genotype"))
     39                        .param(Param.build().id("popsiz").group(2).flags(USERHIDDEN).name("Deprecated; use entities").type(DecimalParam.class))
     40                        .param(Param.build().id("entities").group(2).flags(DONTSAVE).name("Instances").type(DecimalParam.class).help("Copies of this genotype"))
    4041                        .param(Param.build().id("lifespan").group(2).name("Life span").type(FloatParam.class).help("Average life span"))
    4142                        .param(Param.build().id("velocity").group(2).name("Velocity").type(FloatParam.class).help("Average velocity"))
     
    4344                        .param(Param.build().id("vertvel").group(2).name("Vertical velocity").type(FloatParam.class))
    4445                        .param(Param.build().id("vertpos").group(2).name("Vertical position").type(FloatParam.class))
    45                         .param(Param.build().id("fit").group(3).flags(Flags.READONLY | Flags.DONTSAVE).name("Fitness").type(FloatParam.class))
    46                         .param(Param.build().id("fit2").group(3).flags(Flags.READONLY | Flags.DONTSAVE).name("Final fitness").type(FloatParam.class).help("Fitness shifted by (avg-n*stddev)"))
    47                         .param(Param.build().id("f0genotype").group(4).flags(Flags.READONLY | Flags.DONTSAVE).name("f0 genotype").type(StringParam.class).min(1).help("converted to f0 genotype"))
     46                        .param(Param.build().id("fit").group(3).flags(READONLY | DONTSAVE).name("Fitness").type(FloatParam.class))
     47                        .param(Param.build().id("fit2").group(3).flags(READONLY | DONTSAVE).name("Final fitness").type(FloatParam.class).help("Fitness shifted by (avg-n*stddev)"))
     48                        .param(Param.build().id("f0genotype").group(4).flags(READONLY | DONTSAVE).name("f0 genotype").type(StringParam.class).min(1).help("converted to f0 genotype"))
    4849                        .param(Param.build().id("user1").group(2).name("User field 1").type(UniversalParam.class))
    4950                        .param(Param.build().id("user2").group(2).name("User field 2").type(UniversalParam.class))
    5051                        .param(Param.build().id("user3").group(2).name("User field 3").type(UniversalParam.class))
    51                         .param(Param.build().id("isValid").group(0).flags(Flags.READONLY | Flags.DONTSAVE | Flags.USERHIDDEN).name("Valid").type(DecimalParam.class).min(0).max(1))
    52                         .param(Param.build().id("uid").group(0).flags(Flags.READONLY | Flags.USERHIDDEN).name("#").type("s").help("Unique identifier"))
     52                        .param(Param.build().id("isValid").group(0).flags(READONLY | DONTSAVE | USERHIDDEN).name("Valid").type(DecimalParam.class).min(0).max(1))
     53                        .param(Param.build().id("uid").group(0).flags(READONLY | USERHIDDEN).name("#").type("s").help("Unique identifier"))
    5354                        .finish();
    5455
  • java/main/src/main/java/com/framsticks/parsers/XmlLoader.java

    r97 r99  
    1919import com.framsticks.util.AutoBuilder;
    2020import com.framsticks.util.FramsticksException;
     21import com.framsticks.util.lang.Strings;
    2122
    2223public class XmlLoader {
     
    4748        }
    4849
     50        public String mangleName(String name) {
     51                return useLowerCase ? name.toLowerCase() : name;
     52        }
     53
     54        public String mangleAttribute(String name) {
     55                return useLowerCase ? name.toLowerCase() : Strings.uncapitalize(name);
     56        }
     57
    4958        public Object processElement(Element element) {
    50                 String name = element.getNodeName();
    51                 if (useLowerCase) {
    52                         name = name.toLowerCase();
    53                 }
     59                final String name = mangleName(element.getNodeName());
    5460                if (name.equals("import")) {
    5561                        String className = element.getAttribute("class");
     
    7177                for (int i = 0; i < attributes.getLength(); ++i) {
    7278                        Node attributeNode = attributes.item(i);
    73                         access.set(attributeNode.getNodeName().toLowerCase(), attributeNode.getNodeValue());
     79                        access.set(mangleAttribute(attributeNode.getNodeName()), attributeNode.getNodeValue());
    7480                }
    7581
  • java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java

    r98 r99  
    33import static com.framsticks.core.TreeOperations.*;
    44
    5 import com.framsticks.core.Mode;
    65import com.framsticks.core.Node;
    76import com.framsticks.core.Path;
     
    6766                                }
    6867                                ++dispatched;
    69                                 tree.get(childPath, Mode.FETCH, new FutureHandler<Path>(Logging.logger(log, "resolve", RecursiveFetcher.this)) {
     68                                tree.get(childPath, new FutureHandler<Path>(Logging.logger(log, "resolve", RecursiveFetcher.this)) {
    7069                                        @Override
    7170                                        protected void result(Path result) {
     
    8382
    8483        protected void fetch(final Path path) {
    85                 tree.get(path, Mode.FETCH, new Future<Path>() {
     84                tree.get(path, new Future<Path>() {
    8685
    8786                        @Override
  • java/main/src/main/java/com/framsticks/remote/RemoteTree.java

    r98 r99  
    77import com.framsticks.communication.queries.SetRequest;
    88import com.framsticks.core.AbstractTree;
    9 import com.framsticks.core.Mode;
    10 import com.framsticks.core.ListChange;
    119import com.framsticks.core.Path;
    1210import com.framsticks.params.*;
     11import com.framsticks.params.EventListener;
    1312import com.framsticks.params.annotations.AutoAppendAnnotation;
    1413import com.framsticks.params.annotations.FramsClassAnnotation;
     
    2827import com.framsticks.util.dispatching.ThrowExceptionHandler;
    2928import com.framsticks.util.lang.Casting;
    30 import com.framsticks.util.lang.Pair;
    3129import com.framsticks.util.dispatching.RunAt;
    3230import static com.framsticks.core.TreeOperations.*;
     
    4240 */
    4341@FramsClassAnnotation
    44 public class RemoteTree extends AbstractTree implements JoinableParent {
     42public final class RemoteTree extends AbstractTree implements JoinableParent {
    4543
    4644        private final static Logger log = Logger.getLogger(RemoteTree.class);
    4745
    4846        protected ClientSideManagedConnection connection;
    49 
    50         protected final Set<Pair<Path, Subscription<?>>> subscriptions = new HashSet<>();
    51 
    52         public Pair<Path, Subscription<?>> getSubscription(Path path) {
    53                 for (Pair<Path, Subscription<?>> s : subscriptions) {
    54                         if (s.first.isTheSameObjects(path)) {
    55                                 return s;
    56                         }
    57                 }
    58                 return null;
    59         }
    6047
    6148        public RemoteTree() {
     
    8875
    8976        @Override
    90         public void get(final Path path, final ValueParam param, Mode mode, final Future<Object> future) {
     77        public void get(final Path path, final ValueParam param, final Future<Object> future) {
    9178                assert isActive();
    9279                assert param != null;
     
    166153
    167154        @Override
    168         public void get(final Path path, final Mode mode, final Future<Path> future) {
     155        public void get(final Path path, final Future<Path> future) {
    169156                assert isActive();
    170157
     
    187174        }
    188175
    189 
    190         @Override
    191         protected void tryRegisterOnChangeEvents(final Path path) {
    192                 assert isActive();
    193                 AccessInterface access = bindAccess(path);
    194                 if (!(access instanceof ListAccess)) {
    195                         return;
    196                 }
    197 
    198                 assert path.size() >= 2;
    199                 FramsClass underFramsClass = getInfoFromCache(path.getUnder().getParam().getContainedTypeName());
    200 
    201                 EventParam changedEvent;
    202                 try {
    203                         changedEvent = underFramsClass.getParamEntry(path.getTop().getParam().getId() + "_changed", EventParam.class);
    204                 } catch (FramsticksException e) {
    205                         return;
    206                 }
    207 
    208                 log.debug("registering for " + changedEvent);
    209                 if (getSubscription(path) != null) {
    210                         return;
    211                 }
    212 
    213                 final Pair<Path, Subscription<?>> temporary = new Pair<>(path, null);
    214                 subscriptions.add(temporary);
    215 
    216                 connection.subscribe(path.getTextual() + "_changed", this, new SubscriptionCallback<Tree>() {
    217                         @Override
    218                         public EventCallback subscribed(final Subscription<? super Tree> subscription) {
    219                                 if (subscription == null) {
    220                                         log.error("failed to subscribe for change event for " + path);
    221                                         return null;
    222                                 }
    223                                 log.debug("subscribed for change event for " + path);
    224                                 // subscription.setDispatcher(RemoteInstance.this);
    225                                 RemoteTree.this.dispatch(new RunAt<Tree>(this) {
    226                                         @Override
    227                                         protected void runAt() {
    228                                                 subscriptions.remove(temporary);
    229                                                 subscriptions.add(new Pair<Path, Subscription<?>>(path, subscription));
    230                                         }
    231                                 });
    232                                 return new EventCallback() {
    233                                         @Override
    234                                         public void call(List<File> files) {
    235                                                 assert isActive();
    236                                                 assert files.size() == 1;
    237                                                 final MultiParamLoader loader = new MultiParamLoader();
    238                                                 loader.setNewSource(files.get(0).getContent());
    239                                                 loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
    240                                                 loader.addListener(MultiParamLoader.Status.OnComment, new MultiParamLoader.StatusListener() {
    241 
    242                                                         @Override
    243                                                         public void onStatusChange() {
    244                                                                 throw new FramsticksException().msg("multi param loader error").arg("line", loader.getCurrentLine());
    245                                                         }
    246                                                 });
    247                                                 ReflectionAccess access = new ReflectionAccess(ListChange.class, FramsClass.build().forClass(ListChange.class));
    248                                                 loader.addAccessInterface(access);
    249 
    250                                                 MultiParamLoader.Status status;
    251                                                 while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
    252                                                         if (status == MultiParamLoader.Status.AfterObject) {
    253                                                                 AccessInterface accessInterface = loader.getLastAccessInterface();
    254                                                                 reactToChange(path, (ListChange) accessInterface.getSelected());
    255                                                         }
    256                                                 }
    257                                         }
    258                                 };
    259                         }
    260                 });
    261         }
    262 
    263         protected Future<Path> futureListChanger(final ListChange listChange, final String path) {
    264                 return new FutureHandler<Path>(Logging.logger(log, "failed to " + listChange, path)) {
    265                         @Override
    266                         protected void result(Path result) {
    267                                 log.debug(listChange + ": " + result);
    268                         }
    269                 };
    270         }
    271 
    272         protected void reactToChange(final Path path, final ListChange listChange) {
    273                 assert isActive();
    274                 log.debug("reacting to change " + listChange + " in " + path);
    275                 AccessInterface access = bindAccess(path);
    276                 assert access != null;
    277 
    278                 if ((listChange.getAction() == ListChange.Action.Modify) && (listChange.getPosition() == -1)) {
    279                         final String p = path.getTextual();
    280                         tryGet(this, p, futureListChanger(listChange, p));
    281                         return;
    282                 }
    283 
    284                 CompositeParam childParam = Casting.tryCast(CompositeParam.class, access.getParam(listChange.getBestIdentifier()));
    285                 assert childParam != null;
    286                 switch (listChange.getAction()) {
    287                         case Add: {
    288                                 final String p = path.getTextual() + "/" + childParam.getId();
    289                                 tryGet(this, p, futureListChanger(listChange, p));
    290                                 break;
    291                         }
    292                         case Remove: {
    293                                 access.set(childParam, null);
    294                                 break;
    295                         }
    296                         case Modify: {
    297                                 final String p = path.getTextual() + "/" + childParam.getId();
    298                                 tryGet(this, p, futureListChanger(listChange, p));
    299                                 break;
    300                         }
    301                 }
    302         }
    303 
    304176        @Override
    305177        public void set(final Path path, final PrimitiveParam<?> param, final Object value, final Future<Integer> future) {
     
    380252        }
    381253
    382         // @Override
    383         // public Path create(Path path) {
    384         //      assert isActive();
    385         //      assert !path.isResolved();
    386         //      Path resolved = path.tryFindResolution();
    387         //      if (!resolved.isResolved()) {
    388         //              log.debug("creating: " + path);
    389         //              //TODO: access parent here, check if it is valid, only then create
    390         //              AccessInterface access = registry.prepareAccess(path.getTop().getParam());
    391         //              assert access != null;
    392         //              Object child = access.createAccessee();
    393         //              assert child != null;
    394         //              if (path.size() == 1) {
    395         //                      setRoot(new Node(getRoot().getParam(), child));
    396         //              } else {
    397         //                      bindAccess(this, path.getUnder()).set(path.getTop().getParam(), child);
    398         //              }
    399         //              resolved = path.appendResolution(child);
    400         //      }
    401         //      tryRegisterOnChangeEvents(resolved);
    402         //      return resolved;
    403         // }
     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        }
    404307
    405308}
  • java/main/src/main/java/com/framsticks/test/TestClass.java

    r97 r99  
    11package com.framsticks.test;
     2
     3import java.util.LinkedList;
     4import java.util.List;
    25
    36import org.apache.log4j.Logger;
    47
     8import com.framsticks.params.EventListener;
    59import com.framsticks.params.annotations.FramsClassAnnotation;
    610import com.framsticks.params.annotations.ParamAnnotation;
    711import com.framsticks.params.types.ProcedureParam;
    812
    9 @FramsClassAnnotation(order = {"name", "history", "appendHistory", "resetHistory"})
     13@FramsClassAnnotation(order = {"name", "history", "history_changed", "appendHistory", "resetHistory"}, register = {ChangeEvent.class})
    1014public class TestClass {
    1115        private static final Logger log =
     
    1519        protected String name = "test";
    1620        protected String history = "initial|";
     21        protected final List<EventListener<ChangeEvent>> historyListeners = new LinkedList<>();
    1722
    1823        /**
     
    5257                log.debug("appending '" + line + "'");
    5358                history = history + line + "|";
     59                fireHistoryChange();
    5460                return history.length();
    5561        }
     
    5965                log.debug("reseting");
    6066                history = "";
     67                fireHistoryChange();
     68        }
     69
     70        protected void fireHistoryChange() {
     71                for (EventListener<ChangeEvent> l : historyListeners) {
     72                        ChangeEvent event = new ChangeEvent();
     73                        event.history = history;
     74                        l.action(event);
     75                }
     76        }
     77
     78        @ParamAnnotation(id = "history_changed")
     79        public void addHistoryListener(EventListener<ChangeEvent> listener) {
     80                historyListeners.add(listener);
     81        }
     82
     83        @ParamAnnotation(id = "history_changed")
     84        public void removeHistoryListener(EventListener<ChangeEvent> listener) {
     85                historyListeners.remove(listener);
     86        }
     87
     88        @Override
     89        public String toString() {
     90                return "test class " + history;
    6191        }
    6292
  • java/main/src/main/java/com/framsticks/util/dispatching/AtOnceDispatcher.java

    r98 r99  
    55 * @author Piotr Sniegowski
    66 */
    7 public class AtOnceDispatcher<C> implements Dispatcher<C> {
     7public class AtOnceDispatcher<C> extends AbstractJoinable implements JoinableDispatcher<C> {
    88
    99        @SuppressWarnings("rawtypes")
     
    2525        }
    2626
     27        @Override
     28        public String getName() {
     29                return "atonce";
     30        }
     31
     32        @Override
     33        protected void joinableStart() {
     34
     35        }
     36
     37        @Override
     38        protected void joinableInterrupt() {
     39                finish();
     40        }
     41
     42        @Override
     43        protected void joinableFinish() {
     44
     45        }
     46
     47        @Override
     48        protected void joinableJoin() throws InterruptedException {
     49
     50        }
     51
    2752}
  • java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java

    r98 r99  
    224224
    225225                protected final double timeOut;
     226                protected final ExceptionResultHandler handler;
    226227
    227228                /**
    228229                 * @param timeOut
    229230                 */
    230                 public Waiter(double timeOut) {
     231                public Waiter(double timeOut, ExceptionResultHandler handler) {
    231232                        this.timeOut = timeOut;
     233                        this.handler = handler;
    232234                }
    233235
     
    247249                        }
    248250                        if (!done) {
    249                                 throw new FramsticksException().msg("waiter timed out");
    250                         }
     251                                handler.handle(new FramsticksException().msg("waiter timed out"));
     252                        }
     253                }
     254
     255                public <T> Future<T> passInFuture(Class<T> type) {
     256                        return new FutureHandler<T>(handler) {
     257                                @Override
     258                                protected void result(T result) {
     259                                        Waiter.this.pass();
     260                                }
     261                        };
    251262                }
    252263        }
     
    254265
    255266        public static <C> void synchronize(Dispatcher<C> dispatcher, double seconds) {
    256                 final Waiter waiter = new Waiter(seconds);
     267                final Waiter waiter = new Waiter(seconds, ThrowExceptionHandler.getInstance());
    257268                dispatcher.dispatch(new RunAt<C>(ThrowExceptionHandler.getInstance()) {
    258269                        @Override
  • java/main/src/main/java/com/framsticks/util/dispatching/FutureHandler.java

    r97 r99  
    1717        }
    1818
     19        public static <T> FutureHandler<T> doNothing(Class<T> type, ExceptionResultHandler handler) {
     20                return new FutureHandler<T>(handler) {
     21
     22                        @Override
     23                        protected void result(T result) {
     24
     25                        }
     26                };
     27        }
     28
    1929}
  • java/main/src/main/java/com/framsticks/util/dispatching/Thread.java

    r98 r99  
    7373                        }
    7474                        try {
    75                                 task.runAt();
     75                                task.run();
    7676                        } catch (Exception e) {
    7777                                if (exceptionHandler != null) {
     
    122122                                @Override
    123123                                protected void runAt() {
    124                                         runnable.runAt();
     124                                        runnable.run();
    125125                                }
    126126                        });
  • java/main/src/main/java/com/framsticks/util/lang/Casting.java

    r84 r99  
    66 */
    77public abstract class Casting {
    8     public static <T> T tryCast(Class<T> class_, Object object) {
    9         try {
    10             return class_.cast(object);
    11         } catch (ClassCastException ignored) {
    12             return null;
    13         }
    14     }
     8        public static <T> T tryCast(Class<T> class_, Object object) {
     9                try {
     10                        return class_.cast(object);
     11                } catch (ClassCastException ignored) {
     12                        return null;
     13                }
     14        }
    1515
    16     public static <T> T assertCast(Class<T> class_, Object object) {
    17         try {
    18             return class_.cast(object);
    19         } catch (ClassCastException ignored) {
    20             assert false;
    21             return null;
    22         }
    23     }
     16        public static <T> T assertCast(Class<T> class_, Object object) {
     17                try {
     18                        return class_.cast(object);
     19                } catch (ClassCastException ignored) {
     20                        assert false;
     21                        return null;
     22                }
     23        }
    2424
    25     public static <T> T throwCast(Class<T> class_, Object object) {
    26         if (object == null) {
    27             throw new NullPointerException();
    28         }
    29         return class_.cast(object);
    30     }
     25        public static <T> T throwCast(Class<T> class_, Object object) {
     26                if (object == null) {
     27                        throw new NullPointerException();
     28                }
     29                return class_.cast(object);
     30        }
    3131}
  • java/main/src/main/java/com/framsticks/util/lang/Strings.java

    r97 r99  
    3636        }
    3737
     38        public static String toStringEmptyProof(Object object, Object def) {
     39                if (object == null) {
     40                        return def.toString();
     41                }
     42                String v = object.toString();
     43                return notEmpty(v) ? v : def.toString();
     44        }
     45
    3846        public static String collapse(String s) {
    3947                if (s == null) {
  • java/main/src/main/resources/configs/framsticks.xml

    r98 r99  
    11<?xml version="1.0" encoding="UTF-8"?>
    22<Framsticks>
    3         <!-- <import class="com.framsticks.gui.console.ManagedConsole" /> -->
    4         <!-- <import class="com.framsticks.remote.RemoteTree" /> -->
    5         <!-- <ManagedConsole> -->
    6         <!--    <RemoteTree name="remote" address="localhost:9009" /> -->
    7         <!-- </ManagedConsole> -->
    8 
    9         <!-- <import class="com.framsticks.gui.console.DirectConsole" /> -->
    10         <!-- <import class="com.framsticks.communication.ClientSideRawConnection" /> -->
    11         <!-- <DirectConsole> -->
    12         <!--    <ClientSideRawConnection address="localhost:9009" /> -->
    13         <!-- </DirectConsole> -->
    14 
    153        <import class="com.framsticks.gui.Browser" />
    164        <import class="com.framsticks.remote.RemoteTree" />
    17         <import class="com.framsticks.remote.SimulatorTree" />
    185        <import class="com.framsticks.model.ModelPackage" />
    196        <import class="com.framsticks.model.ModelBuilder" />
    207        <import class="com.framsticks.model.f0.SchemaBuilder" />
    21         <import class="com.framsticks.core.ObjectTree" />
     8        <import class="com.framsticks.core.LocalTree" />
    229        <import class="com.framsticks.hosting.Server" />
    2310        <import class="com.framsticks.test.TestClass" />
     11        <import class="com.framsticks.gui.table.ColumnsConfig" />
    2412        <Browser>
    25                 <SimulatorTree name="localhost:9009" address="localhost:9009">
     13                <RemoteTree name="localhost:9009" address="localhost:9009">
    2614                        <ModelPackage />
    27                 </SimulatorTree>
    28                 <!-- <ObjectTree name="model"> -->
     15                </RemoteTree>
     16                <!-- <LocalTree name="model"> -->
    2917                <!--    <ModelBuilder resource="/examples/f0_example.txt" /> -->
    30                 <!-- </ObjectTree> -->
    31                 <!-- <ObjectTree name="f0schema"> -->
     18                <!-- </LocalTree> -->
     19                <!-- <LocalTree name="f0schema"> -->
    3220                <!--    <SchemaBuilder /> -->
    33                 <!-- </ObjectTree> -->
    34                 <!-- <RemoteTree name="remote" address="localhost:9007" /> -->
     21                <!-- </LocalTree> -->
     22                <RemoteTree name="remote" address="localhost:9007" />
     23                <ColumnsConfig className="Genotype" columnsNames="uid name" />
    3524        </Browser>
    36         <!-- <Server name="server" port="9007"> -->
    37         <!--    <ObjectTree name="test"> -->
    38         <!--            <TestClass /> -->
    39         <!--    </ObjectTree> -->
    40         <!-- </Server> -->
     25        <Server name="server" port="9007">
     26                <LocalTree name="test">
     27                        <TestClass />
     28                </LocalTree>
     29        </Server>
    4130</Framsticks>
  • java/main/src/main/resources/configs/log4j.properties

    r98 r99  
    2929
    3030log4j.logger.com.framsticks=INFO
     31# log4j.logger.com.framsticks.gui.table=DEBUG
    3132# log4j.logger.com.framsticks.gui.Panel=DEBUG
    3233# log4j.logger.com.framsticks.remote.RemoteTree=DEBUG
  • java/main/src/test/java/com/framsticks/communication/RequestTest.java

    r96 r99  
    77import com.framsticks.communication.queries.GetRequest;
    88import com.framsticks.communication.queries.InfoRequest;
     9import com.framsticks.communication.queries.RegisterRequest;
    910import com.framsticks.communication.queries.SetRequest;
    1011import com.framsticks.communication.queries.UseRequest;
     
    4647                        { SetRequest.class, "set /test field value"},
    4748                        { SetRequest.class, "set /test field \"value with spaces\""},
     49                        { RegisterRequest.class, "reg /test/field_changed"},
    4850                        { VersionRequest.class, "version 4"},
    4951                        { InfoRequest.class, "info /some/path"},
  • java/main/src/test/java/com/framsticks/core/PathTest.java

    r87 r99  
    88
    99import org.testng.annotations.BeforeClass;
     10import org.testng.annotations.DataProvider;
    1011import org.testng.annotations.Test;
    1112
    1213import com.framsticks.test.TestConfiguration;
     14import com.framsticks.util.lang.Pair;
     15
     16import static org.fest.assertions.Assertions.*;
    1317
    1418@Test
     
    2529        }
    2630
    27         @Test
    28         public void testPath() {
     31        @Test(dataProvider = "pathValidationProvider")
     32        public void pathValidation(String path, boolean ok) {
     33                assertThat(Path.isValidString(path)).describedAs(path).isEqualTo(ok);
     34        }
     35
     36        @Test(dataProvider = "pathSplitingProvider")
     37        public void pathSpliting(String path, String prefix, String suffix) {
     38                Pair<String, String> p = Path.removeLastElement(path);
     39                assertThat(p.first).isEqualTo(prefix);
     40                assertThat(p.second).isEqualTo(suffix);
     41        }
     42
     43        @DataProvider
     44        public Object[][] pathValidationProvider() {
     45                return new Object[][] {
     46                        { "/", true },
     47                        { "/path", true },
     48                        { "path", false },
     49                        { "/path/to/", false },
     50                        { "/path/to", true },
     51                        { "/testClass/history_changed", true },
     52                        { "/cli/events/e0", true }
     53
     54                };
     55        }
     56
     57        @DataProvider
     58        public Object[][] pathSplitingProvider() {
     59                return new Object[][] {
     60                        { "/event", "/", "event" },
     61                        { "/path/event", "/path", "event" }
     62                };
    2963        }
    3064
  • java/main/src/test/java/com/framsticks/gui/BrowserBaseTest.java

    r98 r99  
    5050        protected void clickAndExpandPath(String path) {
    5151                tree.clickPath(path);
    52                 Dispatching.sleep(1.0);
     52                Dispatching.sleep(2.0);
    5353                tree.expandPath(path);
    5454                robot.waitForIdle();
  • java/main/src/test/java/com/framsticks/gui/BrowserTest.java

    r98 r99  
    1212
    1313import com.framsticks.model.ModelPackage;
    14 import com.framsticks.remote.SimulatorTree;
     14import com.framsticks.remote.RemoteTree;
    1515import com.framsticks.util.dispatching.Dispatching;
    1616
     
    1919        private static final Logger log = Logger.getLogger(BrowserTest.class);
    2020
    21         SimulatorTree localhost;
     21        RemoteTree localhost;
    2222
    2323        @Override
     
    2525                browser = new Browser();
    2626
    27                 localhost = new SimulatorTree();
     27                localhost = new RemoteTree();
    2828                localhost.setName("localhost");
    2929                localhost.setAddress("localhost:9009");
     
    3737        public void testShow() {
    3838                Dispatching.synchronize(localhost, 1.0);
    39                 // Dispatching.sleep(0.5);
     39                Dispatching.sleep(2.0);
    4040                log.info("testing");
    41                 tree.clickRow(0).expandRow(0);
    42                 robot.waitForIdle();
     41                clickAndExpandPath("localhost");
     42                // tree.clickRow(0).expandRow(0);
     43                // robot.waitForIdle();
    4344
    44                 tree.clickRow(1).expandRow(1);
    45                 robot.waitForIdle();
     45                clickAndExpandPath("localhost/simulator");
     46                // tree.clickRow(1).expandRow(1);
     47                // robot.waitForIdle();
    4648                assertThat(tree.valueAt(1)).isEqualTo("simulator");
    4749                robot.waitForIdle();
  • java/main/src/test/java/com/framsticks/gui/ProcedureBrowserTest.java

    r97 r99  
    77import org.testng.annotations.Test;
    88
     9import com.framsticks.core.Path;
    910import com.framsticks.core.Tree;
    10 import com.framsticks.core.ObjectTree;
     11import com.framsticks.core.LocalTree;
    1112import com.framsticks.params.AccessInterface;
     13import com.framsticks.params.EventListener;
    1214import com.framsticks.params.FramsClass;
    1315import com.framsticks.params.ReflectionAccess;
     16import com.framsticks.params.types.EventParam;
    1417import com.framsticks.params.types.StringParam;
    1518import com.framsticks.parsers.XmlLoader;
     19import com.framsticks.test.ChangeEvent;
    1620import com.framsticks.test.TestClass;
     21import com.framsticks.util.dispatching.FutureHandler;
    1722// import com.framsticks.util.dispatching.Dispatching;
    1823import com.framsticks.util.dispatching.RunAt;
     
    2227public class ProcedureBrowserTest extends BrowserBaseTest {
    2328
    24         ObjectTree tree;
     29        LocalTree tree;
    2530
    2631        @Override
     
    2934
    3035                assertThat(browser.getTrees().size()).isEqualTo(1);
    31                 assertThat(browser.getTrees().get("test")).isInstanceOf(ObjectTree.class);
     36                assertThat(browser.getTrees().get("test")).isInstanceOf(LocalTree.class);
    3237
    33                 tree = (ObjectTree) browser.getTrees().get("test");
     38                tree = (LocalTree) browser.getTrees().get("test");
    3439        }
    3540
     
    6065                                assertThat(access).isInstanceOf(ReflectionAccess.class);
    6166                                FramsClass framsClass = access.getFramsClass();
    62                                 assertThat(framsClass.getParamCount()).isEqualTo(4);
     67                                assertThat(framsClass.getParamCount()).isEqualTo(5);
    6368                                assertThat(framsClass.getParam(0).getId()).isEqualTo("name");
    6469                                assertThat(framsClass.getParam(1).getId()).isEqualTo("history");
    65                                 assertThat(framsClass.getParam(2).getId()).isEqualTo("appendHistory");
    66                                 assertThat(framsClass.getParam(3).getId()).isEqualTo("resetHistory");
     70                                assertThat(framsClass.getParam(2).getId()).isEqualTo("history_changed");
     71                                assertThat(framsClass.getParam(3).getId()).isEqualTo("appendHistory");
     72                                assertThat(framsClass.getParam(4).getId()).isEqualTo("resetHistory");
    6773
    6874                                assertThat(access.get("history", String.class)).isEqualTo("initial|");
     
    7783                waitForIdle();
    7884
     85                final EventListener<ChangeEvent> listener = new EventListener<ChangeEvent>() {
     86
     87                        @Override
     88                        public void action(ChangeEvent argument) {
     89                                assertThat(argument.history).isEqualTo("");
     90                        }
     91                };
    7992
    8093                tree.dispatch(new RunAt<Tree>(failOnException) {
    8194                        @Override
    8295                        protected void runAt() {
    83                                 assertThat(bindAccess(tree, "/").get("history", String.class)).isEqualTo("initial|Żółw|");
     96                                AccessInterface access = bindAccess(tree, "/");
     97                                assertThat(access.get("history", String.class)).isEqualTo("initial|Żółw|");
     98
     99                                tree.addListener(Path.to(tree, "/"), access.getFramsClass().getParamEntry("history_changed", EventParam.class), listener, ChangeEvent.class, FutureHandler.doNothing(Void.class, failOnException));
    84100                        }
    85101                });
     
    91107                        @Override
    92108                        protected void runAt() {
    93                                 assertThat(bindAccess(tree, "/").get("history", String.class)).isEqualTo("");
     109                                AccessInterface access = bindAccess(tree, "/");
     110                                assertThat(access.get("history", String.class)).isEqualTo("");
     111
     112                                tree.removeListener(Path.to(tree, "/"), access.getFramsClass().getParamEntry("history_changed", EventParam.class), listener, FutureHandler.doNothing(Void.class, failOnException));
    94113                        }
    95114                });
  • java/main/src/test/java/com/framsticks/hosting/ServerTest.java

    r98 r99  
    22
    33// import org.apache.log4j.Logger;
     4import java.util.Arrays;
     5import java.util.LinkedList;
     6import java.util.List;
     7
    48import org.testng.annotations.Test;
    59
    6 import com.framsticks.core.Mode;
    7 import com.framsticks.core.ObjectTree;
     10import com.framsticks.core.LocalTree;
    811import com.framsticks.core.Path;
     12import com.framsticks.core.TreeOperations;
    913import com.framsticks.core.XmlBasedTest;
    1014import com.framsticks.remote.RemoteTree;
    1115
     16import com.framsticks.test.ChangeEvent;
    1217import com.framsticks.test.TestClass;
    1318import com.framsticks.core.Tree;
    1419import com.framsticks.params.FramsClass;
    15 import com.framsticks.util.dispatching.Dispatching;
    1620import com.framsticks.params.AccessInterface;
     21import com.framsticks.params.EventListener;
    1722import com.framsticks.params.PrimitiveParam;
    1823import com.framsticks.params.PropertiesAccess;
     24import com.framsticks.params.types.EventParam;
     25// import com.framsticks.params.types.EventParam;
    1926import com.framsticks.params.types.ProcedureParam;
    2027import com.framsticks.util.dispatching.Dispatching.Waiter;
     
    3441
    3542        protected Server server;
    36         protected ObjectTree hosted;
     43        protected LocalTree hosted;
    3744        protected TestClass hostedObject;
     45        protected EventListener<ChangeEvent> listener;
     46        protected List<String> listenerArguments = new LinkedList<>();
    3847
    3948        @Override
     
    5059                server = (Server) framsticks.get("test");
    5160                remote = (RemoteTree) framsticks.get("remote");
    52                 assertThat(server.getHosted()).isInstanceOf(ObjectTree.class);
    53                 hosted = (ObjectTree) server.getHosted();
     61                assertThat(server.getHosted()).isInstanceOf(LocalTree.class);
     62                hosted = (LocalTree) server.getHosted();
    5463                assertThat(hosted.getRootObject()).isInstanceOf(TestClass.class);
    5564                hostedObject = hosted.getRootObject(TestClass.class);
     
    5867        @Test(dependsOnMethods = "runServer")
    5968        public void fetchInfo() {
    60                 remote.dispatch(new RunAt<Tree>(failOnException) {
     69                final Waiter waiter = produceWaiter(1.0);
     70
     71                TreeOperations.tryGet(remote, "/testClass", new FutureHandler<Path>(failOnException) {
    6172                        @Override
    62                         protected void runAt() {
    63                                 remote.info(Path.to(remote, "/"), new FutureHandler<FramsClass>(failOnException) {
    64                                         @Override
    65                                         protected void result(FramsClass result) {
    66                                                 remoteTestFramsClass = result;
    67                                                 assertThat(result.getId()).isEqualTo("TestClass");
    68                                         }
    69                                 });
     73                        protected void result(Path path) {
     74                                assertThat(path.isResolved()).isTrue();
     75                                remoteTestFramsClass = bindAccess(path).getFramsClass();
     76                                assertThat(remoteTestFramsClass.getName()).isEqualTo("TestClass");
     77                                waiter.pass();
    7078                        }
    7179                });
    7280
    73                 Dispatching.synchronize(remote, 1.0);
    7481        }
    7582
     
    7885                final Waiter waiter = produceWaiter(1.0);
    7986
    80                 remote.dispatch(new RunAt<Tree>(failOnException) {
     87                TreeOperations.tryGet(remote, "/testClass", new FutureHandler<Path>(failOnException) {
    8188                        @Override
    82                         protected void runAt() {
    83                                 final Path path = Path.to(remote, "/");
    84                                 assertThat(path.isResolved()).isFalse();
    85 
    86                                 remote.get(path, Mode.FETCH, new FutureHandler<Path>(failOnException) {
    87                                         @Override
    88                                         protected void result(Path path) {
    89                                                 assertThat(path.isResolved()).isTrue();
    90                                                 remotePath = path;
    91                                                 AccessInterface access = bindAccess(path);
    92                                                 assertThat(access).isInstanceOf(PropertiesAccess.class);
    93                                                 assertThat(access.get("name", String.class)).isEqualTo("a test name");
    94                                                 waiter.pass();
    95                                         }
    96                                 });
     89                        protected void result(Path path) {
     90                                assertThat(path.isResolved()).isTrue();
     91                                remotePath = path;
     92                                AccessInterface access = bindAccess(path);
     93                                assertThat(access).isInstanceOf(PropertiesAccess.class);
     94                                assertThat(access.get("name", String.class)).isEqualTo("a test name");
     95                                waiter.pass();
    9796                        }
    9897                });
     
    120119
    121120        @Test(dependsOnMethods = "setValueName")
     121        public void registerListener() {
     122                final Waiter waiter = produceWaiter(1.0);
     123                listener = new EventListener<ChangeEvent>() {
     124
     125                        @Override
     126                        public void action(ChangeEvent argument) {
     127                                listenerArguments.add(argument.history);
     128                        }
     129                };
     130
     131                TreeOperations.tryGet(remote, "/cli/events", new FutureHandler<Path>(failOnException) {
     132                        @Override
     133                        protected void result(Path path) {
     134                                waiter.pass();
     135                        }
     136                });
     137
     138                addListener(remotePath, remoteTestFramsClass.getParamEntry("history_changed", EventParam.class), listener, ChangeEvent.class, produceWaiter(1.0).passInFuture(Void.class));
     139        }
     140
     141        @Test(dependsOnMethods = "registerListener")
    122142        public void callMethod() {
    123                 final Waiter firstWaiter = produceWaiter(2.0);
    124143                final Waiter waiter = produceWaiter(2.0);
    125144
    126                 call(remotePath, remoteTestFramsClass.getParamEntry("resetHistory", ProcedureParam.class), new Object[] {}, new FutureHandler<Object>(failOnException) {
    127                         @Override
    128                         protected void result(Object result) {
    129                                 firstWaiter.pass();
    130                         }
    131                 });
     145                call(remotePath, remoteTestFramsClass.getParamEntry("resetHistory", ProcedureParam.class), new Object[] {}, produceWaiter(2.0).passInFuture(Object.class));
    132146
    133147                call(remotePath, remoteTestFramsClass.getParamEntry("appendHistory", ProcedureParam.class), new Object[] {"next word"}, new FutureHandler<Object>(failOnException) {
     
    143157                        }
    144158                });
     159        }
    145160
     161
     162        @Test(dependsOnMethods = "callMethod")
     163        public void deregisterListener() {
     164                removeListener(remotePath, remoteTestFramsClass.getParamEntry("history_changed", EventParam.class), listener, produceWaiter(1.0).passInFuture(Void.class));
     165
     166                assertThat(listenerArguments).isEqualTo(Arrays.asList("", "next word|"));
    146167        }
    147168
  • java/main/src/test/java/com/framsticks/params/FramsClassBuilderTest.java

    r97 r99  
    66import org.testng.annotations.Test;
    77
     8import com.framsticks.params.types.EventParam;
    89import com.framsticks.params.types.ProcedureParam;
    910import com.framsticks.params.types.StringParam;
    1011import com.framsticks.parsers.Savers;
     12import com.framsticks.test.ChangeEvent;
    1113import com.framsticks.test.TestClass;
    1214import com.framsticks.test.TestConfiguration;
     15import com.framsticks.util.lang.Holder;
     16
    1317import static org.fest.assertions.Assertions.*;
    1418
     
    3034        @Test
    3135        public void checkProcedureParams() {
    32                 assertThat(framsClass.getParamCount()).isEqualTo(4);
     36                assertThat(framsClass.getParamCount()).isEqualTo(5);
    3337
    3438                assertThat(framsClass.getParam("name")).isInstanceOf(StringParam.class);
    3539                assertThat(framsClass.getParam("history")).isInstanceOf(StringParam.class);
     40                assertThat(framsClass.getParam("history_changed")).isInstanceOf(EventParam.class);
    3641
    3742                assertThat(framsClass.getParam("appendHistory")).isInstanceOf(ProcedureParam.class);
     
    6267                                        "",
    6368                                        "prop:",
     69                                        "id:history_changed",
     70                                        "name:HistoryListener",
     71                                        "type:e ChangeEvent",
     72                                        "",
     73                                        "prop:",
    6474                                        "id:appendHistory",
    6575                                        "name:AppendHistory",
     
    7585        }
    7686
     87        @Test(dependsOnMethods = "print")
     88        public void createAccess() {
     89                access = new ReflectionAccess(TestClass.class, framsClass);
     90                access.select(test);
     91        }
    7792
    78         @Test(dependsOnMethods = "print")
     93        @Test(dependsOnMethods = "createAccess")
    7994        public void callProcedures() {
    80                 access = new ReflectionAccess(TestClass.class, framsClass);
    81 
    82                 access.select(test);
    8395
    8496                assertThat(access.get("history", String.class)).isEqualTo("initial|first|");
     
    93105
    94106                assertThat(access.get("history", String.class)).isEqualTo("");
     107        }
    95108
     109        @Test(dependsOnMethods = "callProcedures")
     110        public void listeners() {
     111
     112                final Holder<String> called = new Holder<>();
     113
     114                final EventListener<ChangeEvent> listener = new EventListener<ChangeEvent>() {
     115
     116                        @Override
     117                        public void action(ChangeEvent argument) {
     118                                called.set(argument.history);
     119                        }
     120                };
     121
     122                final EventParam eventParam = access.getFramsClass().getParamEntry("history_changed", EventParam.class);
     123                access.reg(eventParam, listener);
     124
     125                final String currentHistory = access.get("history", String.class);
     126                final String addition = "test";
     127
     128                access.call("appendHistory", new Object[] { addition });
     129
     130                String expected = currentHistory + addition + "|";
     131                assertThat(access.get("history", String.class)).isEqualTo(expected);
     132                assertThat(called.get()).isEqualTo(expected);
     133                access.regRemove(eventParam, listener);
    96134        }
    97135
  • java/main/src/test/java/com/framsticks/test/TestConfiguration.java

    r98 r99  
    1717import com.framsticks.util.dispatching.ExceptionResultHandler;
    1818
    19 import static org.fest.assertions.Assertions.*;
     19// import static org.fest.assertions.Assertions.*;
    2020
    2121public class TestConfiguration {
     
    3131        private final List<AssertionError> asyncAssertions = new LinkedList<>();
    3232
     33        public static AssertionError wrapInAssertion(Throwable throwable) {
     34                if (throwable instanceof AssertionError) {
     35                        return (AssertionError) throwable;
     36                }
     37
     38                AssertionError ae = new AssertionError();
     39                ae.initCause(throwable);
     40                return ae;
     41        }
     42
     43        public void addAsyncAssertion(Throwable throwable) {
     44                synchronized (asyncAssertions) {
     45                        asyncAssertions.add(wrapInAssertion(throwable));
     46                }
     47        }
     48
    3349        public ExceptionHandler createExceptionHandler() {
    3450                return new ExceptionHandler() {
    3551                        @Override
    3652                        public boolean handle(Dispatcher<?> dispatcher, Throwable throwable) {
    37                                 AssertionError ae;
    38                                 if (AssertionError.class.isInstance(throwable)) {
    39                                         ae = AssertionError.class.cast(throwable);
    40                                 } else {
    41                                         ae = new AssertionError();
    42                                         ae.initCause(throwable);
    43                                 }
    44                                 synchronized (asyncAssertions) {
    45                                         asyncAssertions.add(ae);
    46                                 }
     53                                addAsyncAssertion(throwable);
    4754                                return true;
    4855                        }
     
    8390
    8491        protected Dispatching.Waiter produceWaiter(double timeOut) {
    85                 Waiter waiter = new Waiter(timeOut);
     92                Waiter waiter = new Waiter(timeOut, failOnException);
    8693                waiters.add(waiter);
    8794                return waiter;
    8895        }
    8996
    90         public static final ExceptionResultHandler failOnException = new ExceptionResultHandler() {
     97        public final ExceptionResultHandler failOnException = new ExceptionResultHandler() {
    9198                @Override
    9299                public void handle(FramsticksException e) {
    93                         e.printStackTrace();
    94                         assertThat(e).isNull();
     100                        log.error("passing exception as assertion in " + TestConfiguration.this.getClass(), e);
     101                        addAsyncAssertion(e);
    95102                }
    96103        };
  • java/main/src/test/resources/configs/ProcedureBrowserTest.xml

    r97 r99  
    11<?xml version="1.0" encoding="UTF-8"?>
    22<Browser>
    3         <import class="com.framsticks.core.ObjectTree" />
     3        <import class="com.framsticks.core.LocalTree" />
    44        <import class="com.framsticks.test.TestClass" />
    5         <ObjectTree name="test">
     5        <LocalTree name="test">
    66                <TestClass />
    7         </ObjectTree>
     7        </LocalTree>
    88</Browser>
  • java/main/src/test/resources/configs/ServerTest.xml

    r97 r99  
    33        <import class="com.framsticks.hosting.Server" />
    44        <import class="com.framsticks.remote.RemoteTree" />
    5         <import class="com.framsticks.core.ObjectTree" />
     5        <import class="com.framsticks.core.LocalTree" />
    66        <import class="com.framsticks.test.TestClass" />
    77        <import class="com.framsticks.running.LoggingOutputListener" />
    88        <Server name="server" port="9007">
    9                 <ObjectTree name="test">
     9                <LocalTree name="test">
    1010                        <TestClass name="a test name" />
    11                 </ObjectTree>
     11                </LocalTree>
    1212        </Server>
    1313        <RemoteTree name="remote" address="localhost:9007" />
  • java/main/src/test/resources/configs/test.xml

    r97 r99  
    22<Framsticks>
    33        <import class="com.framsticks.gui.Browser" />
    4         <import class="com.framsticks.remote.SimulatorTree" />
     4        <import class="com.framsticks.remote.RemoteTree" />
    55        <Browser name="browser">
    6                 <SimulatorTree name="localhost:9009" address="localhost:9009" />
     6                <RemoteTree name="localhost:9009" address="localhost:9009" />
    77        </Browser>
    88</Framsticks>
  • java/main/src/test/resources/log4j.properties

    r98 r99  
    2828log4j.logger.com.framsticks=WARN
    2929log4j.logger.com.framsticks.test.TestConfiguration=INFO
    30 # log4j.logger.com.framsticks.core.TreeOperations=DEBUG
     30# log4j.logger.com.framsticks.hosting.Cli=DEBUG
    3131# log4j.logger.com.framsticks.core.AbstractTree=DEBUG
    3232# log4j.logger.com.framsticks.remote.RemoteTree=DEBUG
Note: See TracChangeset for help on using the changeset viewer.