]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/accessor/wire/WireServer.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / accessor / wire / WireServer.java
1 /*******************************************************************************\r
2  * Copyright (c) 2010- Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  * \r
9  * Contributors:\r
10  *    VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.databoard.accessor.wire;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.HashMap;\r
18 import java.util.LinkedList;\r
19 import java.util.List;\r
20 import java.util.Map;\r
21 \r
22 import org.simantics.databoard.Bindings;\r
23 import org.simantics.databoard.Methods;\r
24 import org.simantics.databoard.accessor.Accessor;\r
25 import org.simantics.databoard.accessor.Accessor.Listener;\r
26 import org.simantics.databoard.accessor.ArrayAccessor;\r
27 import org.simantics.databoard.accessor.MapAccessor;\r
28 import org.simantics.databoard.accessor.OptionalAccessor;\r
29 import org.simantics.databoard.accessor.RecordAccessor;\r
30 import org.simantics.databoard.accessor.UnionAccessor;\r
31 import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
32 import org.simantics.databoard.accessor.error.AccessorException;\r
33 import org.simantics.databoard.accessor.event.Event;\r
34 import org.simantics.databoard.accessor.impl.AccessorParams;\r
35 import org.simantics.databoard.accessor.interestset.InterestSet;\r
36 import org.simantics.databoard.accessor.reference.ChildReference;\r
37 import org.simantics.databoard.adapter.AdaptException;\r
38 import org.simantics.databoard.annotations.Optional;\r
39 import org.simantics.databoard.binding.ArrayBinding;\r
40 import org.simantics.databoard.binding.Binding;\r
41 import org.simantics.databoard.binding.MapBinding;\r
42 import org.simantics.databoard.binding.RecordBinding;\r
43 import org.simantics.databoard.binding.UnionBinding;\r
44 import org.simantics.databoard.binding.error.BindingConstructionException;\r
45 import org.simantics.databoard.binding.impl.ObjectArrayBinding;\r
46 import org.simantics.databoard.binding.mutable.MutableVariant;\r
47 import org.simantics.databoard.method.MethodInterface;\r
48 import org.simantics.databoard.method.MethodInterface.Method;\r
49 import org.simantics.databoard.method.MethodNotSupportedException;\r
50 import org.simantics.databoard.method.MethodTypeBinding;\r
51 import org.simantics.databoard.method.TcpConnection;\r
52 import org.simantics.databoard.method.TcpConnection.ConnectionListener;\r
53 import org.simantics.databoard.type.ArrayType;\r
54 import org.simantics.databoard.type.Component;\r
55 import org.simantics.databoard.type.Datatype;\r
56 import org.simantics.databoard.type.MapType;\r
57 import org.simantics.databoard.type.UnionType;\r
58 import org.simantics.databoard.util.BijectionMap;\r
59 \r
60 /**\r
61  * WireServer exposes an accessor over TCP/IP socket. \r
62  *\r
63  * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
64  */\r
65 public class WireServer implements IWireServer {\r
66         \r
67         Accessor accessor;\r
68         Map<TcpConnection, ClientRecord> clients = Collections.synchronizedMap( new HashMap<TcpConnection, ClientRecord>() );\r
69         MethodInterface mi;\r
70         AccessorParams params = AccessorParams.DEFAULT;\r
71         \r
72         public WireServer(Accessor accessor) {\r
73                 this.accessor = accessor;\r
74                 try {\r
75                         this.mi = Methods.bindInterface(IWireServer.class, this);\r
76                 } catch (BindingConstructionException e) {\r
77                         throw new RuntimeException(e);\r
78                 }\r
79         }\r
80         \r
81         public MethodInterface getMethodInterface() {\r
82                 return mi;\r
83         }\r
84         \r
85         static class ClientRecord {\r
86                 TcpConnection connection;\r
87                 MethodInterface clientMethodInterface;\r
88                 Method onEventsMethod;\r
89                 IWireClient clientMethods;\r
90                 int accIdCounter = 0;\r
91                 int listIdCounter = 0;          \r
92                 BijectionMap<Integer, AccRecord> accessorTable = new BijectionMap<Integer, AccRecord>();\r
93                 Map<Integer, LisRecord> listenerTable = new HashMap<Integer, LisRecord>();\r
94                 \r
95                 public void dispose() {                 \r
96                 }               \r
97         }\r
98         \r
99         static class AccRecord {\r
100                 int accId;\r
101                 Accessor accessor;\r
102                 ChildReference reference;\r
103                 Datatype type;\r
104                 Binding binding;\r
105         }       \r
106         \r
107         static class LisRecord {\r
108                 int lisId;\r
109                 int accId;\r
110                 InterestSet is;\r
111                 Listener listener;\r
112         }\r
113         \r
114         static class OnEventsRequest {\r
115                 public @Optional Integer arg1;\r
116                 public @Optional Event[] arg2;\r
117         }\r
118             \r
119         /**\r
120          * Get or create new client handler associated with current thread.\r
121          * The result value depends on the current thread.  \r
122          * \r
123          * @return client handler\r
124          * @throws WireException\r
125          */\r
126         public ClientRecord getClient() throws WireException {\r
127                 TcpConnection connection = TcpConnection.getCurrentConnection();\r
128                 if (connection == null) throw new WireException("Internal Error. This method must be invoked in ConnectionThread");\r
129                 try {\r
130                 synchronized(clients) {\r
131                         ClientRecord handler = clients.get( connection );\r
132                         if (handler == null) {\r
133 \r
134                                 RecordBinding requestBinding = (RecordBinding) Bindings.getBindingUnchecked( OnEventsRequest.class );\r
135                                 Binding responseBinding = Bindings.INTEGER;\r
136                                 UnionType ut = new UnionType();\r
137                                 ut.components = new Component[0];\r
138                                 UnionBinding errorBinding = (UnionBinding) params.bindingScheme.getBinding( ut );\r
139                                 MethodTypeBinding onEventsBinding = new MethodTypeBinding("onEvents", requestBinding, responseBinding, errorBinding);\r
140                                 \r
141                                 try {\r
142                                         handler = new ClientRecord();\r
143                                         handler.clientMethodInterface = connection.getRemoteMethodInterface();\r
144                                         handler.onEventsMethod = handler.clientMethodInterface.getMethod( onEventsBinding );\r
145                                         handler.connection = connection;\r
146                                         handler.clientMethods = Methods.createProxy(IWireClient.class, handler.connection.getRemoteMethodInterface());\r
147                                 } catch (MethodNotSupportedException e) {\r
148                                         throw new WireException(e);\r
149                                 }\r
150                                 \r
151                                 connection.addConnectionListener( new ConnectionListener() {\r
152                                         @Override\r
153                                         public void onError(Exception error) {\r
154                                                 TcpConnection connection = TcpConnection.getCurrentConnection();\r
155                                                 ClientRecord handler = clients.remove(connection);\r
156                                                 if (handler != null) handler.dispose();\r
157                                         }\r
158                                         @Override\r
159                                         public void onClosed() {\r
160                                                 TcpConnection connection = TcpConnection.getCurrentConnection();\r
161                                                 ClientRecord handler = clients.remove(connection);\r
162                                                 if (handler != null) handler.dispose();\r
163                                         }});\r
164                                 clients.put(connection, handler);\r
165                         }\r
166                         return handler;\r
167                 }\r
168                 } catch (BindingConstructionException e) {\r
169                         throw new WireException( e );\r
170                 }\r
171         }\r
172 \r
173         AccRecord getAccessor(int accId) throws WireException {\r
174                 ClientRecord client = getClient();\r
175                 AccRecord acc = client.accessorTable.getRight(accId);\r
176                 if (acc==null) throw new WireException("Invalid accessor id");\r
177                 return acc;\r
178         }\r
179         \r
180         LisRecord getListener(int accId, int lisId) throws WireException {\r
181                 ClientRecord client = getClient();\r
182                 LisRecord lis = client.listenerTable.get(lisId);\r
183                 return lis;\r
184         }\r
185         \r
186         // Assumption is that each method is invoked in a connection thread.\r
187         // Therefore object synchronization is unnecessary.\r
188         \r
189         @Override\r
190         public AccessorInfo openAccessor(ChildReference ref) throws WireException {\r
191                 try {\r
192                         ClientRecord client = getClient();\r
193                         AccRecord acc = new AccRecord();\r
194                         acc.accessor = accessor.getComponent(ref);\r
195                         acc.accId = client.accIdCounter++;\r
196                         acc.reference = ref;\r
197                         acc.type = accessor.type();\r
198                         acc.binding = params.bindingScheme.getBinding(acc.type);\r
199                         client.accessorTable.map(acc.accId, acc);\r
200                         AccessorInfo ai = new AccessorInfo();\r
201                         ai.accessorId = acc.accId;\r
202                         ai.type = acc.type;\r
203                         return ai;\r
204                 } catch (AccessorConstructionException e) {\r
205                         throw new WireException( e );\r
206                 } catch (BindingConstructionException e) {\r
207                         throw new WireException( e );\r
208                 }\r
209         }\r
210 \r
211         @Override\r
212         public int closeAccessors(Integer[] accIds) throws WireException {\r
213                 ClientRecord client = getClient();\r
214                 for (Integer accId : accIds) {\r
215                         client.accessorTable.removeWithLeft(accId);\r
216                 }\r
217                 return 0;\r
218         }\r
219         @Override\r
220         public MutableVariant getValue(int accId) throws WireException {\r
221                 try {\r
222                         AccRecord acc = getAccessor(accId);\r
223                         Object value = acc.accessor.getValue(acc.binding);\r
224                         return new MutableVariant(acc.binding, value);\r
225                 } catch (AccessorException e) {\r
226                         throw new WireException(e);\r
227                 }\r
228         }\r
229 \r
230         @Override\r
231         public ApplyResult apply(int accId, Event[] changeSet, boolean rollback) {\r
232                 ApplyResult result = new ApplyResult();\r
233                 result.rollbackLog = rollback ? new LinkedList<Event>() : null;         \r
234                 try {\r
235                         AccRecord acc = getAccessor(accId);\r
236                         List<Event> changeSetList = new ArrayList<Event>( changeSet.length );\r
237                         for (Event e : changeSet) changeSetList.add( e );\r
238                         acc.accessor.apply(changeSetList, result.rollbackLog);\r
239                 } catch (WireException e) {\r
240                         result.error = e;\r
241                 } catch (AccessorException e) {\r
242                         result.error = new WireException(e);\r
243                 }               \r
244                 return result;\r
245         }\r
246 \r
247         @Override\r
248         public int addListener(int accId, InterestSet interestSet,\r
249                         ChildReference path) throws WireException {\r
250                 try {\r
251                         \r
252                         ClientRecord client = getClient();\r
253                         AccRecord acc = getAccessor(accId);\r
254                         final LisRecord lis = new LisRecord();\r
255                         lis.accId = accId;\r
256                         lis.is = interestSet;\r
257                         lis.lisId = client.listIdCounter++;\r
258                         lis.listener = new Listener() {\r
259                                 @Override\r
260                                 public void onEvents(Collection<Event> events) {\r
261                                         try {\r
262                                                 // Push event to client\r
263                                                 ClientRecord client = getClient();\r
264                                                 Event[] eventArray = events.toArray( new Event[events.size()] );\r
265 \r
266 //                                              client.clientMethods.onEvents(lis.lisId, eventArray);\r
267 \r
268                                                 // Invoke async.\r
269                                                 OnEventsRequest req = new OnEventsRequest();\r
270                                                 req.arg1 = lis.lisId;\r
271                                                 req.arg2 = eventArray;\r
272                                                 client.onEventsMethod.invoke( req );\r
273                                         } catch (WireException e) {\r
274                                         }\r
275                                 }};\r
276                         acc.accessor.addListener(lis.listener, interestSet, path, null /*TODO Dispatch thread*/);\r
277                         client.listenerTable.put(lis.lisId, lis);\r
278                         return lis.lisId;\r
279                 } catch (AccessorException e) {\r
280                         throw new WireException(e.getClass().getName()+": "+e.getMessage());\r
281                 }               \r
282         }\r
283 \r
284         @Override\r
285         public int removeListener(int lisId) throws WireException {\r
286                 try {\r
287                         ClientRecord client = getClient();              \r
288                         LisRecord lis = client.listenerTable.remove(lisId);\r
289                         AccRecord acc = getAccessor(lis.accId);\r
290                         acc.accessor.removeListener(lis.listener);\r
291                         return 0;\r
292                 } catch (AccessorException e) {\r
293                         throw new WireException( e ); \r
294                 }               \r
295         }\r
296 \r
297         @Override\r
298         public int size(int accId) throws WireException {\r
299                 try {\r
300                         Accessor acc = getAccessor(accId).accessor;\r
301                         if (acc instanceof ArrayAccessor) return ((ArrayAccessor)acc).size();\r
302                         if (acc instanceof RecordAccessor) return ((RecordAccessor)acc).count();\r
303                         if (acc instanceof MapAccessor) return ((MapAccessor)acc).size();\r
304                         if (acc instanceof UnionAccessor) return ((UnionAccessor)acc).count();\r
305                         throw new WireException("Cannot get size for "+acc.getClass().getName());\r
306                 } catch (AccessorException e) {\r
307                         throw new WireException( e );\r
308                 }\r
309         }\r
310 \r
311         @Override\r
312         public int clear(int accId) throws WireException {\r
313                 try {\r
314                         Accessor acc = getAccessor(accId).accessor;\r
315                         if (acc instanceof ArrayAccessor) {\r
316                                 ArrayAccessor aa = ((ArrayAccessor)acc); \r
317                                 aa.remove(0, aa.size());\r
318                                 return 0;\r
319                         }\r
320                         if (acc instanceof MapAccessor) {\r
321                                 ((MapAccessor)acc).clear();\r
322                                 return 0;\r
323                         }                       \r
324                         throw new WireException("Cannot clear "+acc.getClass().getName());\r
325                 } catch (AccessorException e) {\r
326                         throw new WireException( e );\r
327                 }\r
328         }\r
329 /*\r
330         @Override\r
331         public void add(int accId, int index, Variant[] values) throws WireException {\r
332                 try {\r
333                         Accessor acc = getAccessor(accId).accessor;\r
334                         if (acc instanceof ArrayAccessor) {\r
335                                 ArrayAccessor aa = (ArrayAccessor) acc;\r
336                                 if (values.length==0) return;\r
337                                 \r
338                                 Binding b = values[0].getBinding();\r
339                                 boolean sameBinding = true;\r
340                                 for (Variant v : values) sameBinding &= v.getBinding()==b;\r
341                                 \r
342                                 if (sameBinding) {\r
343                                         Object[] objs = new Object[ values.length ];\r
344                                         for (int i=0; i<values.length; i++) {\r
345                                                 objs[i] = values[i].getValue();\r
346                                         }\r
347                                         aa.add(index, b, objs);                                 \r
348                                 } else {\r
349                                         // Add entry one by one\r
350                                         for (Variant v : values) {\r
351                                                 aa.add(index, v.getClass(), v.getValue());\r
352                                                 index++;\r
353                                         }\r
354                                 }\r
355                                 \r
356                         } else          \r
357                         throw new WireException("Cannot add to "+acc.getClass().getName());\r
358                 } catch (AccessorException e) {\r
359                         throw new WireException( e );\r
360                 }\r
361         }\r
362 */\r
363 \r
364         @Override\r
365         public boolean containsKey(int accId, MutableVariant key) throws WireException {\r
366                 try {\r
367                         Accessor acc = getAccessor(accId).accessor;\r
368                         if (acc instanceof MapAccessor == false) \r
369                                 throw new WireException("Not a map");\r
370                         MapAccessor ma = (MapAccessor) acc;\r
371                         return ma.containsKey(key.getBinding(), key.getValue());\r
372                 } catch (AccessorException e) {\r
373                         throw new WireException( e );\r
374                 }\r
375         }\r
376 \r
377         @Override\r
378         public boolean containsValue(int accId, MutableVariant value) throws WireException {\r
379                 try {\r
380                         Accessor acc = getAccessor(accId).accessor;\r
381                         if (acc instanceof MapAccessor == false) \r
382                                 throw new WireException("Not a map");\r
383                         MapAccessor ma = (MapAccessor) acc;\r
384                         return ma.containsValue(value.getBinding(), value.getValue());\r
385                 } catch (AccessorException e) {\r
386                         throw new WireException( e );\r
387                 }\r
388         }\r
389 \r
390         @Override\r
391         public MutableVariant getFirstKey(int accId) throws WireException {\r
392                 try {\r
393                         Accessor acc = getAccessor(accId).accessor;\r
394                         if (acc instanceof MapAccessor == false) \r
395                                 throw new WireException("Not a map");\r
396                         MapAccessor ma = (MapAccessor) acc;\r
397                         Binding keyBinding = params.bindingScheme.getBinding( ( (MapType) acc.type() ).keyType );\r
398                         Object key = ma.getFirstKey( keyBinding );\r
399                         return new MutableVariant(keyBinding, key);\r
400                 } catch (AccessorException e) {\r
401                         throw new WireException( e );\r
402                 } catch (BindingConstructionException e) {\r
403                         throw new WireException( e );\r
404                 }\r
405         }\r
406 \r
407         @Override\r
408         public MutableVariant getLastKey(int accId) throws WireException {\r
409                 try {\r
410                         Accessor acc = getAccessor(accId).accessor;\r
411                         if (acc instanceof MapAccessor == false) \r
412                                 throw new WireException("Not a map");\r
413                         MapAccessor ma = (MapAccessor) acc;\r
414                         Binding keyBinding = params.bindingScheme.getBinding( ( (MapType) acc.type() ).keyType );\r
415                         Object key = ma.getLastKey( keyBinding );\r
416                         return new MutableVariant(keyBinding, key);\r
417                 } catch (AccessorException e) {\r
418                         throw new WireException( e );\r
419                 } catch (BindingConstructionException e) {\r
420                         throw new WireException( e );\r
421                 }\r
422         }\r
423 \r
424         @Override\r
425         public MutableVariant getLowerKey(int accId, MutableVariant key) throws WireException {\r
426                 try {\r
427                         Accessor acc = getAccessor(accId).accessor;\r
428                         if (acc instanceof MapAccessor == false) \r
429                                 throw new WireException("Not a map");\r
430                         MapAccessor ma = (MapAccessor) acc;\r
431                         Binding keyBinding = key.getBinding();\r
432                         Object lowerKey = ma.getLowerKey(keyBinding, key.getValue());\r
433                         if (lowerKey==null) return new MutableVariant(Bindings.VOID, null);\r
434                         return new MutableVariant(keyBinding, lowerKey);\r
435                 } catch (AccessorException e) {\r
436                         throw new WireException( e );\r
437                 }       \r
438         }\r
439 \r
440         @Override\r
441         public MutableVariant getFloorKey(int accId, MutableVariant key) throws WireException {\r
442                 try {\r
443                         Accessor acc = getAccessor(accId).accessor;\r
444                         if (acc instanceof MapAccessor == false) \r
445                                 throw new WireException("Not a map");\r
446                         MapAccessor ma = (MapAccessor) acc;\r
447                         Binding keyBinding = key.getBinding();\r
448                         Object floorKey = ma.getFloorKey(keyBinding, key.getValue());\r
449                         if (floorKey==null) return new MutableVariant(Bindings.VOID, null);;                    \r
450                         return new MutableVariant(keyBinding, floorKey);\r
451                 } catch (AccessorException e) {\r
452                         throw new WireException( e );\r
453                 }       \r
454         }\r
455 \r
456         @Override\r
457         public MutableVariant getCeilingKey(int accId, MutableVariant key) throws WireException {\r
458                 try {\r
459                         Accessor acc = getAccessor(accId).accessor;\r
460                         if (acc instanceof MapAccessor == false) \r
461                                 throw new WireException("Not a map");\r
462                         MapAccessor ma = (MapAccessor) acc;\r
463                         Binding keyBinding = key.getBinding();\r
464                         Object ceilingKey = ma.getCeilingKey(keyBinding, key.getValue());\r
465                         if (ceilingKey==null) return new MutableVariant(Bindings.VOID, null);;                  \r
466                         return new MutableVariant(keyBinding, ceilingKey);\r
467                 } catch (AccessorException e) {\r
468                         throw new WireException( e );\r
469                 }       \r
470         }\r
471 \r
472         @Override\r
473         public MutableVariant getHigherKey(int accId, MutableVariant key) throws WireException {\r
474                 try {\r
475                         Accessor acc = getAccessor(accId).accessor;\r
476                         if (acc instanceof MapAccessor == false) \r
477                                 throw new WireException("Not a map");\r
478                         MapAccessor ma = (MapAccessor) acc;\r
479                         Binding keyBinding = key.getBinding();\r
480                         Object higherKey = ma.getHigherKey(keyBinding, key.getValue());\r
481                         if (higherKey==null) return new MutableVariant(Bindings.VOID, null);;                   \r
482                         return new MutableVariant(keyBinding, higherKey);\r
483                 } catch (AccessorException e) {\r
484                         throw new WireException( e );\r
485                 }       \r
486         }\r
487 \r
488         @Override\r
489         public boolean hasValue(int accId) throws WireException {\r
490                 try {\r
491                         Accessor acc = getAccessor(accId).accessor;\r
492                         if (acc instanceof OptionalAccessor == false) \r
493                                 throw new WireException("Not an option");\r
494                         OptionalAccessor ma = (OptionalAccessor) acc;\r
495                         return ma.hasValue();\r
496                 } catch (AccessorException e) {\r
497                         throw new WireException( e );\r
498                 }       \r
499         }\r
500 \r
501         @Override\r
502         public int getTag(int accId) throws WireException {\r
503                 try {\r
504                         Accessor acc = getAccessor(accId).accessor;\r
505                         if (acc instanceof UnionAccessor == false) \r
506                                 throw new WireException("Not an union");\r
507                         UnionAccessor ma = (UnionAccessor) acc;\r
508                         return ma.getTag();\r
509                 } catch (AccessorException e) {\r
510                         throw new WireException( e );\r
511                 }       \r
512         }\r
513         \r
514         @Override\r
515         public int addAll(int accId, int index, MutableVariant array) throws WireException {\r
516                 try {\r
517                         ArrayAccessor acc = (ArrayAccessor) getAccessor(accId).accessor;\r
518                         Datatype type = array.type();\r
519                         if (type instanceof ArrayType == false) {\r
520                                 throw new WireException("addAll() array expepected, got "+array.type());\r
521                         }\r
522                         \r
523                         Binding componentBinding = ( (ArrayBinding) array.getBinding() ).getComponentBinding();\r
524                         ArrayBinding binding = new ObjectArrayBinding((ArrayType) type, componentBinding);\r
525                         Object values[] = (Object[]) array.getValue(binding);\r
526                         if (index==-1) {\r
527                                 int size = acc.size();\r
528                                 acc.addAll(binding, values);\r
529                                 return size;\r
530                         } else {\r
531                                 acc.addAll(index, binding, values);\r
532                                 return index;\r
533                         }\r
534                                                 \r
535                 } catch (AccessorException e) {\r
536                         throw new WireException( e );\r
537                 } catch (AdaptException e) {\r
538                         throw new WireException( e );\r
539                 }\r
540         }\r
541 \r
542         @Override\r
543         public int add(int accId, int index, MutableVariant value) throws WireException {\r
544                 try {\r
545                         ArrayAccessor acc = (ArrayAccessor) getAccessor(accId).accessor;\r
546 \r
547                         if (index==-1) {\r
548                                 int size = acc.size();\r
549                                 acc.add(value.getBinding(), value.getValue());\r
550                                 return size;\r
551                         } else {\r
552                                 acc.add(index, value.getBinding(), value.getValue());\r
553                                 return index;\r
554                         }\r
555                 } catch (AccessorException e) {\r
556                         throw new WireException( e );\r
557                 }\r
558         }\r
559 \r
560         @Override\r
561         public MutableVariant getArrayElement(int accId, int index) throws WireException {\r
562                 try {\r
563                         AccRecord ar = getAccessor(accId);\r
564                         ArrayAccessor acc = (ArrayAccessor) ar.accessor;\r
565                         Binding valueBinding = ((ArrayBinding)ar.binding).getComponentBinding();\r
566                         Object value = acc.get(index, valueBinding );\r
567                         MutableVariant v = new MutableVariant(valueBinding, value);\r
568                         return v;\r
569                 } catch (AccessorException e) {\r
570                         throw new WireException( e );\r
571                 }\r
572         }\r
573         \r
574         @Override\r
575         public MutableVariant getMapValue(int accId, MutableVariant key) throws WireException {\r
576                 try {\r
577                         AccRecord ar = getAccessor(accId);\r
578                         MapAccessor acc = (MapAccessor) ar.accessor;\r
579                         MapBinding mapBinding = (MapBinding)ar.binding;\r
580                         Object value = acc.get(key.getBinding(), key.getValue(), mapBinding.getValueBinding());\r
581                         if (value == null) return new MutableVariant();\r
582                         return new MutableVariant(mapBinding.getValueBinding(), value);\r
583                 } catch (AccessorException e) {\r
584                         throw new WireException( e );\r
585                 }\r
586         }\r
587 \r
588         @Override\r
589         public MutableVariant getMapValues(int accId) throws WireException {\r
590                 try {\r
591                         AccRecord ar = getAccessor(accId);\r
592                         MapAccessor acc = (MapAccessor) ar.accessor;\r
593                         MapBinding mapBinding = (MapBinding)ar.binding;\r
594                         Binding valueBinding = mapBinding.getValueBinding();\r
595                         Object[] values = acc.getValues( valueBinding );\r
596                         ArrayBinding arrayBinding = new ObjectArrayBinding(new ArrayType(valueBinding.type()), valueBinding);\r
597                         return new MutableVariant(arrayBinding, values);\r
598                 } catch (AccessorException e) {\r
599                         throw new WireException( e );\r
600                 }\r
601         }\r
602 \r
603         @Override\r
604         public MutableVariant getMapKeys(int accId) throws WireException {\r
605                 try {\r
606                         AccRecord ar = getAccessor(accId);\r
607                         MapAccessor acc = (MapAccessor) ar.accessor;\r
608                         MapBinding mapBinding = (MapBinding)ar.binding;\r
609                         Binding keyBinding = mapBinding.getKeyBinding();\r
610                         Object[] keys = acc.getKeys( keyBinding );\r
611                         ArrayBinding arrayBinding = new ObjectArrayBinding(new ArrayType(keyBinding.type()), keyBinding);\r
612                         return new MutableVariant(arrayBinding, keys);\r
613                 } catch (AccessorException e) {\r
614                         throw new WireException( e );\r
615                 }\r
616         }\r
617         \r
618 }\r
619 \r