source: java/main/src/main/java/com/framsticks/params/AccessOperations.java @ 107

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

HIGHLIGHTS:

  • add SimultorProviders? hierarchy
  • start Framsticks server over SSH
  • FJF compatible with Framsticks 4.0rc3
  • reading and writing of standard.expt
  • a proof-of-concept implementation of StandardExperiment?

CHANGELOG:
Optionally return FreeAccess? from registry.

Add SimulatorRange?.

StandardExperiment? with genotypes circulation.

Automate registration around StandardState?.

More improvements to StandardExperiment?.

Skeleton version of StandardExperiment?.

Test saving of StandardState?.

Standard experiment state is being loaded.

More development towards StandardState? reading.

Work on reading standard experiment state.

Add classes for standard experiment.

Update example standard.expt

Add FreeAccess? and FreeObject?.

Made compatible with version 4.0rc3

Change deserialization policy.

Improve SSH support.

Working running simulator over SSH.

Fix joining bug in Experiment.

Working version of SimulatorRunner?.

Add more SimulatorProviders?.

Working PrimeExperimentTest? with 4.0rc3

Add references to deserialization.

Add OpaqueObject? and it's serialization.

Add deserialization of dictionaries.

Partial implementation of deserialization.

Add more tests for deserialization.

Prepare tests for deserialization.

Add proper result to prime experiment test.

Minor fixes to simulators providers.

Draft version of SimulatorProvider?.

Add SimulatorProvider? interface.

File size: 14.9 KB
Line 
1package com.framsticks.params;
2
3import java.util.LinkedList;
4import java.util.ListIterator;
5
6import javax.annotation.Nullable;
7
8import org.apache.commons.lang3.ClassUtils;
9import org.apache.logging.log4j.Logger;
10import org.apache.logging.log4j.LogManager;
11
12import com.framsticks.communication.File;
13import com.framsticks.params.types.ListParam;
14import com.framsticks.parsers.MultiParamLoader;
15import com.framsticks.structure.messages.Result;
16import com.framsticks.util.FramsticksException;
17import com.framsticks.util.FramsticksUnsupportedOperationException;
18import com.framsticks.util.Misc;
19import com.framsticks.util.UnimplementedException;
20import com.framsticks.util.lang.Casting;
21import com.framsticks.util.lang.Containers;
22import com.framsticks.util.lang.Holder;
23import com.framsticks.util.lang.Pair;
24// import com.framsticks.util.lang.Containers;
25
26import static com.framsticks.params.SetStateFlags.*;
27import static com.framsticks.util.lang.Containers.filterInstanceof;
28
29public final class AccessOperations {
30
31        private final static Logger log = LogManager.getLogger(AccessOperations.class);
32
33        /**
34         *
35         */
36        private AccessOperations() {
37        }
38
39        /**
40         * Simple String key, value class.
41         */
42        public static class Entry {
43
44                public final String key;
45                public final String value;
46
47                public Entry(String key, String value) {
48                        this.key = key;
49                        this.value = value;
50                }
51
52                @Override
53                public String toString() {
54                        return key + " = " + value;
55                }
56        }
57
58        private static Entry readEntry(Source source) {
59
60                String line;
61                String key = null;
62                StringBuilder value = null;
63                while ((line = source.readLine()) != null) {
64                        if (key == null) {
65                                int colonIndex = line.indexOf(':');
66                                if (colonIndex == -1) {
67                                        return null;
68                                }
69                                key = line.substring(0, colonIndex);
70                                String inlineValue = line.substring(colonIndex + 1);
71
72
73                                if (!inlineValue.startsWith("~")) {
74                                        return new Entry(key, inlineValue);
75                                }
76                                value = new StringBuilder();
77                                value.append(inlineValue.substring(1));
78                                continue;
79                        }
80                        if (value.length() != 0) {
81                                value.append(System.getProperty("line.separator"));
82                        }
83                        if (line.endsWith("~") && !line.endsWith("\\~")) {
84                                value.append(line.substring(0, line.length() - 1));
85                                return new Entry(key, value.toString().replaceAll("\\\\~", "~"));
86                        }
87                        value.append(line);
88                }
89                return null;
90        }
91
92        public static <A extends Access> A assureSelected(A access) {
93                if (access.getSelected() == null) {
94                        access.select(access.createAccessee());
95                }
96                return access;
97        }
98
99        public static Access loadAll(@Nullable final Access rootAccess, Source source, final Registry registry) {
100                final MultiParamLoader loader = new MultiParamLoader();
101                log.trace("loading all from {} into {}", source, rootAccess);
102                loader.setNewSource(source);
103                final LinkedList<Access> accessesStack = new LinkedList<>();
104                if (rootAccess != null) {
105                        assureSelected(rootAccess);
106                        accessesStack.add(rootAccess);
107                }
108                final Holder<Boolean> first = new Holder<>(true);
109                final Holder<Boolean> needAdd = new Holder<>();
110                final Holder<Access> currentAccess = new Holder<>();
111                final Holder<Pair<Access, CompositeParam>> parent = new Holder<>();
112
113                loader.setAccessProvider(new AccessProvider() {
114                        @Override
115                        public Access getAccess(String name) {
116                                if (first.get()) {
117                                        first.set(false);
118                                        if (rootAccess != null) {
119                                                if (name.equals(rootAccess.getTypeId())) {
120                                                        needAdd.set(false);
121                                                        currentAccess.set(rootAccess);
122                                                        return rootAccess;
123                                                }
124                                        } else {
125                                                Access access = registry.createAccess(name);
126                                                needAdd.set(false);
127                                                currentAccess.set(access);
128                                                return access;
129
130                                        }
131                                }
132
133                                ListIterator<Access> accessIterator = accessesStack.listIterator(accessesStack.size());
134                                parent.set(null);
135                                // log.debug("accesses stack: {}", accessesStack);
136
137                                while (accessIterator.hasPrevious()) {
138                                        Access a = accessIterator.previous();
139                                        assert a != null;
140
141                                        for (CompositeParam p : Containers.filterInstanceof(a.getParams(), CompositeParam.class)) {
142                                                if (p.getContainedTypeName().equals(name)) {
143
144                                                        if (parent.get() != null) {
145                                                                throw new FramsticksException().msg("ambiguity encountered during loading").arg("name", name);
146                                                        }
147
148                                                        if (p instanceof ListParam) {
149                                                                ListAccess listAccess = Casting.assertCast(ListAccess.class, registry.prepareAccess(p, true));
150                                                                Object list = a.get(p, Object.class);
151                                                                if (list == null) {
152                                                                        list = listAccess.createAccessee();
153                                                                        a.set(p, list);
154                                                                }
155                                                                listAccess.select(list);
156                                                                parent.set(new Pair<Access, CompositeParam>(listAccess, listAccess.prepareParamFor(Integer.toString(listAccess.getParamCount()))));
157
158                                                        } else {
159                                                                parent.set(Pair.make(a, p));
160                                                        }
161                                                }
162                                        }
163
164                                        if (parent.get() == null) {
165                                                log.trace("{} cannot be placed in {}", name, a);
166                                                accessIterator.remove();
167                                        }
168                                }
169
170                                if (parent.get() == null) {
171                                        throw new FramsticksException().msg("failed to find place for loaded object").arg("name", name); //.arg("in", accessesStack);
172                                }
173
174                                currentAccess.set(registry.prepareAccess(parent.get().second, true));
175                                Object object = parent.get().first.get(parent.get().second, Object.class);
176                                if (object != null) {
177                                        currentAccess.get().select(object);
178                                        needAdd.set(false);
179                                } else {
180                                        object = currentAccess.get().createAccessee();
181                                        currentAccess.get().select(object);
182                                        needAdd.set(true);
183                                }
184
185                                return currentAccess.get();
186                        }
187                });
188
189                loader.addListener(MultiParamLoader.Status.AfterObject, new MultiParamLoader.StatusListener() {
190                        @Override
191                        public void onStatusChange() {
192                                if (needAdd.get()) {
193                                        parent.get().first.set(parent.get().second, currentAccess.get().getSelected());
194                                }
195                                if (currentAccess.get() != rootAccess)  {
196                                        accessesStack.add(currentAccess.get());
197                                }
198                                currentAccess.set(null);
199                        }
200                });
201
202                loader.go();
203                if (accessesStack.isEmpty()) {
204                        throw new FramsticksException().msg("failed to load from source").arg("source", source);
205                }
206                return accessesStack.get(0);
207        }
208
209        public static <S extends Sink> S saveAll(Access access, S sink, Registry registry) {
210                if (access instanceof ObjectAccess) {
211                        savePrimitives(access, sink);
212                }
213                for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
214                        Object child = access.get(p, Object.class);
215                        if (child == null) {
216                                continue;
217                        }
218                        saveAll(registry.prepareAccess(p, true).select(child), sink, registry);
219                }
220                return sink;
221        }
222
223        public static void saveComposites(Access access, Sink sink, Registry registry) {
224                for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
225                        Object child = access.get(p, Object.class);
226                        if (child == null) {
227                                continue;
228                        }
229                        savePrimitives(registry.prepareAccess(p, true).select(child), sink);
230                }
231        }
232
233        public static void savePrimitives(Access access, Sink sink) {
234                if (access instanceof ObjectAccess) {
235                        ObjectAccess objectAccess = (ObjectAccess) access;
236                        boolean headerNeeded = true;
237                        // sink.print(framsClass.getId()).print(":").breakLine();
238                        for (PrimitiveParam<?> p : filterInstanceof(access.getParams(), PrimitiveParam.class)) {
239
240                                Object value = objectAccess.get(p, Object.class);
241                                if ((value == null) || value.equals(p.getDef(Object.class))) {
242                                        continue;
243                                }
244
245                                if (headerNeeded) {
246                                        sink.print(access.getTypeId()).print(":").breakLine();
247                                        headerNeeded = false;
248                                }
249
250                                String stringValue = p.serialize(value);
251
252                                sink.print(p.getId()).print(":").print(stringValue);
253                                // p.save(sink, stringValue);
254                                sink.breakLine();
255                        }
256                        if (!headerNeeded) {
257                                sink.breakLine();
258                        }
259                        return;
260                }
261                throw new FramsticksException().msg("invalid type of access for primitive save").arg("access", access);
262        }
263
264        public static void save(Access access, Sink sink) {
265                if (access instanceof ObjectAccess) {
266                        savePrimitives(access, sink);
267                        return;
268                }
269                if (access instanceof ListAccess) {
270                        ListAccess listAccess = (ListAccess) access;
271                        for (CompositeParam p : filterInstanceof(listAccess.getParams(), CompositeParam.class)) {
272                                Object child = listAccess.get(p, Object.class);
273                                //this is probably an assertion
274                                assert child != null;
275                                save(listAccess.getElementAccess().select(child), sink);
276                        }
277                        return;
278                }
279                throw new FramsticksException().msg("unknown access category").arg("access", access);
280        }
281
282        public static void loadComposites(Access access, Source source, final Registry registry) {
283                if (access instanceof ObjectAccess) {
284                        final ObjectAccess objectAccess = (ObjectAccess) access;
285
286                        MultiParamLoader loader = new MultiParamLoader();
287
288                        loader.setNewSource(source);
289
290                        loader.setAccessProvider(new AccessProvider() {
291                                @Override
292                                public Access getAccess(String name) {
293                                        CompositeParam result = null;
294                                        for (CompositeParam p : filterInstanceof(objectAccess.getParams(), CompositeParam.class)) {
295                                                if (p.getContainedTypeName().equals(name)) {
296                                                        if (result != null) {
297                                                                throw new FramsticksException().msg("class name is ambiguous in access").arg("name", name).arg("first candidate", result).arg("second candidate", p);
298                                                        }
299                                                        result = p;
300
301                                                }
302                                        }
303                                        if (result == null) {
304                                                throw new FramsticksException().msg("class name is unknown").arg("name", name).arg("in", objectAccess);
305                                        }
306
307                                        return registry.prepareAccess(result, true).select(objectAccess.get(result, Object.class));
308                                }
309                        });
310
311
312                        loader.go();
313
314                        return;
315                }
316                throw new UnimplementedException().msg("unknown access category").arg("access", access);
317        }
318
319        public static void load(Access access, Source source) {
320                if (!(access instanceof ObjectAccess)) {
321                        throw new FramsticksException().msg("access is not an object access").arg("access", access);
322                }
323                Entry entry;
324                while ((entry = readEntry(source)) != null) {
325                        Param param = access.getParam(entry.key);
326                        if (param == null) {
327                                throw new FramsticksException().msg("param not found in access").arg("name", entry.key).arg("access", access);
328                        }
329                        if (!(param instanceof ValueParam)) {
330                                throw new FramsticksException().msg("param is not a value param").arg("param", param).arg("access", access);
331                        }
332                        if ((param.getFlags() & ParamFlags.DONTLOAD) == 0) {
333                                ValueParam valueParam = (ValueParam) param;
334                                // Object object = valueParam.deserialize(entry.value, null,  Object.class);
335                                int retFlags = access.set(valueParam, entry.value);
336                                if ((retFlags & (PSET_HITMIN | PSET_HITMAX)) != 0) {
337                                        String which = ((retFlags & PSET_HITMIN) != 0) ? "small" : "big";
338                                        log.warn("value of key '{}' was too {}, adjusted", entry.key, which);
339                                }
340                        }
341                }
342        }
343
344        public interface Adjuster {
345                public Holder<Object> adjust(ValueParam param);
346                public Class<? extends ValueParam> getParamType();
347        }
348
349        public static class MinAdjuster implements Adjuster {
350
351                /**
352                 *
353                 */
354                public MinAdjuster() {
355                }
356
357                @Override
358                public Class<? extends ValueParam> getParamType() {
359                        return PrimitiveParam.class;
360                }
361
362                @Override
363                public Holder<Object> adjust(ValueParam param) {
364                        Object value = ((PrimitiveParam<?>) param).getMin(Object.class);
365                        if (value == null) {
366                                return null;
367                        }
368                        return Holder.make(value);
369                }
370        }
371
372        public static class MaxAdjuster implements Adjuster {
373
374                /**
375                 *
376                 */
377                public MaxAdjuster() {
378                }
379
380                @Override
381                public Class<? extends ValueParam> getParamType() {
382                        return PrimitiveParam.class;
383                }
384
385                @Override
386                public Holder<Object> adjust(ValueParam param) {
387                        Object value = ((PrimitiveParam<?>) param).getMax(Object.class);
388                        if (value == null) {
389                                return null;
390                        }
391                        return Holder.make(value);
392                }
393        }
394
395        public static class DefAdjuster implements Adjuster {
396
397                protected final boolean numericOnly;
398
399                /**
400                 * @param numericOnly
401                 */
402                public DefAdjuster(boolean numericOnly) {
403                        this.numericOnly = numericOnly;
404                }
405
406                public Class<? extends ValueParam> getParamType() {
407                        return ValueParam.class;
408                }
409
410                @Override
411                public Holder<Object> adjust(ValueParam param) {
412                        if (numericOnly && !(param.isNumeric())) {
413                                return null;
414                        }
415                        return Holder.make(param.getDef(Object.class));
416                }
417        }
418
419        public static void adjustAll(Access access, Adjuster adjuster) {
420                for (ValueParam param : Containers.filterInstanceof(access.getParams(), adjuster.getParamType())) {
421                        Holder<Object> value = adjuster.adjust(param);
422                        if (value != null) {
423                                access.set(param, value.get());
424                        }
425                }
426        }
427
428        public static Object wrapValueInResultIfPrimitive(Object object) {
429                Class<?> javaClass = object.getClass();
430                if (ClassUtils.isPrimitiveOrWrapper(javaClass)) {
431                        return new Result(object);
432                }
433                if (javaClass.equals(String.class)) {
434                        return new Result(object);
435                }
436                return object;
437        }
438
439        /**
440         *
441         * If both arguments are File, than do nothing; otherwise:
442         *
443         * If from argument is a File:
444         * - if toJavaClass is Object.class, than try read using registry
445         * - otherwise: try use loadComposites
446         *
447         * If to argument is a File:
448         * - use Registry to saveAll
449         *
450         */
451        public static <T, F> T convert(Class<T> toJavaClass, F from, Registry registry) {
452                log.trace("converting from {} to {}", from, toJavaClass);
453                if (toJavaClass.equals(from.getClass())) {
454                        return toJavaClass.cast(from);
455                }
456                if (from instanceof File) {
457                        File file = (File) from;
458                        return Casting.throwCast(toJavaClass, loadAll((toJavaClass.equals(Object.class) ? null : registry.createAccess(toJavaClass)), file.getContent(), registry).getSelected());
459                }
460                if (toJavaClass.equals(File.class)) {
461                        ListSink sink = new ListSink();
462                        saveAll(registry.createAccess(from.getClass()).select(from), sink, registry);
463                        return Casting.throwCast(toJavaClass, new File("", new ListSource(sink.getOut())));
464                }
465
466                throw new FramsticksUnsupportedOperationException().msg("conversion").arg("from", from.getClass()).arg("to", toJavaClass);
467        }
468
469        @SuppressWarnings("serial")
470        public static class EqualityException extends FramsticksException {
471        }
472
473
474        public static void assureEquality(Access a, Access b, Registry registry) {
475                try {
476                        if (a.getParamCount() != b.getParamCount()) {
477                                throw new EqualityException().msg("param count not equal").arg("left", a.getParamCount()).arg("right", b.getParamCount());
478                        }
479                        for (ValueParam avp : Containers.filterInstanceof(a.getParams(), ValueParam.class)) {
480                                Param bp = b.getParam(avp.getId());
481                                if (bp == null) {
482                                        throw new EqualityException().msg("param from left not present in right").arg("param", avp);
483                                }
484                                Misc.checkEquals(avp.getClass(), bp.getClass(), "params type not equals", null);
485                                ValueParam bvp = (ValueParam) bp;
486
487                                Object oa = a.get(avp, Object.class);
488                                Object ob = b.get(avp, Object.class);
489
490                                if (avp instanceof CompositeParam) {
491                                        assureEquality(registry.prepareAccess((CompositeParam) avp, false).select(oa), registry.prepareAccess((CompositeParam) bvp, false).select(ob), registry);
492                                        continue;
493                                }
494                                Misc.checkEquals(oa, ob, "values not equal", null);
495                        }
496                } catch (EqualityException e) {
497                        throw e.arg("left", a).arg("right", b);
498                }
499        }
500
501        public static boolean areEqual(Access a, Access b, Registry registry) {
502                try {
503                        assureEquality(a, b, registry);
504                        return true;
505                } catch (EqualityException e) {
506                }
507                return false;
508        }
509
510}
Note: See TracBrowser for help on using the repository browser.