--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.graph.utils;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Stack;\r
+\r
+import org.simantics.databoard.Accessors;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.accessor.Accessor;\r
+import org.simantics.databoard.accessor.ArrayAccessor;\r
+import org.simantics.databoard.accessor.LongAccessor;\r
+import org.simantics.databoard.accessor.MapAccessor;\r
+import org.simantics.databoard.accessor.OptionalAccessor;\r
+import org.simantics.databoard.accessor.RecordAccessor;\r
+import org.simantics.databoard.accessor.UnionAccessor;\r
+import org.simantics.databoard.accessor.VariantAccessor;\r
+import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
+import org.simantics.databoard.accessor.error.AccessorException;\r
+import org.simantics.databoard.accessor.reference.ChildReference;\r
+import org.simantics.databoard.accessor.reference.ComponentReference;\r
+import org.simantics.databoard.accessor.reference.IndexReference;\r
+import org.simantics.databoard.binding.Binding;\r
+import org.simantics.databoard.type.ArrayType;\r
+import org.simantics.databoard.type.Datatype;\r
+import org.simantics.databoard.type.LongType;\r
+import org.simantics.databoard.type.MapType;\r
+import org.simantics.databoard.type.OptionalType;\r
+import org.simantics.databoard.type.RecordType;\r
+import org.simantics.databoard.type.UnionType;\r
+import org.simantics.databoard.type.VariantType;\r
+import org.simantics.databoard.util.DatatypeVisitorAdapter;\r
+\r
+/**\r
+ * Util for converting all the Long values in a TG, that have metadata "resource=true".\r
+ * \r
+ * @author toni.kalajainen\r
+ */\r
+public class TGResourceUtil {\r
+ \r
+ public static final Datatype RESOURCE_TYPE;\r
+ \r
+ Map<Datatype, Item> items = new HashMap<Datatype, Item>();\r
+ int index = 0;\r
+\r
+ /**\r
+ * Add type to the cache and get some info.\r
+ * \r
+ * @param type\r
+ * @return\r
+ */\r
+ public Item createItem( Datatype type )\r
+ {\r
+ Item item = new Item();\r
+ item.index = index++;\r
+ item.type = type;\r
+ HasResVisitor v = new HasResVisitor();\r
+ type.accept( v, item );\r
+ if ( v.hasRes || v.hasVariant ) {\r
+ GetRefsVisitor vv = new GetRefsVisitor();\r
+ type.accept( vv, item );\r
+ }\r
+ return item;\r
+ }\r
+ \r
+ \r
+ /**\r
+ * Find all resources in the value. The resources are added to the result-collection.\r
+ * It may be good to idea to use a Set to avoid duplicate values. \r
+ * \r
+ * @param type\r
+ * @param value\r
+ * @param result\r
+ * @throws AccessorException \r
+ * @throws AccessorConstructionException \r
+ */\r
+ public void findResources( Datatype type, byte[] value, final Collection<Long> result) throws AccessorConstructionException, AccessorException\r
+ {\r
+ LongAdapter la = new LongAdapter() {\r
+ @Override\r
+ public long adapt(long in) {\r
+ result.add(in);\r
+ // Return same value\r
+ return in;\r
+ } \r
+ };\r
+ \r
+ adaptValue( type, value, la );\r
+ }\r
+\r
+ public void findResources( Binding binding, Object value, final Collection<Long> result) throws AccessorConstructionException, AccessorException\r
+ {\r
+ LongAdapter la = new LongAdapter() {\r
+ @Override\r
+ public long adapt(long in) {\r
+ result.add(in);\r
+ // Return same value\r
+ return in;\r
+ } \r
+ };\r
+ \r
+ adaptValue( binding, value, la );\r
+ }\r
+ \r
+ /**\r
+ * Add type to the util.\r
+ * @param type\r
+ * @return\r
+ */\r
+ public Item addType( Datatype type )\r
+ {\r
+ Item i = items.get( type );\r
+ if ( i==null ) {\r
+ i = createItem(type);\r
+ items.put(type, i);\r
+ }\r
+ return i;\r
+ }\r
+ \r
+ public void adaptValue( Datatype type, byte[] value, LongAdapter adapter ) throws AccessorException\r
+ {\r
+ Item i = addType( type );\r
+ if (!i.mayHaveResource()) return;\r
+ try {\r
+ Accessor a = Accessors.getAccessor(value, type);\r
+ adaptValue(i, a, adapter);\r
+ } catch (AccessorConstructionException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ public boolean mayHaveResource( Datatype type ) {\r
+ Item i = addType( type );\r
+ return i.mayHaveResource();\r
+ }\r
+ \r
+ public void adaptValue( Binding binding, Object value, LongAdapter adapter ) throws AccessorException\r
+ {\r
+ Item i = addType( binding.type() );\r
+ if (!i.mayHaveResource()) return;\r
+ try {\r
+ Accessor a = Accessors.getAccessor(binding, value);\r
+ adaptValue(i, a, adapter);\r
+ } catch (AccessorConstructionException e) {\r
+ throw new AccessorException(e);\r
+ }\r
+ }\r
+ \r
+ void adaptValue( Item i, Accessor a, LongAdapter adapter ) throws AccessorException, AccessorConstructionException\r
+ {\r
+ if ( i.resources != null ) {\r
+ for (ChildReference r : i.resources)\r
+ {\r
+ adaptValue(a, r, adapter);\r
+ }\r
+ }\r
+ if ( i.variants != null ) {\r
+ for (ChildReference r : i.variants)\r
+ {\r
+ adaptValue(a, r, adapter);\r
+ }\r
+ }\r
+ }\r
+ \r
+ void adaptValue( Accessor a, ChildReference r, LongAdapter adapter ) throws AccessorException, AccessorConstructionException\r
+ {\r
+ if ( a instanceof LongAccessor ) {\r
+ LongAccessor x = (LongAccessor) a;\r
+ long value = x.getValue();\r
+ long newValue = adapter.adapt( value );\r
+ if ( newValue != value ) x.setValue( newValue );\r
+ }\r
+\r
+ if ( a instanceof VariantAccessor ) {\r
+ VariantAccessor x = (VariantAccessor) a;\r
+ Item i = createItem( x.getContentType() );\r
+ adaptValue(i, x.getContentAccessor(), adapter);\r
+ }\r
+ \r
+ if ( a instanceof MapAccessor ) {\r
+ MapAccessor x = (MapAccessor) a;\r
+ if (r instanceof IndexReference) {\r
+ IndexReference ir = (IndexReference) r;\r
+ // Resource is in the Key\r
+ if (ir.index==0) {\r
+ // Read the key as whole\r
+ Binding keyBinding = Bindings.getBinding( x.type().keyType );\r
+ Binding valueBinding = Bindings.getBinding( x.type().valueType );\r
+ Object[] keys = x.getKeys(keyBinding);\r
+ for ( Object key : keys ) {\r
+ Object value = x.get(keyBinding, key, valueBinding);\r
+ // Fix the key\r
+ Accessor ka = Accessors.getAccessor(keyBinding, key);\r
+ adaptValue(ka, r.childReference, adapter);\r
+ \r
+ // Write \r
+ x.remove(keyBinding, key);\r
+ x.put(keyBinding, key, valueBinding, value);\r
+ }\r
+ }\r
+ \r
+ // Resource is in the value\r
+ if (ir.index==1) {\r
+ Binding keyBinding = Bindings.getBinding( x.type().keyType );\r
+ Object[] keys = x.getKeys(keyBinding);\r
+ for ( Object key : keys ) {\r
+ Accessor va = x.getValueAccessor(keyBinding, key);\r
+ adaptValue(va, r.childReference, adapter);\r
+ }\r
+ }\r
+ } \r
+ }\r
+ \r
+ if ( a instanceof ArrayAccessor ) {\r
+ ArrayAccessor x = (ArrayAccessor) a;\r
+ int len = x.size();\r
+ for (int i=0; i<len; i++) {\r
+ Accessor sa = x.getAccessor(i); \r
+ adaptValue(sa, r.childReference, adapter);\r
+ }\r
+ }\r
+ \r
+ if ( a instanceof UnionAccessor ) {\r
+ UnionAccessor x = (UnionAccessor) a;\r
+ IndexReference ir = (IndexReference) r;\r
+ if ( x.getTag() == ir.index ) {\r
+ Accessor sa = x.getComponentAccessor();\r
+ adaptValue(sa, ir.childReference, adapter);\r
+ }\r
+ }\r
+ \r
+ if ( a instanceof RecordAccessor ) {\r
+ RecordAccessor x = (RecordAccessor) a;\r
+ IndexReference ir = (IndexReference) r;\r
+ Accessor sa = x.getFieldAccessor(ir.index);\r
+ adaptValue(sa, ir.childReference, adapter);\r
+ }\r
+ \r
+ if ( a instanceof OptionalAccessor ) {\r
+ OptionalAccessor x = (OptionalAccessor) a;\r
+ if (x.hasValue()) {\r
+ Accessor sa = x.getComponentAccessor();\r
+ adaptValue(sa, r.childReference, adapter);\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ public interface LongAdapter {\r
+ long adapt(long in);\r
+ }\r
+ \r
+ public static class Item {\r
+ // The datatype\r
+ public Datatype type;\r
+ // Index of the type\r
+ public int index;\r
+ // Locations of variants in Datatype \r
+ List<ChildReference> variants; \r
+ // Locations of resources in Datatype \r
+ List<ChildReference> resources;\r
+ \r
+ public boolean mayHaveResource() {\r
+ return (variants!=null&&!variants.isEmpty()) || \r
+ (resources!=null&&!resources.isEmpty());\r
+ }\r
+ \r
+ void addVariant(ChildReference ref) {\r
+ if ( variants == null ) variants = new ArrayList<ChildReference>();\r
+ variants.add(ref);\r
+ }\r
+ \r
+ void addResource(ChildReference ref) {\r
+ if ( resources == null ) resources = new ArrayList<ChildReference>();\r
+ resources.add( ref );\r
+ }\r
+ }\r
+ \r
+ static {\r
+ RESOURCE_TYPE = new LongType();\r
+ RESOURCE_TYPE.metadata.put("resource", "true");\r
+ }\r
+ \r
+ /**\r
+ * This visitor makes a quick peek to see if there is resource or variants.\r
+ */\r
+ static class HasResVisitor extends DatatypeVisitorAdapter {\r
+\r
+ boolean hasRes = false, hasVariant = false;\r
+ \r
+ @Override\r
+ public void visit(VariantType b, Object obj) {\r
+ hasVariant = true;\r
+ }\r
+ \r
+ @Override\r
+ public void visit(LongType b, Object obj) {\r
+ String s = b.metadata.get("unit");\r
+ hasRes |= s!=null && s.equals("resource");\r
+ }\r
+ \r
+ }\r
+ \r
+ static class GetRefsVisitor extends DatatypeVisitorAdapter {\r
+ \r
+ Stack<ChildReference> stack = new Stack<ChildReference>(); \r
+ \r
+ @Override\r
+ public void visit(ArrayType b, Object obj) { \r
+ if ( !visited.add(b) ) return; \r
+ \r
+ ComponentReference r = new ComponentReference();\r
+ stack.push(r);\r
+ b.componentType.accept(this, obj);\r
+ stack.pop();\r
+ }\r
+ \r
+ @Override\r
+ public void visit(LongType b, Object obj) {\r
+ String s = b.metadata.get("unit");\r
+ boolean isRes = s!=null && s.equals("resource");\r
+ if ( isRes ) {\r
+ Item item = (Item) obj;\r
+ item.addResource( toRef() );\r
+ }\r
+ }\r
+ @Override\r
+ public void visit(MapType b, Object obj) {\r
+ if ( !visited.add(b) ) return; \r
+ \r
+ IndexReference r = new IndexReference(0);\r
+ stack.push(r);\r
+ b.keyType.accept(this, obj);\r
+ stack.pop();\r
+ r.index = 1;\r
+ stack.push(r);\r
+ b.valueType.accept(this, obj);\r
+ stack.pop();\r
+ }\r
+ @Override\r
+ public void visit(OptionalType b, Object obj) {\r
+ if ( !visited.add(b) ) return; \r
+ \r
+ ComponentReference r = new ComponentReference();\r
+ stack.push(r);\r
+ b.componentType.accept(this, obj);\r
+ stack.pop();\r
+ }\r
+ @Override\r
+ public void visit(RecordType b, Object obj) {\r
+ if ( !visited.add(b) ) return; \r
+ \r
+ IndexReference r = new IndexReference(0);\r
+ stack.push(r);\r
+ for (int i=0; i<b.getComponentCount(); i++) {\r
+ r.index = i;\r
+ b.getComponent(i).type.accept(this, obj);\r
+ }\r
+ stack.pop();\r
+ }\r
+ @Override\r
+ public void visit(UnionType b, Object obj) {\r
+ if ( !visited.add(b) ) return; \r
+ \r
+ IndexReference r = new IndexReference(0);\r
+ stack.push(r);\r
+ for (int i=0; i<b.getComponentCount(); i++) {\r
+ r.index = i;\r
+ b.getComponent(i).type.accept(this, obj);\r
+ }\r
+ stack.pop();\r
+ }\r
+ @Override\r
+ public void visit(VariantType b, Object obj) {\r
+ Item item = (Item) obj;\r
+ item.addVariant( toRef() );\r
+ }\r
+ ChildReference toRef() {\r
+ return ChildReference.compile(stack);\r
+ }\r
+ \r
+ }\r
+ \r
+\r
+}\r