Changeset 96 for java/main


Ignore:
Timestamp:
07/04/13 20:29:50 (11 years ago)
Author:
psniegowski
Message:

HIGHLIGHTS:

  • cleanup Instance management
    • extract Instance interface
    • extract Instance common algorithms to InstanceUtils?
  • fix closing issues: Ctrl+C or window close button

properly shutdown whole program

by Java Framsticks framework

  • fix parsing and printing of all request types
  • hide exception passing in special handle method of closures
    • substantially improve readability of closures
    • basically enable use of exception in asynchronous closures

(thrown exception is transported back to the caller)

  • implement call request on both sides

CHANGELOG:
Further improve calling.

Improve instance calling.

Calling is working on both sides.

Improve exception handling in testing.

Waiters do not supercede other apllication exception being thrown.

Finished parsing and printing of all request types (with tests).

Move implementation and tests of request parsing to Request.

Add tests for Requests.

Improve waits in asynchronours tests.

Extract more algorithms to InstanceUtils?.

Extract Instance.resolve to InstanceUtils?.

Improve naming.

Improve passing exception in InstanceClient?.

Hide calling of passed functor in StateCallback?.

Hide Exception passing in asynchronous closures.

Hide exception passing in Future.

Make ResponseCallback? an abstract class.

Make Future an abstract class.

Minor change.

Move getPath to Path.to()

Move bindAccess to InstanceUtils?.

Extract common things to InstanceUtils?.

Fix synchronization bug in Connection.

Move resolve to InstanceUtils?.

Allow names of Joinable to be dynamic.

Add support for set request server side.

More fixes in communication.

Fix issues with parsing in connection.

Cut new line characters when reading.

More improvements.

Migrate closures to FramsticksException?.

Several changes.

Extract resolveAndFetch to InstanceUtils? algorithms.

Test resolving and fetching.

More fixes with function signature deduction.

Do not print default values in SimpleAbstractAccess?.

Add test of FramsClass? printing.

Improve FramsticksException? messages.

Add explicit dispatcher synchronization feature.

Rework assertions in tests.

Previous solution was not generic enough.

Allow addition of joinables to collection after start.

Extract SimulatorInstance? from RemoteInstance?.

Remove PrivateJoinableCollection?.

Improve connections.

Move shutdown hook to inside the Monitor.

It should work in TestNG tests, but it seems that
hooks are not called.

In ServerTest? client connects to testing server.

Move socket initialization to receiver thread.

Add proper closing on Ctrl+C (don't use signals).

Fix bugs with server accepting connections.

Merge Entity into Joinable.

Reworking ServerInstance?.

Extract more algorithm to InstanceUtils?.

Extract some common functionality from AbstractInstance?.

Functions were placed in InstanceUtils?.

Hide registry of Instance.

Use ValueParam? in Instance interface.

Minor change.

Extract Instance interface.

Old Instance is now AbstractInstance?.

Location:
java/main
Files:
23 added
5 deleted
81 edited

Legend:

Unmodified
Added
Removed
  • java/main/pom.xml

    r88 r96  
    147147                                        <workingDirectory>/home/psniegowski/mgr/framsticks</workingDirectory>
    148148                                        <arguments>
    149                                                 <!-- <argument>-ea</argument> -->
     149                                                <argument>-ea</argument>
    150150                                                <argument>-Xdebug</argument>
    151151                                                <argument>-Xrunjdwp:transport=dt_socket,address=4711,server=y,suspend=n</argument>
  • java/main/src/main/java/com/framsticks/communication/ClientConnection.java

    r90 r96  
    1111import com.framsticks.util.dispatching.Dispatcher;
    1212import com.framsticks.util.dispatching.Dispatching;
     13import com.framsticks.util.dispatching.JoinableState;
    1314import com.framsticks.util.lang.Pair;
    1415import com.framsticks.util.lang.Strings;
     16
     17import org.apache.log4j.Level;
    1518import org.apache.log4j.Logger;
    1619
    1720import java.io.IOException;
    1821import java.net.Socket;
    19 import java.net.SocketException;
    2022import java.util.*;
    2123import java.util.regex.Matcher;
     
    3941        }
    4042
     43        public ClientConnection(String address) {
     44                super(address, "client connection");
     45                Matcher matcher = addressPattern.matcher(address);
     46                if (!matcher.matches()) {
     47                        log.fatal("invalid address: " + address);
     48                        hostName = null;
     49                        port = 0;
     50                        return;
     51                }
     52                hostName = matcher.group(1);
     53                port = matcher.group(3) != null ? Integer.parseInt(matcher.group(3)) : 9009;
     54        }
    4155
    4256        protected StateFunctor connectedFunctor;
    43 
    44         @Override
    45         protected void joinableStart() {
    46                 try {
    47                         log.debug("connecting to " + address);
    48 
    49                         socket = new Socket(hostName, port);
    50 
    51                         socket.setSoTimeout(500);
    52 
    53                         log.debug("connected to " + hostName + ":" + port);
    54                         connected = true;
    55                         runThreads();
    56 
    57                         connectedFunctor.call(null);
    58                 } catch (SocketException e) {
    59                         log.error("failed to connect: " + e);
    60                         connectedFunctor.call(e);
    61                 } catch (IOException e) {
    62                         log.error("buffer creation failure");
    63                         connectedFunctor.call(e);
    64                         // close();
    65                 }
    66         }
    67 
    6857
    6958        private static abstract class InboundMessage {
     
    7867                        currentFilePath = path;
    7968                }
     69
    8070                protected void finishCurrentFile() {
    8171                        if (currentFileContent == null) {
     
    8474                        files.add(new File(currentFilePath, new ListSource(currentFileContent)));
    8575                        currentFilePath = null;
    86                         currentFileContent= null;
     76                        currentFileContent = null;
    8777                }
    8878
    8979                public abstract void startFile(String path);
    9080
    91                 public void addLine(String line) {
     81                public final void addLine(String line) {
    9282                        assert line != null;
    9383                        assert currentFileContent != null;
    94                         currentFileContent.add(line.substring(0, line.length() - 1));
     84                        currentFileContent.add(line);
    9585                }
    9686
     
    127117                public void startFile(String path) {
    128118                        finishCurrentFile();
    129                         if (path == null) {
     119                        if (!Strings.notEmpty(path)) {
    130120                                assert request instanceof ApplicationRequest;
    131                                 path = ((ApplicationRequest)request).getPath();
    132                         }
     121                                path = ((ApplicationRequest) request).getPath();
     122                        }
     123                        Strings.assureNotEmpty(path);
    133124                        initCurrentFile(path);
    134125                }
    135126
    136127                public void eof() {
     128                        assert Strings.notEmpty(currentFilePath);
    137129                        finishCurrentFile();
    138130                        //no-operation
     
    153145                }
    154146        }
     147
    155148        private Map<Integer, SentQuery<?>> queryMap = new HashMap<>();
    156 
    157149
    158150        protected final String hostName;
     
    161153        private static Pattern addressPattern = Pattern.compile("^([^:]*)(:([0-9]+))?$");
    162154
    163         public ClientConnection(String address) {
    164                 super(address);
    165                 Matcher matcher = addressPattern.matcher(address);
    166                 if (!matcher.matches()) {
    167                         log.fatal("invalid address: " + address);
    168                         hostName = null;
    169                         port = 0;
    170                         return;
    171                 }
    172                 hostName = matcher.group(1);
    173                 port = matcher.group(3) != null ? Integer.parseInt(matcher.group(3)) : 9009;
    174         }
    175155
    176156        private SentQuery<?> currentlySentQuery;
    177 
    178157
    179158        public <C extends Connection> void send(Request request, ResponseCallback<C> callback) {
     
    184163        public <C> void send(Request request, Dispatcher<C> dispatcher, ResponseCallback<? extends C> callback) {
    185164
    186                 if (!isConnected()) {
     165                if (getState().ordinal() > JoinableState.RUNNING.ordinal()) {
    187166                        log.fatal("not connected");
    188167                        return;
    189168                }
     169
    190170                final SentQuery<C> sentQuery = new SentQuery<C>();
    191171                sentQuery.request = request;
     
    193173                sentQuery.dispatcher = dispatcher;
    194174
    195                 senderThread.dispatch(new RunAt<Connection>(){
     175                senderThread.dispatch(new RunAt<Connection>() {
    196176                        @Override
    197177                        public void run() {
     
    220200                                        message.append(" ").append(id);
    221201                                }
     202                                message.append(" ");
    222203                                sentQuery.request.construct(message);
    223204                                String out = message.toString();
    224205
    225206                                output.println(out);
     207                                output.flush();
    226208                                log.debug("sending query: " + out);
    227209
     
    234216                        notifyAll();
    235217                }
    236                 */
    237         }
    238 
     218                 */
     219        }
    239220
    240221        @Override
     
    272253        }
    273254
    274         public void sendQueryVersion(final int version, final StateFunctor stateFunctor) {
    275                 send(new VersionRequest().version(version), new StateCallback<Connection>() {
     255        public void sendQueryVersion(final int version, StateFunctor stateFunctor) {
     256                send(new VersionRequest().version(version), new StateCallback<Connection>(stateFunctor) {
    276257                        @Override
    277                         public void call(Exception e) {
    278                                 if (e != null) {
    279                                         log.fatal("failed to upgrade protocol to version: " + version);
    280                                         return;
    281                                 }
     258                        public void callImpl() {
    282259                                protocolVersion = version;
    283260                                if (version < 4) {
    284261                                        /** it is an implicit loop here*/
    285                                         sendQueryVersion(version + 1, stateFunctor);
     262                                        sendQueryVersion(version + 1, move());
    286263                                        return;
    287264                                }
    288                                 send(new UseRequest().feature("request_id"), new StateCallback<Connection>() {
     265                                send(new UseRequest().feature("request_id"), new StateCallback<Connection>(move()) {
    289266                                        @Override
    290                                         public void call(Exception e) {
    291                                                 requestIdEnabled = e == null;
    292                                                 /*
    293                                                 synchronized (ClientConnection.this) {
    294                                                         ClientConnection.this.notifyAll();
    295                                                 }
    296                                                 */
    297                                                 if (!requestIdEnabled) {
    298                                                         log.fatal("protocol negotiation failed");
    299                                                         stateFunctor.call(new Exception("protocol negotiation failed", e));
    300                                                         return;
    301                                                 }
    302                                                 stateFunctor.call(null);
     267                                        public void handle(FramsticksException exception) {
     268                                                requestIdEnabled = false;
     269                                                log.fatal("protocol negotiation failed");
     270                                                super.handle(new FramsticksException().msg("protocol negotiation failed").cause(exception));
     271                                        }
     272
     273                                        @Override
     274                                        public void callImpl() {
     275                                                requestIdEnabled = true;
    303276                                        }
    304277                                });
     
    307280                });
    308281        }
    309 
    310282
    311283        private synchronized SentQuery<?> fetchQuery(Integer id, boolean remove) {
     
    348320
    349321        protected void processEvent(String rest) {
    350                 Matcher matcher = eventPattern.matcher(rest);
     322                Matcher matcher = Request.EVENT_PATTERN.matcher(rest);
    351323                if (!matcher.matches()) {
    352324                        log.error("invalid event line: " + rest);
     
    363335        }
    364336
    365 
    366337        protected void processMessageStartingWith(String line) {
    367                 Pair<String, String> command = Strings.splitIntoPair(line, ' ', "\n");
    368                 if (command.first.equals("event")) {
    369                         processEvent(command.second);
    370                         return;
    371                 }
    372                 Pair<Integer, String> rest = parseRest(command.second);
    373 
    374                 if (command.first.equals("file")) {
    375                         SentQuery<?> sentQuery = fetchQuery(rest.first, false);
    376                         sentQuery.startFile(rest.second);
    377                         processMessage(sentQuery);
    378                         return;
    379                 }
    380 
    381                 SentQuery<?> sentQuery = fetchQuery(rest.first, true);
    382                 if (sentQuery == null) {
    383                         return;
    384                 }
    385                 log.debug("parsing response for request " + sentQuery);
    386 
    387                 sentQuery.dispatchResponseProcess(new Response(command.first.equals("ok"), rest.second, sentQuery.getFiles()));
     338                try {
     339                        Pair<CharSequence, CharSequence> command = Request.takeIdentifier(line);
     340                        if (command.first.equals("event")) {
     341                                processEvent(command.second.toString());
     342                                return;
     343                        }
     344                        Pair<Integer, CharSequence> rest = takeRequestId(command.second);
     345
     346                        if (command.first.equals("file")) {
     347                                SentQuery<?> sentQuery = fetchQuery(rest.first, false);
     348                                sentQuery.startFile(rest.second.toString());
     349                                processMessage(sentQuery);
     350                                return;
     351                        }
     352
     353                        SentQuery<?> sentQuery = fetchQuery(rest.first, true);
     354                        if (sentQuery == null) {
     355                                return;
     356                        }
     357                        log.debug("parsing response for request " + sentQuery);
     358
     359                        sentQuery.dispatchResponseProcess(new Response(command.first.equals("ok"), rest.second.toString(), sentQuery.getFiles()));
     360                } catch (FramsticksException e) {
     361                        throw new FramsticksException().msg("failed to process message").arg("starting with line", line).cause(e);
     362                }
    388363        }
    389364
    390365        @Override
    391366        protected void receiverThreadRoutine() {
    392                 while (connected) {
     367                while (isRunning() && !isConnected()) {
     368                        log.debug("connecting to " + address);
     369                        try {
     370                                socket = new Socket(hostName, port);
     371                        } catch (IOException e) {
     372                                log.info(this + " failed to connect (retrying): " + e);
     373                                Dispatching.sleep(0.5);
     374                        }
     375                }
     376
     377                log.debug(this + " connected");
     378                try {
     379                        socket.setSoTimeout(500);
     380                        setupStreams();
     381                } catch (Exception e) {
     382                        throw new FramsticksException().msg("failed to initialize socket").cause(e).arg("connection", this);
     383                }
     384
     385                connectedFunctor.call();
     386
     387                while (isRunning() && isConnected()) {
    393388                        try {
    394389                                processMessageStartingWith(getLine());
    395390                        } catch (Exception e) {
     391                                log.log(isRunning() ? Level.ERROR : Level.DEBUG, "caught exception: ", e);
    396392                                break;
    397393                        }
    398394                }
    399         }
    400 
    401 
     395                interrupt();
     396                finish();
     397        }
    402398}
  • java/main/src/main/java/com/framsticks/communication/Connection.java

    r90 r96  
    1212import java.net.Socket;
    1313import java.net.SocketTimeoutException;
    14 import java.util.regex.Matcher;
    15 import java.util.regex.Pattern;
    1614
    1715import com.framsticks.util.dispatching.AbstractJoinable;
     
    3331        protected Socket socket = null;
    3432
    35         protected volatile boolean connected = false;
    36 
    3733        public boolean requestIdEnabled = false;
    3834
     
    4339        }
    4440        protected final String address;
     41        protected final String description;
    4542
    4643        protected final Thread<Connection> senderThread = new Thread<>();
    4744        protected final Thread<Connection> receiverThread = new Thread<>();
    48         protected final JoinableCollection<Thread<Connection>> threads = new JoinableCollection<>(true);
     45        protected final JoinableCollection<Thread<Connection>> threads = new JoinableCollection<>();
     46
     47        protected void setUpThreadNames(String name) {
     48        }
    4949
    5050        /**
    5151         *
    5252         */
    53         public Connection(String address) {
     53        public Connection(String address, String description) {
    5454                this.address = address;
     55                this.description = description;
     56                threads.setObservableName(address + " connection threads");
    5557                threads.add(senderThread);
    5658                threads.add(receiverThread);
    57         }
    58         public boolean isConnected() {
    59                 return connected;
    60         }
    61 
    62 
    63         protected static final String ARGUMENT_PATTERN_FRAGMENT = "((?:\\S+)|(?:\"[^\"]*\"))";
    64         protected static final Pattern requestIdEnabledPattern = Pattern.compile("^\\s*([0-9]+)(?:\\s+" + ARGUMENT_PATTERN_FRAGMENT + ")?\\n$");
    65         protected static final Pattern requestIDisabledPattern = Pattern.compile("^\\s*" + ARGUMENT_PATTERN_FRAGMENT + "?\\n$");
    66         protected static final Pattern eventPattern = Pattern.compile("^\\s*(\\S+)\\s*(\\S+)\\n");
    67 
    68 
    69         protected final Pair<Integer, String> parseRest(String rest) {
    70                 Matcher matcher = (requestIdEnabled ? requestIdEnabledPattern : requestIDisabledPattern).matcher(rest);
    71                 if (!matcher.matches()) {
    72                         log.fatal("unmatched first line of input: " + rest);
    73                         return null;
    74                 }
    75                 return new Pair<Integer, String>(requestIdEnabled ? Integer.parseInt(matcher.group(1)) : null, matcher.group(requestIdEnabled ? 2 : 1));
     59
     60                senderThread.setName(description + " thread " + address + " sender");
     61                receiverThread.setName(description + " thread " + address + " receiver");
     62        }
     63
     64        public synchronized boolean isConnected() {
     65                return socket != null && socket.isConnected();
     66        }
     67
     68
     69        // protected static final String ARGUMENT_PATTERN_FRAGMENT = "((?:\\S+)|(?:\\\"[^\"]*\\\"))";
     70        // protected static final Pattern REQUEST_ID_ENABLED_PATTERN = Pattern.compile("^\\s*([0-9]+)(?:\\s+" + ARGUMENT_PATTERN_FRAGMENT + ")?$");
     71        // protected static final Pattern REQUEST_ID_DISABLED_PATTERN = Pattern.compile("^\\s*" + ARGUMENT_PATTERN_FRAGMENT + "?$");
     72
     73        // // protected final Pair<String, String> breakLine(String line)
     74        // protected final Pair<Integer, String> parseRest(String rest) {
     75        //      Matcher matcher = (requestIdEnabled ? REQUEST_ID_ENABLED_PATTERN : REQUEST_ID_DISABLED_PATTERN).matcher(rest);
     76        //      if (!matcher.matches()) {
     77        //              log.fatal("unmatched first line of input: '" + rest + "'");
     78        //              return null;
     79        //      }
     80        //      return new Pair<Integer, String>(requestIdEnabled ? Integer.parseInt(matcher.group(1)) : null, matcher.group(requestIdEnabled ? 2 : 1));
     81        // }
     82
     83        protected final Pair<Integer, CharSequence> takeRequestId(CharSequence line) {
     84                return Request.takeRequestId(requestIdEnabled, line);
    7685        }
    7786
     
    8190        int iterator = 0;
    8291        int bufferStart = 0;
    83         char[] readBuffer = new char[BUFFER_LENGTH];
     92        final char[] readBuffer = new char[BUFFER_LENGTH];
    8493
    8594        protected String getLine() {
    86                 StringBuilder lineBuffer = new StringBuilder();
     95                final StringBuilder lineBuffer = new StringBuilder();
    8796                try {
    8897                        while (!Thread.interrupted()) {
     
    92101                                                continue;
    93102                                        }
    94                                         lineBuffer.append(readBuffer, bufferStart, iterator - bufferStart + 1);
     103                                        /** Do not append new line. */
     104                                        lineBuffer.append(readBuffer, bufferStart, iterator - bufferStart);
    95105                                        ++iterator;
    96106                                        bufferStart = iterator;
    97107                                        return lineBuffer.toString();
    98108                                }
    99                                 lineBuffer.append(readBuffer, bufferStart, readChars - bufferStart);
     109                                final int length = readChars - bufferStart;
     110                                if (length > 0) {
     111                                        assert bufferStart >= 0 && bufferStart < BUFFER_LENGTH;
     112                                        assert bufferStart + length <= BUFFER_LENGTH;
     113                                        lineBuffer.append(readBuffer, bufferStart, length);
     114                                }
    100115
    101116                                readChars = 0;
     
    118133        protected abstract void receiverThreadRoutine();
    119134
    120         protected void setUpThread(Thread<Connection> thread, String name) {
    121                 thread.setName("connection thread " + address + " " + name);
    122         }
    123 
    124         protected void runThreads() {
     135
     136        protected void setupStreams() {
    125137                try {
    126138                        output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), Encoding.getFramsticksCharset()), true);
    127139                        input = new BufferedReader(new InputStreamReader(socket.getInputStream(), Encoding.getFramsticksCharset()));
     140                        synchronized (this) {
     141                                this.notifyAll();
     142                        }
    128143                } catch (IOException e) {
    129                         log.error("buffer creation failure");
    130                         return;
     144                        throw new FramsticksException().msg("failed to setup streams").cause(e).arg("connection", this);
    131145                }
    132 
    133                 setUpThread(senderThread, "sender");
    134                 setUpThread(receiverThread, "receiver");
    135                 Dispatching.use(threads, this);
    136 
    137                 receiverThread.dispatch(new RunAt<Connection>() {
    138                         @Override
    139                         public void run() {
    140                                 receiverThreadRoutine();
    141                         }
    142                 });
    143 
    144146        }
    145147
     
    153155        }
    154156
    155         @Override
    156         protected void joinableInterrupt() {
    157                 protocolVersion = -1;
    158 
    159                 connected = false;
    160                 Dispatching.drop(threads, this);
    161 
    162                 // finish();
    163         }
    164157
    165158        @Override
     
    193186
    194187        @Override
     188        public String getName() {
     189                return description + " " + address;
     190        }
     191
     192        @Override
     193        protected void joinableStart() {
     194                Dispatching.use(threads, this);
     195
     196                senderThread.dispatch(new RunAt<Connection>() {
     197                        @Override
     198                        public void run() {
     199                                synchronized (Connection.this) {
     200                                        while (state.equals(JoinableState.RUNNING) && output == null) {
     201                                                Dispatching.wait(Connection.this, 500);
     202                                        }
     203                                }
     204                        }
     205                });
     206
     207                receiverThread.dispatch(new RunAt<Connection>() {
     208                        @Override
     209                        public void run() {
     210                                receiverThreadRoutine();
     211                        }
     212                });
     213        }
     214
     215        @Override
     216        protected void joinableInterrupt() {
     217                protocolVersion = -1;
     218                Dispatching.drop(threads, this);
     219                finish();
     220        }
     221
     222
     223        @Override
    195224        protected void joinableJoin() throws InterruptedException {
    196225                Dispatching.join(threads);
    197 
    198226        }
    199227
  • java/main/src/main/java/com/framsticks/communication/File.java

    r77 r96  
    11package com.framsticks.communication;
    22
     3import java.util.ArrayList;
     4import java.util.List;
     5
     6import javax.annotation.Nonnull;
     7
    38import com.framsticks.params.SourceInterface;
     9// import com.framsticks.util.lang.Strings;
    410
    511/**
     
    713 */
    814public final class File {
    9     protected final String path;
    10     protected final SourceInterface content;
     15        protected final String path;
     16        protected final SourceInterface content;
    1117
    12     public File(String path, SourceInterface content) {
    13         this.path = path;
    14         this.content = content;
    15     }
     18        public File(@Nonnull String path, @Nonnull SourceInterface content) {
     19                // assert Strings.notEmpty(path);
     20                this.path = path;
     21                this.content = content;
     22        }
    1623
    17     public String getPath() {
    18         return path;
    19     }
     24        public String getPath() {
     25                return path;
     26        }
    2027
    21     public SourceInterface getContent() {
    22         return content;
    23     }
     28        public SourceInterface getContent() {
     29                return content;
     30        }
     31
     32        public static List<File> single(File file) {
     33                List<File> result = new ArrayList<File>();
     34                result.add(file);
     35                return result;
     36        }
    2437}
  • java/main/src/main/java/com/framsticks/communication/Request.java

    r84 r96  
    11package com.framsticks.communication;
    22
     3import java.util.regex.Matcher;
     4import java.util.regex.Pattern;
     5
    36import com.framsticks.communication.queries.*;
     7import com.framsticks.util.FramsticksException;
     8import com.framsticks.util.lang.Pair;
    49
    510/**
     
    813public abstract class Request {
    914
     15        public abstract String getCommand();
     16
     17        protected abstract StringBuilder construct(StringBuilder buffer);
     18
     19
     20
     21
    1022        public static void quoteValue(StringBuilder builder, String value) {
    1123                String quote = ((value.indexOf(' ') > 0) || (value.length() == 0) ? "\"" : "");
     
    1325        }
    1426
    15         public abstract String getCommand();
    16 
    17         protected abstract StringBuilder construct(StringBuilder buffer);
    18         //private static Pattern queryPattern = Pattern.compile("^(\\S+)\\s+(\\S+)(?:\\s+(\\S+))?$");
     27        public static Request parse(CharSequence type, CharSequence rest) {
     28                final Request request = Request.createRequestByTypeString(type.toString());
     29                request.parseRest(rest);
     30                return request;
     31        }
    1932
    2033        public static Request createRequestByTypeString(String type) {
    21                 if (type.equals("get")) {
    22                         return new GetRequest();
     34                switch (type) {
     35                        case "get": return new GetRequest();
     36                        case "set": return new SetRequest();
     37                        case "info": return new InfoRequest();
     38                        case "call": return new CallRequest();
     39                        case "reg": return new RegistrationRequest();
     40                        case "use": return new UseRequest();
     41                        case "version": return new VersionRequest();
    2342                }
    24                 if (type.equals("set")) {
    25                         return new SetRequest();
    26                 }
    27                 if (type.equals("info")) {
    28                         return new InfoRequest();
    29                 }
    30                 if (type.equals("call")) {
    31                         return new CallRequest();
    32                 }
    33                 if (type.equals("reg")) {
    34                         return new RegistrationRequest();
    35                 }
    36                 if (type.equals("use")) {
    37                         return new UseRequest();
    38                 }
    39                 if (type.equals("version")) {
    40                         return new VersionRequest();
    41                 }
    42                 return null;
     43                throw new FramsticksException().msg("unknown request type").arg("type", type);
    4344        }
    4445
    45         public abstract void parseRest(String rest);
     46        public abstract CharSequence parseRest(CharSequence rest);
    4647
    4748        @Override
    4849        public String toString() {
    49                 return construct(new StringBuilder().append(getCommand())).toString();
     50                return getCommand() + " request";
    5051        }
     52
     53        public String stringRepresentation() {
     54                return construct(new StringBuilder().append(getCommand()).append(" ")).toString();
     55        }
     56
     57        public static final Pattern EVENT_PATTERN = Pattern.compile("^\\s*(\\S+)\\s*(\\S+)");
     58
     59        public static final Pattern STRING_BREAKER_PATTERN = Pattern.compile("^\\s*(?:(?:\\\"([^\"]*)\\\")|([^ ]+))\\s*(.*)$");
     60        public static final Pattern IDENTIFIER_BREAKER_PATTERN = Pattern.compile("^\\s*([^ ]+)\\s*(.*)$");
     61
     62        // public static Matcher match(Pattern pattern, CharSequence line) {
     63        //      Matcher matcher = pattern.matcher(line);
     64        //      if (!matcher.matches()) {
     65        //              return null;
     66        //              // throw new FramsticksException().msg("failed to take").arg("pattern", pattern).arg("line", line);
     67        //      }
     68        //      return matcher;
     69        // }
     70
     71        public static Pair<CharSequence, CharSequence> takeIdentifier(CharSequence line) {
     72                Matcher matcher = IDENTIFIER_BREAKER_PATTERN.matcher(line);
     73                if (!matcher.matches()) {
     74                        return null;
     75                }
     76                return new Pair<CharSequence, CharSequence>(line.subSequence(matcher.start(1), matcher.end(1)), line.subSequence(matcher.start(2), matcher.end(2)));
     77        }
     78
     79        public static CharSequence takeGroup(CharSequence input, Matcher matcher, int group) {
     80                // return (matcher.start(group) == matcher.end(group)) ? null : input.subSequence(matcher.start(group), matcher.end(group));
     81                return input.subSequence(matcher.start(group), matcher.end(group));
     82        }
     83
     84        public static Pair<CharSequence, CharSequence> takeString(CharSequence line) {
     85                Matcher matcher = STRING_BREAKER_PATTERN.matcher(line);
     86                if (!matcher.matches()) {
     87                        return null;
     88                }
     89                assert ((matcher.start(1) == -1) != (matcher.start(2) == -1));
     90                return new Pair<CharSequence, CharSequence>(takeGroup(line, matcher, (matcher.start(1) != -1 ? 1 : 2)), takeGroup(line, matcher, 3));
     91        }
     92
     93        protected static final Pattern REQUEST_ID_BREAKER_PATTERN = Pattern.compile("^\\s*([0-9]+)\\s*(.*)$");
     94
     95        protected final static Pair<Integer, CharSequence> takeRequestId(boolean withId, CharSequence line) {
     96                if (withId) {
     97                        Matcher matcher = REQUEST_ID_BREAKER_PATTERN.matcher(line);
     98                        if (!matcher.matches()) {
     99                                return null;
     100                        }
     101                        return new Pair<Integer, CharSequence>(Integer.valueOf(takeGroup(line, matcher, 1).toString()), takeGroup(line, matcher, 2));
     102                }
     103                return new Pair<Integer, CharSequence>(null, line);
     104        }
     105
     106        public static StringBuilder quoteArgumentIfNeeded(StringBuilder builder, Object argument) {
     107                String r = argument.toString();
     108                if (r.indexOf(' ') != -1) {
     109                        builder.append('"').append(r).append('"');
     110                } else {
     111                        builder.append(r);
     112                }
     113                return builder;
     114        }
     115
    51116}
  • java/main/src/main/java/com/framsticks/communication/Response.java

    r77 r96  
    77 */
    88public class Response {
    9     protected final boolean ok;
    10     protected final String comment;
    11     protected final List<File> files;
     9        protected final boolean ok;
     10        protected final String comment;
     11        protected final List<File> files;
    1212
    13     public Response(boolean ok, String comment, List<File> files) {
    14         this.ok = ok;
    15         this.comment = comment;
    16         this.files = files;
    17     }
     13        public Response(boolean ok, String comment, List<File> files) {
     14                this.ok = ok;
     15                this.comment = comment;
     16                this.files = files;
     17        }
    1818
    19     public final String getComment() {
    20         return comment;
    21     }
     19        public final String getComment() {
     20                return comment;
     21        }
    2222
    23     public final boolean getOk() {
    24         return ok;
    25     }
     23        public final boolean getOk() {
     24                return ok;
     25        }
    2626
    27     public final List<File> getFiles() {
    28         return files;
    29     }
     27        public final List<File> getFiles() {
     28                return files;
     29        }
    3030
    31     public final boolean hasFiles() {
    32         return files != null && !files.isEmpty();
    33     }
     31        public final boolean hasFiles() {
     32                return files != null && !files.isEmpty();
     33        }
    3434}
  • java/main/src/main/java/com/framsticks/communication/ResponseCallback.java

    r85 r96  
    11package com.framsticks.communication;
     2
     3import com.framsticks.util.FramsticksException;
     4import com.framsticks.util.dispatching.ExceptionResultHandler;
    25
    36/**
    47 * @author Piotr Sniegowski
    58 */
    6 public interface ResponseCallback<C> {
    7         public void process(Response response);
     9public abstract class ResponseCallback<C> implements ExceptionResultHandler {
     10        public abstract void process(Response response);
     11
     12        @Override
     13        public void handle(FramsticksException e) {
     14                process(new Response(false, e.getMsg(), null));
     15        }
     16
    817}
  • java/main/src/main/java/com/framsticks/communication/ServerConnection.java

    r90 r96  
    33import com.framsticks.communication.queries.*;
    44import com.framsticks.params.SourceInterface;
     5import com.framsticks.util.FramsticksException;
     6import com.framsticks.util.lang.Holder;
    57import com.framsticks.util.lang.Pair;
    68import com.framsticks.util.lang.Strings;
     9
     10import org.apache.log4j.Level;
    711import org.apache.log4j.Logger;
    812
     
    2024
    2125        public ServerConnection(Socket socket, RequestHandler requestHandler) {
    22                 super("todo");
     26                super(socket.getInetAddress().getHostAddress(), "server connection");
    2327                this.socket = socket;
    2428                this.requestHandler = requestHandler;
    25                 connected = true;
    26 
     29                // socket.setSoTimeout(500);
     30                setupStreams();
    2731        }
    2832
    29         @Override
    30         public String toString() {
    31                 return socket.getInetAddress().getHostAddress();
    32         }
    3333
    3434        @Override
    3535        protected void receiverThreadRoutine() {
    36                 while (connected) {
    37                         processNextRequest();
     36                while (isRunning() && isConnected()) {
     37                        try {
     38                                processNextRequest();
     39                        } catch (Exception e) {
     40                                log.log((isRunning() ? Level.ERROR : Level.DEBUG), "caught exception: ", e);
     41                                break;
     42                        }
    3843                }
     44                interrupt();
     45                finish();
    3946        }
    4047
     
    8592                                output.print(outId);
    8693                                if (Strings.notEmpty(response.getComment())) {
    87                                         output.print(' ');
     94                                        output.print(" \"");
    8895                                        output.print(response.getComment());
     96                                        output.print('"');
    8997                                }
    9098                                output.print('\n');
     
    96104
    97105        protected void processNextRequest() {
    98                 String line = getLine();
    99                 Pair<String, String> command = Strings.splitIntoPair(line, ' ', "\n");
    100                 final Pair<Integer, String> rest = parseRest(command.second);
    101                 if (rest == null) {
    102                         respond(new Response(false, "\"invalid input\"", null), null);
     106                final Holder<Integer> id = new Holder<>();
     107                final String line = getLine();
     108                try {
     109                        Pair<CharSequence, CharSequence> command = Request.takeIdentifier(line);
     110                        final Pair<Integer, CharSequence> rest = takeRequestId(command.second);
     111                        id.set(rest.first);
     112
     113                        final Request request = Request.parse(command.first, rest.second);
     114
     115                        if (log.isTraceEnabled()) {
     116                                log.trace("read request: " + request);
     117                        }
     118
     119                        handleRequest(request, new ResponseCallback<ServerConnection>() {
     120                                @Override
     121                                public void process(Response response) {
     122                                        respond(response, rest.first);
     123                                }
     124                        });
     125                } catch (FramsticksException e) {
     126                        e.arg("id", id.get()).arg("line", line);
     127                        log.error("error: ", e);
     128                        respond(new Response(false, "invalid input: " + e.getMsg(), null), id.get());
    103129                        return;
    104130                }
    105131
    106                 final Request request = Request.createRequestByTypeString(command.first);
    107                 if (request == null) {
    108                         respond(new Response(false, "\"invalid input\"", null), null);
    109                         return;
    110                 }
    111                 request.parseRest(rest.second);
    112                 if (log.isTraceEnabled()) {
    113                         log.trace("read request: " + request);
    114                 }
    115 
    116                 handleRequest(request, new ResponseCallback<ServerConnection>() {
    117                         @Override
    118                         public void process(Response response) {
    119                                 respond(response, rest.first);
    120                         }
    121                 });
    122         }
    123 
    124         @Override
    125         protected void joinableStart() {
    126                 // TODO Auto-generated method stub
    127 
    128132        }
    129133}
  • java/main/src/main/java/com/framsticks/communication/StateCallback.java

    r85 r96  
    11package com.framsticks.communication;
    22
     3import com.framsticks.util.FramsticksException;
    34import com.framsticks.util.StateFunctor;
    45
     
    67 * @author Piotr Sniegowski
    78 */
    8 public abstract class StateCallback<C> implements ResponseCallback<C>, StateFunctor {
     9public abstract class StateCallback<C> extends ResponseCallback<C> implements StateFunctor {
     10
     11
     12        protected StateFunctor wrapped;
     13
     14        public StateCallback(StateFunctor wrapped) {
     15                this.wrapped = wrapped;
     16        }
     17
     18        public StateCallback() {
     19                this.wrapped = null;
     20        }
     21
     22        protected StateFunctor move() {
     23                assert wrapped != null;
     24                StateFunctor result = wrapped;
     25                wrapped = null;
     26                return result;
     27        }
     28
     29        protected abstract void callImpl();
     30
     31        @Override
     32        public final void call() {
     33                try {
     34                        callImpl();
     35                } catch (FramsticksException e) {
     36                        handle(e);
     37                        return;
     38                }
     39                if (wrapped != null) {
     40                        wrapped.call();
     41                }
     42        }
     43
     44        @Override
     45        public void handle(FramsticksException exception) {
     46                if (wrapped != null) {
     47                        wrapped.handle(exception);
     48                        return;
     49                }
     50                throw exception;
     51        }
     52
    953        @Override
    1054        public void process(Response response) {
    11                 call(response.getOk() ? null : new Exception(response.getComment()));
     55                if (response.getOk()) {
     56                        call();
     57                } else {
     58                        handle(new FramsticksException().msg("non-ok response").arg("comment", response.getComment()));
     59                }
    1260        }
    1361}
  • java/main/src/main/java/com/framsticks/communication/Subscription.java

    r90 r96  
    77import com.framsticks.util.dispatching.Dispatching;
    88import com.framsticks.util.dispatching.RunAt;
     9import com.framsticks.util.FramsticksException;
    910import com.framsticks.util.StateFunctor;
    1011import org.apache.log4j.Logger;
     
    5253                                if (!response.getOk()) {
    5354                                        log.error("failed to unsunscribe " + this + ": " + response.getComment());
    54                                         stateFunctor.call(new Exception(response.getComment()));
     55                                        stateFunctor.handle(new FramsticksException().msg("unsubscription failed").arg("comment", response.getComment()));
    5556                                        return;
    5657                                }
    5758                                assert response.hasFiles();
    5859                                log.debug("unsunscribed " + this);
    59                                 stateFunctor.call(null);
     60                                stateFunctor.call();
    6061                        }
    6162                });
  • java/main/src/main/java/com/framsticks/communication/queries/ApplicationRequest.java

    r85 r96  
    22
    33import com.framsticks.communication.Request;
    4 import com.framsticks.util.lang.Delimeted;
     4import com.framsticks.util.lang.Pair;
     5import com.framsticks.util.lang.Strings;
    56
    6 import java.util.Collection;
    77
    88/**
     
    1212
    1313        protected String path;
    14         protected String fields;
    1514
    1615        public ApplicationRequest path(String path) {
    17                 assert path != null;
     16                Strings.assureNotEmpty(path);
    1817                this.path = path;
    1918                return this;
    2019        }
    21 
    22         public ApplicationRequest field(String field) {
    23                 this.fields = field;
    24                 return this;
    25         }
    26 
    27         public ApplicationRequest fields(Collection<String> fields) {
    28                 Delimeted d = new Delimeted(",", "");
    29                 for (String f : fields) {
    30                         d.append(f);
    31                 }
    32                 return field(d.build());
    33         }
    34 
    3520
    3621        public String getPath() {
     
    3823        }
    3924
     25
    4026        @Override
    4127        protected StringBuilder construct(StringBuilder buffer) {
    42                 buffer.append(' ').append(path);
    43                 if (fields != null) {
    44                         buffer.append(' ').append(fields);
    45                 }
    46                 return buffer;
     28                return buffer.append(path);
    4729        }
    4830
    4931        @Override
    50         public void parseRest(String rest) {
    51                 path = rest;
     32        public CharSequence parseRest(CharSequence rest) {
     33                final Pair<CharSequence, CharSequence> p = takeIdentifier(rest);
     34                path = p.first.toString();
     35                return p.second;
    5236        }
    5337
  • java/main/src/main/java/com/framsticks/communication/queries/CallRequest.java

    r84 r96  
    11package com.framsticks.communication.queries;
    22
    3 import com.framsticks.communication.Request;
     3import com.framsticks.util.Misc;
     4import com.framsticks.util.lang.Pair;
    45
     6import java.util.ArrayList;
     7import java.util.Collection;
    58import java.util.List;
    69
     
    1013public class CallRequest extends ApplicationRequest {
    1114
    12         protected String arguments;
    13         protected String method;
     15        protected final List<Object> arguments = new ArrayList<>();
     16        protected String procedure;
    1417
    15         public CallRequest setArguments(String arguments) {
    16                 this.arguments = arguments;
     18        public CallRequest addArguments(String arguments) {
     19                // this.arguments = arguments;
    1720                return this;
    1821        }
    1922
    20         public CallRequest setArguments(List<String> arguments) {
    21                 StringBuilder buffer = new StringBuilder();
    22                 for (String a : arguments) {
    23                         buffer.append(" ");
    24                         Request.quoteValue(buffer, a.trim());
    25                 }
    26                 return this.setArguments(buffer.toString());
     23        /**
     24         * @return the arguments
     25         */
     26        public List<Object> getArguments() {
     27                return arguments;
    2728        }
    2829
    29         public CallRequest setMethod(String method) {
    30                 this.method = method;
     30        /**
     31         * @return the procedure
     32         */
     33        public String getProcedure() {
     34                return procedure;
     35        }
     36
     37        /**
     38         * @param arguments the arguments to set
     39         */
     40        public CallRequest arguments(Collection<Object> arguments) {
     41                this.arguments.clear();
     42                this.arguments.addAll(arguments);
     43                return this;
     44        }
     45
     46        public CallRequest argument(Object argument) {
     47                arguments.add(argument);
     48                return this;
     49        }
     50
     51        public CallRequest procedure(String procedure) {
     52                this.procedure = procedure;
    3153                return this;
    3254        }
     
    3557        protected StringBuilder construct(StringBuilder buffer) {
    3658                super.construct(buffer);
    37                 if (method != null) {
    38                         buffer.append(" ").append(method);
    39                 }
    40                 if (arguments != null) {
    41                         buffer.append(arguments);
     59                Misc.throwIfNull(procedure);
     60                buffer.append(' ').append(procedure);
     61                for (Object arg : arguments) {
     62                        buffer.append(' ');
     63                        quoteArgumentIfNeeded(buffer, arg);
    4264                }
    4365                return buffer;
     
    4971        }
    5072
     73        @Override
     74        public CharSequence parseRest(CharSequence rest) {
     75                rest = super.parseRest(rest);
     76                Pair<CharSequence, CharSequence> p = Misc.throwIfNull(takeIdentifier(rest));
     77                this.procedure = p.first.toString();
     78                while ((p = takeString(p.second)) != null) {
     79                        arguments.add(p.first);
     80                }
     81                return null;
     82        }
     83
    5184}
  • java/main/src/main/java/com/framsticks/communication/queries/GetRequest.java

    r84 r96  
    11package com.framsticks.communication.queries;
     2
     3import java.util.ArrayList;
     4import java.util.List;
     5
     6import com.framsticks.util.lang.Delimeted;
     7import com.framsticks.util.lang.Pair;
    28
    39/**
     
    511 */
    612public class GetRequest extends ApplicationRequest {
     13        protected final List<String> fields = new ArrayList<>();
     14
    715        public GetRequest() {
     16        }
     17
     18        public GetRequest fields(List<String> fields) {
     19                this.fields.clear();
     20                this.fields.addAll(fields);
     21                return this;
     22        }
     23
     24        public GetRequest field(String field) {
     25                this.fields.clear();
     26                this.fields.add(field);
     27                return this;
    828        }
    929
     
    1232                return "get";
    1333        }
     34
     35        @Override
     36        protected StringBuilder construct(StringBuilder buffer) {
     37                super.construct(buffer);
     38                if (!fields.isEmpty()) {
     39                        buffer.append(' ').append(new Delimeted<String>(",", "").append(fields.iterator()));
     40                }
     41                return buffer;
     42        }
     43
     44        /**
     45         * @return the fields
     46         */
     47        public List<String> getFields() {
     48                return fields;
     49        }
     50
     51        @Override
     52        public CharSequence parseRest(CharSequence rest) {
     53                rest = super.parseRest(rest);
     54                Pair<CharSequence, CharSequence> p = takeIdentifier(rest);
     55                if (p != null) {
     56                        for (String a : p.first.toString().split(",")) {
     57                                fields.add(a);
     58                        }
     59                }
     60                return null;
     61        }
    1462}
  • java/main/src/main/java/com/framsticks/communication/queries/SetRequest.java

    r84 r96  
    11package com.framsticks.communication.queries;
     2
     3import com.framsticks.util.lang.Pair;
    24
    35/**
     
    57 */
    68public class SetRequest extends ApplicationRequest {
     9
     10        protected String field;
    711        protected String value;
    812
    913        public SetRequest() {
     14        }
     15
     16        public SetRequest field(String field) {
     17                this.field = field;
     18                return this;
    1019        }
    1120
     
    1726        @Override
    1827        protected StringBuilder construct(StringBuilder buffer) {
    19                 super.construct(buffer);
    20                 if (value != null) {
    21                         buffer.append(" \"").append(value).append("\"");
    22                 }
    23                 return buffer;
     28                return quoteArgumentIfNeeded(super.construct(buffer).append(' ').append(field).append(' '), value);
    2429        }
     30
    2531        @Override
    2632        public String getCommand() {
    2733                return "set";
    2834        }
     35
     36
     37        @Override
     38        public CharSequence parseRest(CharSequence rest) {
     39                final Pair<CharSequence, CharSequence> fp = takeString(super.parseRest(rest));
     40                field = fp.first.toString();
     41                final Pair<CharSequence, CharSequence> vp = takeString(fp.second);
     42                value = vp.first.toString();
     43
     44                return vp.second;
     45        }
     46
     47        /**
     48         * @return the field
     49         */
     50        public String getField() {
     51                return field;
     52        }
     53
     54        /**
     55         * @return the value
     56         */
     57        public String getValue() {
     58                return value;
     59        }
    2960}
  • java/main/src/main/java/com/framsticks/communication/queries/UseRequest.java

    r84 r96  
    11package com.framsticks.communication.queries;
     2
     3import com.framsticks.util.lang.Strings;
    24
    35/**
     
    1921        @Override
    2022        protected StringBuilder construct(StringBuilder buffer) {
    21                 return buffer.append(' ').append(feature);
     23                return buffer.append(feature);
    2224        }
    2325
    2426        @Override
    25         public void parseRest(String rest) {
    26                 feature = rest;
     27        public CharSequence parseRest(CharSequence rest) {
     28                feature = rest.toString();
     29                Strings.assureNotEmpty(feature);
     30                return null;
    2731        }
    2832
  • java/main/src/main/java/com/framsticks/communication/queries/VersionRequest.java

    r84 r96  
    2323
    2424        @Override
    25         public void parseRest(String rest) {
    26                 version = Numbers.parse(rest, Integer.class);
     25        public CharSequence parseRest(CharSequence rest) {
     26                version = Numbers.parse(rest.toString(), Integer.class);
     27                return null;
    2728        }
    2829
    2930        @Override
    3031        protected StringBuilder construct(StringBuilder buffer) {
    31                 return buffer.append(' ').append(version);
     32                return buffer.append(version);
    3233        }
    3334
  • java/main/src/main/java/com/framsticks/communication/util/LoggingStateCallback.java

    r85 r96  
    22
    33import com.framsticks.communication.StateCallback;
     4import com.framsticks.util.FramsticksException;
     5
    46import org.apache.log4j.Logger;
    57
     
    1820
    1921        @Override
    20         public void call(Exception e) {
    21                 if (e != null) {
    22                         logger.error("failed to " + message + " with " + e);
    23                         return;
    24                 }
     22        public void handle(FramsticksException e) {
     23                logger.error("failed to " + message + " with " + e);
     24        }
     25
     26        @Override
     27        public void callImpl() {
    2528                logger.debug(message);
    2629        }
  • java/main/src/main/java/com/framsticks/core/Framsticks.java

    r90 r96  
    33import com.framsticks.params.annotations.FramsClassAnnotation;
    44import com.framsticks.parsers.XmlLoader;
     5import com.framsticks.util.dispatching.Joinable;
    56import com.framsticks.util.dispatching.JoinableCollection;
    67import com.framsticks.util.dispatching.Monitor;
     
    1516 */
    1617@FramsClassAnnotation
    17 public class Framsticks extends JoinableCollection<Entity> {
     18public class Framsticks extends JoinableCollection<Joinable> {
    1819        private static final Logger log = Logger.getLogger(Framsticks.class);
    1920
     
    2829        public static void main(final String[] args) {
    2930
    30                 new Monitor(loadConfiguration(Framsticks.class.getResourceAsStream("/configs/framsticks.xml")))
    31                         .use()
    32                         .waitFor()
    33                         .drop()
    34                         .join();
     31                new Monitor(loadConfiguration(Framsticks.class.getResourceAsStream("/configs/framsticks.xml"))).use().waitFor().drop().join();
    3532
    36                 log.info("exiting main");
     33                log.debug("exiting main");
    3734        }
    3835
  • java/main/src/main/java/com/framsticks/core/Instance.java

    r90 r96  
    11package com.framsticks.core;
    2 
    3 import java.util.HashSet;
    4 import java.util.Iterator;
    5 import java.util.LinkedList;
    6 import java.util.List;
    7 import java.util.Set;
    82
    93import javax.annotation.Nonnull;
    104
    11 import org.apache.log4j.Logger;
    12 
    13 import com.framsticks.communication.File;
    145import com.framsticks.params.AccessInterface;
    156import com.framsticks.params.CompositeParam;
    16 import com.framsticks.params.ConstructionException;
    177import com.framsticks.params.FramsClass;
    18 import com.framsticks.params.ListAccess;
    19 import com.framsticks.params.Param;
    20 import com.framsticks.params.ParamsPackage;
    218import com.framsticks.params.Registry;
    229import com.framsticks.params.ValueParam;
    23 import com.framsticks.params.annotations.AutoAppendAnnotation;
    24 import com.framsticks.params.annotations.FramsClassAnnotation;
    25 import com.framsticks.params.types.ObjectParam;
    2610import com.framsticks.params.types.ProcedureParam;
    27 import com.framsticks.parsers.Loaders;
    28 import com.framsticks.parsers.MultiParamLoader;
    29 import com.framsticks.util.FramsticksException;
    3011import com.framsticks.util.StateFunctor;
    31 import com.framsticks.util.UnsupportedOperationException;
    32 import com.framsticks.util.dispatching.Dispatching;
     12import com.framsticks.util.dispatching.Dispatcher;
    3313import com.framsticks.util.dispatching.Future;
    34 import com.framsticks.util.dispatching.RunAt;
    35 import com.framsticks.util.dispatching.Thread;
    36 import com.framsticks.util.lang.Casting;
     14import com.framsticks.util.dispatching.Joinable;
    3715
    38 /**
    39  * @author Piotr Sniegowski
    40  */
    41 @FramsClassAnnotation
    42 public abstract class Instance extends Thread<Instance> implements Entity {
     16public interface Instance extends Dispatcher<Instance>, Joinable {
    4317
    44         private static final Logger log = Logger.getLogger(Instance.class.getName());
     18        public @Nonnull Node getRoot();
     19        public @Nonnull void setRoot(Node node);
    4520
    46         private Node root;
     21        public @Nonnull AccessInterface prepareAccess(CompositeParam param);
     22        public void takeAllFrom(Registry source);
    4723
    48         protected @Nonnull Node setRoot(CompositeParam param, Object object) {
    49                 // if (isRootAssigned()) {
    50                 //      throw new FramsticksException().msg("root is already assigned");
    51                 // }
    52                 // assert isActive();
    53                 root = new Node(param, object);
    54                 return root;
    55         }
     24        public void addListener(InstanceListener listener);
     25        public void removeListener(InstanceListener listener);
    5626
    57         protected @Nonnull Node getRoot() {
    58                 // assert isActive();
    59                 assert root != null;
    60                 return root;
    61         }
     27        public void notifyOfFetch(Path path);
    6228
    63         public boolean isRootAssigned() {
    64                 // assert isActive();
    65                 return root != null;
    66         }
     29        public FramsClass getInfoFromCache(String id);
    6730
    68         protected Set<InstanceListener> listeners = new HashSet<InstanceListener>();
     31        public void putInfoIntoCache(FramsClass framclass);
    6932
    70         public Instance() {
    71                 setName("entity");
    72         }
    73 
    74         protected void fetchInfo(Path path, Future<FramsClass> future) {
    75                 future.result(null, new UnsupportedOperationException());
    76         }
    77 
    78         public void resolve(Path path, Future<Path> future) {
    79                 assert isActive();
    80                 assert path.isOwner(this);
    81                 if (path.getTop().getObject() != null) {
    82                         future.result(path, null);
    83                         return;
    84                 }
    85                 AccessInterface access = bindAccess(path.getUnder());
    86                 Object object = access.get(path.getTop().getParam(), Object.class);
    87                 if (object == null) {
    88                         future.result(path, null);
    89                         return;
    90                 }
    91                 future.result(path.appendResolution(object), null);
    92         }
     33        public void resolve(Path path, Future<Path> future);
    9334
    9435        /** This is part of the Instance interface.
    9536         *
    9637         */
    97         public abstract void fetchValue(Path path, Param param, StateFunctor stateFunctor);
     38        public void fetchValue(Path path, ValueParam param, StateFunctor stateFunctor);
    9839
    9940        /** This is part of the Instance interface.
    10041         *
    10142         */
    102         public abstract void fetchValues(Path path, StateFunctor stateFunctor);
     43        public void fetchValues(Path path, StateFunctor stateFunctor);
    10344
    10445        /** This is part of the Instance interface.
    10546         *
    10647         */
    107         public abstract void call(Path path, ProcedureParam param, Object[] arguments, StateFunctor stateFunctor);
     48        public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future);
    10849
    109         protected void tryRegisterOnChangeEvents(Path path) {
     50        public void storeValue(Path path, ValueParam param, Object value, StateFunctor stateFunctor);
    11051
    111         }
     52        public void fetchInfo(Path path, Future<FramsClass> future);
    11253
    113         public void storeValue(Path path, Param param, Object value, final StateFunctor stateFunctor) {
    114                 assert isActive();
    115                 dispatch(new RunAt<Instance>() {
    116                         @Override
    117                         public void run() {
    118                                 stateFunctor.call(new UnsupportedOperationException());
    119                         }
    120                 });
    121         }
    122 
    123         protected void fireRun(Exception e) {
    124                 for (InstanceListener l : this.listeners) {
    125                         l.onRun(e);
    126                 }
    127         }
    128 
    129         protected void fireStop(Exception e) {
    130                 for (InstanceListener l : this.listeners) {
    131                         l.onStop(e);
    132                 }
    133         }
    134 
    135         public void addListener(final InstanceListener listener) {
    136                 assert Dispatching.isThreadSafe();
    137                 Dispatching.dispatchIfNotActive(this, new RunAt<Instance>() {
    138                         @Override
    139                         public void run() {
    140                                 listeners.add(listener);
    141                         }
    142                 });
    143         }
    144 
    145         public void removeListener(final InstanceListener listener) {
    146                 assert Dispatching.isThreadSafe();
    147                 Dispatching.dispatchIfNotActive(this, new RunAt<Instance>() {
    148                         @Override
    149                         public void run() {
    150                                 listeners.remove(listener);
    151                         }
    152                 });
    153         }
    154 
    155         protected void fireListChange(Path path, ListChange change) {
    156                 assert isActive();
    157                 for (InstanceListener l : this.listeners) {
    158                         l.onListChange(path, change);
    159                 }
    160         }
    161 
    162         protected void fireFetch(Path path) {
    163                 assert isActive();
    164                 for (InstanceListener l : this.listeners) {
    165                         l.onFetch(path);
    166                 }
    167         }
    168 
    169         public final FramsClass getInfoFromCache(Path path) {
    170                 return getInfoFromCache(path.getTop().getParam().getContainedTypeName());
    171         }
    172 
    173         public FramsClass getInfoFromCache(String id) {
    174                 assert isActive();
    175                 return registry.getFramsClass(id);
    176         }
    177 
    178         protected Registry registry = new Registry();
    179 
    180         public AccessInterface createAccess(String name) throws ConstructionException {
    181                 assert isActive();
    182                 return registry.createAccess(name);
    183         }
    184 
    185         // TODO: make ValueParam
    186         public <T> T get(Node node, Param childParam, Class<T> type) {
    187                 return bindAccess(node).get((ValueParam) childParam, type);
    188         }
    189 
    190         public void findInfo(final Path path, final Future<FramsClass> future) {
    191                 assert isActive();
    192                 final String name = path.getTop().getParam().getContainedTypeName();
    193                 final FramsClass framsClass = getInfoFromCache(name);
    194                 if (framsClass != null) {
    195                         log.trace("info for " + name + " found in cache");
    196                         future.result(framsClass, null);
    197                         return;
    198                 }
    199                 fetchInfo(path, future);
    200         }
    201 
    202         public final AccessInterface bindAccess(String path) {
    203                 return bindAccess(getPath(path));
    204         }
    205 
    206         public final AccessInterface bindAccess(Node node) {
    207                 assert isActive();
    208                 assert node.getObject() != null;
    209 
    210                 try {
    211                         AccessInterface access = registry.prepareAccess(node.getParam());
    212                         if (access == null) {
    213                                 throw new FramsticksException().msg("failed to prepare access for param").arg("param", node.getParam());
    214                         }
    215                         return access.select(node.getObject());
    216                 } catch (ConstructionException e) {
    217                         log.error("failed to bind access for " + node.getParam() + ": " + e);
    218                 }
    219                 return null;
    220         }
    221 
    222         public final <T> T getParam(Path path, String id, Class<T> type) {
    223                 return Casting.tryCast(type, registry.prepareAccess(path.getTop().getParam()).getParam(id));
    224         }
    225 
    226         public final AccessInterface bindAccess(Path path) {
    227                 path.assureResolved();
    228                 return bindAccess(path.getTop());
    229         }
    230 
    231         public void resolve(final String targetPath, final Future<Path> future) {
    232                 assert isActive();
    233                 final Path path = getPath(targetPath);
    234                 resolve(path, new Future<Path>() {
    235                         @Override
    236                         public void result(Path result, Exception e) {
    237                                 assert isActive();
    238                                 if (e != null) {
    239                                         future.result(path, e);
    240                                         return;
    241                                 }
    242                                 if (path.isResolved(targetPath)) {
    243                                         future.result(path, null);
    244                                         return;
    245                                 }
    246                                 if (path.isResolved()) {
    247                                         future.result(path, new Exception("testing"));
    248                                         return;
    249                                 }
    250                                 resolve(targetPath, future);
    251                         }
    252                 });
    253         }
    254 
    255         public void resolveAndFetch(final String targetPath, final Future<Path> future) {
    256                 assert isActive();
    257                 resolve(targetPath, new Future<Path>() {
    258                         @Override
    259                         public void result(final Path path, Exception e) {
    260                                 if (e != null) {
    261                                         future.result(path, e);
    262                                         return;
    263                                 }
    264                                 assert path.isResolved(targetPath);
    265                                 fetchValues(path, new StateFunctor() {
    266                                         @Override
    267                                         public void call(Exception e) {
    268                                                 future.result(path, e);
    269                                         }
    270                                 });
    271                         }
    272                 });
    273         }
    274 
    275         public Path createIfNeeded(String path) {
    276                 Path p;
    277                 while (!(p = getPath(path)).isResolved(path)) {
    278                         create(p);
    279                 }
    280                 return p;
    281         }
    282 
    283         public Path createIfNeeded(Path path) {
    284                 assert isActive();
    285                 if (path.isResolved()) {
    286                         return path;
    287                 }
    288                 return create(path);
    289         }
    290 
    291         public Path create(Path path) {
    292                 assert isActive();
    293                 assert !path.isResolved();
    294                 Path resolved = path.tryFindResolution();
    295                 if (!resolved.isResolved()) {
    296                         log.debug("creating: " + path);
    297                         AccessInterface access = registry.prepareAccess(path.getTop().getParam());
    298                         assert access != null;
    299                         Object child = access.createAccessee();
    300                         assert child != null;
    301                         if (path.size() == 1) {
    302                                 setRoot(getRoot().getParam(), child);
    303                         } else {
    304                                 bindAccess(path.getUnder()).set(path.getTop().getParam(), child);
    305                         }
    306                         resolved = path.appendResolution(child);
    307                 }
    308                 tryRegisterOnChangeEvents(resolved);
    309                 return resolved;
    310         }
    311 
    312 
    313 
    314 
    315         public @Nonnull FramsClass processFetchedInfo(File file) {
    316                 assert isActive();
    317                 FramsClass framsClass = Loaders.loadFramsClass(file.getContent());
    318                 if ("/".equals(file.getPath())) {
    319                         if (getRoot().getParam().getContainedTypeName() == null) {
    320                                 setRoot(Param.build().name("Instance").id(getName()).type("o " + framsClass.getId()).finish(CompositeParam.class), getRoot().getObject());
    321                         }
    322                 }
    323                 registry.putFramsClass(framsClass);
    324                 return framsClass;
    325         }
    326 
    327         public void processFetchedValues(Path path, List<File> files) {
    328                 assert isActive();
    329                 assert files.size() == 1;
    330                 assert path.isTheSame(files.get(0).getPath());
    331                 Node node = path.getTop();
    332                 MultiParamLoader loader = new MultiParamLoader();
    333                 loader.setNewSource(files.get(0).getContent());
    334                 loader.addBreakCondition(MultiParamLoader.Status.AfterObject);
    335 
    336                 try {
    337                         if (node.getParam() instanceof ObjectParam) {
    338                                 loader.addAccessInterface(bindAccess(node));
    339                                 loader.go();
    340                                 fireFetch(path);
    341                                 return;
    342                         }
    343 
    344                         ListAccess listAccess = ((ListAccess)bindAccess(node));
    345                         assert listAccess != null;
    346                         listAccess.clearValues();
    347 
    348                         AccessInterface elementAccess = listAccess.getElementAccess();
    349                         loader.addAccessInterface(elementAccess);
    350                         MultiParamLoader.Status status;
    351                         while ((status = loader.go()) != MultiParamLoader.Status.Finished) {
    352                                 if (status == MultiParamLoader.Status.AfterObject) {
    353                                         AccessInterface accessInterface = loader.getLastAccessInterface();
    354 
    355                                         String id = listAccess.computeIdentifierFor(accessInterface.getSelected());
    356                                         //TODO listAccessParam
    357                                         Param param = Param.build().forAccess(accessInterface).id(id).finish();
    358                                         Object child = accessInterface.getSelected();
    359                                         accessInterface.select(null);
    360                                         assert child != null;
    361                                         bindAccess(node).set((ValueParam) param, child);
    362                                 }
    363                         }
    364 
    365                         fireFetch(path);
    366                 } catch (Exception e) {
    367                         log.error("exception occurred while loading: " + e);
    368                 }
    369 
    370         }
    371 
    372         public static Iterator<String> splitPath(String path) {
    373                 List<String> list = new LinkedList<String>();
    374                 for (String s : path.split("/")) {
    375                         if (!s.isEmpty()) {
    376                                 list.add(s);
    377                         }
    378                 }
    379                 return list.iterator();
    380         }
    381 
    382         public Registry getRegistry() {
    383                 return registry;
    384         }
    385 
    386         public Path getPath(String textual) {
    387                 return Path.build().resolve(this, textual).finish();
    388         }
    389 
    390         public Path getRootPath() {
    391                 return getPath("/");
    392         }
    393 
    394         @AutoAppendAnnotation
    395         public void usePackage(ParamsPackage paramsPackage) {
    396                 log.debug("using package " + paramsPackage + " in instance " + this);
    397                 paramsPackage.register(registry);
    398         }
    399 
    400         @AutoAppendAnnotation
    401         public void takeFromRegistry(Registry registry) {
    402                 log.debug("taking from registry " + registry + " in instance " + this);
    403                 this.registry.takeAllFrom(registry);
    404         }
    405 
    406         @Override
    407         protected void joinableStart() {
    408                 dispatch(new RunAt<Instance>() {
    409                         @Override
    410                         public void run() {
    411                                 if (!isRootAssigned()) {
    412                                         setRoot(Param.build().name("Instance").id(getName()).type("o").finish(CompositeParam.class), null);
    413                                 }
    414                         }
    415                 });
    416                 super.joinableStart();
    417         }
    418 
     54        public Path create(Path path);
    41955}
    420 
  • java/main/src/main/java/com/framsticks/core/ObjectInstance.java

    r90 r96  
    55import com.framsticks.params.AccessInterface;
    66import com.framsticks.params.CompositeParam;
     7import com.framsticks.params.FramsClass;
    78import com.framsticks.params.Param;
     9import com.framsticks.params.ValueParam;
    810import com.framsticks.params.annotations.AutoAppendAnnotation;
    911import com.framsticks.params.annotations.FramsClassAnnotation;
     12import com.framsticks.util.UnsupportedOperationException;
    1013import com.framsticks.params.types.ProcedureParam;
    1114import com.framsticks.util.FramsticksException;
    1215import com.framsticks.util.StateFunctor;
     16import com.framsticks.util.dispatching.Future;
     17// import static com.framsticks.core.InstanceUtils.*;
    1318
    1419@FramsClassAnnotation
    15 public class ObjectInstance extends Instance {
     20public class ObjectInstance extends AbstractInstance {
    1621        private static final Logger log = Logger.getLogger(ObjectInstance.class);
    1722
     
    2025                registry.registerAndBuild(object.getClass());
    2126                AccessInterface access = registry.createAccess(object.getClass());
    22                 setRoot(Param.build().forAccess(access).id(getName()).finish(CompositeParam.class), object);
     27                setRoot(new Node(Param.build().forAccess(access).id(getName()).finish(CompositeParam.class), object));
    2328        }
    2429
     
    4348                log.debug("requesting: " + path);
    4449                fireFetch(path);
    45                 stateFunctor.call(null);
     50                stateFunctor.call();
    4651        }
    4752
    4853        @Override
    49         public void fetchValue(Path path, Param param, StateFunctor stateFunctor) {
     54        public void fetchValue(Path path, ValueParam param, StateFunctor stateFunctor) {
    5055                assert isActive();
    5156                fireFetch(path);
    52                 stateFunctor.call(null);
     57                stateFunctor.call();
    5358        }
    5459
    5560        @Override
    56         public void call(Path path, ProcedureParam param, Object[] arguments, StateFunctor stateFunctor) {
     61        public void call(Path path, ProcedureParam param, Object[] arguments, Future<Object> future) {
    5762                assert isActive();
    5863                try {
    59                         bindAccess(path).call(param, arguments);
    60                         stateFunctor.call(null);
     64                        future.pass(InstanceUtils.bindAccess(path).call(param, arguments));
    6165                } catch (FramsticksException e) {
    62                         stateFunctor.call(e);
     66                        future.handle(e);
    6367                }
    6468        }
     69
     70        @Override
     71        public void fetchInfo(Path path, Future<FramsClass> future) {
     72                assert isActive();
     73                Path p = path.tryResolveIfNeeded();
     74                Class<?> javaClass = p.getTopObject().getClass();
     75                FramsClass framsClass = registry.registerReflectedIfNeeded(javaClass);
     76                if (framsClass != null) {
     77                        future.pass(framsClass);
     78                } else {
     79                        future.handle(new FramsticksException().msg("failed to find info for class").arg("java class", javaClass));
     80                }
     81        }
     82
     83        @Override
     84        public void resolve(Path path, Future<Path> future) {
     85                assert isActive();
     86                assert path.isOwner(this);
     87                if (path.getTop().getObject() != null) {
     88                        future.pass(path);
     89                        return;
     90                }
     91                AccessInterface access = InstanceUtils.bindAccess(this, path.getUnder());
     92                Object object = access.get(path.getTop().getParam(), Object.class);
     93                if (object == null) {
     94                        future.pass(path);
     95                        return;
     96                }
     97                future.pass(path.appendResolution(object));
     98        }
     99
     100        @Override
     101        public void storeValue(Path path, ValueParam param, Object value, final StateFunctor stateFunctor) {
     102                assert isActive();
     103                stateFunctor.handle(new UnsupportedOperationException());
     104        }
     105
     106        @Override
     107        public Path create(Path path) {
     108                assert isActive();
     109                assert !path.isResolved();
     110                throw new UnsupportedOperationException();
     111        }
     112
    65113}
  • java/main/src/main/java/com/framsticks/core/Path.java

    r90 r96  
    1111import java.util.List;
    1212
     13import javax.annotation.Nonnull;
    1314import javax.annotation.concurrent.Immutable;
    1415
     
    3233                }
    3334                try {
    34                         instance.registry.prepareAccess(param);
     35                        instance.prepareAccess(param);
    3536                        return child;
    3637                } catch (FramsticksException e) {
     
    119120                }
    120121
    121                 public PathBuilder resolve(Instance instance, String textual) {
     122                public static Iterator<String> splitPath(String path) {
     123                        List<String> list = new LinkedList<String>();
     124                        for (String s : path.split("/")) {
     125                                if (!s.isEmpty()) {
     126                                        list.add(s);
     127                                }
     128                        }
     129                        return list.iterator();
     130                }
     131
     132                public PathBuilder resolve(@Nonnull Instance instance, String textual) {
    122133
    123134                        assert nodes.isEmpty();
     
    129140
    130141                        StringBuilder b = new StringBuilder();
    131                         Iterator<String> i = Instance.splitPath(textual);
     142                        Iterator<String> i = splitPath(textual);
    132143                        while (i.hasNext() && current.getObject() != null) {
    133                                 AccessInterface access = instance.registry.prepareAccess(current.getParam());
     144                                AccessInterface access = instance.prepareAccess(current.getParam());
    134145                                if (access == null) {
    135146                                        break;
     
    205216        }
    206217
    207         public final Instance getInstance() {
     218        public final @Nonnull Instance getInstance() {
    208219                assert Dispatching.isThreadSafe();
    209220                return instance;
    210221        }
    211222
     223        public Path tryResolveIfNeeded() {
     224                if (isResolved()) {
     225                        return this;
     226                }
     227                return tryFindResolution();
     228        }
    212229
    213230        /** Attach resolution at end, if available.
     
    221238                        return Path.build().resolve(instance, "/").finish();//appendResolution(instance.root.object);
    222239                }
    223                 Object child = getKnownChild(instance, instance.bindAccess(getUnder()), getTop().getParam());
     240                Object child = getKnownChild(instance, InstanceUtils.bindAccess(instance, getUnder()), getTop().getParam());
    224241                if (child == null) {
    225242                        return this;
     
    266283                }
    267284        }
     285
     286        public static Path to(@Nonnull Instance instance, String textual) {
     287                return Path.build().resolve(instance, textual).finish();
     288        }
    268289}
    269290
  • java/main/src/main/java/com/framsticks/diagnostics/Diagnostics.java

    r88 r96  
    11package com.framsticks.diagnostics;
    2 
    32
    43import java.util.Date;
     
    1413import com.framsticks.core.AbstractInstanceListener;
    1514import com.framsticks.core.Instance;
     15import com.framsticks.core.Path;
    1616import com.framsticks.dumping.PrintWriterSink;
    1717import com.framsticks.dumping.SaveStream;
    1818import com.framsticks.params.annotations.AutoAppendAnnotation;
    1919import com.framsticks.remote.RecursiveFetcher;
     20import com.framsticks.util.FramsticksException;
    2021import com.framsticks.util.Logging;
    2122import com.framsticks.util.PeriodicTask;
     
    2829 */
    2930public class Diagnostics extends JoinableCollection<Instance> {
    30         private static final Logger log =
    31                 Logger.getLogger(Diagnostics.class);
     31        private static final Logger log = Logger.getLogger(Diagnostics.class);
    3232
    3333
     
    5959
    6060                                                        log.info("starting periodic dump");
    61                                                         new RecursiveFetcher(instance, instance.getRootPath(), new StateFunctor() {
     61                                                        new RecursiveFetcher(instance, Path.to(instance, "/"), new StateFunctor() {
    6262                                                                @Override
    63                                                                 public void call(Exception e) {
    64                                                                         if (Logging.log(log, "recursively fetch", instance, e)) {
    65                                                                                 again();
    66                                                                                 return;
    67                                                                         }
     63                                                                public void handle(FramsticksException e) {
     64                                                                        Logging.log(log, "recursively fetch", instance, e);
     65                                                                        again();
     66                                                                }
     67
     68                                                                @Override
     69                                                                public void call() {
    6870                                                                        log.info("instance resolved, saving");
    6971                                                                        try {
    7072                                                                                final String fileName = dumpsPath + "/" + instance + "_" + new SimpleDateFormat(dumpsFormat).format(new Date()) + ".param";
    7173                                                                                File file = new File(fileName);
    72                                                                                 new SaveStream(new PrintWriterSink(new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Encoding.getFramsticksCharset()))), instance, instance.getRootPath(), new StateFunctor() {
     74                                                                                new SaveStream(new PrintWriterSink(new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Encoding.getFramsticksCharset()))), instance, Path.to(instance, "/"), new StateFunctor() {
    7375                                                                                        @Override
    74                                                                                         public void call(Exception e) {
     76                                                                                        public void handle(FramsticksException e) {
    7577                                                                                                Logging.log(log, "periodic dump in " + fileName + " of", instance, e);
     78                                                                                                again();
     79                                                                                        }
     80
     81                                                                                        @Override
     82                                                                                        public void call() {
    7683                                                                                                again();
    7784                                                                                        }
  • java/main/src/main/java/com/framsticks/dumping/LoadStream.java

    r84 r96  
    22
    33import com.framsticks.communication.File;
     4import com.framsticks.core.InstanceUtils;
    45import com.framsticks.core.Path;
    56import com.framsticks.params.ListSource;
     
    1920 * @author Piotr Sniegowski
    2021 */
    21 public class LoadStream {
     22public class LoadStream extends Stream {
    2223
    2324        private final static Logger log = Logger.getLogger(LoadStream.class.getName());
     
    4647                        while ((line = stream.readLine()) != null) {
    4748                                if (query == null) {
    48                                         query = Strings.splitIntoPair(line, ' ', "\n");
     49                                        query = Strings.splitIntoPair(line, ' ', "");
    4950                                        files = new LinkedList<File>();
    5051                                        log.trace("loading " + line);
     
    5859                                        if (line.equals("ok")) {
    5960                                                if (query.first.equals("get")) {
    60                                                         Path path = instance.createIfNeeded(query.second);
    61                                                         instance.processFetchedValues(path, files);
     61                                                        Path path = InstanceUtils.createIfNeeded(instance, query.second);
     62                                                        InstanceUtils.processFetchedValues(path, files);
    6263                                                } else if (query.first.equals("info")) {
    6364                                                        assert files.size() == 1;
    64                                                         instance.processFetchedInfo(files.get(0));
     65                                                        InstanceUtils.processFetchedInfo(instance, files.get(0));
    6566                                                } else {
    6667                                                        assert false;
     
    8283                } catch (IOException e) {
    8384                        log.error("failed to load: " + e);
    84                         future.result(null, e);
     85                        future.handle(new FramsticksException().msg("failed to load stream").cause(e));
    8586                        return;
    8687                }
    8788                log.info("loaded in: " + stopwatch);
    88                 future.result(instance.getPath(mountPath.getTextual()), null);
     89                future.pass(Path.to(instance, mountPath.getTextual()));
    8990        }
    9091
  • java/main/src/main/java/com/framsticks/dumping/SaveStream.java

    r90 r96  
    11package com.framsticks.dumping;
    22
     3import static com.framsticks.core.InstanceUtils.*;
    34import com.framsticks.core.Node;
    45import com.framsticks.core.Path;
     
    2223 * @author Piotr Sniegowski
    2324 */
    24 public class SaveStream {
     25public class SaveStream extends Stream {
    2526
    2627        private final static Logger log = Logger.getLogger(SaveStream.class.getName());
     
    5556                assert instance.isActive();
    5657                log.info("stored in " + stopwatch);
    57                 stateFunctor.call(null);
     58                stateFunctor.call();
    5859        }
    5960
     
    6364                        log.debug("path " + path + " is not resolved - skipping");
    6465                } else {
    65                         AccessInterface access = instance.bindAccess(path);
     66                        AccessInterface access = bindAccess(path);
    6667                        assert access != null;
    6768                        FramsClass framsClass = access.getFramsClass();
     
    8586                        for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
    8687                                final Path childPath = path.appendNode(new Node(p, access.get(p, Object.class)));
    87                                 if (childPath.isResolved() && instance.getInfoFromCache(childPath) != null) {
     88                                if (childPath.isResolved() && getInfoFromCache(childPath) != null) {
    8889                                        dispatchWrite(childPath);
    8990                                }
  • java/main/src/main/java/com/framsticks/gui/Browser.java

    r90 r96  
    55import com.framsticks.params.annotations.FramsClassAnnotation;
    66import com.framsticks.params.annotations.ParamAnnotation;
    7 import com.framsticks.util.Logging;
    87import com.framsticks.util.dispatching.AbstractJoinable;
    98import com.framsticks.util.dispatching.Dispatcher;
     
    2221import java.util.ArrayList;
    2322import java.util.List;
    24 import java.util.Map;
    2523import com.framsticks.util.dispatching.RunAt;
    2624
     
    2927 */
    3028@FramsClassAnnotation
    31 public class Browser extends AbstractJoinable implements Dispatcher<Browser>, Entity, JoinableParent {
     29public class Browser extends AbstractJoinable implements Dispatcher<Browser>, JoinableParent {
    3230
    3331        private static final Logger log = Logger.getLogger(Browser.class.getName());
     
    7270                        @Override
    7371                        public void run() {
    74                                 i.resolveAndFetch(path, new Future<Path>() {
     72                                InstanceUtils.resolveAndFetch(i, path, new Future<Path>(future) {
    7573                                        @Override
    76                                         public void result(final Path p, Exception e) {
    77                                                 Logging.log(log, "auto resolve path", path, e);
    78                                                 if (future != null) {
    79                                                         future.result(p, e);
    80                                                 }
    81                                                 if (e == null) {
    82                                                         mainFrame.dispatch(new RunAt<Frame>() {
    83                                                                 @Override
    84                                                                 public void run() {
    85                                                                         mainFrame.goTo(p);
    86                                                                 }
    87                                                         });
    88                                                 }
     74                                        protected void result(final Path p) {
     75                                                future.pass(p);
     76                                                mainFrame.dispatch(new RunAt<Frame>() {
     77                                                        @Override
     78                                                        public void run() {
     79                                                                mainFrame.goTo(p);
     80                                                        }
     81                                                });
    8982                                        }
    9083                                });
     
    132125                                @Override
    133126                                public void run() {
    134                                         final Path p = i.getRootPath();
     127                                        final Path p = Path.to(i, "/");
    135128                                        dispatch(new RunAt<Browser>() {
    136129                                                @Override
     
    194187         * @return the instances
    195188         */
    196         public Map<String, Instance> getInstances() {
    197                 return instances.getObservables();
     189        public JoinableCollection<Instance> getInstances() {
     190                return instances;
    198191        }
    199192
     
    254247        @Override
    255248        protected void joinableFinish() {
    256                 // TODO Auto-generated method stub
    257249
    258250        }
  • java/main/src/main/java/com/framsticks/gui/Frame.java

    r90 r96  
    11package com.framsticks.gui;
    22
    3 import com.framsticks.core.Entity;
    43import com.framsticks.core.Instance;
    54import com.framsticks.core.Path;
     
    3231 */
    3332@SuppressWarnings("serial")
    34 public class Frame extends JoinableCollection<Instance> implements Entity, Dispatcher<Frame> {
     33public class Frame extends JoinableCollection<Instance> implements Dispatcher<Frame> {
    3534
    3635        private static final Logger log = Logger.getLogger(Frame.class.getName());
     
    8281                        public void windowClosing(WindowEvent e) {
    8382                                log.info("received closing");
    84                                 joinableFinish();
     83                                interrupt();
    8584                        }
    8685                });
     
    268267                assert isActive();
    269268                Instance instance = path.getInstance();
    270                 assert browser.getInstances().containsValue(instance);
     269                assert browser.getInstances().contains(instance);
    271270
    272271                InstanceAtFrame e = new InstanceAtFrame(instance, this);
  • java/main/src/main/java/com/framsticks/gui/TreeNode.java

    r90 r96  
    55import com.framsticks.communication.util.LoggingStateCallback;
    66import com.framsticks.core.Instance;
     7import com.framsticks.core.InstanceUtils;
    78import com.framsticks.core.ListChange;
    89import com.framsticks.core.Path;
     
    1516import com.framsticks.remote.*;
    1617import com.framsticks.util.lang.Casting;
     18import com.framsticks.util.lang.Holder;
    1719import com.framsticks.util.swing.TooltipConstructor;
    1820import com.framsticks.util.dispatching.Future;
     21import com.framsticks.util.AbstractStateFunctor;
    1922import com.framsticks.util.Logging;
    20 import com.framsticks.util.StateFunctor;
    2123import org.apache.log4j.Logger;
    2224import com.framsticks.util.dispatching.RunAt;
     
    2931import static com.framsticks.util.lang.Containers.filterInstanceof;
    3032import com.framsticks.util.swing.TreeNodeUtils;
     33import static com.framsticks.core.InstanceUtils.*;
    3134
    3235/**
     
    7376                assert p.getInstance().isActive();
    7477                log.debug("fetching: " + p);
    75                 p.getInstance().fetchValues(p, new StateFunctor() {
    76                         @Override
    77                         public void call(Exception e) {
    78                                 //TODO removing should stay here
     78                p.getInstance().fetchValues(p, new AbstractStateFunctor() {
     79                        @Override
     80                        public void call() {
    7981                                // reactForFetchResult(p, e);
    8082                        }
     
    140142                assert p.getInstance().isActive();
    141143                log.debug("updating children of " + this);
    142                 AccessInterface access = p.getInstance().bindAccess(p.getTop());
     144                AccessInterface access = InstanceUtils.bindAccess(p.getInstance(), p.getTop());
    143145                if (access == null) {
    144146                        return;
     
    199201                                        return;
    200202                                }
    201                                 p.getInstance().resolve(updated, new Future<Path>() {
     203                                p.getInstance().resolve(updated, new Future<Path>(Logging.logger(log, "resolve and select", TreeNode.this)) {
    202204                                        @Override
    203                                         public void result(final Path result, Exception e) {
    204                                                 if (Logging.log(log, "resolve and select", TreeNode.this, e)) {
    205                                                         return;
    206                                                 }
    207 
     205                                        protected void result(Path result) {
    208206                                                fetch(result);
    209207                                                postUpdatePath(result);
     
    231229                        return;
    232230                }
    233                 AccessInterface access = p.getInstance().bindAccess(p);
    234                 if (access == null) {
    235                         return;
    236                 }
     231                AccessInterface access = InstanceUtils.bindAccess(p);
    237232
    238233                final String tooltip = new TooltipConstructor()
     
    309304                        @Override
    310305                        public void run() {
    311                                 AccessInterface access = p.getInstance().bindAccess(p);
     306                                AccessInterface access = InstanceUtils.bindAccess(p);
    312307                                panel.pullValuesFromLocalToUser(access);
    313308
     
    501496                        return;
    502497                }
    503                 final Map<ValueControl, Object> changes = localChanges;
     498                Map<ValueControl, Object> changes = localChanges;
    504499                localChanges = null;
    505                 instanceAtFrame.getInstance().dispatch(new RunAt<Instance>() {
    506                         @Override
    507                         public void run() {
    508                                 for (Map.Entry<ValueControl, Object> e : changes.entrySet()) {
    509                                         final ValueControl key = e.getKey();
    510                                         final Path p = path;
    511                                         instanceAtFrame.getInstance().storeValue(p, e.getKey().getParam(), e.getValue(), new StateFunctor() {
     500                final Holder<Integer> counter = new Holder<>(changes.size());
     501                final Path p = path;
     502
     503                for (Map.Entry<ValueControl, Object> e : localChanges.entrySet()) {
     504                        storeValue(p, e.getKey().getParam(), e.getValue(), new AbstractStateFunctor() {
     505                                @Override
     506                                public void call() {
     507                                        counter.set(counter.get() - 1);
     508                                        if (counter.get() != 0) {
     509                                                return;
     510                                        }
     511                                        log.debug("applied changes for: " + p);
     512                                        frame.dispatch(new RunAt<Frame>() {
    512513                                                @Override
    513                                                 public void call(Exception e) {
    514                                                         changes.remove(key);
    515                                                         if (!changes.isEmpty()) {
    516                                                                 return;
    517                                                         }
    518                                                         log.debug("applied changes for: " + p);
    519                                                         frame.dispatch(new RunAt<Frame>() {
    520                                                                 @Override
    521                                                                 public void run() {
    522                                                                         fillPanelWithValues();
    523                                                                 }
    524                                                         });
     514                                                public void run() {
     515                                                        fillPanelWithValues();
    525516                                                }
    526517                                        });
    527518                                }
    528                         }
    529                 });
     519                        });
     520                }
    530521        }
    531522}
  • java/main/src/main/java/com/framsticks/gui/controls/ProcedureControl.java

    r90 r96  
    88import com.framsticks.params.ValueParam;
    99import com.framsticks.params.types.ProcedureParam;
     10import com.framsticks.util.FramsticksException;
    1011import com.framsticks.util.Logging;
    11 import com.framsticks.util.StateFunctor;
     12import com.framsticks.util.dispatching.Future;
    1213import com.framsticks.util.dispatching.RunAt;
    1314
     
    6768                                        @Override
    6869                                        public void run() {
    69                                                 path.getInstance().call(path, getParam(), arguments.toArray(), new StateFunctor() {
     70                                                path.getInstance().call(path, getParam(), arguments.toArray(), new Future<Object>() {
     71
    7072                                                        @Override
    71                                                         public void call(Exception e) {
     73                                                        public void handle(FramsticksException e) {
    7274                                                                Logging.log(log, "call procedure", path, e);
     75                                                        }
     76
     77                                                        @Override
     78                                                        public void result(Object result) {
     79
    7380                                                        }
    7481                                                });
  • java/main/src/main/java/com/framsticks/gui/windows/console/ConsoleFrame.java

    r85 r96  
    161161                }
    162162                String commandText = commandLine.getText();
    163                 Pair<String, String> command = Strings.splitIntoPair(commandText, ' ', "\n");
     163                Pair<String, String> command = Strings.splitIntoPair(commandText, ' ', "");
    164164                Request request = Request.createRequestByTypeString(command.first);
    165165                if (request == null) {
  • java/main/src/main/java/com/framsticks/hosting/InstanceClient.java

    r90 r96  
    11package com.framsticks.hosting;
     2
     3import static com.framsticks.util.lang.Strings.assureNotEmpty;
    24
    35import com.framsticks.communication.*;
    46import com.framsticks.communication.queries.ApplicationRequest;
     7import com.framsticks.communication.queries.CallRequest;
    58import com.framsticks.communication.queries.GetRequest;
    69import com.framsticks.communication.queries.InfoRequest;
     10import com.framsticks.communication.queries.SetRequest;
    711import com.framsticks.core.Instance;
     12import com.framsticks.core.InstanceUtils;
    813import com.framsticks.core.Path;
    914import com.framsticks.params.*;
     15import com.framsticks.params.types.ProcedureParam;
    1016import com.framsticks.parsers.Savers;
    11 import com.framsticks.core.LocalInstance;
     17import com.framsticks.util.FramsticksException;
    1218import com.framsticks.util.dispatching.AbstractJoinable;
    1319import com.framsticks.util.dispatching.Dispatching;
     
    1622import com.framsticks.util.dispatching.JoinableParent;
    1723import com.framsticks.util.dispatching.JoinableState;
     24import static com.framsticks.core.InstanceUtils.*;
    1825
    1926import java.net.Socket;
    20 import java.util.ArrayList;
    2127import java.util.LinkedList;
    2228import java.util.List;
    23 import com.framsticks.util.dispatching.RunAt;
    2429
    2530/**
     
    2833public class InstanceClient extends AbstractJoinable implements RequestHandler, JoinableParent {
    2934
    30         protected final LocalInstance instance;
     35        protected final Server server;
     36        protected final Instance instance;
    3137        protected final ServerConnection connection;
    3238
    33         public InstanceClient(LocalInstance instance, Socket socket) {
    34                 this.instance = instance;
    35                 connection = new ServerConnection(socket, this);
     39        public InstanceClient(Server server, Socket socket) {
     40                this.server = server;
     41                this.instance = server.hosted;
     42                this.connection = new ServerConnection(socket, this);
    3643        }
    3744
    3845        @Override
    39         public String toString() {
    40                 return instance + "|" + connection.toString();
     46        public String getName() {
     47                return connection + " to " + server;
    4148        }
    4249
    4350        @Override
    4451        public void handle(final ApplicationRequest request, final ResponseCallback<?> responseCallback) {
    45                 instance.dispatch(new RunAt<Instance>() {
     52                assureNotEmpty(request.getPath());
     53
     54                resolve(instance, request.getPath(), new Future<Path>(responseCallback) {
    4655                        @Override
    47                         public void run() {
    48                                 final Path path = instance.getPath(request.getPath());
    49                                 if (!path.isResolved(request.getPath())) {
    50                                         responseCallback.process(new Response(false, "\"invalid path\"", null));
     56                        protected void result(final Path path) {
     57
     58                                // final AccessInterface access = instance.prepareAccess(path);
     59                                final AccessInterface access = instance.prepareAccess(path.getTop().getParam());
     60
     61                                if (request instanceof SetRequest) {
     62                                        SetRequest set = (SetRequest) request;
     63                                        //TODO Proxy - here is break of chain, instance should have hosted
     64                                        //hosted set
     65                                        AccessInterface access2 = InstanceUtils.bindAccess(path);
     66                                        int flag = access2.set(set.getField(), set.getValue());
     67
     68                                        responseCallback.process(new Response(true, Flags.write(flag, null), null));
    5169                                        return;
    5270                                }
     71
    5372                                if (request instanceof GetRequest) {
    54                                         instance.findInfo(path, new Future<FramsClass>() {
     73                                        InstanceUtils.findInfo(path, new Future<FramsClass>(responseCallback) {
    5574                                                @Override
    56                                                 public void result(FramsClass result, Exception e) {
     75                                                protected void result(FramsClass result) {
    5776                                                        if (result == null) {
    58                                                                 responseCallback.process(new Response(false, "\"failed to find info for access bind\"", null));
    59                                                                 return;
     77                                                                throw new FramsticksException().msg("failed to find info for access bind");
    6078                                                        }
    6179                                                        List<File> files = new LinkedList<File>();
    62                                                         AccessInterface access = instance.bindAccess(path);
     80                                                        AccessInterface access = bindAccess(path);
    6381
    6482                                                        if (access == null) {
     83                                                                throw new FramsticksException().msg("failed to bind access");
     84                                                        }
    6585
    66                                                                 responseCallback.process(new Response(false, "\"failed to bind access\"", null));
    67                                                                 return;
    68                                                         }
    6986                                                        ListSink sink = new ListSink();
    7087                                                        access.save(sink);
     
    7592                                        return;
    7693                                }
    77                                 if (request instanceof InfoRequest) {
    78                                         instance.findInfo(path, new Future<FramsClass>() {
     94                                if (request instanceof CallRequest) {
     95                                        final CallRequest callRequest = (CallRequest) request;
     96                                        instance.call(path, access.getFramsClass().getParamEntry(callRequest.getProcedure(), ProcedureParam.class), callRequest.getArguments().toArray(), new Future<Object>(responseCallback) {
    7997                                                @Override
    80                                                 public void result(FramsClass result, Exception e) {
    81                                                         if (result == null) {
    82                                                                 responseCallback.process(new Response(false, "\"info not found\"", null));
    83                                                                 return;
     98                                                protected void result(Object result) {
     99                                                        ListSink sink = new ListSink();
     100                                                        sink.print("Result:").breakLine();
     101                                                        sink.print("value:").print("[");
     102                                                        if (result != null) {
     103                                                                sink.print(result);
    84104                                                        }
    85                                                         ListSink sink = new ListSink();
    86                                                         Savers.saveFramsClass(sink, result);
    87                                                         List<File> files = new ArrayList<File>();
    88                                                         files.add(new File(path.getTextual(), new ListSource(sink.getOut())));
    89                                                         responseCallback.process(new Response(true, null, files));
     105                                                        sink.print("]");
     106
     107                                                        responseCallback.process(new Response(true, "", File.single(new File("", new ListSource(sink.getOut())))));
    90108                                                }
    91109                                        });
    92110                                        return;
    93111                                }
    94                                 responseCallback.process(new Response(false, "invalid", null));
     112                                if (request instanceof InfoRequest) {
     113                                        findInfo(path, new Future<FramsClass>(responseCallback) {
     114                                                @Override
     115                                                protected void result(FramsClass result) {
     116                                                        if (result == null) {
     117                                                                throw new FramsticksException().msg("info not found");
     118                                                        }
     119                                                        responseCallback.process(new Response(true, null, File.single(new File(path.getTextual(), new ListSource(Savers.saveFramsClass(new ListSink(), result).getOut())))));
     120                                                }
     121                                        });
     122                                        return;
     123                                }
     124
     125                                throw new FramsticksException().msg("invalid request type: " + request.getCommand());
    95126                        }
    96127                });
     
    122153        }
    123154
     155
    124156}
  • java/main/src/main/java/com/framsticks/params/AccessInterface.java

    r90 r96  
    7575        FramsClass getFramsClass();
    7676
    77         boolean tryAutoAppend(Object object);
     77        void tryAutoAppend(Object object);
    7878
    7979
  • java/main/src/main/java/com/framsticks/params/Flags.java

    r85 r96  
    5050
    5151        public static String write(int flags, String empty) {
    52                 Delimeted d = new Delimeted("+", empty);
     52                Delimeted<String> d = new Delimeted<String>("+", empty);
    5353                try {
    5454                        for (Field f : Flags.class.getDeclaredFields()) {
  • java/main/src/main/java/com/framsticks/params/FramsClass.java

    r90 r96  
    130130        }
    131131
    132         public <T extends Param> T castedParam(@Nonnull final Param param, @Nonnull final Class<T> type, Object name) {
     132        public @Nonnull <T extends Param> T castedParam(@Nonnull final Param param, @Nonnull final Class<T> type, Object name) {
    133133                if (param == null) {
    134134                        // return null;
     
    149149         * @return the param entry
    150150         */
    151         public <T extends Param> T getParamEntry(final int i, @Nonnull final Class<T> type) {
     151        public @Nonnull <T extends Param> T getParamEntry(final int i, @Nonnull final Class<T> type) {
    152152                return castedParam(getParam(i), type, i);
    153153        }
     
    160160         * @return the param entry
    161161         */
    162         public <T extends Param> T getParamEntry(@Nonnull final String id, @Nonnull final Class<T> type) {
     162        public @Nonnull <T extends Param> T getParamEntry(@Nonnull final String id, @Nonnull final Class<T> type) {
    163163                return castedParam(getParam(id), type, id);
    164164        }
  • java/main/src/main/java/com/framsticks/params/FramsClassBuilder.java

    r90 r96  
    2222import com.framsticks.parsers.Loaders;
    2323import com.framsticks.util.Builder;
     24import com.framsticks.util.Misc;
    2425import com.framsticks.util.lang.Containers;
    2526import com.framsticks.util.lang.Strings;
     
    7879                        // TODO: future support for enum
    7980                        // if (cl.isEnum()) {
    80                         //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
    81                         //      Enum<?>[] enums = enumType.getEnumConstants();
    82                         //      StringBuilder b = new StringBuilder();
    83 
    84                         //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
    85                         //      for (Enum<?> e : enums) {
    86                         //              b.append("~").append(e.name());
    87                         //      }
    88                         //      return b.toString();
     81                        //      Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) cl;
     82                        //      Enum<?>[] enums = enumType.getEnumConstants();
     83                        //      StringBuilder b = new StringBuilder();
     84
     85                        //      b.append("d 0 ").append(enums.length - 1).append(" 0 ");
     86                        //      for (Enum<?> e : enums) {
     87                        //              b.append("~").append(e.name());
     88                        //      }
     89                        //      return b.toString();
    8990                        // }
    9091                        if (cl.equals(Integer.class) || cl.equals(int.class)) {
     
    125126                }
    126127
    127                 builder.resultType(induceParamType(Param.build(), method.getGenericReturnType()).finish(ValueParam.class));
     128                if (!method.getReturnType().equals(Void.TYPE)) {
     129                        builder.resultType(induceParamType(Param.build(), method.getGenericReturnType()).finish(ValueParam.class));
     130                }
    128131
    129132                List<ValueParam> arguments = new ArrayList<>();
     
    337340        }
    338341
     342        @Override
     343        public String toString() {
     344                return "FramsClassBuilder for " + Misc.returnNotNull(id, "<not yet known>");
     345        }
    339346
    340347}
  • java/main/src/main/java/com/framsticks/params/ListAccess.java

    r90 r96  
    7979        //TODO it could actually be used also
    8080        @Override
    81         public boolean tryAutoAppend(Object object) {
    82                 return false;
     81        public void tryAutoAppend(Object object) {
     82                throw new InvalidOperationException();
    8383        }
    8484
  • java/main/src/main/java/com/framsticks/params/Param.java

    r90 r96  
    1717 */
    1818@Immutable
    19 @FramsClassAnnotation(id = "prop", name = "prop")
     19@FramsClassAnnotation(id = "prop", name = "prop", order = {"id", "name", "type", "flags", "help", "group", "extra"})
    2020public abstract class Param {
    2121
     
    3333
    3434        /** The getFlags stored as a bit sum. */
    35         protected final Integer flags;
     35        protected final int flags;
    3636
    3737        //TODO
    3838        /** The variable determining whether the parameter is an extra parameter. */
    39         protected final Integer extra;
     39        protected final int extra;
    4040
    4141        public Param(ParamBuilder builder) {
     
    6868        }
    6969
    70         @ParamAnnotation
     70        @ParamAnnotation(def = "0")
    7171        public Integer getFlags() {
    7272                return flags;
    7373        }
    7474
     75        @ParamAnnotation(id = "type")
    7576        public abstract String getFramsTypeName();
    7677
     
    9293
    9394        public boolean hasFlag(int flag) {
    94                 return flags != null && (flags & flag) != 0;
     95                return (flags & flag) != 0;
    9596        }
    9697
  • java/main/src/main/java/com/framsticks/params/ParamBuilder.java

    r90 r96  
    66import com.framsticks.util.Builder;
    77import com.framsticks.util.FramsticksException;
     8import com.framsticks.util.Misc;
    89import com.framsticks.util.lang.Strings;
    910
     
    4647
    4748        /** The flags stored as a bit sum. */
    48         private Integer flags = 0;
     49        private int flags = 0;
    4950
    5051        /** The parameter name. */
     
    6364        private Object def;
    6465
    65         private Integer extra;
     66        private int extra = 0;
    6667
    6768        String containedTypeName;
     
    179180                try {
    180181                        if (paramType == null) {
    181                                 throw new FramsticksException().msg("trying to finish incomplete param");
     182                                throw new FramsticksException().msg("trying to finish incomplete param while type is missing");
    182183                        }
    183184                        return paramType.getConstructor(ParamBuilder.class).newInstance(this);
     
    214215
    215216        @ParamAnnotation
    216         public ParamBuilder flags(Integer flags) {
     217        public ParamBuilder flags(int flags) {
    217218                this.flags = flags;
    218219                return this;
     
    359360         */
    360361        @ParamAnnotation
    361         public Integer getFlags() {
     362        public int getFlags() {
    362363                return flags;
    363364        }
     
    385386
    386387        @ParamAnnotation(id = "xtra")
    387         public Integer getExtra() {
     388        public int getExtra() {
    388389                return extra;
    389390        }
     
    397398
    398399        @ParamAnnotation(id = "xtra")
    399         public ParamBuilder extra(Integer extra) {
     400        public ParamBuilder extra(int extra) {
    400401                this.extra = extra;
    401402                return this;
     
    517518                }
    518519                String result = Strings.collapse(matcher.group(1));
    519                 resultType = (result != null) ? parseProcedureTypePart(result, null) : null;
     520                if (result != null) {
     521                        resultType = Param.build().type(result).finish(ValueParam.class);
     522                } else {
     523                        resultType = null;
     524                }
    520525                String arguments = matcher.group(2);
    521526                if (!Strings.notEmpty(arguments)) {
     
    524529                int number = 0;
    525530                for (String a : arguments.split(",")) {
     531                        ParamBuilder arg = Param.build();
     532
    526533                        int space = a.indexOf(' ');
    527                         String type;
    528                         String name;
    529534                        if (space == -1) {
    530                                 type = a;
    531                                 name = "arg" + number;
     535                                arg.type(a).id("arg" + number);
    532536                        } else {
    533                                 type = a.substring(0, space);
    534                                 name = a.substring(space + 1);
    535                         }
    536                         argumentsType.add(parseProcedureTypePart(type, name));
     537                                String name = a.substring(space + 1);
     538                                arg.type(a.substring(0, space)).id(name).name(name);
     539                        }
     540                        argumentsType.add(arg.finish(ValueParam.class));
    537541                        ++number;
    538542                }
     
    546550                return this;
    547551        }
     552
     553        @Override
     554        public String toString() {
     555                return "ParamBuilder for " + Misc.returnNotNull(id, "<not yet known>");
     556        }
    548557}
    549558
  • java/main/src/main/java/com/framsticks/params/PropertiesAccess.java

    r90 r96  
    9191
    9292        @Override
    93         public boolean tryAutoAppend(Object object) {
    94                 return false;
     93        public void tryAutoAppend(Object object) {
     94                throw new InvalidOperationException();
    9595        }
    9696
  • java/main/src/main/java/com/framsticks/params/ReflectionAccess.java

    r90 r96  
    378378
    379379        @Override
    380         public boolean tryAutoAppend(Object value) {
     380        public void tryAutoAppend(Object value) {
    381381                assert object != null;
    382                 for (Method m : backend.autoAppendMethods) {
    383                         if (m.getParameterTypes()[0].isAssignableFrom(value.getClass())) {
    384                                 try {
    385                                         log.trace("auto appending with value " + value + " with method " + m);
    386                                         m.invoke(object, value);
    387                                         return true;
    388                                 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | FramsticksException e) {
    389                                         throw new FramsticksException().msg("failed to auto append").cause(e).arg("value", value).arg("into object", object).arg("with method", m);
    390                                 }
    391                         }
    392                 }
    393                 return false;
     382                try {
     383                        for (Method m : backend.autoAppendMethods) {
     384                                if (m.getParameterTypes()[0].isAssignableFrom(value.getClass())) {
     385                                        try {
     386                                                log.trace("auto appending with value " + value + " with method " + m);
     387                                                m.invoke(object, value);
     388                                                return;
     389                                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | FramsticksException e) {
     390                                                throw new FramsticksException().msg("failed to auto append").cause(e).arg("with method", m);
     391                                        }
     392                                }
     393                        }
     394                        throw new FramsticksException().msg("no method found to append");
     395                } catch (FramsticksException e) {
     396                        throw e.arg("value", value).arg("into object", object);
     397                }
     398
    394399        }
    395400
  • java/main/src/main/java/com/framsticks/params/Registry.java

    r90 r96  
    4646                associate(javaClass, putFramsClass(FramsClass.build().forClass(javaClass)));
    4747                return this;
     48        }
     49
     50        public FramsClass registerReflectedIfNeeded(Class<?> javaClass) {
     51                if (!javaToFramsAssociation.containsKey(javaClass)) {
     52                        registerAndBuild(javaClass);
     53                }
     54                return javaToFramsAssociation.get(javaClass);
    4855        }
    4956
  • java/main/src/main/java/com/framsticks/params/SimpleAbstractAccess.java

    r90 r96  
    77
    88import org.apache.log4j.Logger;
     9
     10import com.framsticks.util.UnimplementedException;
    911
    1012/**
     
    177179        @Override
    178180        public void copyFrom(AccessInterface src) {
    179                 clearValues();
     181                throw new UnimplementedException();
     182                // clearValues();
    180183                //TODO: iterate over self, and pull from src
    181184                /*
     
    185188                */
    186189        }
    187 
    188 
    189 
    190190
    191191        @Override
     
    195195                for (PrimitiveParam<?> p : filterInstanceof(framsClass.getParamEntries(), PrimitiveParam.class)) {
    196196                        Object value = get(p, Object.class);
    197                         if (value == null) {
     197                        if ((value == null) || value.equals(p.getDef(Object.class))) {
    198198                                continue;
    199199                        }
  • java/main/src/main/java/com/framsticks/params/SinkInterface.java

    r77 r96  
    55 */
    66public interface SinkInterface {
    7     SinkInterface print(String str);
    8     SinkInterface print(Object obj);
    9     void breakLine();
    10     void close();
     7        SinkInterface print(String str);
     8        SinkInterface print(Object obj);
     9        void breakLine();
     10        void close();
    1111}
  • java/main/src/main/java/com/framsticks/params/types/ProcedureParam.java

    r90 r96  
    77import java.util.List;
    88
     9import javax.annotation.Nullable;
    910import javax.annotation.concurrent.Immutable;
    1011
     
    1617        private final ValueParam resultType;
    1718        private final List<ValueParam> argumentsType;
     19        private final String signatureString;
    1820
    1921        /**
     
    2426                resultType = builder.getResultType();
    2527                argumentsType = builder.getArgumentsType();
     28
     29                StringBuilder b = new StringBuilder().append("p");
     30
     31                if (resultType != null) {
     32                        b.append(" ").append(resultType.getFramsTypeName());
     33                }
     34                b.append("(");
     35                boolean first = true;
     36                for (ValueParam arg : argumentsType) {
     37                        if (first) {
     38                                first = false;
     39                        } else {
     40                                b.append(", ");
     41                        }
     42
     43                        b.append(arg.getFramsTypeName());
     44                        if (arg.getName() != null) {
     45                                b.append(" ").append(arg.getName());
     46                        }
     47                }
     48                b.append(")");
     49
     50                signatureString = b.toString();
    2651                assert argumentsType != null;
    2752        }
     
    3257        }
    3358
    34         public ValueParam getResultType() {
     59        public @Nullable ValueParam getResultType() {
    3560                return resultType;
    3661        }
     
    4267        @Override
    4368        public String getFramsTypeName() {
    44                 return "p";
     69                return signatureString;
    4570        }
    4671
  • java/main/src/main/java/com/framsticks/parsers/Loaders.java

    r88 r96  
    3232                                        return;
    3333                                }
    34                                 if (framsClassAccess.select(builder).tryAutoAppend(object)) {
    35                                         return;
    36                                 }
    37                                 throw new ConstructionException().msg("failed to interpretate object").arg("object", object);
     34                                framsClassAccess.select(builder).tryAutoAppend(object);
     35                                // throw new ConstructionException().msg("failed to interpretate object").arg("object", object);
    3836
    3937                        }
  • java/main/src/main/java/com/framsticks/parsers/Savers.java

    r86 r96  
    88 */
    99public class Savers {
    10         public static void saveFramsClass(SinkInterface sink, FramsClass framsClass) {
     10        public static <S extends SinkInterface> S saveFramsClass(S sink, FramsClass framsClass) {
    1111
    1212                AccessInterface framsClassAccess = new ReflectionAccess(FramsClass.class);
     
    1818                        paramAccess.save(sink);
    1919                }
     20                return sink;
    2021        }
    2122
  • java/main/src/main/java/com/framsticks/parsers/XmlLoader.java

    r90 r96  
    9898
    9999                        for (Object child : childrenObjects) {
    100                                 if (!access.tryAutoAppend(child)) {
    101                                         throw new FramsticksException().msg("failed to auto append").arg("child", child).arg("parent", object);
    102                                 }
     100                                access.tryAutoAppend(child);
    103101                        }
    104102                }
  • java/main/src/main/java/com/framsticks/portals/Portal.java

    r90 r96  
    44import com.framsticks.core.AbstractInstanceListener;
    55import com.framsticks.core.Instance;
     6import com.framsticks.core.InstanceUtils;
    67import com.framsticks.core.Path;
    78import com.framsticks.params.annotations.FramsClassAnnotation;
     
    6162                                        @Override
    6263                                        public void run() {
    63                                                 instance.resolve(path, new Future<Path>() {
     64                                                InstanceUtils.resolve(instance, path, new Future<Path>(Logging.logger(log, "resolve", path)) {
    6465                                                        @Override
    65                                                         public void result(Path result, Exception e) {
    66                                                                 Logging.log(log, "resolve", path, e);
     66                                                        public void result(Path result) {
     67                                                                Logging.log(log, "resolve", path, null);
    6768                                                        }
    6869                                                });
  • java/main/src/main/java/com/framsticks/remote/RecursiveFetcher.java

    r90 r96  
    11package com.framsticks.remote;
    22
     3import static com.framsticks.core.InstanceUtils.*;
    34import com.framsticks.core.Node;
    45import com.framsticks.core.Path;
     
    89import com.framsticks.core.Instance;
    910import com.framsticks.util.dispatching.Future;
     11import com.framsticks.util.FramsticksException;
     12import com.framsticks.util.Logging;
    1013import com.framsticks.util.StateFunctor;
    1114import com.framsticks.util.Stopwatch;
     
    3639                assert instance.isActive();
    3740                log.info("recursively fetched in " + stopwatch);
    38                 stateFunctor.call(null);
     41                stateFunctor.call();
    3942        }
    4043
     
    4447                        log.warn("path " + path + " is not resolved - skipping");
    4548                } else {
    46                         AccessInterface access = instance.bindAccess(path);
     49                        AccessInterface access = bindAccess(path);
    4750                        FramsClass framsClass = access.getFramsClass();
    4851                        assert framsClass != null;
     
    5053                                Object child = access.get(p, Object.class);
    5154                                final Path childPath = path.appendNode(new Node(p, child));
    52                                 if (childPath.isResolved() && instance.getInfoFromCache(childPath) != null) {
     55                                if (childPath.isResolved() && getInfoFromCache(childPath) != null) {
    5356                                        ++dispatched;
    5457                                        instance.dispatch(new RunAt<Instance>() {
     
    6164                                }
    6265                                ++dispatched;
    63                                 instance.resolve(childPath, new Future<Path>() {
     66                                instance.resolve(childPath, new Future<Path>(Logging.logger(log, "resolve", RecursiveFetcher.this)) {
    6467                                        @Override
    65                                         public void result(Path result, Exception e) {
     68                                        protected void result(Path result) {
    6669                                                assert instance.isActive();
    67                                                 if (e != null) {
    68                                                         log.error(e);
    69                                                         return;
    70                                                 }
    7170                                                fetch(result);
    7271                                        }
     
    8382                instance.fetchValues(path, new StateFunctor() {
    8483                        @Override
    85                         public void call(Exception e) {
    86                                 if (e != null) {
    87                                         log.error("failed to fetch values for " + path + ": " + e);
    88                                         process(null);
    89                                         return;
    90                                 }
     84                        public void handle(FramsticksException e) {
     85                                log.error("failed to fetch values for " + path + ": " + e);
     86                                process(null);
     87                        }
     88
     89                        @Override
     90                        public void call() {
    9191                                process(path);
    9292                        }
  • java/main/src/main/java/com/framsticks/remote/RemoteInstance.java

    r90 r96  
    22
    33import com.framsticks.communication.*;
     4import com.framsticks.communication.queries.CallRequest;
    45import com.framsticks.communication.queries.GetRequest;
    56import com.framsticks.communication.queries.InfoRequest;
    67import com.framsticks.communication.queries.SetRequest;
    7 import com.framsticks.communication.util.LoggingSubscriptionCallback;
     8import com.framsticks.core.AbstractInstance;
     9import com.framsticks.core.InstanceUtils;
    810import com.framsticks.core.ListChange;
     11import com.framsticks.core.Node;
    912import com.framsticks.core.Path;
    1013import com.framsticks.params.*;
     
    1720import com.framsticks.util.*;
    1821import com.framsticks.util.dispatching.Dispatching;
     22import com.framsticks.util.dispatching.ExceptionResultHandler;
    1923import com.framsticks.util.dispatching.Future;
    2024import com.framsticks.util.dispatching.Joinable;
     
    2428import com.framsticks.util.lang.Pair;
    2529import com.framsticks.util.dispatching.RunAt;
     30import static com.framsticks.core.InstanceUtils.*;
    2631
    2732import java.util.*;
     33
     34import javax.annotation.Nonnull;
    2835
    2936import org.apache.log4j.Logger;
     
    3340 */
    3441@FramsClassAnnotation
    35 public class RemoteInstance extends Instance implements JoinableParent {
     42public class RemoteInstance extends AbstractInstance implements JoinableParent {
    3643
    3744        private final static Logger log = Logger.getLogger(RemoteInstance.class.getName());
    3845
    39         protected Path simulator;
    4046        protected ClientConnection connection;
    4147
     
    6470        }
    6571
     72        protected void onProtocolVersionNegotiated() {
     73        }
     74
     75
    6676        public void setConnection(final ClientConnection connection) {
    6777                this.connection = connection;
    68                 this.connection.setConnectedFunctor(new StateFunctor() {
    69                         @Override
    70                         public void call(Exception e) {
    71                                 if (e != null) {
    72                                         fireRun(e);
    73                                         return;
    74                                 }
    75                                 connection.negotiateProtocolVersion(new StateFunctor() {
     78                final ExceptionResultHandler failure = new ExceptionResultHandler() {
     79                        @Override
     80                        public void handle(FramsticksException exception) {
     81                                log.fatal("failed to establish connection: ", exception);
     82                                // log.fatal("unsupported protocol version!\n minimal version is: " + "\nmanager protocol is: " + connection.getProtocolVersion());
     83                                Dispatching.drop(connection, RemoteInstance.this);
     84                                fireRun(exception);
     85                        }
     86                };
     87
     88                this.connection.setConnectedFunctor(new AbstractStateFunctor(failure) {
     89                        @Override
     90                        public void call() {
     91                                connection.negotiateProtocolVersion(new AbstractStateFunctor(failure) {
    7692                                        @Override
    77                                         public void call(Exception e) {
    78                                                 if (e != null) {
    79                                                         log.fatal("unsupported protocol version!\n minimal version is: " + "\nmanager protocol is: " + connection.getProtocolVersion());
    80                                                         Dispatching.drop(connection, RemoteInstance.this);
    81                                                         fireRun(e);
    82                                                         return;
    83                                                 }
    84 
    85                                                 dispatch(new RunAt<Instance>() {
    86                                                         @Override
    87                                                         public void run() {
    88                                                                 resolveAndFetch("/simulator", new Future<Path>() {
    89                                                                         @Override
    90                                                                         public void result(Path path, Exception e) {
    91                                                                                 if (e != null) {
    92                                                                                         log.fatal("failed to resolve simulator node");
    93                                                                                         fireRun(e);
    94                                                                                         return;
    95                                                                                 }
    96                                                                                 assert isActive();
    97                                                                                 simulator = path;
    98                                                                                 fireRun(null);
    99                                                                                 log.info("resolved simulator node");
    100 
    101                                                                                 EventParam param = getParam(simulator, "running_changed", EventParam.class);
    102                                                                                 assert param != null;
    103                                                                                 connection.subscribe(simulator.getTextual() + "/" + param.getId(), RemoteInstance.this, new LoggingSubscriptionCallback<Instance>(log, "server running state change", new EventCallback() {
    104                                                                                         @Override
    105                                                                                         public void call(List<File> files) {
    106                                                                                                 dispatch(new RunAt<Instance>() {
    107                                                                                                         @Override
    108                                                                                                         public void run() {
    109                                                                                                                 updateSimulationRunning();
    110                                                                                                         }
    111                                                                                                 });
    112                                                                                         }
    113                                                                                 }));
    114                                                                                 new PeriodicTask<Instance>(RemoteInstance.this, 1000) {
    115                                                                                         @Override
    116                                                                                         public void run() {
    117                                                                                                 updateSimulationRunning();
    118                                                                                                 again();
    119                                                                                         }
    120                                                                                 };
    121                                                                         }
    122                                                                 });
    123                                                         }
    124                                                 });
     93                                        public void call() {
     94                                                onProtocolVersionNegotiated();
    12595                                        }
    12696                                });
    12797                        }
    12898                });
    129 
    13099        }
    131100
     
    136105        }
    137106
    138         public void setRunning(final boolean running) {
    139                 assert isActive();
    140                 //simulator.call(simulator.getParam(running ? "start" : "stop", ProcedureParam.class), new LoggingStateCallback(log, (running ? "starting" : "stopping") + " server"));
    141         }
    142 
    143         protected final UnaryListenersSet<Boolean> simulationRunningListeners = new UnaryListenersSet<Boolean>();
    144 
    145         protected void updateSimulationRunning() {
    146                 assert isActive();
    147                 /*
    148                 fetchValue(simulator, getParam(simulator, "running", Param.class), new StateFunctor() {
    149                         @Override
    150                         public void call(Exception e) {
    151                                 if (e != null) {
    152                                         log.fatal("failed to query simulator running status: " + e);
    153                                         return;
    154                                 }
    155 
    156                                 invokeLater(new Runnable() {
    157                                         @Override
    158                                         public void run() {
    159                                                 boolean value = bindAccess(simulator).get("running", Boolean.class);
    160                                                 log.trace("server running: " + value);
    161                                                 simulationRunningListeners.call(value);
    162                                         }
    163                                 });
    164 
    165                         }
    166                 });
    167                  */
    168         }
    169 
    170         public void addRunningStateListener(UnaryFunctor<Boolean, Boolean> listener) {
    171                 assert isActive();
    172                 simulationRunningListeners.add(listener);
    173         }
    174 
    175         // public void disconnect() {
    176         //      assert isActive();
    177         //      if (connection.isConnected()) {
    178         //              Dispatching.stop(connection, this);
    179         //      }
    180         // }
    181 
    182107        public final ClientConnection getConnection() {
    183108                return connection;
     
    185110
    186111        @Override
    187         public void fetchValue(final Path path, final Param param, final StateFunctor stateFunctor) {
     112        public void fetchValue(final Path path, final ValueParam param, final StateFunctor stateFunctor) {
    188113                assert isActive();
    189114                assert param != null;
     
    194119                                assert isActive();
    195120                                if (!response.getOk()) {
    196                                         stateFunctor.call(new Exception(response.getComment()));
     121                                        stateFunctor.handle(new FramsticksException().msg("failed to fetch value").arg("comment", response.getComment()));
    197122                                        return;
    198123                                }
    199124                                try {
    200                                         processFetchedValues(path, response.getFiles());
    201                                         stateFunctor.call(null);
    202                                 } catch (Exception ex) {
    203                                         stateFunctor.call(ex);
     125                                        InstanceUtils.processFetchedValues(path, response.getFiles());
     126                                        stateFunctor.call();
     127                                } catch (FramsticksException ex) {
     128                                        stateFunctor.handle(ex);
    204129                                }
    205130                        }
     
    209134        protected final Map<String, Set<Future<FramsClass>>> infoRequests = new HashMap<String, Set<Future<FramsClass>>>();
    210135
    211         protected void finishInfoRequest(String id, FramsClass result, Exception e) {
     136        protected void finishInfoRequest(String id, FramsClass result, FramsticksException e) {
    212137                assert isActive();
    213138                Set<Future<FramsClass>> futures = infoRequests.get(id);
    214139                infoRequests.remove(id);
    215140                for (Future<FramsClass> f : futures) {
    216                         f.result(result, e);
    217                 }
    218         }
    219 
    220         @Override
    221         protected void fetchInfo(final Path path, final Future<FramsClass> future) {
     141                        Future.passOrHandle(f, result, e);
     142                }
     143        }
     144
     145        @Override
     146        public void fetchInfo(final Path path, final Future<FramsClass> future) {
    222147
    223148                final String name = path.getTop().getParam().getContainedTypeName();
     
    238163                        public void process(Response response) {
    239164                                assert isActive();
    240                                 if (!response.getOk()) {
    241                                         finishInfoRequest(name, null, new Exception(response.getComment()));
    242                                         return;
    243                                 }
    244 
    245                                 assert response.getFiles().size() == 1;
    246                                 assert path.isTheSame(response.getFiles().get(0).getPath());
    247                                 FramsClass framsClass;
    248165                                try {
    249                                         framsClass = processFetchedInfo(response.getFiles().get(0));
    250                                 } catch (ConstructionException e) {
    251                                         log.fatal("could not read class info");
    252                                         finishInfoRequest(name, null, new Exception("could not read class info"));
    253                                         return;
    254                                 }
    255 
    256                                 CompositeParam thisParam = path.getTop().getParam();
    257                                 if (!thisParam.isMatchingContainedName(framsClass.getId())) {
    258                                         String mismatch = "class name mismatch: param=" + thisParam.getContainedTypeName() + " differs from fetched=" + framsClass.getId();
    259                                         log.error(mismatch);
    260                                         finishInfoRequest(name, null, new Exception(mismatch));
    261                                         return;
    262                                 }
    263                                 finishInfoRequest(name, framsClass, null);
     166                                        if (!response.getOk()) {
     167                                                throw new FramsticksException().msg("invalid response").arg("comment", response.getComment());
     168                                        }
     169                                        if (response.getFiles().size() != 1) {
     170                                                throw new FramsticksException().msg("invalid number of files in response").arg("files", response.getFiles().size());
     171                                        }
     172                                        if (!path.isTheSame(response.getFiles().get(0).getPath())) {
     173                                                throw new FramsticksException().msg("path mismatch").arg("returned path", response.getFiles().get(0).getPath());
     174                                        }
     175                                        FramsClass framsClass = InstanceUtils.processFetchedInfo(RemoteInstance.this, response.getFiles().get(0));
     176
     177                                        CompositeParam thisParam = path.getTop().getParam();
     178                                        if (!thisParam.isMatchingContainedName(framsClass.getId())) {
     179                                                throw new FramsticksException().msg("framsclass id mismatch").arg("request", thisParam.getContainedTypeName()).arg("fetched", framsClass.getId());
     180                                        }
     181
     182                                        finishInfoRequest(name, framsClass, null);
     183                                } catch (FramsticksException e) {
     184                                        finishInfoRequest(name, null, e.arg("path", path));
     185                                }
    264186                        }
    265187                });
     
    276198                        public void process(Response response) {
    277199                                assert isActive();
    278                                 if (!response.getOk()) {
    279                                         stateFunctor.call(new Exception(response.getComment()));
    280                                         return;
    281                                 }
    282200                                try {
    283                                         processFetchedValues(path, response.getFiles());
    284                                         stateFunctor.call(null);
    285                                 } catch (Exception ex) {
    286                                         log.error("an exception occurred while loading: " + ex);
    287                                         ex.printStackTrace();
    288                                         stateFunctor.call(ex);
     201                                        if (!response.getOk()) {
     202                                                throw new FramsticksException().msg("failed to fetch values").arg("comment", response.getComment());
     203                                        }
     204                                        InstanceUtils.processFetchedValues(path, response.getFiles());
     205                                        stateFunctor.call();
     206                                } catch (FramsticksException e) {
     207                                        stateFunctor.handle(e);
    289208                                }
    290209                        }
     
    294213        @Override
    295214        public void resolve(final Path path, final Future<Path> future) {
    296                 assert isActive();
    297                 if (path.getTop().getObject() != null) {
    298                         if (getInfoFromCache(path) != null) {
    299                                 future.result(path, null);
    300                                 return;
    301                         }
    302                         findInfo(path, new Future<FramsClass>() {
    303                                 @Override
    304                                 public void result(FramsClass result, Exception e) {
    305                                         if (e != null) {
    306                                                 future.result(null, e);
    307                                                 return;
    308                                         }
    309                                         future.result(path, null);
    310                                 }
    311                         });
    312                         return;
    313                 }
    314                 findInfo(path, new Future<FramsClass>() {
    315                         @Override
    316                         public void result(FramsClass result, Exception e) {
    317                                 assert isActive();
    318                                 if (e != null) {
    319                                         future.result(null, e);
    320                                         return;
    321                                 }
    322                                 assert path.getTop().getParam().isMatchingContainedName(result.getId());
    323                                 Path p = (path.getTop().getParam().getContainedTypeName() != null ? path : path.tryFindResolution());
    324                                 future.result(createIfNeeded(p), null);
    325                         }
    326                 });
     215                InstanceUtils.resolve(path, future);
    327216        }
    328217
     
    330219        protected void tryRegisterOnChangeEvents(final Path path) {
    331220                assert isActive();
    332                 AccessInterface access = bindAccess(path);
     221                AccessInterface access = InstanceUtils.bindAccess(path);
    333222                if (!(access instanceof ListAccess)) {
    334223                        return;
     
    396285        }
    397286
     287        protected Future<Path> futureListChanger(final ListChange listChange, final String path) {
     288                return new Future<Path>(Logging.logger(log, "failed to " + listChange, path)) {
     289                        @Override
     290                        protected void result(Path result) {
     291                                log.debug(listChange + ": " + result);
     292                                fireListChange(result, listChange);
     293                        }
     294                };
     295        }
     296
    398297        protected void reactToChange(final Path path, final ListChange listChange) {
    399298                assert isActive();
    400299                log.debug("reacting to change " + listChange + " in " + path);
    401                 AccessInterface access = bindAccess(path);
     300                AccessInterface access = InstanceUtils.bindAccess(path);
    402301                assert access != null;
    403302
    404303                if ((listChange.getAction() == ListChange.Action.Modify) && (listChange.getPosition() == -1)) {
    405304                        final String p = path.getTextual();
    406                         resolveAndFetch(p, new Future<Path>() {
    407                                 @Override
    408                                 public void result(Path result, Exception e) {
    409                                         if (e != null) {
    410                                                 log.error("failed to modify " + p + ": " + e);
    411                                                 return;
    412                                         }
    413                                         fireListChange(path, listChange);
    414                                 }
    415                         });
     305                        InstanceUtils.resolveAndFetch(this, p, futureListChanger(listChange, p));
    416306                        return;
    417307                }
     
    420310                assert childParam != null;
    421311                switch (listChange.getAction()) {
    422                 case Add: {
    423                         final String p = path.getTextual() + "/" + childParam.getId();
    424                         resolveAndFetch(p, new Future<Path>() {
    425                                 @Override
    426                                 public void result(Path result, Exception e) {
    427                                         if (e != null) {
    428                                                 log.error("failed to add " + p + ": " + e);
    429                                                 return;
    430                                         }
    431                                         log.debug("added: " + result);
    432                                         fireListChange(path, listChange);
    433                                 }
    434                         });
    435                         break;
    436                 }
    437                 case Remove: {
    438                         access.set(childParam, null);
    439                         fireListChange(path, listChange);
    440                         break;
    441                 }
    442                 case Modify: {
    443                         final String p = path.getTextual() + "/" + childParam.getId();
    444                         resolveAndFetch(p, new Future<Path>() {
    445                                 @Override
    446                                 public void result(Path result, Exception e) {
    447                                         if (e != null) {
    448                                                 log.error("failed to modify " + p + ": " + e);
    449                                                 return;
    450                                         }
    451                                         fireListChange(path, listChange);
    452                                 }
    453                         });
    454                         break;
    455                 }
    456                 }
    457         }
    458 
    459         //TODO ValueParam
    460         @Override
    461         public void storeValue(final Path path, final Param param, final Object value, final StateFunctor stateFunctor) {
     312                        case Add: {
     313                                final String p = path.getTextual() + "/" + childParam.getId();
     314                                InstanceUtils.resolveAndFetch(this, p, futureListChanger(listChange, p));
     315                                break;
     316                        }
     317                        case Remove: {
     318                                access.set(childParam, null);
     319                                fireListChange(path, listChange);
     320                                break;
     321                        }
     322                        case Modify: {
     323                                final String p = path.getTextual() + "/" + childParam.getId();
     324                                InstanceUtils.resolveAndFetch(this, p, futureListChanger(listChange, p));
     325                                break;
     326                        }
     327                }
     328        }
     329
     330        @Override
     331        public void storeValue(final Path path, final ValueParam param, final Object value, StateFunctor stateFunctor) {
    462332                assert isActive();
    463333
    464334                log.trace("storing value " + param + " for " + path);
    465                 connection.send(new SetRequest().value(value.toString()).field(param.getId()).path(path.getTextual()), this, new StateCallback<Instance>() {
    466                         @Override
    467                         public void call(Exception e) {
    468                                 if (e == null) {
    469                                         bindAccess(path).set((ValueParam) param, value);
    470                                 }
    471                                 stateFunctor.call(e);
     335                connection.send(new SetRequest().value(value.toString()).field(param.getId()).path(path.getTextual()), this, new StateCallback<Instance>(stateFunctor) {
     336                        @Override
     337                        protected void callImpl() {
     338                                InstanceUtils.bindAccess(path).set((ValueParam) param, value);
    472339                        }
    473340                });
     
    504371
    505372        @Override
    506         public void call(Path path, ProcedureParam param, Object[] arguments, StateFunctor stateFunctor) {
    507                 throw new UnimplementedException();
     373        public void call(@Nonnull final Path path, @Nonnull final ProcedureParam procedure, @Nonnull Object[] arguments, final Future<Object> future) {
     374                assert isActive();
     375                assert path.isResolved();
     376
     377                //TODO validate arguments type using params
     378                connection.send(new CallRequest().procedure(procedure.getId()).arguments(Arrays.asList(arguments)).path(path.getTextual()), this, new ResponseCallback<Instance>() {
     379                        @Override
     380                        public void process(Response response) {
     381                                assert isActive();
     382                                try {
     383                                        if (!response.getOk()) {
     384                                                throw new FramsticksException().msg("failed to call procedure").arg("procedure", procedure).arg("comment", response.getComment());
     385                                        }
     386                                        // InstanceUtils.processFetchedValues(path, response.getFiles());
     387                                        future.pass(null);
     388                                } catch (FramsticksException ex) {
     389                                        future.handle(ex);
     390                                }
     391                        }
     392                });
     393
     394        }
     395
     396        @Override
     397        public Path create(Path path) {
     398                assert isActive();
     399                assert !path.isResolved();
     400                Path resolved = path.tryFindResolution();
     401                if (!resolved.isResolved()) {
     402                        log.debug("creating: " + path);
     403                        AccessInterface access = registry.prepareAccess(path.getTop().getParam());
     404                        assert access != null;
     405                        Object child = access.createAccessee();
     406                        assert child != null;
     407                        if (path.size() == 1) {
     408                                setRoot(new Node(getRoot().getParam(), child));
     409                        } else {
     410                                bindAccess(this, path.getUnder()).set(path.getTop().getParam(), child);
     411                        }
     412                        resolved = path.appendResolution(child);
     413                }
     414                tryRegisterOnChangeEvents(resolved);
     415                return resolved;
    508416        }
    509417
  • java/main/src/main/java/com/framsticks/running/ExternalProcess.java

    r90 r96  
    1414import org.apache.log4j.Logger;
    1515
    16 import com.framsticks.core.Entity;
    1716import com.framsticks.params.annotations.AutoAppendAnnotation;
    1817import com.framsticks.params.annotations.FramsClassAnnotation;
     
    3029
    3130@FramsClassAnnotation
    32 public class ExternalProcess extends AbstractJoinable implements JoinableParent, Entity {
     31public class ExternalProcess extends AbstractJoinable implements JoinableParent {
    3332        private static final Logger log = Logger.getLogger(ExternalProcess.class);
    3433
  • java/main/src/main/java/com/framsticks/util/FramsticksException.java

    r88 r96  
    3535        }
    3636
    37         @Override
    38         public String getMessage() {
    39                 StringBuilder b = new StringBuilder();
     37        public void getShortMessage(StringBuilder b) {
    4038                if (message != null) {
    4139                        b.append(message);
     40                } else {
     41                        b.append("?");
    4242                }
    4343                if (arguments != null) {
     
    4545                                b.append(" ");
    4646                        }
    47                         Delimeted d = new Delimeted(", ", "");
     47                        Delimeted<Pair<String, Object>> d = new Delimeted<>(", ", "");
    4848                        d.append(arguments.iterator());
    4949
    5050                        b.append("(").append(d.build()).append(")");
    5151                }
    52                 if (this.getCause() != null) {
    53                         b.append(" caused by: [").append(this.getCause().getMessage()).append("]");
     52        }
     53
     54        public String getMsg() {
     55                return message;
     56        }
     57
     58        @Override
     59        public String getMessage() {
     60                StringBuilder b = new StringBuilder();
     61                getShortMessage(b);
     62                Throwable cause = this.getCause();
     63                while (cause != null) {
     64                        b.append(" caused by: [").append(cause.getClass().getCanonicalName()).append(": ");
     65                        if (cause instanceof FramsticksException) {
     66                                ((FramsticksException) cause).getShortMessage(b);
     67                        } else {
     68                                b.append(cause.getMessage());
     69                        }
     70                        b.append("]");
     71                        cause = cause.getCause();
    5472                }
    5573                return b.toString();
  • java/main/src/main/java/com/framsticks/util/Logging.java

    r90 r96  
    22
    33import org.apache.log4j.Logger;
     4
     5import com.framsticks.util.dispatching.ExceptionResultHandler;
    46
    57/**
     
    1719                return false;
    1820        }
     21
     22        public static ExceptionResultHandler logger(final Logger logger, final String action, final Object subject) {
     23                return new ExceptionResultHandler() {
     24                        @Override
     25                        public void handle(FramsticksException e) {
     26                                Logging.log(logger, action, subject, e);
     27                        }
     28                };
     29        }
    1930}
  • java/main/src/main/java/com/framsticks/util/PeriodicTask.java

    r90 r96  
    2121
    2222        public void again() {
    23                 dispatcher.dispatch(new Task<C>(System.currentTimeMillis() + period) {
     23                dispatcher.dispatch(new Task<C>(period) {
    2424                        @Override
    2525                        public void run() {
  • java/main/src/main/java/com/framsticks/util/StateFunctor.java

    r85 r96  
    11package com.framsticks.util;
     2
     3import com.framsticks.util.dispatching.ExceptionResultHandler;
    24
    35/**
    46 * @author Piotr Sniegowski
    57 */
    6 public interface StateFunctor {
     8public interface StateFunctor extends ExceptionResultHandler {
    79        //TODO RunAt
    8         public void call(Exception e);
     10        public void call();
    911}
  • java/main/src/main/java/com/framsticks/util/UnsupportedOperationException.java

    r84 r96  
    44 * @author Piotr Sniegowski
    55 */
    6 public class UnsupportedOperationException extends Exception {
     6public class UnsupportedOperationException extends FramsticksException {
    77
    88        /**
  • java/main/src/main/java/com/framsticks/util/dispatching/AbstractJoinable.java

    r90 r96  
    1414import com.framsticks.util.FramsticksException;
    1515
    16 
    17 
    1816public abstract class AbstractJoinable implements Joinable {
     17
    1918        private static final Logger log = Logger.getLogger(AbstractJoinable.class);
    20 
    2119
    2220        protected final Set<JoinableParent> owners = new HashSet<JoinableParent>();
     
    2523        protected static final Set<AbstractJoinable> joinablesRegistry = Collections.synchronizedSet(new HashSet<AbstractJoinable>());
    2624
    27         JoinableState state = JoinableState.INITILIAZED;
     25        protected JoinableState state = JoinableState.INITILIAZED;
     26        protected JoinableParent parent;
     27        protected Monitor monitor;
    2828
    2929        /**
     
    5353                this.state = state;
    5454
    55                 synchronized (this) {
    56                         log.debug(this + " is notifying " + joinableListeners.size() + " parents");
    57 
    58                         List<JoinableParent> parents = new LinkedList<>();
    59                         CollectionUtils.addAll(parents, joinableListeners.iterator());
    60 
    61                         for (JoinableParent p : parents) {
    62                                 if (p != null) {
    63                                         Dispatching.childChangedState(p, this, state);
    64                                 }
    65                         }
    66                         this.notifyAll();
    67                 }
     55                log.debug(this + " is notifying " + joinableListeners.size() + " parents");
     56
     57                List<JoinableParent> parents = new LinkedList<>();
     58                CollectionUtils.addAll(parents, joinableListeners.iterator());
     59
     60                for (JoinableParent p : parents) {
     61                        if (p != null) {
     62                                Dispatching.childChangedState(p, this, state);
     63                        }
     64                }
     65                this.notifyAll();
     66
    6867                report();
    6968
     
    145144                }
    146145                if (start) {
     146                        assert monitor == null;
     147                        monitor = owner.getMonitor();
    147148                        return this.start();
    148149                }
     
    185186        }
    186187
     188        protected boolean isRunning() {
     189                return state.equals(JoinableState.RUNNING);
     190        }
     191
     192        @Override
     193        public String toString() {
     194                return getName();
     195        }
     196
     197        // @Override
     198        public Monitor getMonitor() {
     199                return monitor;
     200        }
     201
    187202
    188203}
  • java/main/src/main/java/com/framsticks/util/dispatching/Dispatching.java

    r90 r96  
    33import org.apache.log4j.Logger;
    44
     5import com.framsticks.util.FramsticksException;
    56import com.framsticks.util.StateFunctor;
    67
     
    2829                        @Override
    2930                        public void run() {
    30                                 stateFunctor.call(null);
     31                                stateFunctor.call();
    3132                        }
    3233                });
     
    170171        }
    171172
    172 
     173        public static class Waiter {
     174                protected boolean done = false;
     175
     176                protected final double timeOut;
     177
     178                /**
     179                 * @param timeOut
     180                 */
     181                public Waiter(double timeOut) {
     182                        this.timeOut = timeOut;
     183                }
     184
     185                public synchronized void pass() {
     186                        done = true;
     187                        this.notify();
     188                }
     189
     190                public synchronized void waitFor() {
     191                        long end = System.currentTimeMillis() + (int)(timeOut * 1000);
     192                        while ((!done) && System.currentTimeMillis() < end) {
     193                                try {
     194                                        this.wait(end - System.currentTimeMillis());
     195                                } catch (InterruptedException e) {
     196                                        break;
     197                                }
     198                        }
     199                        if (!done) {
     200                                throw new FramsticksException().msg("waiter timed out");
     201                        }
     202                }
     203        }
     204
     205
     206        public static <C> void synchronize(Dispatcher<C> dispatcher, double seconds) {
     207                final Waiter waiter = new Waiter(seconds);
     208                dispatcher.dispatch(new RunAt<C>() {
     209                        @Override
     210                        public void run() {
     211                                waiter.pass();
     212                        }
     213                });
     214                waiter.waitFor();
     215        }
    173216
    174217}
  • java/main/src/main/java/com/framsticks/util/dispatching/Future.java

    r84 r96  
    11package com.framsticks.util.dispatching;
     2
     3import com.framsticks.util.FramsticksException;
    24
    35/**
    46 * @author Piotr Sniegowski
    57 */
    6 public interface Future <T> {
    7     void result(T result, Exception e);
     8public abstract class Future<T> implements ExceptionResultHandler {
     9
     10        protected final ExceptionResultHandler handler;
     11
     12        public Future(ExceptionResultHandler handler) {
     13                this.handler = handler;
     14        }
     15
     16        public Future() {
     17                this.handler = null;
     18        }
     19
     20        protected abstract void result(T result);
     21
     22        public final void pass(T result) {
     23                try {
     24                        result(result);
     25                } catch (FramsticksException e) {
     26                        handle(e);
     27                }
     28        }
     29
     30        public static <T> void passOrHandle(Future<T> future, T value, FramsticksException e) {
     31                if (e != null) {
     32                        future.handle(e);
     33                } else {
     34                        future.pass(value);
     35                }
     36        }
     37
     38        @Override
     39        public void handle(FramsticksException exception) {
     40                if (handler != null) {
     41                        handler.handle(exception);
     42                        return;
     43                }
     44                throw exception;
     45        }
    846}
  • java/main/src/main/java/com/framsticks/util/dispatching/Joinable.java

    r88 r96  
    55
    66public interface Joinable {
     7
     8        /** The name of the joinable.
     9         *
     10         * It should never be empty, but it is not required to remain
     11         * constant during lifetime of the object.
     12         */
     13        public String getName();
    714
    815        public boolean use(@Nonnull JoinableParent owner);
  • java/main/src/main/java/com/framsticks/util/dispatching/JoinableCollection.java

    r88 r96  
    22
    33import java.util.Collections;
    4 import java.util.HashMap;
    54import java.util.HashSet;
    65import java.util.Iterator;
    7 import java.util.Map;
    86import java.util.Set;
    97
    10 import com.framsticks.core.Entity;
    118import com.framsticks.params.annotations.AutoAppendAnnotation;
    129import com.framsticks.params.annotations.FramsClassAnnotation;
     
    1916
    2017        protected final Set<T> joinables = new HashSet<T>();
    21         protected final Map<String, T> namedJoinables = new HashMap<>();
    2218
    2319        protected boolean finishIfOne;
     
    3430
    3531        @AutoAppendAnnotation
    36         public void add(T joinable) {
    37                 assert isInState(JoinableState.INITILIAZED);
     32        public synchronized void add(T joinable) {
     33                if (this.state.ordinal() > JoinableState.RUNNING.ordinal()) {
     34                        throw new FramsticksException().msg("failed to add joinable - collection is passed running state").arg("joinable", joinable).arg("collection", this);
     35                }
    3836
    3937                if (joinables.contains(joinable)) {
    4038                        throw new FramsticksException().msg("joinable is already observed").arg("joinable", joinable).arg("in", this);
    4139                }
    42                 // if (observables.containsKey(observable.getName())) {
    43                 //      throw new FramsticksException().msg("observable with given name already exists").arg("name", observable.getName()).arg("in", this);
    44                 // }
     40                joinables.add(joinable);
    4541
    46                 if (joinable instanceof Entity) {
    47                         Entity e = (Entity) joinable;
    48                         if (!namedJoinables.containsKey(e.getName())) {
    49                                 namedJoinables.put(e.getName(), joinable);
    50                         }
     42                if (this.state.equals(JoinableState.RUNNING)) {
     43                        Dispatching.use(joinable, this);
    5144                }
    52 
    53                 joinables.add(joinable);
    5445        }
    5546
     
    10798        public void childChangedState(Joinable joinable, JoinableState state) {
    10899                proceedToState(getNextState());
    109 
    110100        }
    111101
     
    129119
    130120        public T get(String name) {
    131                 return namedJoinables.get(name);
     121                for (T j : joinables) {
     122                        if (j.getName().equals(name)) {
     123                                return j;
     124                        }
     125                }
     126                return null;
    132127        }
    133128
     129        public int size() {
     130                return joinables.size();
     131        }
    134132
    135         public Map<String, T> getObservables() {
    136                 return Collections.unmodifiableMap(namedJoinables);
     133        public boolean contains(T joinable) {
     134                return joinables.contains(joinable);
     135        }
     136
     137        @Override
     138        public String getName() {
     139                return observableName;
    137140        }
    138141
  • java/main/src/main/java/com/framsticks/util/dispatching/JoinableParent.java

    r88 r96  
    44
    55        public void childChangedState(Joinable joinable, JoinableState state);
     6        public Monitor getMonitor();
    67
    78}
  • java/main/src/main/java/com/framsticks/util/dispatching/Monitor.java

    r90 r96  
    22
    33import org.apache.log4j.Logger;
    4 // import edu.umd.cs.findbugs.annotations.SuppressWarnings;
    54import com.framsticks.util.dispatching.Dispatching;
     5import java.lang.Thread;
    66
    77public class Monitor implements JoinableParent {
     
    1010
    1111        protected final Joinable joinable;
     12        protected final Thread shutdownHook;
    1213
    1314        /**
     
    1617        public Monitor(Joinable joinable) {
    1718                this.joinable = joinable;
     19
     20                shutdownHook = new Thread(new Runnable() {
     21                        @Override
     22                        public void run() {
     23                                log.debug("running shutdown hook");
     24                                Monitor.this.drop().join();
     25                        }
     26                });
     27        }
     28
     29        public Monitor use() {
     30                Runtime.getRuntime().addShutdownHook(shutdownHook);
     31
     32                log.debug(this + " is using");
     33                Dispatching.use(joinable, this);
     34                return this;
    1835        }
    1936
     
    3451        }
    3552
    36         public Monitor use() {
    37                 log.debug(this + " is using");
    38                 Dispatching.use(joinable, this);
    39                 return this;
    40         }
    4153
    4254        public Monitor drop() {
     
    5062                Dispatching.joinAbsolutely(joinable);
    5163                log.debug(this + " is joined");
     64
     65                try {
     66                        Runtime.getRuntime().removeShutdownHook(shutdownHook);
     67                } catch (IllegalStateException e) {
     68                        /** In case IllegalStateException is caught, it means that JVM is in finalization stage */
     69                }
     70
    5271                return this;
    5372        }
     
    6786        }
    6887
     88        @Override
     89        public Monitor getMonitor() {
     90                return this;
     91        }
     92
     93        protected ExceptionHandler taskExceptionHandler;
     94
     95        /**
     96         * @return the taskExceptionHandler
     97         */
     98        public ExceptionHandler getTaskExceptionHandler() {
     99                return taskExceptionHandler;
     100        }
     101
     102        /**
     103         * @param taskExceptionHandler the taskExceptionHandler to set
     104         */
     105        public void setTaskExceptionHandler(ExceptionHandler taskExceptionHandler) {
     106                this.taskExceptionHandler = taskExceptionHandler;
     107        }
     108
    69109}
  • java/main/src/main/java/com/framsticks/util/dispatching/Task.java

    r85 r96  
    1313
    1414        public Task(long moment) {
    15                 this.moment = moment;
     15                this.moment = System.currentTimeMillis() + moment;
    1616        }
    1717
  • java/main/src/main/java/com/framsticks/util/dispatching/Thread.java

    r90 r96  
    4747        protected void routine() {
    4848                log.debug("starting thread " + this);
     49                assert getMonitor() != null;
     50                ExceptionHandler exceptionHandler = getMonitor().getTaskExceptionHandler();
    4951                while (!java.lang.Thread.interrupted()) {
    5052                        Task<? extends C> task;
     
    7375                                task.run();
    7476                        } catch (Exception e) {
     77                                if (exceptionHandler != null) {
     78                                        if (exceptionHandler.handle(this, e)) {
     79                                                continue;
     80                                        }
     81                                }
    7582                                log.error("error in thread: ", e);
    7683                        }
  • java/main/src/main/java/com/framsticks/util/lang/Delimeted.java

    r86 r96  
    33import java.util.Iterator;
    44
    5 import org.apache.commons.collections.Closure;
     5// import org.apache.commons.collections.Closure;
    66
    7 public class Delimeted implements Closure {
     7public class Delimeted<T> {
    88
    99        protected final String delimeter;
     
    1919        }
    2020
    21         public final Delimeted append(Object object) {
     21        public final Delimeted<T> append(T object) {
    2222                if (builder != null) {
    2323                        builder.append(delimeter);
     
    2929        }
    3030
    31         public final Delimeted append(Iterator<?> i) {
     31        public final Delimeted<T> append(Iterator<T> i) {
    3232                while (i.hasNext()) {
    3333                        append(i.next());
     
    4141
    4242        @Override
    43         public void execute(Object input) {
    44                 append(input);
     43        public String toString() {
     44                return build();
    4545        }
    4646
     47        // @Override
     48        // public void execute(Object input) {
     49        //      append(input);
     50        // }
     51
    4752}
  • java/main/src/main/java/com/framsticks/util/lang/Pair.java

    r87 r96  
    2424                }
    2525                Pair<?, ?> p = (Pair<?, ?>) obj;
    26                 // return first == p.first && second.equals(se)
    2726                return first.equals(p.first) && second.equals(p.second);
    2827        }
     
    3332        }
    3433
     34        public static <U1, U2> Pair<U1, U2> make(U1 first, U2 second) {
     35                return new Pair<U1, U2>(first, second);
     36        }
     37
    3538}
  • java/main/src/main/java/com/framsticks/util/lang/Strings.java

    r86 r96  
    11package com.framsticks.util.lang;
     2
     3import com.framsticks.util.FramsticksException;
    24
    35/**
     
    1517        public static boolean notEmpty(String str) {
    1618                return str != null && !str.equals("");
     19        }
     20
     21        public static void assureNotEmpty(String str) {
     22                if (!notEmpty(str)) {
     23                        throw new FramsticksException().msg("string is empty");
     24                }
    1725        }
    1826
     
    3543                int pos = string.indexOf(separator);
    3644                if (pos == -1) {
    37                         return new Pair<String, String>(string.substring(0,
    38                                         string.length() - 1), second);