]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graph/src/org/simantics/graph/utils/TGResourceUtil.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.graph / src / org / simantics / graph / utils / TGResourceUtil.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 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.graph.utils;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.HashMap;\r
17 import java.util.List;\r
18 import java.util.Map;\r
19 import java.util.Stack;\r
20 \r
21 import org.simantics.databoard.Accessors;\r
22 import org.simantics.databoard.Bindings;\r
23 import org.simantics.databoard.accessor.Accessor;\r
24 import org.simantics.databoard.accessor.ArrayAccessor;\r
25 import org.simantics.databoard.accessor.LongAccessor;\r
26 import org.simantics.databoard.accessor.MapAccessor;\r
27 import org.simantics.databoard.accessor.OptionalAccessor;\r
28 import org.simantics.databoard.accessor.RecordAccessor;\r
29 import org.simantics.databoard.accessor.UnionAccessor;\r
30 import org.simantics.databoard.accessor.VariantAccessor;\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.reference.ChildReference;\r
34 import org.simantics.databoard.accessor.reference.ComponentReference;\r
35 import org.simantics.databoard.accessor.reference.IndexReference;\r
36 import org.simantics.databoard.binding.Binding;\r
37 import org.simantics.databoard.type.ArrayType;\r
38 import org.simantics.databoard.type.Datatype;\r
39 import org.simantics.databoard.type.LongType;\r
40 import org.simantics.databoard.type.MapType;\r
41 import org.simantics.databoard.type.OptionalType;\r
42 import org.simantics.databoard.type.RecordType;\r
43 import org.simantics.databoard.type.UnionType;\r
44 import org.simantics.databoard.type.VariantType;\r
45 import org.simantics.databoard.util.DatatypeVisitorAdapter;\r
46 \r
47 /**\r
48  * Util for converting all the Long values in a TG, that have metadata "resource=true".\r
49  * \r
50  * @author toni.kalajainen\r
51  */\r
52 public class TGResourceUtil {\r
53         \r
54         public static final Datatype RESOURCE_TYPE;\r
55         \r
56         Map<Datatype, Item> items = new HashMap<Datatype, Item>();\r
57         int index = 0;\r
58 \r
59         /**\r
60          * Add type to the cache and get some info.\r
61          * \r
62          * @param type\r
63          * @return\r
64          */\r
65         public Item createItem( Datatype type )\r
66         {\r
67                 Item item = new Item();\r
68                 item.index = index++;\r
69                 item.type = type;\r
70                 HasResVisitor v = new HasResVisitor();\r
71                 type.accept( v, item );\r
72                 if ( v.hasRes || v.hasVariant ) {\r
73                         GetRefsVisitor vv = new GetRefsVisitor();\r
74                         type.accept( vv, item );\r
75                 }\r
76                 return item;\r
77         }\r
78         \r
79         \r
80         /**\r
81          * Find all resources in the value. The resources are added to the result-collection.\r
82          * It may be good to idea to use a Set to avoid duplicate values.  \r
83          * \r
84          * @param type\r
85          * @param value\r
86          * @param result\r
87          * @throws AccessorException \r
88          * @throws AccessorConstructionException \r
89          */\r
90         public void findResources( Datatype type, byte[] value, final Collection<Long> result) throws AccessorConstructionException, AccessorException\r
91         {\r
92                 LongAdapter la = new LongAdapter() {\r
93                         @Override\r
94                         public long adapt(long in) {\r
95                                 result.add(in);\r
96                                 // Return same value\r
97                                 return in;\r
98                         }                       \r
99                 };\r
100                 \r
101                 adaptValue( type, value, la );\r
102         }\r
103 \r
104         public void findResources( Binding binding, Object value, final Collection<Long> result) throws AccessorConstructionException, AccessorException\r
105         {\r
106                 LongAdapter la = new LongAdapter() {\r
107                         @Override\r
108                         public long adapt(long in) {\r
109                                 result.add(in);\r
110                                 // Return same value\r
111                                 return in;\r
112                         }                       \r
113                 };\r
114                 \r
115                 adaptValue( binding, value, la );\r
116         }\r
117         \r
118         /**\r
119          * Add type to the util.\r
120          * @param type\r
121          * @return\r
122          */\r
123         public Item addType( Datatype type )\r
124         {\r
125                 Item i = items.get( type );\r
126                 if ( i==null ) {\r
127                         i = createItem(type);\r
128                         items.put(type, i);\r
129                 }\r
130                 return i;\r
131         }\r
132         \r
133         public void adaptValue( Datatype type, byte[] value, LongAdapter adapter ) throws AccessorException\r
134         {\r
135                 Item i = addType( type );\r
136                 if (!i.mayHaveResource()) return;\r
137                 try {\r
138                         Accessor a = Accessors.getAccessor(value, type);\r
139                         adaptValue(i, a, adapter);\r
140                 } catch (AccessorConstructionException e) {\r
141                         throw new AccessorException(e);\r
142                 }\r
143         }\r
144         \r
145         public boolean mayHaveResource( Datatype type ) {\r
146         Item i = addType( type );\r
147         return i.mayHaveResource();\r
148         }\r
149         \r
150         public void adaptValue( Binding binding, Object value, LongAdapter adapter ) throws AccessorException\r
151         {\r
152                 Item i = addType( binding.type() );\r
153                 if (!i.mayHaveResource()) return;\r
154                 try {\r
155                         Accessor a = Accessors.getAccessor(binding, value);\r
156                         adaptValue(i, a, adapter);\r
157                 } catch (AccessorConstructionException e) {\r
158                         throw new AccessorException(e);\r
159                 }\r
160         }\r
161         \r
162         void adaptValue( Item i, Accessor a, LongAdapter adapter ) throws AccessorException, AccessorConstructionException\r
163         {\r
164                 if ( i.resources != null ) {\r
165                         for (ChildReference r : i.resources)\r
166                         {\r
167                                 adaptValue(a, r, adapter);\r
168                         }\r
169                 }\r
170                 if ( i.variants != null ) {\r
171                         for (ChildReference r : i.variants)\r
172                         {\r
173                                 adaptValue(a, r, adapter);\r
174                         }\r
175                 }\r
176         }\r
177         \r
178         void adaptValue( Accessor a, ChildReference r, LongAdapter adapter ) throws AccessorException, AccessorConstructionException\r
179         {\r
180                 if ( a instanceof LongAccessor ) {\r
181                         LongAccessor x = (LongAccessor) a;\r
182                         long value = x.getValue();\r
183                         long newValue = adapter.adapt( value );\r
184                         if ( newValue != value ) x.setValue( newValue );\r
185                 }\r
186 \r
187                 if ( a instanceof VariantAccessor ) {\r
188                         VariantAccessor x = (VariantAccessor) a;\r
189                         Item i = createItem( x.getContentType() );\r
190                         adaptValue(i, x.getContentAccessor(), adapter);\r
191                 }\r
192                 \r
193                 if ( a instanceof MapAccessor ) {\r
194                         MapAccessor x = (MapAccessor) a;\r
195                         if (r instanceof IndexReference) {\r
196                                 IndexReference ir = (IndexReference) r;\r
197                                 // Resource is in the Key\r
198                                 if (ir.index==0) {\r
199                                         // Read the key as whole\r
200                                         Binding keyBinding = Bindings.getBinding( x.type().keyType );\r
201                                         Binding valueBinding = Bindings.getBinding( x.type().valueType );\r
202                                         Object[] keys = x.getKeys(keyBinding);\r
203                                         for ( Object key : keys ) {\r
204                                                 Object value = x.get(keyBinding, key, valueBinding);\r
205                                                 // Fix the key\r
206                                                 Accessor ka = Accessors.getAccessor(keyBinding, key);\r
207                                                 adaptValue(ka, r.childReference, adapter);\r
208                                                 \r
209                                                 // Write \r
210                                                 x.remove(keyBinding, key);\r
211                                                 x.put(keyBinding, key, valueBinding, value);\r
212                                         }\r
213                                 }\r
214                                 \r
215                                 // Resource is in the value\r
216                                 if (ir.index==1) {\r
217                                         Binding keyBinding = Bindings.getBinding( x.type().keyType );\r
218                                         Object[] keys = x.getKeys(keyBinding);\r
219                                         for ( Object key : keys ) {\r
220                                                 Accessor va = x.getValueAccessor(keyBinding, key);\r
221                                                 adaptValue(va, r.childReference, adapter);\r
222                                         }\r
223                                 }\r
224                         }                       \r
225                 }\r
226                 \r
227                 if ( a instanceof ArrayAccessor ) {\r
228                         ArrayAccessor x = (ArrayAccessor) a;\r
229                         int len = x.size();\r
230                         for (int i=0; i<len; i++) {\r
231                                 Accessor sa = x.getAccessor(i);                         \r
232                                 adaptValue(sa, r.childReference, adapter);\r
233                         }\r
234                 }\r
235                 \r
236                 if ( a instanceof UnionAccessor ) {\r
237                         UnionAccessor x = (UnionAccessor) a;\r
238                         IndexReference ir = (IndexReference) r;\r
239                         if ( x.getTag() == ir.index ) {\r
240                                 Accessor sa = x.getComponentAccessor();\r
241                                 adaptValue(sa, ir.childReference, adapter);\r
242                         }\r
243                 }\r
244                 \r
245                 if ( a instanceof RecordAccessor ) {\r
246                         RecordAccessor x = (RecordAccessor) a;\r
247                         IndexReference ir = (IndexReference) r;\r
248                         Accessor sa = x.getFieldAccessor(ir.index);\r
249                         adaptValue(sa, ir.childReference, adapter);\r
250                 }\r
251                 \r
252                 if ( a instanceof OptionalAccessor ) {\r
253                         OptionalAccessor x = (OptionalAccessor) a;\r
254                         if (x.hasValue()) {\r
255                                 Accessor sa = x.getComponentAccessor();\r
256                                 adaptValue(sa, r.childReference, adapter);\r
257                         }\r
258                 }\r
259                 \r
260         }\r
261         \r
262         public interface LongAdapter {\r
263                 long adapt(long in);\r
264         }\r
265         \r
266         public static class Item {\r
267                 // The datatype\r
268                 public Datatype type;\r
269                 // Index of the type\r
270                 public int index;\r
271                 // Locations of variants in Datatype  \r
272                 List<ChildReference> variants; \r
273                 // Locations of resources in Datatype  \r
274                 List<ChildReference> resources;\r
275                 \r
276                 public boolean mayHaveResource() {\r
277                         return (variants!=null&&!variants.isEmpty()) || \r
278                                         (resources!=null&&!resources.isEmpty());\r
279                 }\r
280                 \r
281                 void addVariant(ChildReference ref) {\r
282                         if ( variants == null ) variants = new ArrayList<ChildReference>();\r
283                         variants.add(ref);\r
284                 }\r
285                 \r
286                 void addResource(ChildReference ref) {\r
287                         if ( resources == null ) resources = new ArrayList<ChildReference>();\r
288                         resources.add( ref );\r
289                 }\r
290         }\r
291         \r
292     static {\r
293         RESOURCE_TYPE = new LongType();\r
294         RESOURCE_TYPE.metadata.put("resource", "true");\r
295     }\r
296     \r
297     /**\r
298      * This visitor makes a quick peek to see if there is resource or variants.\r
299      */\r
300     static class HasResVisitor extends DatatypeVisitorAdapter {\r
301 \r
302         boolean hasRes = false, hasVariant = false;\r
303         \r
304         @Override\r
305         public void visit(VariantType b, Object obj) {\r
306                 hasVariant = true;\r
307         }\r
308         \r
309         @Override\r
310         public void visit(LongType b, Object obj) {\r
311                 String s = b.metadata.get("unit");\r
312                 hasRes |= s!=null && s.equals("resource");\r
313         }\r
314         \r
315     }\r
316     \r
317     static class GetRefsVisitor extends DatatypeVisitorAdapter {\r
318         \r
319         Stack<ChildReference> stack = new Stack<ChildReference>(); \r
320     \r
321         @Override\r
322         public void visit(ArrayType b, Object obj) {                    \r
323                 if ( !visited.add(b) ) return; \r
324                 \r
325                 ComponentReference r = new ComponentReference();\r
326                 stack.push(r);\r
327                 b.componentType.accept(this, obj);\r
328                 stack.pop();\r
329         }\r
330         \r
331         @Override\r
332         public void visit(LongType b, Object obj) {\r
333                 String s = b.metadata.get("unit");\r
334                 boolean isRes = s!=null && s.equals("resource");\r
335                 if ( isRes ) {\r
336                         Item item = (Item) obj;\r
337                         item.addResource( toRef() );\r
338                 }\r
339         }\r
340         @Override\r
341         public void visit(MapType b, Object obj) {\r
342                 if ( !visited.add(b) ) return;                  \r
343                 \r
344                 IndexReference r = new IndexReference(0);\r
345                 stack.push(r);\r
346                 b.keyType.accept(this, obj);\r
347                 stack.pop();\r
348                 r.index = 1;\r
349                 stack.push(r);\r
350                 b.valueType.accept(this, obj);\r
351                 stack.pop();\r
352         }\r
353         @Override\r
354         public void visit(OptionalType b, Object obj) {\r
355                 if ( !visited.add(b) ) return; \r
356                 \r
357                 ComponentReference r = new ComponentReference();\r
358                 stack.push(r);\r
359                 b.componentType.accept(this, obj);\r
360                 stack.pop();\r
361         }\r
362         @Override\r
363         public void visit(RecordType b, Object obj) {\r
364                 if ( !visited.add(b) ) return; \r
365                 \r
366                         IndexReference r = new IndexReference(0);\r
367                         stack.push(r);\r
368                 for (int i=0; i<b.getComponentCount(); i++) {\r
369                         r.index = i;\r
370                         b.getComponent(i).type.accept(this, obj);\r
371                 }\r
372                 stack.pop();\r
373         }\r
374         @Override\r
375         public void visit(UnionType b, Object obj) {\r
376                 if ( !visited.add(b) ) return;                  \r
377                 \r
378                         IndexReference r = new IndexReference(0);\r
379                         stack.push(r);\r
380                 for (int i=0; i<b.getComponentCount(); i++) {\r
381                         r.index = i;\r
382                         b.getComponent(i).type.accept(this, obj);\r
383                 }\r
384                 stack.pop();\r
385         }\r
386         @Override\r
387         public void visit(VariantType b, Object obj) {\r
388                         Item item = (Item) obj;\r
389                         item.addVariant( toRef() );\r
390         }\r
391         ChildReference toRef() {\r
392                 return ChildReference.compile(stack);\r
393         }\r
394         \r
395     }\r
396         \r
397 \r
398 }\r