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

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

HIGHLIGHTS:

  • import refactorization: move Tree, Path, etc.

from core to structure package

  • initial serialization implementation
  • improve PrimeExperiment? test
  • many organizational changes and convenience improvements

CHANGELOG:
Make registry in AbstractTree? final.

Move most classes from core to structure package.

Minor changes.

Switch names of Future and FutureHandler?.

Rename ExceptionResultHandler? to ExceptionHandler?.

Rename ExceptionHandler? to ExceptionDispatcherHandler?.

Fix bug in ParamCandidate? cache.

Add missing synchronization to the BufferedDispatcher?.

Develop @Serialized support.

Rework serialization further.

Add serialization/deserialization interface to ValueParam?.

Move getStorageType and isNumeric from Param down to params hierarchy.

Minor changes.

Improve param type induction.

Add TestSerializedClass? for testing new serialization.

Add info files gor GenePool? and Population.

Add standard.expt exemplary netfile.

Add type name field to PropertiesObject?.

Use PropertiesObject? for PropertiesAccess? instead of ordinary map.

Hide getFramsClass is several more places.

More unification accross FramsClass?, Access and Path.

Add ParamCollection?.

Simplify interface for getting params from FramsClass?, Access
or Path.

Make Access.call() interface variadic.

Add arguments(args) convenience wrapper around new Object[] {args}.

Upgrade to apache.commons.lang version 3.1

Minor improvement with Response constructors.

Develop proper result printing in ClientAtServer?.

Add experimentNetsave to PrimeExperiment?.

File size: 14.3 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                loader.setNewSource(source);
102                final LinkedList<Access> accessesStack = new LinkedList<>();
103                if (rootAccess != null) {
104                        assureSelected(rootAccess);
105                        accessesStack.add(rootAccess);
106                }
107                final Holder<Boolean> first = new Holder<>(true);
108                final Holder<Boolean> needAdd = new Holder<>();
109                final Holder<Access> currentAccess = new Holder<>();
110                final Holder<Pair<Access, CompositeParam>> parent = new Holder<>();
111
112                loader.setAccessProvider(new AccessProvider() {
113                        @Override
114                        public Access getAccess(String name) {
115                                if (first.get()) {
116                                        first.set(false);
117                                        if (rootAccess != null) {
118                                                if (name.equals(rootAccess.getTypeId())) {
119                                                        needAdd.set(false);
120                                                        currentAccess.set(rootAccess);
121                                                        return rootAccess;
122                                                }
123                                        } else {
124                                                Access access = registry.createAccess(name);
125                                                needAdd.set(false);
126                                                currentAccess.set(access);
127                                                return access;
128
129                                        }
130                                }
131
132                                ListIterator<Access> accessIterator = accessesStack.listIterator(accessesStack.size());
133                                parent.set(null);
134                                // log.debug("accesses stack: {}", accessesStack);
135
136                                while (accessIterator.hasPrevious()) {
137                                        Access a = accessIterator.previous();
138                                        assert a != null;
139
140                                        for (CompositeParam p : Containers.filterInstanceof(a.getParams(), CompositeParam.class)) {
141                                                if (p.getContainedTypeName().equals(name)) {
142
143                                                        if (parent.get() != null) {
144                                                                throw new FramsticksException().msg("ambiguity encountered during loading").arg("name", name);
145                                                        }
146
147                                                        if (p instanceof ListParam) {
148                                                                ListAccess listAccess = Casting.assertCast(ListAccess.class, registry.prepareAccess(p));
149                                                                listAccess.select(a.get(p, Object.class));
150                                                                parent.set(new Pair<Access, CompositeParam>(listAccess, listAccess.prepareParamFor(Integer.toString(listAccess.getParamCount()))));
151
152                                                        } else {
153                                                                parent.set(Pair.make(a, p));
154                                                        }
155                                                }
156                                        }
157
158                                        if (parent.get() == null) {
159                                                accessIterator.remove();
160                                        }
161                                }
162
163                                if (parent.get() == null) {
164                                        throw new FramsticksException().msg("failed to find place for loaded object").arg("name", name);
165                                }
166
167                                currentAccess.set(registry.prepareAccess(parent.get().second));
168                                Object object = parent.get().first.get(parent.get().second, Object.class);
169                                if (object != null) {
170                                        currentAccess.get().select(object);
171                                        needAdd.set(false);
172                                } else {
173                                        object = currentAccess.get().createAccessee();
174                                        currentAccess.get().select(object);
175                                        needAdd.set(true);
176                                }
177
178                                return currentAccess.get();
179                        }
180                });
181
182                loader.addListener(MultiParamLoader.Status.AfterObject, new MultiParamLoader.StatusListener() {
183                        @Override
184                        public void onStatusChange() {
185                                if (needAdd.get()) {
186                                        parent.get().first.set(parent.get().second, currentAccess.get().getSelected());
187                                }
188                                if (currentAccess.get() != rootAccess)  {
189                                        accessesStack.add(currentAccess.get());
190                                }
191                                currentAccess.set(null);
192                        }
193                });
194
195                loader.go();
196                if (accessesStack.isEmpty()) {
197                        throw new FramsticksException().msg("failed to load from source").arg("source", source);
198                }
199                return accessesStack.get(0);
200        }
201
202        public static void saveAll(Access access, Sink sink, Registry registry) {
203                if (access instanceof ObjectAccess) {
204                        savePrimitives(access, sink);
205                }
206                for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
207                        Object child = access.get(p, Object.class);
208                        if (child == null) {
209                                continue;
210                        }
211                        saveAll(registry.prepareAccess(p).select(child), sink, registry);
212                }
213        }
214
215        public static void saveComposites(Access access, Sink sink, Registry registry) {
216                for (CompositeParam p : filterInstanceof(access.getParams(), CompositeParam.class)) {
217                        Object child = access.get(p, Object.class);
218                        if (child == null) {
219                                continue;
220                        }
221                        savePrimitives(registry.prepareAccess(p).select(child), sink);
222                }
223        }
224
225        public static void savePrimitives(Access access, Sink sink) {
226                if (access instanceof ObjectAccess) {
227                        ObjectAccess objectAccess = (ObjectAccess) access;
228                        boolean headerNeeded = true;
229                        // sink.print(framsClass.getId()).print(":").breakLine();
230                        for (PrimitiveParam<?> p : filterInstanceof(access.getParams(), 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(access.getTypeId()).print(":").breakLine();
239                                        headerNeeded = false;
240                                }
241
242                                String stringValue = p.serialize(value);
243
244                                sink.print(p.getId()).print(":").print(stringValue);
245                                // p.save(sink, stringValue);
246                                sink.breakLine();
247                        }
248                        if (!headerNeeded) {
249                                sink.breakLine();
250                        }
251                        return;
252                }
253                throw new FramsticksException().msg("invalid type of access for primitive save").arg("access", access);
254        }
255
256        public static void save(Access access, Sink sink) {
257                if (access instanceof ObjectAccess) {
258                        savePrimitives(access, sink);
259                        return;
260                }
261                if (access instanceof ListAccess) {
262                        ListAccess listAccess = (ListAccess) access;
263                        for (CompositeParam p : filterInstanceof(listAccess.getParams(), CompositeParam.class)) {
264                                Object child = listAccess.get(p, Object.class);
265                                //this is probably an assertion
266                                assert child != null;
267                                save(listAccess.getElementAccess().select(child), sink);
268                        }
269                        return;
270                }
271                throw new FramsticksException().msg("unknown access category").arg("access", access);
272        }
273
274        public static void loadComposites(Access access, Source source, final Registry registry) {
275                if (access instanceof ObjectAccess) {
276                        final ObjectAccess objectAccess = (ObjectAccess) access;
277
278                        MultiParamLoader loader = new MultiParamLoader();
279
280                        loader.setNewSource(source);
281
282                        loader.setAccessProvider(new AccessProvider() {
283                                @Override
284                                public Access getAccess(String name) {
285                                        CompositeParam result = null;
286                                        for (CompositeParam p : filterInstanceof(objectAccess.getParams(), CompositeParam.class)) {
287                                                if (p.getContainedTypeName().equals(name)) {
288                                                        if (result != null) {
289                                                                throw new FramsticksException().msg("class name is ambiguous in access").arg("name", name).arg("first candidate", result).arg("second candidate", p);
290                                                        }
291                                                        result = p;
292
293                                                }
294                                        }
295                                        if (result == null) {
296                                                throw new FramsticksException().msg("class name is unknown").arg("name", name).arg("in", objectAccess);
297                                        }
298
299                                        return registry.prepareAccess(result).select(objectAccess.get(result, Object.class));
300                                }
301                        });
302
303
304                        loader.go();
305
306                        return;
307                }
308                throw new UnimplementedException().msg("unknown access category").arg("access", access);
309        }
310
311        public static void load(Access access, Source source) {
312                if (!(access instanceof ObjectAccess)) {
313                        throw new FramsticksException().msg("access is not an object access").arg("access", access);
314                }
315                Entry entry;
316                while ((entry = readEntry(source)) != null) {
317                        Param param = access.getParam(entry.key);
318                        if (param == null) {
319                                throw new FramsticksException().msg("param not found in access").arg("name", entry.key).arg("access", access);
320                        }
321                        if (!(param instanceof ValueParam)) {
322                                throw new FramsticksException().msg("param is not a value param").arg("param", param).arg("access", access);
323                        }
324                        if ((param.getFlags() & ParamFlags.DONTLOAD) == 0) {
325                                int retFlags = access.set((ValueParam) param, entry.value);
326                                if ((retFlags & (PSET_HITMIN | PSET_HITMAX)) != 0) {
327                                        String which = ((retFlags & PSET_HITMIN) != 0) ? "small" : "big";
328                                        log.warn("value of key '{}' was too {}, adjusted", entry.key, which);
329                                }
330                        }
331                }
332        }
333
334        public interface Adjuster {
335                public Holder<Object> adjust(ValueParam param);
336                public Class<? extends ValueParam> getParamType();
337        }
338
339        public static class MinAdjuster implements Adjuster {
340
341                /**
342                 *
343                 */
344                public MinAdjuster() {
345                }
346
347                @Override
348                public Class<? extends ValueParam> getParamType() {
349                        return PrimitiveParam.class;
350                }
351
352                @Override
353                public Holder<Object> adjust(ValueParam param) {
354                        Object value = ((PrimitiveParam<?>) param).getMin(Object.class);
355                        if (value == null) {
356                                return null;
357                        }
358                        return Holder.make(value);
359                }
360        }
361
362        public static class MaxAdjuster implements Adjuster {
363
364                /**
365                 *
366                 */
367                public MaxAdjuster() {
368                }
369
370                @Override
371                public Class<? extends ValueParam> getParamType() {
372                        return PrimitiveParam.class;
373                }
374
375                @Override
376                public Holder<Object> adjust(ValueParam param) {
377                        Object value = ((PrimitiveParam<?>) param).getMax(Object.class);
378                        if (value == null) {
379                                return null;
380                        }
381                        return Holder.make(value);
382                }
383        }
384
385        public static class DefAdjuster implements Adjuster {
386
387                protected final boolean numericOnly;
388
389                /**
390                 * @param numericOnly
391                 */
392                public DefAdjuster(boolean numericOnly) {
393                        this.numericOnly = numericOnly;
394                }
395
396                public Class<? extends ValueParam> getParamType() {
397                        return ValueParam.class;
398                }
399
400                @Override
401                public Holder<Object> adjust(ValueParam param) {
402                        if (numericOnly && !(param.isNumeric())) {
403                                return null;
404                        }
405                        return Holder.make(param.getDef(Object.class));
406                }
407        }
408
409        public static void adjustAll(Access access, Adjuster adjuster) {
410                for (ValueParam param : Containers.filterInstanceof(access.getParams(), adjuster.getParamType())) {
411                        Holder<Object> value = adjuster.adjust(param);
412                        if (value != null) {
413                                access.set(param, value.get());
414                        }
415                }
416        }
417
418        public static Object wrapValueInResultIfPrimitive(Object object) {
419                Class<?> javaClass = object.getClass();
420                if (ClassUtils.isPrimitiveOrWrapper(javaClass)) {
421                        return new Result(object);
422                }
423                if (javaClass.equals(String.class)) {
424                        return new Result(object);
425                }
426                return object;
427        }
428
429        /**
430         *
431         * If both arguments are File, than do nothing; otherwise:
432         *
433         * If from argument is a File:
434         * - if toJavaClass is Object.class, than try read using registry
435         * - otherwise: try use loadComposites
436         *
437         * If to argument is a File:
438         * - use Registry to saveAll
439         *
440         */
441        public static <T, F> T convert(Class<T> toJavaClass, F from, Registry registry) {
442                if (toJavaClass.equals(from.getClass())) {
443                        return toJavaClass.cast(from);
444                }
445                if (from instanceof File) {
446                        File file = (File) from;
447                        return Casting.throwCast(toJavaClass, loadAll((toJavaClass.equals(Object.class) ? null : registry.createAccess(toJavaClass)), file.getContent(), registry).getSelected());
448                }
449                if (toJavaClass.equals(File.class)) {
450                        ListSink sink = new ListSink();
451                        saveAll(registry.createAccess(from.getClass()).select(from), sink, registry);
452                        return Casting.throwCast(toJavaClass, new File("", new ListSource(sink.getOut())));
453                }
454
455                throw new FramsticksUnsupportedOperationException().msg("conversion").arg("from", from.getClass()).arg("to", toJavaClass);
456        }
457
458        @SuppressWarnings("serial")
459        public static class EqualityException extends FramsticksException {
460        }
461
462
463        public static void assureEquality(Access a, Access b, Registry registry) {
464                try {
465                        if (a.getParamCount() != b.getParamCount()) {
466                                throw new EqualityException().msg("param count not equal").arg("left", a.getParamCount()).arg("right", b.getParamCount());
467                        }
468                        for (ValueParam avp : Containers.filterInstanceof(a.getParams(), ValueParam.class)) {
469                                Param bp = b.getParam(avp.getId());
470                                if (bp == null) {
471                                        throw new EqualityException().msg("param from left not present in right").arg("param", avp);
472                                }
473                                Misc.checkEquals(avp.getClass(), bp.getClass(), "params type not equals", null);
474                                ValueParam bvp = (ValueParam) bp;
475
476                                Object oa = a.get(avp, Object.class);
477                                Object ob = b.get(avp, Object.class);
478
479                                if (avp instanceof CompositeParam) {
480                                        assureEquality(registry.prepareAccess((CompositeParam) avp).select(oa), registry.prepareAccess((CompositeParam) bvp).select(ob), registry);
481                                        continue;
482                                }
483                                Misc.checkEquals(oa, ob, "values not equal", null);
484                        }
485                } catch (EqualityException e) {
486                        throw e.arg("left", a).arg("right", b);
487                }
488        }
489
490        public static boolean areEqual(Access a, Access b, Registry registry) {
491                try {
492                        assureEquality(a, b, registry);
493                        return true;
494                } catch (EqualityException e) {
495                }
496                return false;
497        }
498
499}
Note: See TracBrowser for help on using the repository browser.