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

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

HIGHLIGHTS:

  • add auto loading and saving algorithms between

frams files format and Java classes

  • respect ValueChange? events in GUI (do not reload object)
  • support results of procedures in Java server
  • make Experiment automatically convert between frams file and NetFile? object
  • add MessageLogger? (compatible with original frams server messages)
  • WorkPackageLogic? now validates results, is able to discard them, reschedule

whole package, or only uncomputed remainder

CHANGELOG:
Show just a short description in PrimeExperiment?.

Add primes_changed event to the PrimeExperiment?.

Make WorkPackageLogic? robust to frams server returning invalid results.

Add MessageLogger? to logics.

Add NetFile? interface. Support Messages from server.

Minor changes to connections.

Merge results in the PrimeExperiment?.

More netload class->file conversion to Simulator.

Move netsave parsing to Simulator.

Fix bug with inverted ordering of events firing in Experiment.

Minor changes.

Minor logging changes.

Use AccessOperations?.convert in NetLoadSaveLogic?

NetLoadSaveLogic? now encloses the conversion.

Use more generic AccessOperations? saveAll and loadAll in PrimePackage?.

Add Result class for enclosing of call invocations' results.

Improve feature request handling in Connections.

Use AccessOperations?.convert in RemoteTree? events parsing.

Minor change.

Add some information params to Java server root and CLI objects.

A draft implementation of loadAll algorithm.

That algorithm tries to load objects into a tree structure.

Add AccessOperationsTest? test.

Develop WorkPackageLogic?.

  • add state tracking fields
  • add work package generation

Add utility class SimplePrimitive?.

Meant for Java backend classes, enclose a single primitive value
and set of listeners.

Improve primitive value refresh in GUI.

When ValueChange? found in called event, do not reload whole
object, but only update GUI (no communication is performed).

Use ValueChange? in the TestClass? test.

Minor changes.

Sending all packages in PrimeExperiment? to the frams servers.

Develop AccessOperations?.loadComposites().

Remove addAccess from MultiParamLoader? interface.

There is now no default AccessProvider? in MultiParamLoader?.
User must explicitely set AccessStash? or Registry.

Improve saving algorithms in AccessOperations?.

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