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

HIGHLIGHTS:

  • improve tree side notes
  • improve GUI layout
  • add foldable list of occured events to EventControl?
  • improve automatic type conversion in proxy listeners
  • implement several Access functionalities as algorithms independent of Access type
  • introduce draft base classes for distributed experiments
  • automatically register dependant Java classes to FramsClass? registry
  • add testing prime experiment and configuration
  • simplify and improve task dispatching

CHANGELOG:
Improve task dispatching in RemoteTree?.

GUI no longer hangs on connection problems.

Make all dispatchers joinables.

Refactorize Thread dispatcher.

Remove Task and PeriodicTask?.

Use Java utilities in those situations.

Reworking tasks dispatching.

Fix bug in EventControl? listener dispatching.

Minor improvements.

Add testing configuration for ExternalProcess? in GUI.

More improvement to prime.

Support for USERREADONLY in GUI.

Add that flag to various params in Java classes.

Remove redundant register clauses from several FramsClassAnnotations?.

Automatically gather and register dependant classes.

Add configuration for prime.

Improve Simulator class.

Add prime.xml configuration.

Introduce draft Experiment and Simulator classes.

Add prime experiment tests.

Enclose typical map with listeners into SimpleUniqueList?.

Needfile works in GUI.

Improve needfile handling in Browser.

More improvement with NeedFile?.

Implementing needfile.

Update test.

Rename ChangeEvent? to TestChangeEvent?.

Automatic argument type search in RemoteTree? listeners.

MultiParamLoader? uses AccessProvider?. By default old implementation
enclosed in AccessStash? or Registry.

Minor changes.

Rename SourceInterface? to Source.

Also improve toString of File and ListSource?.

Remove unused SimpleSource? class.

Add clearing in HistoryControl?.

Show entries in table at EventControl?.

Improve EventControl?.

Add listeners registration to EventControl?.

Add foldable table to HistoryControl?.

Add control row to Procedure and Event controls.

Improve layout of controls.

Another minor change to gui layout.

Minor improvement in the SliderControl?.

Minor changes.

Move ReflectionAccess?.Backend to separate file.

It was to cluttered.

Cleanup in ReflectionAccess?.

Move setMin, setMax, setDef to AccessOperations?.

Extract loading operation into AccessOperations?.

Append Framsticks to name of UnsupportedOperationException?.

The java.lang.UnsupportedOperationException? was shadowing this class.

Rename params.Util to params.ParamsUtil?.

Several improvements.

Minor changes.

Implement revert functionality.

Improve local changes management.

Minor improvement.

Remove methods rendered superfluous after SideNoteKey? improvement.

Improve SideNoteKey?.

It is now generic type, so explicit type specification at
call site is no more needed.

Introduce SideNoteKey? interface.

Only Objects implementing that key may be used as side note keys.

Minor improvements.

Use strings instead of ValueControls? in several gui mappings.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • java/main/src/main/java/com/framsticks/params/ReflectionAccess.java

    r100 r101  
    11package com.framsticks.params;
    22
    3 import java.lang.reflect.Field;
    43import java.lang.reflect.InvocationTargetException;
    54import java.lang.reflect.Method;
    6 import java.util.ArrayList;
    7 import java.util.Collections;
    8 import java.util.Comparator;
    9 import java.util.HashMap;
    10 import java.util.IdentityHashMap;
    11 import java.util.List;
    12 import java.util.Map;
    13 
    14 import javax.annotation.concurrent.Immutable;
     5
    156
    167import org.apache.logging.log4j.Logger;
    178import org.apache.logging.log4j.LogManager;
    189
    19 import com.framsticks.params.annotations.AutoAppendAnnotation;
    2010import com.framsticks.params.types.EventParam;
    2111import com.framsticks.params.types.ProcedureParam;
    2212import com.framsticks.util.FramsticksException;
    23 import com.framsticks.util.lang.Pair;
    2413
    2514import static com.framsticks.util.lang.Containers.*;
     
    3726
    3827        protected final Class<?> javaClass;
    39         protected final Backend backend;
     28        protected final ReflectionAccessBackend backend;
    4029
    4130        private Object object;
    42 
    43         @Immutable
    44         public static class Backend {
    45 
    46                 protected static final Map<Pair<Class<?>, FramsClass>, Backend> synchronizedCache = Collections.synchronizedMap(new HashMap<Pair<Class<?>, FramsClass>, Backend>());
    47 
    48 
    49                 public interface ReflectedGetter {
    50                         public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    51                 }
    52 
    53                 public interface ReflectedSetter {
    54                         public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    55                 }
    56 
    57                 public interface ReflectedCaller {
    58                         public Object call(Object object, Object[] arguments) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    59                 }
    60 
    61                 public interface ReflectedAdder{
    62                         public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    63                 }
    64 
    65                 public interface ReflectedRemover{
    66                         public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
    67                 }
    68 
    69                 protected final Map<ValueParam, ReflectedSetter> setters = new IdentityHashMap<>();
    70                 protected final Map<ValueParam, ReflectedGetter> getters = new IdentityHashMap<>();
    71                 protected final Map<ProcedureParam, ReflectedCaller> callers = new IdentityHashMap<>();
    72                 protected final Map<EventParam, ReflectedAdder> adders = new IdentityHashMap<>();
    73                 protected final Map<EventParam, ReflectedRemover> removers = new IdentityHashMap<>();
    74 
    75                 protected final List<Method> autoAppendMethods = new ArrayList<>();
    76 
    77                 /**
    78                  * @param params
    79                  */
    80                 public Backend() {
    81                 }
    82 
    83                 public static Backend getOrCreateFor(Class<?> reflectedClass, FramsClass framsClass) {
    84 
    85                         Pair<Class<?>, FramsClass> id = new Pair<Class<?>, FramsClass>(reflectedClass, framsClass);
    86                         Backend backend = synchronizedCache.get(id);
    87                         if (backend != null) {
    88                                 return backend;
    89                         }
    90 
    91                         log.debug("constructing backend for {}", id);
    92                         backend = new Backend();
    93 
    94                         Map<String, ParamCandidate> candidates = ParamCandidate.getAllCandidates(reflectedClass).getCandidates();
    95 
    96                         try {
    97                                 for (final ProcedureParam pp : filterInstanceof(framsClass.getParamEntries(), ProcedureParam.class)) {
    98                                         if (!candidates.containsKey(pp.getId())) {
    99                                                 log.trace("java class does implement method {}", pp);
    100                                                 continue;
    101                                         }
    102                                         ParamCandidate pc = candidates.get(pp.getId());
    103                                         final Method method = pc.getCaller();
    104 
    105                                         backend.callers.put(pp, new ReflectedCaller() {
    106 
    107                                                 @Override
    108                                                 public Object call(Object object, Object[] arguments) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    109                                                         return method.invoke(object, arguments);
    110                                                 }
    111                                         });
    112 
    113                                 }
    114 
    115                                 for (final EventParam ep : filterInstanceof(framsClass.getParamEntries(), EventParam.class)) {
    116                                         if (!candidates.containsKey(ep.getId())) {
    117                                                 log.trace("java class does not implement the event param {}", ep);
    118                                                 continue;
    119                                         }
    120                                         ParamCandidate ec = candidates.get(ep.getId());
    121                                         final Method adder = ec.getAdder();
    122                                         final Method remover = ec.getRemover();
    123 
    124                                         backend.adders.put(ep, new ReflectedAdder() {
    125 
    126                                                 @Override
    127                                                 public void reg(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    128                                                         adder.invoke(object, listener);
    129                                                 }
    130                                         });
    131 
    132                                         backend.removers.put(ep, new ReflectedRemover() {
    133 
    134                                                 @Override
    135                                                 public void regRemove(Object object, EventListener<?> listener) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    136                                                         remover.invoke(object, listener);
    137                                                 }
    138                                         });
    139                                 }
    140 
    141                                 for (final ValueParam vp : filterInstanceof(framsClass.getParamEntries(), ValueParam.class)) {
    142                                         if (!candidates.containsKey(vp.getId())) {
    143                                                 throw new ConstructionException().msg("missing candidate for param").arg("param", vp);
    144                                         }
    145                                         ParamCandidate pc = candidates.get(vp.getId());
    146                                         if (pc.isReadOnly() && !vp.hasFlag(ParamFlags.READONLY)) {
    147                                                 throw new ConstructionException().msg("readonly state conflict").arg("param", vp);
    148                                         }
    149                                         if (!typeMatch(pc.getRawType(), vp.getStorageType())) {
    150                                                 throw new ConstructionException().msg("types mismatch for param").arg("param", vp).arg("candidate", pc.getType()).arg("storage", vp.getStorageType());
    151                                         }
    152 
    153                                         final boolean primitive = pc.isPrimitive();
    154                                         if (pc.getField() != null) {
    155                                                 final Field f = pc.getField();
    156                                                 backend.getters.put(vp, new ReflectedGetter() {
    157                                                         @Override
    158                                                         public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException {
    159                                                                 return type.cast(f.get(object));
    160                                                         }
    161                                                 });
    162                                                 if (!pc.isFinal()) {
    163                                                         backend.setters.put(vp, new ReflectedSetter() {
    164                                                                 @Override
    165                                                                 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException {
    166                                                                         if (value == null && primitive) {
    167                                                                                 throw new FramsticksException().msg("setting null to primitive value");
    168                                                                         }
    169                                                                         f.set(object, value);
    170                                                                 }
    171                                                         });
    172                                                 }
    173                                         } else {
    174                                                 final Method g = pc.getGetter();
    175 
    176                                                 backend.getters.put(vp, new ReflectedGetter() {
    177                                                         @Override
    178                                                         public <T> T get(Object object, Class<T> type) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    179                                                                 return type.cast(g.invoke(object));
    180                                                         }
    181                                                 });
    182 
    183                                                 if (!pc.isFinal()) {
    184                                                         final Method s = pc.getSetter();
    185                                                         backend.setters.put(vp, new ReflectedSetter() {
    186                                                                 @Override
    187                                                                 public <T> void set(Object object, T value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    188                                                                         if (value == null && primitive) {
    189                                                                                 throw new FramsticksException().msg("setting null to primitive value");
    190                                                                         }
    191                                                                         s.invoke(object, value);
    192                                                                 }
    193                                                         });
    194                                                 }
    195                                         }
    196                                 }
    197                         } catch (ConstructionException e) {
    198                                 throw e.arg("java class", reflectedClass).arg("framsClass", framsClass);
    199                         }
    200 
    201                         Class<?> javaClass = reflectedClass;
    202                         while (javaClass != null) {
    203 
    204                                 for (Method m : javaClass.getDeclaredMethods()) {
    205                                         AutoAppendAnnotation a = m.getAnnotation(AutoAppendAnnotation.class);
    206                                         if (a == null) {
    207                                                 continue;
    208                                         }
    209                                         Class<?>[] args = m.getParameterTypes();
    210                                         if (args.length != 1) {
    211                                                 throw new ConstructionException().msg("invalid number of arguments in AutoAppend marked method").arg("method", m).arg("arguments", args.length);
    212                                         }
    213                                         backend.autoAppendMethods.add(m);
    214                                 }
    215 
    216                                 javaClass = javaClass.getSuperclass();
    217                         }
    218 
    219                         Collections.sort(backend.autoAppendMethods, new Comparator<Method>() {
    220 
    221                                 @Override
    222                                 public int compare(Method m0, Method m1) {
    223                                         Class<?> arg0 = m0.getParameterTypes()[0];
    224                                         Class<?> arg1 = m1.getParameterTypes()[0];
    225                                         if (arg0.isAssignableFrom(arg1)) {
    226                                                 return 1;
    227                                         }
    228                                         if (arg1.isAssignableFrom(arg0)) {
    229                                                 return -1;
    230                                         }
    231                                         return 0;
    232                                 }
    233                         });
    234 
    235                         synchronizedCache.put(id, backend);
    236                         return backend;
    237                 }
    238 
    239         }
    240 
    241         public static boolean typeMatch(Class<?> a, Class<?> b) {
    242                 if (b.isPrimitive()) {
    243                         throw new FramsticksException().msg("failed to match type, right argument is primitive").arg("left", a).arg("right", b);
    244                 }
    245                 if (!a.isPrimitive()) {
    246                         return a.equals(b);
    247                 }
    248 
    249                 if (a.equals(int.class)) {
    250                         return b.equals(Integer.class);
    251                 }
    252                 if (a.equals(double.class)) {
    253                         return b.equals(Double.class);
    254                 }
    255                 if (a.equals(boolean.class)) {
    256                         return b.equals(Boolean.class);
    257                 }
    258                 throw new FramsticksException().msg("failed to match types").arg("left", a).arg("right", b);
    259         }
    260 
    261 
    262 
    26331
    26432        public ReflectionAccess(Class<?> javaClass) throws ConstructionException {
     
    26836
    26937        public ReflectionAccess(Class<?> javaClass, FramsClass framsClass) throws ConstructionException {
    270                 this(javaClass, framsClass, Backend.getOrCreateFor(javaClass, framsClass));
    271         }
    272 
    273         protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, Backend backend) throws ConstructionException {
     38                this(javaClass, framsClass, ReflectionAccessBackend.getOrCreateFor(javaClass, framsClass));
     39        }
     40
     41        protected ReflectionAccess(Class<?> javaClass, FramsClass framsClass, ReflectionAccessBackend backend) throws ConstructionException {
    27442                super(framsClass);
    27543                this.javaClass = javaClass;
     
    27846
    27947        @Override
    280         public ReflectionAccess cloneAccess() throws ConstructionException {
     48        public ReflectionAccess cloneAccess() {
    28149                return new ReflectionAccess(javaClass, framsClass, backend);
    28250        }
     
    29058                                }
    29159
    292                                 return backend.getters.get(param).get(object, type);
     60                                return backend.getters.get(param.getId()).get(object, type);
    29361                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    29462                                throw new FramsticksException().msg("failed to get").cause(e);
     
    31078                                        throw new FramsticksException().msg("no object set");
    31179                                }
    312                                 Backend.ReflectedSetter s = backend.setters.get(param);
     80                                ReflectionAccessBackend.ReflectedSetter s = backend.setters.get(param.getId());
    31381                                if (s == null) {
    31482                                        throw new FramsticksException().msg("trying to set unsettable");
     
    334102                                }
    335103
    336                                 backend.adders.get(param).reg(object, listener);
     104                                backend.adders.get(param.getId()).reg(object, listener);
    337105                                return;
    338106                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     
    352120                                }
    353121
    354                                 backend.removers.get(param).regRemove(object, listener);
     122                                backend.removers.get(param.getId()).regRemove(object, listener);
    355123                                return;
    356124                        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
     
    364132        @Override
    365133        public Object call(String id, Object[] arguments) {
    366                 return call(framsClass.getParamEntry(id, ProcedureParam.class), arguments);
    367         }
    368 
    369         @Override
    370         public Object call(ProcedureParam param, Object[] arguments) {
    371                 try {
    372                         try {
    373                                 if (object == null) {
    374                                         throw new FramsticksException().msg("no object set");
    375                                 }
    376                                 Backend.ReflectedCaller c = backend.callers.get(param);
     134                try {
     135                        try {
     136                                if (object == null) {
     137                                        throw new FramsticksException().msg("no object set");
     138                                }
     139                                ReflectionAccessBackend.ReflectedCaller c = backend.callers.get(id);
    377140                                if (c == null) {
    378141                                        throw new FramsticksException().msg("method is not bound");
     
    383146                        }
    384147                } catch (FramsticksException e) {
    385                         throw e.arg("param", param).arg("access", this);
    386                 }
    387         }
    388 
    389         void resetErrors() {
    390                 //TODO this replaces returnedObject.resetErrors();
     148                        throw e.arg("param", framsClass.getParam(id)).arg("access", this);
     149                }
     150        }
     151
     152        @Override
     153        public Object call(ProcedureParam param, Object[] arguments) {
     154                return call(param.getId(), arguments);
    391155        }
    392156
     
    396160                        return;
    397161                }
    398 
    399                 resetErrors();
    400162
    401163                try {
     
    416178        @Override
    417179        public ReflectionAccess select(Object object) {
    418                 this.object = Util.selectObjectForAccess(this, object, javaClass);
     180                this.object = ParamsUtil.selectObjectForAccess(this, object, javaClass);
    419181                return this;
    420182        }
     
    425187        }
    426188
    427         // TODO: find a better place for it
    428         public static String objectToString(Object object) {
    429                 StringBuilder b = new StringBuilder();
    430                 for (Field f : object.getClass().getFields()) {
    431                         b.append(f.getName());
    432                         b.append(":");
    433                         try {
    434                                 Object value = f.get(object);
    435                                 b.append((value != null) ? value.toString() : "<null>");
    436                         } catch (IllegalAccessException e) {
    437                                 e.printStackTrace();
    438                         }
    439                         b.append("\n");
    440                 }
    441                 return b.toString();
    442         }
    443 
    444 
    445189        @Override
    446190        public Object createAccessee() {
     
    448192                        return javaClass.newInstance();
    449193                } catch (InstantiationException | IllegalAccessException e) {
    450                         e.printStackTrace();
    451                 }
    452                 log.fatal("failed to create reflected object of class {} for frams type {}", javaClass.getCanonicalName(), framsClass.getId());
    453                 return null;
    454         }
    455 
     194                        throw new FramsticksException().msg("failed to create reflected object").arg("java class", javaClass).arg("frams class", framsClass).cause(e);
     195                }
     196        }
    456197
    457198        @Override
Note: See TracChangeset for help on using the changeset viewer.