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