Changeset 262:a98145868480 in finroc_core-java


Ignore:
Timestamp:
08.06.2017 03:15:27 (20 months ago)
Author:
Max Reichardt <mreichardt@…>
Branch:
17.03
Phase:
public
Message:

Adapts to changes in Finroc 17. In particular, this includes addition/improvements of remote elements required for handling connectors and new type conversion mechanism. Furthermore, the generic protocol is factored out from TCP plugin (similar to what was done in C++).

Files:
32 added
4 deleted
28 edited

Legend:

Unmodified
Added
Removed
  • FinrocAnnotation.java

    r238 r262  
    8383 
    8484    @Override 
    85     public void deserialize(BinaryInputStream is) { 
     85    public void deserialize(BinaryInputStream is) throws Exception { 
    8686        throw new RuntimeException("Unsupported"); 
    8787    } 
  • RuntimeSettings.java

    r220 r262  
    6767    //public static final IntSetting NUM_OF_EVENT_THREADS = inst.add("NUM_OF_EVENT_THREADS", 2, false); 
    6868 
    69     /** Default minimum network update time (ms) */ 
    70     public static ParameterNumeric<Integer> DEFAULT_MINIMUM_NETWORK_UPDATE_TIME; 
     69    /** Default minimum network update times (ms) */ 
     70    public static final int DEFAULT_MINIMUM_NETWORK_UPDATE_TIME_BULK = 40; 
     71    public static final int DEFAULT_MINIMUM_NETWORK_UPDATE_TIME_EXPRESS = 0; 
    7172 
    7273    public static final int EDGE_LIST_DEFAULT_SIZE = 0; 
     
    168169        WARN_ON_CYCLE_TIME_EXCEED = new ParameterBool("WARN_ON_CYCLE_TIME_EXCEED", this, true); 
    169170        DEFAULT_CYCLE_TIME = new ParameterNumeric<Long>("DEFAULT_CYCLE_TIME", this, 50L, new Bounds<Long>(1, 2000)); 
    170         DEFAULT_MINIMUM_NETWORK_UPDATE_TIME = new ParameterNumeric<Integer>("DEFAULT_MINIMUM_NETWORK_UPDATE_TIME", this, 40, new Bounds<Integer>(1, 2000)); 
    171171        STREAM_THREAD_CYCLE_TIME = new ParameterNumeric<Integer>("STREAM_THREAD_CYCLE_TIME", this, 200, new Bounds<Integer>(1, 2000)); 
    172172        GARBAGE_COLLECTOR_SAFETY_PERIOD = new ParameterNumeric<Integer>("GARBAGE_COLLECTOR_SAFETY_PERIOD", this, 5000, new Bounds<Integer>(500, 50000)); 
     
    186186        //inst.init(RuntimeEnvironment.getInstance()); 
    187187        getInstance(); 
    188         DEFAULT_MINIMUM_NETWORK_UPDATE_TIME.addPortListener(inst); 
    189188    } 
    190189 
     
    254253     */ 
    255254    public static void setUseCCPorts(boolean newUseCCPorts) { 
    256         if (DataTypeBase.getTypeCount() > 0) { 
     255        if (DataTypeBase.getTypeCount() > 1) { 
    257256            throw new RuntimeException("This is only possible before any type has been loaded."); 
    258257        } 
  • admin/AdminClient.java

    r255 r262  
    2222package org.finroc.core.admin; 
    2323 
     24import java.net.URI; 
    2425import java.util.ArrayList; 
    2526import java.util.List; 
    2627 
    27 import org.finroc.core.FinrocAnnotation; 
    2828import org.finroc.core.FrameworkElement; 
    2929import org.finroc.core.parameter.ConfigFile; 
    3030import org.finroc.core.parameter.ParameterInfo; 
    31 import org.finroc.core.parameter.StaticParameterList; 
    32 import org.finroc.core.plugin.RemoteCreateModuleAction; 
    3331import org.finroc.core.port.PortCreationInfo; 
    34 import org.finroc.core.port.net.NetPort; 
    3532import org.finroc.core.port.rpc.ClientPort; 
    3633import org.finroc.core.port.rpc.ResponseHandler; 
     34import org.finroc.core.remote.FrameworkElementInfo; 
     35import org.finroc.core.remote.RemoteConnectOptions; 
     36import org.finroc.core.remote.RemoteConnector; 
     37import org.finroc.core.remote.RemoteCreateAction; 
    3738import org.finroc.core.remote.RemoteFrameworkElement; 
     39import org.finroc.core.remote.RemotePort; 
    3840import org.finroc.core.remote.RemoteRuntime; 
     41import org.finroc.core.remote.RemoteStaticParameterList; 
     42import org.finroc.core.remote.RemoteUriConnector; 
    3943import org.rrlib.logging.Log; 
    4044import org.rrlib.logging.LogLevel; 
    4145import org.rrlib.serialization.BinaryInputStream; 
    4246import org.rrlib.serialization.BinaryOutputStream; 
     47import org.rrlib.serialization.BinarySerializable; 
    4348import org.rrlib.serialization.MemoryBuffer; 
    44 import org.rrlib.serialization.BinaryOutputStream.TypeEncoding; 
    45 import org.rrlib.serialization.rtti.DataTypeBase; 
    4649import org.rrlib.serialization.rtti.GenericObject; 
    4750 
     
    5760    } 
    5861 
     62//    /** 
     63//     * Connect two ports in remote runtime 
     64//     * 
     65//     * @param port1 Port1 
     66//     * @param port2 Port2 
     67//     */ 
     68//    public void connect(RemotePort port1, RemotePort port2) { 
     69//        if (port1 != null && port2 != null && getAdminInterface(port1) == this && getAdminInterface(port2) == this) { 
     70//            this.call(AdminServer.CONNECT, port1.getRemoteHandle(), port2.getRemoteHandle()); 
     71//            return; 
     72//        } 
     73//        Log.log(LogLevel.WARNING, getLogDescription(), "Connecting remote ports failed"); 
     74//    } 
     75 
    5976    /** 
    6077     * Connect two ports in remote runtime 
    6178     * 
    62      * @param np1 Port1 
    63      * @param np2 Port2 
    64      */ 
    65     public void connect(NetPort np1, NetPort np2) { 
    66         if (np1 != null && np2 != null && getAdminInterface(np1) == this && getAdminInterface(np2) == this) { 
    67             this.call(AdminServer.CONNECT, np1.getRemoteHandle(), np2.getRemoteHandle()); 
     79     * @param port1 Port1 
     80     * @param port2 Port2 
     81     * @param connectOptions Connect options 
     82     */ 
     83    public String connectPorts(RemotePort port1, RemotePort port2, RemoteConnectOptions connectOptions) { 
     84        if (port1 != null && port2 != null && getAdminInterface(port1) == this && getAdminInterface(port2) == this) { 
     85            RemoteRuntime runtime = RemoteRuntime.find(port1); 
     86            try { 
     87                if (runtime.getSerializationInfo().getRevision() == 0) { 
     88                    this.call(AdminServer.CONNECT, port1.getRemoteHandle(), port2.getRemoteHandle()); 
     89                    return ""; 
     90                } else { 
     91                    return (String)this.callSynchronous(2000, AdminServer.CONNECT_PORTS, port1.getRemoteHandle(), port2.getRemoteHandle(), connectOptions); 
     92                } 
     93            } catch (Exception e) { 
     94                return "Timeout"; 
     95            } 
     96        } else { 
     97            return "Connecting remote ports failed"; 
     98        } 
     99    } 
     100 
     101    /** 
     102     * Create URI connector in remote runtime connecting port using one of the supported URI schemes (provided e.g. by network transports). 
     103     * 
     104     * @param port Owner port of URI connector 
     105     * @param uri URI of partner port 
     106     * @param connectOptions Connect options 
     107     * @return Returns error message if connecting failed. On success an empty string is returned. 
     108     */ 
     109    public String createUriConnector(RemotePort port, String uri, RemoteConnectOptions connectOptions) { 
     110        if (port != null && getAdminInterface(port) == this) { 
     111            RemoteRuntime runtime = RemoteRuntime.find(port); 
     112            try { 
     113                if (runtime.getSerializationInfo().getRevision() == 0) { 
     114                    URI uriObject = new URI(uri); 
     115                    String authority = uriObject.getAuthority(); 
     116                    if (authority == null || authority.length() == 0) { 
     117                        return "Local URI connectors are not supported for legacy Finroc runtimes"; 
     118                    } 
     119                    String[] authorityParts = authority.split(":"); 
     120                    if (authorityParts.length != 2) { 
     121                        return "Invalid authority: " + authority; 
     122                    } 
     123                    String path = uriObject.getPath(); 
     124                    if (!path.startsWith("/")) { 
     125                        path = "/" + path; 
     126                    } 
     127                    return (String)this.callSynchronous(2000, AdminServer.NETWORK_CONNECT, port.getRemoteHandle(), "tcp", authorityParts[0], authorityParts[1], path, false); 
     128                } else { 
     129                    return (String)this.callSynchronous(2000, AdminServer.CREATE_URI_CONNECTOR, port.getRemoteHandle(), uri, connectOptions); 
     130                } 
     131            } catch (Exception e) { 
     132                return "Timeout"; 
     133            } 
     134        } else { 
     135            return "Connecting remote ports failed"; 
     136        } 
     137    } 
     138 
     139    /** 
     140     * Remove connector in remote runtime 
     141     * 
     142     * @param connector Connector to remove 
     143     */ 
     144    public void disconnect(RemoteConnector connector) { 
     145        try { 
     146            if (connector instanceof FrameworkElementInfo.LegacyNetworkConnector) { 
     147                FrameworkElementInfo.LegacyNetworkConnector legacyConnector = (FrameworkElementInfo.LegacyNetworkConnector)connector; 
     148                RemotePort port = legacyConnector.getOwnerRuntime().getRemotePort(legacyConnector.getOwnerPortHandle()); 
     149                networkConnect(port, "tcp", legacyConnector.uuid, legacyConnector.portHandle, "", true); 
     150            } else if (connector instanceof RemoteUriConnector) { 
     151                RemoteUriConnector uriConnector = (RemoteUriConnector)connector; 
     152                //if (remoteRuntime.getSerializationInfo().getRevision() == 0) { 
     153                //    throw new Exception("Disconnecting URI connector not supported for legacy runtimes");  // TODO 
     154                //} else { 
     155                this.call(AdminServer.DELETE_URI_CONNECTOR, uriConnector.getOwnerPortHandle(), uriConnector.getIndex()); 
     156                return; 
     157                //} 
     158            } else { 
     159                this.call(AdminServer.DISCONNECT, connector.getSourceHandle(), connector.getDestinationHandle()); 
     160                return; 
     161            } 
     162        } catch (Exception e) { 
     163            Log.log(LogLevel.WARNING, getLogDescription(), "Disconnecting remote ports failed: " + e.toString()); 
     164        } 
     165        Log.log(LogLevel.WARNING, getLogDescription(), "Disconnecting remote ports failed"); 
     166    } 
     167 
     168    /** 
     169     * Remove local connector in remote runtime 
     170     * 
     171     * @param port1 Port1 
     172     * @param port2 Port2 
     173     */ 
     174    public void disconnect(RemotePort port1, RemotePort port2) { 
     175 
     176 
     177        // TODO search for connector (might be local URI connector) 
     178        if (port1 != null && port2 != null && getAdminInterface(port1) == this && getAdminInterface(port2) == this) { 
     179            try { 
     180                this.call(AdminServer.DISCONNECT, port1.getRemoteHandle(), port2.getRemoteHandle()); 
     181                return; 
     182            } catch (Exception e) { 
     183                Log.log(LogLevel.WARNING, getLogDescription(), "Disconnecting remote ports failed: " + e.toString()); 
     184            } 
     185        } else { 
     186            Log.log(LogLevel.WARNING, getLogDescription(), "Disconnecting remote ports failed"); 
     187        } 
     188    } 
     189 
     190    /** 
     191     * Disconnect port in remote runtime 
     192     * 
     193     * @param port Port 
     194     */ 
     195    public void disconnectAll(RemotePort port) { 
     196        if (port != null && getAdminInterface(port) == this) { 
     197            this.call(AdminServer.DISCONNECT_ALL, port.getRemoteHandle()); 
    68198            return; 
    69199        } 
    70         Log.log(LogLevel.WARNING, getLogDescription(), "Connecting remote ports failed"); 
    71     } 
    72  
    73     /** 
    74      * Disconnect two ports in remote runtime 
    75      * 
    76      * @param np1 Port1 
    77      * @param np2 Port2 
    78      */ 
    79     public void disconnect(NetPort np1, NetPort np2) { 
    80         if (np1 != null && np2 != null && getAdminInterface(np1) == this && getAdminInterface(np2) == this) { 
    81             this.call(AdminServer.DISCONNECT, np1.getRemoteHandle(), np2.getRemoteHandle()); 
    82             return; 
    83         } 
    84         Log.log(LogLevel.WARNING, getLogDescription(), "Disconnecting remote ports failed"); 
    85     } 
    86  
    87     /** 
    88      * Disconnect port in remote runtime 
    89      * 
    90      * @param np1 Port1 
    91      */ 
    92     public void disconnectAll(NetPort np1) { 
    93         if (np1 != null && getAdminInterface(np1) == this) { 
    94             this.call(AdminServer.DISCONNECT_ALL, np1.getRemoteHandle()); 
    95             return; 
    96         } 
    97200        Log.log(LogLevel.WARNING, getLogDescription(), "Disconnecting remote port failed"); 
    98201    } 
    99202 
    100203    /** 
    101      * Connect port in remote runtime to port in another remote runtime 
    102      * 
    103      * @param port1 Port1 
     204     * Connect port in remote runtime to port in another remote runtime (legacy) 
     205     * 
     206     * @param port Remote port to connect 
    104207     * @param preferredTransport ID of preferred network transport to be used (e.g. "tcp"). If specified, it will be attempted to create the connection using this transport first. 
    105208     * @param remoteRuntimeUuid UUID of remote runtime 
     
    109212     * @return Returns error message if connecting failed. On success, null is returned. 
    110213     */ 
    111     public String networkConnect(NetPort port1, String preferredTransport, String remoteRuntimeUuid, int remotePortHandle, String remotePortLink, boolean disconnect) { 
     214    public String networkConnect(RemotePort port, String preferredTransport, String remoteRuntimeUuid, int remotePortHandle, String remotePortLink, boolean disconnect) { 
    112215        String result; 
    113         if (port1 != null && getAdminInterface(port1) == this) { 
     216        if (port != null && getAdminInterface(port) == this) { 
    114217            try { 
    115                 result = (String)this.callSynchronous(2000, AdminServer.NETWORK_CONNECT, port1.getRemoteHandle(), preferredTransport, remoteRuntimeUuid, remotePortHandle, remotePortLink, disconnect); 
     218                result = (String)this.callSynchronous(2000, AdminServer.NETWORK_CONNECT, port.getRemoteHandle(), preferredTransport, remoteRuntimeUuid, remotePortHandle, remotePortLink, disconnect); 
    116219                if (result.length() == 0) { 
    117220                    result = null; 
     
    122225            return result; 
    123226        } 
    124         result = "No suitable administration interface found for connecting port '" + port1.getPort().getQualifiedLink() + "'"; 
     227        result = "No suitable administration interface found for connecting port '" + port.getQualifiedLink() + "'"; 
    125228        Log.log(LogLevel.WARNING, getLogDescription(), result); 
    126229        return result; 
     
    130233     * Sets value of remote port 
    131234     * 
    132      * @param np network port of remote port 
     235     * @param port Remote port 
    133236     * @param container Data to assign to remote port 
    134237     * @param handler Method return handler. Receives empty string if everything worked out - otherwise an error message. 
    135238     */ 
    136     public void setRemotePortValue(NetPort np, GenericObject container, ResponseHandler handler) { 
    137         if (np != null && getAdminInterface(np) == this) { 
     239    public void setRemotePortValue(RemotePort port, GenericObject container, ResponseHandler handler) { 
     240        if (port != null && getAdminInterface(port) == this) { 
    138241            MemoryBuffer mb = new MemoryBuffer(); 
    139             BinaryOutputStream co = new BinaryOutputStream(mb, BinaryOutputStream.TypeEncoding.Names); 
     242            BinaryOutputStream stream = new BinaryOutputStream(mb, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
     243            final byte STATIC_CAST = 3; 
     244            if (port.getDataType().getCastCountForDefaultLocalType() > 0) { 
     245                stream.writeByte(STATIC_CAST - 1 + port.getDataType().getCastCountForDefaultLocalType()); 
     246                stream.writeByte(port.getDataType().getEncodingForDefaultLocalType().ordinal()); 
     247                stream.writeShort(port.getDataType().getHandle()); 
     248                if (port.getDataType().getCastCountForDefaultLocalType() > 1) { 
     249                    stream.writeShort(port.getDataType().getDefaultLocalTypeIsCastedFrom().getHandle()); 
     250                } 
     251            } else { 
     252                stream.writeByte(port.getDataType().getEncodingForDefaultLocalType().ordinal()); 
     253            } 
     254            port.getDataType().serializeData(stream, container); 
     255 
     256            /*NetPort np = port.getPort().asNetPort(); 
    140257            co.writeEnum(np.getNetworkEncoding()); 
    141258            if (np.getRemoteType() == null) { 
     
    143260            } else { 
    144261                np.getRemoteType().serialize(co, container); 
    145             } 
    146             co.close(); 
    147             this.callAsynchronous(handler, AdminServer.SET_PORT_VALUE, np.getRemoteHandle(), mb); 
     262            }*/ 
     263            stream.close(); 
     264            this.callAsynchronous(handler, AdminServer.SET_PORT_VALUE, port.getRemoteHandle(), mb); 
    148265            return; 
    149266        } 
     
    152269 
    153270    /** 
     271     * @param remoteRuntime Runtime to read annotation from 
    154272     * @return Module types in remote Runtime 
    155273     */ 
    156     public ArrayList<RemoteCreateModuleAction> getRemoteModuleTypes() { 
     274    public ArrayList<RemoteCreateAction> getRemoteModuleTypes(RemoteRuntime remoteRuntime) { 
    157275        try { 
    158276            MemoryBuffer mb = (MemoryBuffer)this.callSynchronous(2000, AdminServer.GET_CREATE_MODULE_ACTIONS); 
    159             return toRemoteCreateModuleActionArray(mb); 
    160         } catch (Exception e) { 
    161             Log.log(LogLevel.WARNING, getLogDescription(), e); 
    162         } 
    163         return new ArrayList<RemoteCreateModuleAction>(); 
     277            return toRemoteCreateModuleActionArray(mb, remoteRuntime); 
     278        } catch (Exception e) { 
     279            Log.log(LogLevel.WARNING, getLogDescription(), e); 
     280        } 
     281        return new ArrayList<RemoteCreateAction>(); 
    164282    } 
    165283 
     
    168286     * @return List with Deserialized remote create module actions 
    169287     */ 
    170     private ArrayList<RemoteCreateModuleAction> toRemoteCreateModuleActionArray(MemoryBuffer mb) { 
    171         ArrayList<RemoteCreateModuleAction> result = new ArrayList<RemoteCreateModuleAction>(); 
    172         BinaryInputStream ci = new BinaryInputStream(mb, BinaryInputStream.TypeEncoding.Names); 
    173         while (ci.moreDataAvailable()) { 
    174             String name = ci.readString(); 
    175             RemoteCreateModuleAction a = new RemoteCreateModuleAction(this, name, ci.readString(), result.size()); 
    176             boolean hasParameters = ci.readBoolean(); 
     288    private ArrayList<RemoteCreateAction> toRemoteCreateModuleActionArray(MemoryBuffer mb, RemoteRuntime remoteRuntime) throws Exception { 
     289        ArrayList<RemoteCreateAction> result = new ArrayList<RemoteCreateAction>(); 
     290        remoteRuntime.resolveDefaultLocalTypes(); 
     291        BinaryInputStream stream = new BinaryInputStream(mb, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
     292        stream.setSharedSerializationInfo(AdministrationService.BASIC_UID_SERIALIZATION_INFO, remoteRuntime.getInputStream()); 
     293        while (stream.moreDataAvailable()) { 
     294            String name = stream.readString(); 
     295            RemoteCreateAction a = new RemoteCreateAction(name, stream.readString(), result.size()); 
     296            boolean hasParameters = stream.readBoolean(); 
    177297            if (hasParameters) { 
    178                 a.parameters.deserialize(ci); 
     298                a.createParametersObject(); 
     299                a.getParameters().deserialize(stream); 
    179300            } 
    180301            result.add(a); 
     
    192313     * @return Did module creation succeed? If not, contains error message. 
    193314     */ 
    194     public String createModule(RemoteCreateModuleAction cma, String name, int parentHandle, StaticParameterList spl) { 
     315    public String createModule(RemoteCreateAction cma, String name, int parentHandle, RemoteStaticParameterList spl) { 
    195316        MemoryBuffer mb = new MemoryBuffer(); 
    196         BinaryOutputStream co = new BinaryOutputStream(mb, TypeEncoding.Names); 
     317        BinaryOutputStream co = new BinaryOutputStream(mb, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
    197318        if (spl != null) { 
    198319            for (int i = 0; i < spl.size(); i++) { 
     
    203324 
    204325        try { 
    205             String cs = (String)this.callSynchronous(5000, AdminServer.CREATE_MODULE, cma.remoteIndex, name, parentHandle, mb); 
     326            String cs = (String)this.callSynchronous(5000, AdminServer.CREATE_MODULE, cma.getHandle(), name, parentHandle, mb); 
    206327            if (cs != null) { 
    207328                return cs; 
     
    214335    } 
    215336 
    216     /** 
    217      * @param np Remote port 
     337//    /** 
     338//     * @param np Remote port 
     339//     * @return Admin interface for remote port 
     340//     */ 
     341//    private AdminClient getAdminInterface(NetPort np) { 
     342//        return RemoteRuntime.find(np).getAdminInterface(); 
     343//    } 
     344 
     345    /** 
     346     * @param port Remote port 
    218347     * @return Admin interface for remote port 
    219348     */ 
    220     private AdminClient getAdminInterface(NetPort np) { 
    221         return RemoteRuntime.find(np).getAdminInterface(); 
     349    private AdminClient getAdminInterface(RemotePort port) { 
     350        return RemoteRuntime.find(port).getAdminInterface(); 
    222351    } 
    223352 
     
    250379     * 
    251380     * @param remoteHandle remote handle of framework element 
    252      * @param annType Annotation type 
    253      * @return Annotation - or null, if element has no annotation 
    254      */ 
    255     public FinrocAnnotation getAnnotation(int remoteHandle, DataTypeBase annType) { 
    256         try { 
    257             MemoryBuffer mb = (MemoryBuffer)this.callSynchronous(5000, AdminServer.GET_ANNOTATION, remoteHandle, annType.getName()); 
    258             if (mb == null || mb.getSize() == 0) { 
     381     * @param annotationTypeName Annotation type name in remote runtime 
     382     * @param remoteRuntime Runtime to read annotation from 
     383     * @return Stream that annotation can be serialized from (has BASIC_UID_SERIALIZATION_INFO by default - for simplicity e.g. with backward-compatibility) 
     384     */ 
     385    public BinaryInputStream getAnnotation(int remoteHandle, String annotationTypeName, RemoteRuntime remoteRuntime) { 
     386        try { 
     387            MemoryBuffer buffer = (MemoryBuffer)this.callSynchronous(5000, AdminServer.GET_ANNOTATION, remoteHandle, annotationTypeName); 
     388            if (buffer == null || buffer.getSize() == 0) { 
    259389                return null; 
    260390            } 
    261             BinaryInputStream ci = new BinaryInputStream(mb, BinaryInputStream.TypeEncoding.Names); 
    262             //DataTypeBase dt = DataTypeBase.findType(ci.readString()); 
    263             FinrocAnnotation fa = (FinrocAnnotation)annType.createInstance(); 
    264             fa.deserialize(ci); 
    265             ci.close(); 
    266             return fa; 
     391            remoteRuntime.resolveDefaultLocalTypes(); 
     392            BinaryInputStream stream = new BinaryInputStream(buffer, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
     393            stream.setSharedSerializationInfo(AdministrationService.BASIC_UID_SERIALIZATION_INFO, remoteRuntime.getInputStream()); 
     394            return stream; 
    267395        } catch (Exception e) { 
    268396            Log.log(LogLevel.WARNING, getLogDescription(), e); 
     
    276404     * 
    277405     * @param remoteHandle remote handle of framework element 
    278      * @param ann Annotation to write 
    279      */ 
    280     public void setAnnotation(int remoteHandle, FinrocAnnotation ann) { 
    281         MemoryBuffer mb = new MemoryBuffer(); 
    282         BinaryOutputStream co = new BinaryOutputStream(mb, BinaryOutputStream.TypeEncoding.Names); 
    283         if (ann.getType() == null) { 
    284             ann.initDataType(); 
    285         } 
    286         co.writeType(ann.getType()); 
    287         ann.serialize(co); 
    288         co.close(); 
    289  
    290         try { 
    291             this.call(AdminServer.SET_ANNOTATION, remoteHandle, mb); 
     406     * @param annotationTypeName Annotation type name in remote runtime 
     407     * @param annotation Annotation to write 
     408     */ 
     409    public void setAnnotation(int remoteHandle, String annotationTypeName, BinarySerializable annotation) { 
     410        MemoryBuffer buffer = new MemoryBuffer(); 
     411        BinaryOutputStream stream = new BinaryOutputStream(buffer, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
     412        stream.writeString(annotationTypeName); 
     413        annotation.serialize(stream); 
     414        stream.close(); 
     415 
     416        try { 
     417            this.call(AdminServer.SET_ANNOTATION, remoteHandle, buffer); 
    292418        } catch (Exception e) { 
    293419            Log.log(LogLevel.WARNING, getLogDescription(), e); 
     
    361487                return; 
    362488            } 
    363             BinaryInputStream ci = new BinaryInputStream(mb, BinaryInputStream.TypeEncoding.Names); 
     489            BinaryInputStream ci = new BinaryInputStream(mb, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
    364490 
    365491            // No config file available? 
     
    419545        try { 
    420546            MemoryBuffer mb = (MemoryBuffer)this.callSynchronous(2000, AdminServer.GET_MODULE_LIBRARIES); 
    421             BinaryInputStream ci = new BinaryInputStream(mb, BinaryInputStream.TypeEncoding.Names); 
     547            BinaryInputStream ci = new BinaryInputStream(mb, AdministrationService.BASIC_UID_SERIALIZATION_INFO); 
    422548            while (ci.moreDataAvailable()) { 
    423549                result.add(ci.readString()); 
     
    433559     * Load module library in external runtime 
    434560     * 
    435      * @param load module library to load 
     561     * @param load Module library to load 
     562     * @param remoteRuntime Runtime to read annotation from 
    436563     * @return Updated list of remote create module actions 
    437564     */ 
    438     public List<RemoteCreateModuleAction> loadModuleLibrary(String load) { 
     565    public List<RemoteCreateAction> loadModuleLibrary(String load, RemoteRuntime remoteRuntime) { 
    439566        try { 
    440567            MemoryBuffer mb = (MemoryBuffer)this.callSynchronous(5000, AdminServer.LOAD_MODULE_LIBRARY, load); 
     
    442569                return null; 
    443570            } 
    444             return toRemoteCreateModuleActionArray(mb); 
     571            return toRemoteCreateModuleActionArray(mb, remoteRuntime); 
    445572        } catch (Exception e) { 
    446573            Log.log(LogLevel.WARNING, getLogDescription(), e); 
     
    448575        return null; 
    449576    } 
     577 
     578    /** 
     579     * Gets all updates on specified register and all registers to be updated on change. 
     580     * After calling this method, the client's data on these remote registers is up to date. 
     581     * 
     582     * @param registerUid Uid of register to obtain updates for 
     583     */ 
     584    public void getRegisterUpdates(int registerUid) { 
     585        try { 
     586            this.callSynchronous(5000, AdminServer.GET_REGISTER_UPDATES, registerUid); 
     587        } catch (Exception e) { 
     588            Log.log(LogLevel.WARNING, getLogDescription(), e); 
     589        } 
     590    } 
    450591} 
  • admin/AdminServer.java

    r208 r262  
    5353    SET_PORT_VALUE = new Method(AdministrationService.class, "setPortValue"), 
    5454    START_EXECUTION = new Method(AdministrationService.class, "startExecution"), 
    55     NETWORK_CONNECT = new Method(AdministrationService.class, "networkConnect"); 
     55    NETWORK_CONNECT = new Method(AdministrationService.class, "networkConnect"), 
     56    CONNECT_PORTS = new Method(AdministrationService.class, "connectPorts"), 
     57    CREATE_URI_CONNECTOR = new Method(AdministrationService.class, "createUriConnector"), 
     58    DELETE_URI_CONNECTOR = new Method(AdministrationService.class, "deleteUriConnector"), 
     59    GET_REGISTER_UPDATES = new Method(AdministrationService.class, "getRegisterUpdates"); 
    5660 
    5761    /** Data Type of method calls to this port */ 
     
    5963            DISCONNECT, DISCONNECT_ALL, GET_ANNOTATION, GET_CREATE_MODULE_ACTIONS, GET_MODULE_LIBRARIES, GET_PARAMETER_INFO, IS_EXECUTING, 
    6064            LOAD_MODULE_LIBRARY, PAUSE_EXECUTION, SAVE_ALL_FINSTRUCTABLE_FILES, SAVE_FINSTRUCTABLE_GROUP, SET_ANNOTATION, SET_PORT_VALUE, START_EXECUTION, 
    61             NETWORK_CONNECT); 
     65            NETWORK_CONNECT, CONNECT_PORTS, CREATE_URI_CONNECTOR, DELETE_URI_CONNECTOR, GET_REGISTER_UPDATES); 
    6266 
    6367    public AdminServer() { 
  • admin/AdministrationService.java

    r217 r262  
    3636import org.finroc.core.parameter.ParameterInfo; 
    3737import org.finroc.core.parameter.StaticParameterBase; 
    38 import org.finroc.core.parameter.StaticParameterList; 
    3938import org.finroc.core.plugin.CreateFrameworkElementAction; 
    4039import org.finroc.core.plugin.Plugins; 
     
    4645import org.finroc.core.port.std.PortDataManager; 
    4746import org.finroc.core.portdatabase.FinrocTypeInfo; 
     47import org.finroc.core.remote.RemoteConnectOptions; 
    4848import org.finroc.core.thread.ExecutionControl; 
    4949import org.rrlib.logging.Log; 
     
    5252import org.rrlib.serialization.BinaryOutputStream; 
    5353import org.rrlib.serialization.MemoryBuffer; 
     54import org.rrlib.serialization.RegisterUpdate; 
    5455import org.rrlib.serialization.Serialization; 
    55 import org.rrlib.serialization.BinaryInputStream.TypeEncoding; 
     56import org.rrlib.serialization.SerializationInfo; 
    5657import org.rrlib.serialization.rtti.DataTypeBase; 
    5758 
     
    115116            Log.log(LogLevel.USER, this, "Connected ports " + src.getQualifiedName() + " " + dest.getQualifiedName()); 
    116117        } 
     118    } 
     119 
     120    /** 
     121     * Connect source port to destination port with connect options 
     122     * (new connect method) 
     123     * 
     124     * @param sourcePortHandle Handle of source port 
     125     * @param destinationPortHandle Handle of destination port 
     126     * @param connectOptions Connect options 
     127     * @return Returns error message if connecting failed. On success an empty string is returned. 
     128     */ 
     129    public String connectPorts(int sourcePortHandle, int destinationPortHandle, RemoteConnectOptions connectOptions) { 
     130        return "Not implemented in Java yet"; 
    117131    } 
    118132 
     
    145159                    if (cma.getParameterTypes() != null && cma.getParameterTypes().size() > 0) { 
    146160                        params = cma.getParameterTypes().instantiate(); 
    147                         BinaryInputStream ci = new BinaryInputStream(serializedCreationParameters, TypeEncoding.Names); 
     161                        BinaryInputStream ci = new BinaryInputStream(serializedCreationParameters, BASIC_UID_SERIALIZATION_INFO); 
    148162                        for (int i = 0; i < params.size(); i++) { 
    149163                            StaticParameterBase param = params.get(i); 
     
    174188 
    175189    /** 
     190     * Create URI connector connecting local port using one of the supported URI schemes (provided e.g. by network transports). 
     191     * 
     192     * @param localPortHandle Handle of local owner port 
     193     * @param uri URI of partner port 
     194     * @param connectOptions Connect options 
     195     * @return Returns error message if connecting failed. On success an empty string is returned. 
     196     */ 
     197    public String createUriConnector(int localPortHandle, String uri, RemoteConnectOptions connectOptions) { 
     198        return "Not implemented in Java yet"; 
     199    } 
     200 
     201    /** 
    176202     * Deletes specified framework element 
    177203     * 
     
    187213        } 
    188214        return; 
     215    } 
     216 
     217    /** 
     218     * Delete URI connector 
     219     * 
     220     * @param localPortHandle Handle of local owner port 
     221     * @param uri Index of URI connector in owner port's list 
     222     * @return Whether any connector was deleted 
     223     */ 
     224    public boolean deleteUriConnector(int localPortHandle, int index) { 
     225        Log.log(LogLevel.WARNING, this, "Not implemented in Java yet"); 
     226        return false; 
    189227    } 
    190228 
     
    256294        } else { 
    257295            MemoryBuffer buf = new MemoryBuffer(); 
    258             BinaryOutputStream co = new BinaryOutputStream(buf, BinaryOutputStream.TypeEncoding.Names); 
    259             co.writeType(result.getType()); 
     296            BinaryOutputStream co = new BinaryOutputStream(buf, BASIC_UID_SERIALIZATION_INFO); 
     297            result.getType().serialize(co); 
    260298            result.serialize(co); 
    261299            co.close(); 
     
    268306     */ 
    269307    public MemoryBuffer getCreateModuleActions() { 
    270         MemoryBuffer mb = new MemoryBuffer(); 
    271         BinaryOutputStream co = new BinaryOutputStream(mb, BinaryOutputStream.TypeEncoding.Names); 
    272  
    273         ArrayList<CreateFrameworkElementAction> moduleTypes = Plugins.getInstance().getModuleTypes(); 
    274         for (int i = 0; i < moduleTypes.size(); i++) { 
    275             CreateFrameworkElementAction cma = moduleTypes.get(i); 
    276             co.writeString(cma.getName()); 
    277             co.writeString(cma.getModuleGroup()); 
    278             if (cma.getParameterTypes() != null) { 
    279                 cma.getParameterTypes().serialize(co); 
    280             } else { 
    281                 StaticParameterList.EMPTY.serialize(co); 
    282             } 
    283         } 
    284  
    285         co.close(); 
    286         return mb; 
     308        Log.log(LogLevel.WARNING, this, "GetCreateModuleActions() is superseded"); 
     309        return new MemoryBuffer(); 
    287310    } 
    288311 
     
    308331        ConfigFile cf = ConfigFile.find(fe); 
    309332        MemoryBuffer buf = new MemoryBuffer(); 
    310         BinaryOutputStream co = new BinaryOutputStream(buf, BinaryOutputStream.TypeEncoding.Names); 
     333        BinaryOutputStream co = new BinaryOutputStream(buf, BASIC_UID_SERIALIZATION_INFO); 
    311334        if (cf == null) { 
    312335            co.writeBoolean(false); 
     
    321344        co.close(); 
    322345        return buf; 
     346    } 
     347 
     348    /** 
     349     * Gets all updates on specified register and all registers to be updated on change. 
     350     * After calling this method, the client's data on these remote registers is up to date. 
     351     * 
     352     * @param registerUid Uid of register to obtain updates for 
     353     * @return Updates (object does not need to be processed - does its work during deserialization) 
     354     */ 
     355    public RegisterUpdate getRegisterUpdates(int registerUid) { 
     356        return new RegisterUpdate(registerUid); 
    323357    } 
    324358 
     
    430464            Log.log(LogLevel.ERROR, this, "Parent not available. Cancelling setting of annotation."); 
    431465        } else { 
    432             BinaryInputStream ci = new BinaryInputStream(serializedAnnotation, BinaryInputStream.TypeEncoding.Names); 
    433             DataTypeBase dt = ci.readType(); 
    434             if (dt == null) { 
    435                 Log.log(LogLevel.ERROR, this, "Data type not available. Cancelling setting of annotation."); 
    436             } else { 
    437                 FinrocAnnotation ann = elem.getAnnotation(dt); 
    438                 if (ann == null) { 
    439                     Log.log(LogLevel.ERROR, this, "Creating new annotations not supported yet. Cancelling setting of annotation."); 
    440                 } else if (ann.getType() != dt) { 
    441                     Log.log(LogLevel.ERROR, this, "Existing annotation has wrong type?!. Cancelling setting of annotation."); 
     466            try { 
     467                BinaryInputStream ci = new BinaryInputStream(serializedAnnotation, BASIC_UID_SERIALIZATION_INFO); 
     468                DataTypeBase dt = DataTypeBase.deserialize(ci); 
     469                if (dt == null) { 
     470                    Log.log(LogLevel.ERROR, this, "Data type not available. Cancelling setting of annotation."); 
    442471                } else { 
    443                     ann.deserialize(ci); 
     472                    FinrocAnnotation ann = elem.getAnnotation(dt); 
     473                    if (ann == null) { 
     474                        Log.log(LogLevel.ERROR, this, "Creating new annotations not supported yet. Cancelling setting of annotation."); 
     475                    } else if (ann.getType() != dt) { 
     476                        Log.log(LogLevel.ERROR, this, "Existing annotation has wrong type?!. Cancelling setting of annotation."); 
     477                    } else { 
     478                        ann.deserialize(ci); 
     479                    } 
    444480                } 
    445             } 
    446             ci.close(); 
     481                ci.close(); 
     482            } catch (Exception e) { 
     483                Log.log(LogLevel.ERROR, this, "Error setting annotation: ", e); 
     484            } 
    447485        } 
    448486    } 
     
    462500                if (port.isReady()) { 
    463501                    try { 
    464                         BinaryInputStream ci = new BinaryInputStream(serializedNewValue, BinaryInputStream.TypeEncoding.Names); 
     502                        BinaryInputStream ci = new BinaryInputStream(serializedNewValue, BASIC_UID_SERIALIZATION_INFO); 
    465503                        Serialization.DataEncoding enc = ci.readEnum(Serialization.DataEncoding.class); 
    466                         DataTypeBase dt = ci.readType(); 
     504                        DataTypeBase dt = DataTypeBase.deserialize(ci); 
    467505                        if (FinrocTypeInfo.isCCType(port.getDataType()) && FinrocTypeInfo.isCCType(dt)) { 
    468506                            CCPortBase p = (CCPortBase)port; 
     
    583621        return "AdministrationService"; 
    584622    } 
     623 
     624    /** Serialization info for memory buffers in some commands */ 
     625    static final SerializationInfo BASIC_UID_SERIALIZATION_INFO = new SerializationInfo(0, SerializationInfo.RegisterEntryEncoding.UID, 0); 
    585626} 
  • datatype/DataTypeReference.java

    r217 r262  
    2222package org.finroc.core.datatype; 
    2323 
     24import org.finroc.core.remote.RemoteType; 
    2425import org.rrlib.serialization.rtti.DataType; 
    2526import org.rrlib.serialization.rtti.DataTypeBase; 
     
    3940 
    4041    public DataTypeReference() { 
    41         set(CoreNumber.TYPE); // default is CoreNumber 
     42        set(CoreString.TYPE); // default is CoreString 
    4243    } 
    4344 
    4445    /** 
    45      * @param dt DataType to reference 
     46     * @param type DataType to reference 
    4647     */ 
    47     public DataTypeReference(DataTypeBase dt) { 
    48         set(dt); 
     48    public DataTypeReference(DataTypeBase type) { 
     49        set(type); 
    4950    } 
    5051 
    5152    /** 
    52      * @param dt new DataType to reference 
     53     * @param type DataType to reference 
    5354     */ 
    54     public void set(DataTypeBase dt) { 
    55         super.set(dt.getName()); 
     55    public DataTypeReference(RemoteType type) { 
     56        set(type); 
    5657    } 
    5758 
    5859    /** 
    59      * @return Referenced data type - null if it doesn't exist in this runtime 
     60     * @param other DataTypeReference to copy 
    6061     */ 
    61     public DataTypeBase get() { 
    62         return DataTypeBase.findType(getBuffer().toString()); 
     62    public DataTypeReference(DataTypeReference other) { 
     63        set(other.toString()); 
    6364    } 
     65 
     66    /** 
     67     * @param name Name of type 
     68     */ 
     69    public DataTypeReference(String name) { 
     70        set(name); 
     71    } 
     72 
     73    /** 
     74     * @param type new DataType to reference 
     75     */ 
     76    public void set(DataTypeBase type) { 
     77        super.set(type.getName()); 
     78    } 
     79 
     80    /** 
     81     * @param type new DataType to reference 
     82     */ 
     83    public void set(RemoteType type) { 
     84        super.set(type.getName()); 
     85    } 
     86 
     87//    /** 
     88//     * @return Referenced data type - null if it doesn't exist in this runtime 
     89//     */ 
     90//    public DataTypeBase get() { 
     91//        return DataTypeBase.findType(getBuffer().toString()); 
     92//    } 
    6493 
    6594    public boolean equals(Object other) { 
  • datatype/PortCreationList.java

    r222 r262  
    7979        public Entry(String name, DataTypeReference type, byte createOptions) { 
    8080            this.name = name; 
    81             this.type = new DataTypeReference(type.get()); 
     81            this.type = new DataTypeReference(type); 
    8282            this.createOptions = createOptions; 
    8383        } 
  • parameter/StaticParameterBase.java

    r238 r262  
    2929import org.finroc.core.finstructable.FinstructableGroup; 
    3030import org.finroc.core.portdatabase.SerializationHelper; 
    31 import org.rrlib.finroc_core_utils.jc.HasDestructor; 
    3231import org.rrlib.logging.Log; 
    3332import org.rrlib.logging.LogLevel; 
     
    4645 * (Generic base class without template type) 
    4746 */ 
    48 public class StaticParameterBase implements HasDestructor { 
     47public class StaticParameterBase { 
    4948 
    5049    /** Name of parameter */ 
     
    7776    protected int listIndex; 
    7877 
    79     /** Is this a remote parameter? */ 
    80     private final boolean remote; 
    81  
    8278    /** 
    8379     * Command line option to set this parameter 
     
    111107    private ArrayList<StaticParameterBase> attachedParameters = new ArrayList<StaticParameterBase>(); 
    112108 
    113     /** Constructor for remote parameters */ 
    114     public StaticParameterBase() { 
    115         remote = true; 
    116     } 
    117109 
    118110    /** 
     
    138130            createBuffer(type); 
    139131        } 
    140         remote = false; 
    141132    } 
    142133 
    143134    public void serialize(BinaryOutputStream os) { 
    144135        os.writeString(name); 
    145         os.writeType(type); 
     136        type.serialize(os); 
    146137        os.writeString(commandLineOption); 
    147138        os.writeString(outerParameterAttachment); 
     
    163154        os.writeBoolean(val != null); 
    164155        if (val != null) { 
    165             os.writeType(val.getType()); 
     156            val.getType().serialize(os); 
    166157            val.serialize(os, Serialization.DataEncoding.XML); 
    167158        } 
    168159    } 
    169160 
    170     public void deserialize(BinaryInputStream is) { 
    171         if (remoteValue()) { 
    172             name = is.readString(); 
    173             type = is.readType(); 
    174         } else { 
    175             is.readString(); 
    176             is.readType(); 
    177         } 
     161    public void deserialize(BinaryInputStream is) throws Exception { 
     162        is.readString(); 
     163        DataTypeBase.deserialize(is); 
    178164 
    179165        String commandLineOptionTmp = is.readString(); 
     
    200186    public void deserializeValue(BinaryInputStream is) throws Exception { 
    201187        if (is.readBoolean()) { 
    202             DataTypeBase dt = is.readType(); 
     188            DataTypeBase dt = DataTypeBase.deserialize(is); 
    203189            GenericObject val = valPointer(); 
    204190            if (val == null || val.getType() != dt) { 
     
    269255    } 
    270256 
    271     @Override 
    272     public void delete() { 
    273     } 
    274  
    275257    /** 
    276258     * @return Value serialized as string (reverse operation to set) 
     
    320302        sp.value = type.createInstanceGeneric(null); 
    321303        assert(sp.value != null); 
    322     } 
    323  
    324     /** 
    325      * @return Is this a remote parameter? 
    326      */ 
    327     private boolean remoteValue() { 
    328         return remote; 
    329304    } 
    330305 
     
    554529     */ 
    555530    public void loadValue() { 
    556         if (remote) { 
    557             return; 
    558         } 
    559531 
    560532        FrameworkElement parent = parentList.getAnnotated(); 
  • parameter/StaticParameterList.java

    r222 r262  
    6767    } 
    6868 
    69     public void delete() { 
    70         clear(); 
    71         super.delete(); 
    72     } 
    73  
    74     /** Clear list (deletes parameters) */ 
    75     private void clear() { 
    76         for (int i = parameters.size() - 1; i >= 0; i--) { 
    77             parameters.remove(i).delete(); 
    78         } 
    79     } 
    80  
    8169    @Override 
    8270    public void serialize(BinaryOutputStream os) { 
     
    8977 
    9078    @Override 
    91     public void deserialize(BinaryInputStream is) { 
     79    public void deserialize(BinaryInputStream is) throws Exception { 
    9280        if (getAnnotated() == null) { 
    93             createAction = is.readInt(); 
    94             clear(); 
    95             int newSize = is.readInt(); 
    96             for (int i = 0; i < newSize; i++) { 
    97                 StaticParameterBase param = new StaticParameterBase(); 
    98                 param.deserialize(is); 
    99                 add(param); 
    100             } 
     81            throw new RuntimeException("RemoteStaticParameters class should be used"); 
    10182        } else { // attached to module - only update parameter values 
    10283            if (createAction != is.readInt() || ((int)parameters.size()) != is.readInt()) { 
  • plugin/ExternalConnection.java

    r224 r262  
    3131import org.finroc.core.parameter.StaticParameterString; 
    3232import org.finroc.core.parameter.StaticParameterList; 
     33import org.finroc.core.remote.BufferedModelChanges; 
    3334import org.finroc.core.remote.ModelHandler; 
    34 import org.finroc.core.remote.ModelNode; 
    3535 
    3636 
     
    258258 
    259259        @Override 
    260         public void addNode(ModelNode parent, ModelNode newChild) {} 
    261  
    262         @Override 
    263         public void changeNodeName(ModelNode node, String newName) {} 
    264  
    265         @Override 
    266         public void removeNode(ModelNode childToRemove) {} 
    267  
    268         @Override 
    269         public void replaceNode(ModelNode oldNode, ModelNode newNode) {} 
    270  
    271         @Override 
    272         public void setModelRoot(ModelNode root) {} 
    273  
    274         @Override 
    275         public void updateModel(Runnable updateTask) {} 
     260        public void applyModelChanges(BufferedModelChanges bufferedChanges) { 
     261        } 
     262 
    276263    } 
    277264} 
  • port/AbstractPort.java

    r234 r262  
    4242import org.finroc.core.port.std.PortDataManager; 
    4343import org.finroc.core.portdatabase.FinrocTypeInfo; 
    44 import org.finroc.core.remote.RemoteType; 
    4544 
    4645/** 
     
    7271     * List class for edges 
    7372     */ 
    74     protected static class EdgeList<T> extends SafeConcurrentlyIterableList<T> { 
     73    public static class EdgeList<T> extends SafeConcurrentlyIterableList<T> { 
    7574 
    7675        public EdgeList() { 
     
    716715    } 
    717716 
    718     /** 
    719      * Find network port connected to this port that belongs to specified framework element 
    720      * 
    721      * @param belongsTo Instance (usually TCPServerConnection or RemoteServer) that this port belongs to 
    722      * @return Network port if it could be found - otherwise null 
    723      */ 
    724     @SuppressWarnings("unchecked") 
    725     public NetPort findNetPort(Object belongsTo) { 
    726         if (belongsTo == null) { 
    727             return null; 
    728         } 
    729         ArrayWrapper<AbstractPort> it = isOutputPort() ? edgesSrc.getIterable() : edgesDest.getIterable(); 
    730         for (int i = 0, n = it.size(); i < n; i++) { 
    731             AbstractPort port = it.get(i); 
    732             if (port != null && port.getFlag(Flag.NETWORK_ELEMENT)) { 
    733                 NetPort np = port.asNetPort(); 
    734                 if (np != null && np.getBelongsTo() == belongsTo) { 
    735                     return np; 
    736                 } 
    737             } 
    738         } 
    739         return null; 
    740     } 
     717//    /** 
     718//     * Find network port connected to this port that belongs to specified framework element 
     719//     * 
     720//     * @param belongsTo Instance (usually TCPServerConnection or RemoteServer) that this port belongs to 
     721//     * @return Network port if it could be found - otherwise null 
     722//     */ 
     723//    @SuppressWarnings("unchecked") 
     724//    public NetPort findNetPort(Object belongsTo) { 
     725//        if (belongsTo == null) { 
     726//            return null; 
     727//        } 
     728//        ArrayWrapper<AbstractPort> it = isOutputPort() ? edgesSrc.getIterable() : edgesDest.getIterable(); 
     729//        for (int i = 0, n = it.size(); i < n; i++) { 
     730//            AbstractPort port = it.get(i); 
     731//            if (port != null && port.getFlag(Flag.NETWORK_ELEMENT)) { 
     732//                NetPort np = port.asNetPort(); 
     733//                if (np != null && np.getBelongsTo() == belongsTo) { 
     734//                    return np; 
     735//                } 
     736//            } 
     737//        } 
     738//        return null; 
     739//    } 
    741740 
    742741    /** 
     
    11791178    @Override 
    11801179    public GenericObject createGenericObject(DataTypeBase dt, Object factoryParameter) { 
    1181         if (FinrocTypeInfo.isStdType(dt) || (dt instanceof RemoteType)) { 
     1180        if (FinrocTypeInfo.isStdType(dt)) { 
    11821181            return getUnusedBufferRaw(dt).getObject(); 
    11831182        } else if (FinrocTypeInfo.isCCType(dt)) { 
  • port/Port.java

    r217 r262  
    390390        } 
    391391    } 
     392 
     393    /** 
     394     * Wraps abstract port as port 
     395     * 
     396     * @param port Abstract port to wrap 
     397     * @return Wrapped port 
     398     */ 
     399    public static Port<?> wrap(AbstractPort port) { 
     400        Port<?> result = new Port<>(); 
     401        result.wrapped = port; 
     402        result.ccType = FinrocTypeInfo.isCCType(port.getDataType()); 
     403        return result; 
     404    } 
    392405} 
  • port/net/NetPort.java

    r247 r262  
    2121//---------------------------------------------------------------------- 
    2222package org.finroc.core.port.net; 
    23  
    24 import java.util.ArrayList; 
    25 import java.util.List; 
    2623 
    2724import org.finroc.core.FrameworkElementFlags; 
     
    4037import org.rrlib.finroc_core_utils.jc.ArrayWrapper; 
    4138import org.rrlib.serialization.BinaryInputStream; 
    42 import org.rrlib.serialization.Serialization; 
    4339import org.rrlib.serialization.Serialization.DataEncoding; 
    4440import org.rrlib.serialization.rtti.DataTypeBase; 
     
    5349public abstract class NetPort implements PortListener { 
    5450 
    55     public interface ExtraEdgeProvider { 
    56  
    57         /** 
    58          * @param resultList List to put the targets of the remote edges in (filled after call) - edges with reverse direction are the last in the list 
    59          * @return Index of the first edge in reverse direction 
    60          */ 
    61         public abstract int getRemoteEdgeDestinations(List<AbstractPort> resultList); 
    62     } 
    63  
    6451    /** Default timeout for pulling data over the net */ 
    6552    public final static int PULL_TIMEOUT = 1000; 
    6653 
    67     /** TCPServerConnection or RemoteServer instance that this port belongs to */ 
    68     protected final Object belongsTo; 
     54    ///** TCPServerConnection or RemoteServer instance that this port belongs to */ 
     55    //protected final Object belongsTo; 
    6956 
    7057    /** Last time the value was updated (used to make sure that minimum update interval is kept) */ 
     
    7764    protected int remoteHandle; 
    7865 
    79     /** Finroc Type info type */ 
    80     protected final FinrocTypeInfo.Type ftype; 
    81  
    82     /** Data type to use when writing data to the network */ 
    83     private Serialization.DataEncoding encoding = Serialization.DataEncoding.BINARY; 
    84  
    85     /** If network port has a data type whose implementation is only available remotely, this stores the remote type - otherwise null */ 
    86     private RemoteType remoteType; 
    87  
    88     /** Attached extra provider of remote edges (null if none is attached) */ 
    89     private ExtraEdgeProvider extraEdgeProvider = null; 
    90  
    91  
    92     public NetPort(PortCreationInfo pci, Object belongsTo) { 
     66    /** Data type in remote runtime environment */ 
     67    private final RemoteType remoteType; 
     68 
     69    /** Data type used in this runtime environment to represent remoteType */ 
     70    private final DataTypeBase localType; 
     71 
     72 
     73    public NetPort(PortCreationInfo pci, /*Object belongsTo,*/ RemoteType remoteType) { 
     74        this.remoteType = remoteType; 
    9375        // keep most these flags 
    9476        int f = pci.flags & (FrameworkElementFlags.ACCEPTS_DATA | FrameworkElementFlags.EMITS_DATA | FrameworkElementFlags.IS_OUTPUT_PORT | 
     
    10587            } 
    10688        } 
    107         ftype = FinrocTypeInfo.get(pci.dataType).getType(); 
    108         remoteType = (pci.dataType instanceof RemoteType) ? (RemoteType)pci.dataType : null; 
    109         if (isStdType() || isMethodType() || (remoteType != null && remoteType.isAdaptable())) { 
     89        if (isMethodType()) { 
    11090            f |= FrameworkElementFlags.MULTI_TYPE_BUFFER_POOL; // different data types may be incoming - cc types are thread local 
    11191        } 
    11292        pci.flags = f; 
    113         this.belongsTo = belongsTo; 
    114  
    115         if (remoteType != null) { 
    116             if (remoteType.isAdaptable()) { 
    117                 encoding = remoteType.getNetworkEncoding(); 
    118                 wrapped = new StdNetPort(pci); 
    119             } else { 
    120                 wrapped = new UnknownTypedNetPort(pci); 
    121             } 
    122             return; 
    123         } 
     93        //this.belongsTo = belongsTo; 
     94        localType = remoteType.getDefaultLocalDataType(); 
     95        pci.dataType = localType; 
    12496 
    12597        wrapped = (isMethodType() ? (AbstractPort)new RPCNetPort(pci) : 
     
    135107    /** Helper methods for data type type */ 
    136108    public boolean isStdType() { 
    137         return ftype == FinrocTypeInfo.Type.STD; 
     109        return FinrocTypeInfo.isStdType(localType); 
    138110    } 
    139111 
    140112    public boolean isCCType() { 
    141         return ftype == FinrocTypeInfo.Type.CC; 
     113        return FinrocTypeInfo.isCCType(localType); 
    142114    } 
    143115 
    144116    public boolean isMethodType() { 
    145         return ftype == FinrocTypeInfo.Type.METHOD; 
     117        return (remoteType.getTypeTraits() & DataTypeBase.IS_RPC_TYPE) != 0; 
    146118    } 
    147119 
    148120    public boolean isTransactionType() { 
    149         return ftype == FinrocTypeInfo.Type.TRANSACTION; 
     121        return false; 
    150122    } 
    151123 
     
    158130        flags |= curFlags; 
    159131 
    160         if (remoteType != null && (!remoteType.isAdaptable())) { 
    161             ((UnknownTypedNetPort)wrapped).updateFlags(flags); 
    162             return; 
    163         } 
    164  
    165         if (isStdType() || isTransactionType() || (remoteType != null && remoteType.isAdaptable())) { 
     132        if (isStdType() || isTransactionType()) { 
    166133            ((StdNetPort)wrapped).updateFlags(flags); 
    167134        } else if (isCCType()) { 
     
    186153    } 
    187154 
    188     /** 
    189      * @return TCPServerConnection or RemoteServer instance that this port belongs to 
    190      */ 
    191     public Object getBelongsTo() { 
    192         return belongsTo; 
    193     } 
     155//    /** 
     156//     * @return TCPServerConnection or RemoteServer instance that this port belongs to 
     157//     */ 
     158//    public Object getBelongsTo() { 
     159//        return belongsTo; 
     160//    } 
    194161 
    195162    /** 
     
    279246                    manager.getTimestamp().deserialize(stream); 
    280247                } 
    281                 if (remoteType == null) { 
    282                     manager.getObject().deserialize(stream, dataEncoding); 
    283                 } else { 
    284                     remoteType.deserialize(stream, manager.getObject()); 
    285                 } 
     248                remoteType.deserializeData(stream, manager.getObject()); 
    286249                pb.publishFromNet(manager, changeType); 
    287250            } else if (isCCType()) { 
     
    291254                    manager.getTimestamp().deserialize(stream); 
    292255                } 
    293                 manager.getObject().deserialize(stream, dataEncoding); 
     256                remoteType.deserializeData(stream, manager.getObject()); 
    294257                pb.publishFromNet(manager, changeType); 
    295258            } else { // interface port 
     
    613576    } 
    614577 
    615     /** 
    616      * Remote port with unknown type 
    617      * 
    618      * Artificial construct for finstruct. 
    619      * This way, ports with unknown types can be displayed and connected. 
    620      */ 
    621     public class UnknownTypedNetPort extends AbstractPort { 
    622  
    623         /** Edges emerging from this port */ 
    624         protected final EdgeList<AbstractPort> edgesSrc = new EdgeList<AbstractPort>(); 
    625  
    626         /** Edges ending at this port */ 
    627         protected final EdgeList<AbstractPort> edgesDest = new EdgeList<AbstractPort>(); 
    628  
    629         public UnknownTypedNetPort(PortCreationInfo pci) { 
    630             super(pci); 
    631             assert(remoteType != null); 
    632             initLists(edgesSrc, edgesDest); 
    633         } 
    634  
    635         @Override 
    636         public NetPort asNetPort() { 
    637             return NetPort.this; 
    638         } 
    639  
    640         @Override 
    641         protected synchronized void prepareDelete() { 
    642             super.prepareDelete(); 
    643             NetPort.this.prepareDelete(); 
    644         } 
    645  
    646         @Override 
    647         protected void postChildInit() { 
    648             super.postChildInit(); 
    649             NetPort.this.postChildInit(); 
    650         } 
    651  
    652         @Override 
    653         protected void preChildInit() { 
    654             super.preChildInit(); 
    655             NetPort.this.preChildInit(); 
    656         } 
    657  
    658         @Override 
    659         public void notifyDisconnect() { 
    660             NetPort.this.notifyDisconnect(); 
    661         } 
    662  
    663         public void updateFlags(int flags) { 
    664             setFlag(flags & Flag.NON_CONSTANT_FLAGS); 
    665         } 
    666  
    667         @Override 
    668         protected void connectionRemoved(AbstractPort partner, boolean partnerIsDestination) { 
    669             NetPort.this.connectionRemoved(); 
    670         } 
    671  
    672         @Override 
    673         protected void connectionAdded(AbstractPort partner, boolean partnerIsDestination) { 
    674             NetPort.this.connectionAdded(); 
    675         } 
    676  
    677         @Override 
    678         protected void initialPushTo(AbstractPort target, boolean reverse) {} 
    679  
    680         @Override 
    681         protected void setMaxQueueLengthImpl(int length) {} 
    682  
    683         @Override 
    684         protected int getMaxQueueLengthImpl() { 
    685             return 0; 
    686         } 
    687  
    688         @Override 
    689         protected void clearQueueImpl() {} 
    690  
    691         @Override 
    692         public void forwardData(AbstractPort other) {} 
    693  
    694     } 
    695  
    696578    @Override 
    697579    public void portChanged(AbstractPort origin, Object value) { 
     
    733615 
    734616    /** 
    735      * @return Targets of remote edges 
    736      */ 
    737     public List<AbstractPort> getRemoteEdgeDestinations() { 
    738         ArrayList<AbstractPort> result = new ArrayList<AbstractPort>(); 
    739         getRemoteEdgeDestinations(result); 
    740         return result; 
    741     } 
    742  
    743     /** 
    744      * @param resultList List to put the targets of the remote edges in (filled after call) - edges with reverse direction are the last in the list 
    745      * @return Index of the first edge in reverse direction 
    746      */ 
    747     public abstract int getRemoteEdgeDestinations(List<AbstractPort> resultList); 
    748  
    749     /** 
    750617     * @return Data type of port in remote runtime (with unknown types this might be different from type of local port) 
    751618     */ 
     
    755622 
    756623    /** 
    757      * @return Data type to use when writing data to the network 
    758      */ 
    759     public Serialization.DataEncoding getNetworkEncoding() { 
    760         return encoding; 
    761     } 
    762  
    763     /** 
    764      * @param enc Data type to use when writing data to the network 
    765      */ 
    766     public void setEncoding(Serialization.DataEncoding enc) { 
    767         encoding = enc; 
    768     } 
    769  
    770     /** 
    771624     * @return If network port has a data type whose implementation is only available remotely, this stores the remote type - otherwise null 
    772625     */ 
     
    774627        return remoteType; 
    775628    } 
    776  
    777     /** 
    778      * @return Attached extra provider of remote edges (null if none is attached) 
    779      */ 
    780     public ExtraEdgeProvider getExtraEdgeProvider() { 
    781         return extraEdgeProvider; 
    782     } 
    783  
    784     /** 
    785      * @param extraEdgeProvider Attach new extra provider of remote edges (null if none is to be attached) 
    786      */ 
    787     public void setExtraEdgeProvider(ExtraEdgeProvider extraEdgeProvider) { 
    788         this.extraEdgeProvider = extraEdgeProvider; 
    789     } 
    790629} 
  • port/rpc/Promise.java

    r217 r262  
    114114        public void serialize(BinaryOutputStream stream) { 
    115115            // Deserialized by network transport implementation 
    116             stream.writeType(method.getInterfaceType()); 
     116            method.getInterfaceType().serialize(stream); 
    117117            stream.writeByte(method.getMethodID()); 
    118118            stream.writeLong(remotePromiseCallId); 
  • port/rpc/RPCInterfaceType.java

    r235 r262  
    4444    public RPCInterfaceType(String name, Method ... methods) { 
    4545        super(name); 
    46         type = DataTypeBase.Classification.OTHER; 
     46        typeTraits |= IS_RPC_TYPE; 
    4747        FinrocTypeInfo.get(this).init(FinrocTypeInfo.Type.METHOD); 
    4848        this.methods = methods; 
  • port/rpc/internal/RPCMessage.java

    r217 r262  
    6969    public void serialize(BinaryOutputStream stream) { 
    7070        // Deserialized by network transport implementation 
    71         stream.writeType(method.getInterfaceType()); 
     71        method.getInterfaceType().serialize(stream); 
    7272        stream.writeByte(method.getMethodID()); 
    7373 
  • port/rpc/internal/RPCPort.java

    r217 r262  
    7878            for (int i = 0; i < it.size(); i++) { 
    7979                current = it.get(i); 
    80                 break; 
     80                if (current != null) { 
     81                    break; 
     82                } 
    8183            } 
    8284 
  • port/rpc/internal/RPCRequest.java

    r217 r262  
    138138    public void serialize(BinaryOutputStream stream) { 
    139139        // Deserialized by network transport implementation 
    140         stream.writeType(method.getInterfaceType()); 
     140        method.getInterfaceType().serialize(stream); 
    141141        stream.writeByte(method.getMethodID()); 
    142142 
  • port/rpc/internal/RPCResponse.java

    r217 r262  
    9696    public void serialize(BinaryOutputStream stream) { 
    9797        // Deserialized by network transport implementation 
    98         stream.writeType(method.getInterfaceType()); 
     98        method.getInterfaceType().serialize(stream); 
    9999        stream.writeByte(method.getMethodID()); 
    100100        stream.writeLong(clientCallId); 
  • port/std/PortBase.java

    r234 r262  
    3636import org.finroc.core.port.ThreadLocalCache; 
    3737import org.finroc.core.portdatabase.FinrocTypeInfo; 
    38 import org.finroc.core.remote.RemoteType; 
    3938 
    4039/** 
     
    108107    public PortBase(PortCreationInfo pci) { 
    109108        super(processPci(pci)); 
    110         assert(FinrocTypeInfo.isStdType(pci.dataType) || (pci.dataType instanceof RemoteType)); 
     109        assert(FinrocTypeInfo.isStdType(pci.dataType)); 
    111110        initLists(edgesSrc, edgesDest); 
    112111 
  • portdatabase/FinrocTypeInfo.java

    r234 r262  
    2525 
    2626import org.finroc.core.RuntimeSettings; 
    27 import org.finroc.core.remote.RemoteType; 
    2827import org.rrlib.serialization.rtti.DataTypeBase; 
    2928import org.rrlib.serialization.rtti.GenericObject; 
     
    186185    } 
    187186 
    188     /** 
    189      * @param dt Data type to look this up for 
    190      * @param includeRemoteTypes Also return true for remote (unknown) RPC types? 
    191      * @return is this a RPC interface port data type? 
    192      */ 
    193     public static boolean isMethodType(DataTypeBase dt, boolean includeRemoteTypes) { 
    194         return get(dt).getType() == Type.METHOD && (includeRemoteTypes || (dt instanceof RemoteType)); 
    195     } 
     187//    /** 
     188//     * @param dt Data type to look this up for 
     189//     * @param includeRemoteTypes Also return true for remote (unknown) RPC types? 
     190//     * @return is this a RPC interface port data type? 
     191//     */ 
     192//    public static boolean isMethodType(DataTypeBase dt, boolean includeRemoteTypes) { 
     193//        return get(dt).getType() == Type.METHOD && (includeRemoteTypes || (dt instanceof RemoteType)); 
     194//    } 
    196195 
    197196    /** 
  • remote/ModelHandler.java

    r205 r262  
    3636 
    3737    /** 
    38      * Adds node to specified parent node. 
    39      * The ordering of elements is determined by the model handler. 
     38     * Applies buffered model changes 
    4039     * 
    41      * @param parent Parent node 
    42      * @param newChild Child node to add to parent node 
     40     * @param bufferedChanges Buffered changes 
    4341     */ 
    44     public void addNode(ModelNode parent, ModelNode newChild); 
    45  
    46     /** 
    47      * Changes name of specified node. 
    48      * 
    49      * @param node Node to change name of. 
    50      * @param newName New name. 
    51      */ 
    52     public void changeNodeName(ModelNode node, String newName); 
    53  
    54     /** 
    55      * Removes node from parent node. 
    56      * 
    57      * @param childToRemove Child node to remove from parent node 
    58      */ 
    59     public void removeNode(ModelNode childToRemove); 
    60  
    61     /** 
    62      * Replaces node with new node 
    63      * 
    64      * @param oldNode Node to be replaced and removed from model 
    65      * @param newNode Node that replaces old node (added to model) 
    66      */ 
    67     public void replaceNode(ModelNode oldNode, ModelNode newNode); 
    68  
    69     /** 
    70      * Replaces model. 
    71      * The old model is to be discarded. 
    72      * 
    73      * @param root Root element of new model 
    74      */ 
    75     public void setModelRoot(ModelNode root); 
    76  
    77     /** 
    78      * Updates model. 
    79      * The update task is provided as a runnable. 
    80      * This way, model updates can be dispatched e.g. to the Swing UI thread. 
    81      * 
    82      * @param updateTask Update task. run() must be called to trigger the update. 
    83      *        It might be called later (after the method has already returned). 
    84      */ 
    85     public void updateModel(Runnable updateTask); 
     42    public void applyModelChanges(BufferedModelChanges bufferedChanges); 
    8643} 
  • remote/ModelNode.java

    r255 r262  
    250250     */ 
    251251    public ModelNode getChildByQualifiedName(String qualifiedName, char separator) { 
    252         return getChildByQualifiedName(qualifiedName, 0, separator); 
     252        return getChildByQualifiedName(qualifiedName, 0, separator, false); 
    253253    } 
    254254 
     
    259259     * @param qualifiedNameStartIndex Start index of relevant substring in qualifiedName 
    260260     * @param separator Separator 
    261      * @return Child with the specified qualified name. Null if no such child exists. 
    262      */ 
    263     public ModelNode getChildByQualifiedName(String qualifiedName, int qualifiedNameStartIndex, char separator) { 
     261     * @param returnDeepestAncestorElement If element with specified link is not in tree, return element whose link has the longest match with qualified name 
     262     * @return ModelNode with the specified qualified name. Null or deepest ancestor if no such child exists. 
     263     */ 
     264    public ModelNode getChildByQualifiedName(String qualifiedName, int qualifiedNameStartIndex, char separator, boolean returnDeepestAncestorElement) { 
    264265        if (children == null) { 
    265             return null; 
     266            return returnDeepestAncestorElement ? this : null; 
    266267        } 
    267268        for (ModelNode child : children) { 
     
    271272                } 
    272273                if (qualifiedName.charAt(qualifiedNameStartIndex + child.name.length()) == separator) { 
    273                     ModelNode result = child.getChildByQualifiedName(qualifiedName, qualifiedNameStartIndex + child.name.length() + 1, separator); 
     274                    ModelNode result = child.getChildByQualifiedName(qualifiedName, qualifiedNameStartIndex + child.name.length() + 1, separator, returnDeepestAncestorElement); 
    274275                    if (result != null) { 
    275276                        return result; 
     
    278279            } 
    279280        } 
    280         return null; 
     281        return returnDeepestAncestorElement ? this : null; 
     282    } 
     283 
     284    /** 
     285     * Returns child with the specified path 
     286     * 
     287     * @param path Path 
     288     * @return Child with the specified path. null if no such child exists. 
     289     */ 
     290    public ModelNode getChildByPath(Path path) { 
     291        if (children == null) { 
     292            return null; 
     293        } 
     294        ModelNode current = this; 
     295        for (int i = 0; i < path.path.length; i++) { 
     296            current = current.getChildByName(path.path[i]); 
     297            if (current == null) { 
     298                return null; 
     299            } 
     300        } 
     301        return current; 
    281302    } 
    282303 
  • remote/RemoteFrameworkElement.java

    r255 r262  
    2828import org.finroc.core.FinrocAnnotation; 
    2929import org.finroc.core.FrameworkElementFlags; 
    30 import org.finroc.core.finstructable.EditableInterfaces; 
    31 import org.finroc.core.portdatabase.FinrocTypeInfo; 
    32 import org.rrlib.logging.Log; 
    33 import org.rrlib.logging.LogLevel; 
    3430import org.rrlib.serialization.rtti.DataTypeBase; 
    3531 
     
    5753    private boolean editableInterfacesChecked = false; 
    5854 
    59     /** List of editable interfaces of this element - if it has any (lazily initialized). List may contain empty, not-yet-existent interfaces (that could be created). They have remoteHandle 0. */ 
     55    /** List of editable interfaces of this element */ 
    6056    private ArrayList<RemoteFrameworkElement> editableInterfaces; 
    6157 
     
    247243     */ 
    248244    public boolean isEditableInterface() { 
    249         if (isInterface() && getParent() instanceof RemoteFrameworkElement) { 
    250             ArrayList<RemoteFrameworkElement> editableInterfaces = ((RemoteFrameworkElement)getParent()).getEditableInterfaces(); 
    251             return editableInterfaces != null && editableInterfaces.contains(this); 
    252         } 
    253         return false; 
     245        return isInterface() && isTagged("edit"); 
    254246    } 
    255247 
     
    260252 
    261253    /** 
    262      * Unlike getEditableInterfacesObject(), this method only blocks on the first call (light-weight version). 
     254     * Unlike getEditableInterfacesObject() this method does not block 
    263255     * 
    264      * @return Editable interfaces of this element (which is typically a component). null if it has no editable interfaces - or if they could not be queried. List may contain empty, not-yet-existent interfaces (that could be created). They have remoteHandle 0. 
     256     * @return Editable interfaces of this element (which is typically a component). null if it has no editable interfaces. 
    265257     */ 
    266258    public synchronized ArrayList<RemoteFrameworkElement> getEditableInterfaces() { 
     259 
    267260        if (!editableInterfacesChecked) { 
    268             try { 
    269                 EditableInterfaces interfaces = getEditableInterfacesObject(); 
    270                 editableInterfacesChecked = true; 
    271                 if (interfaces == null) { 
    272                     editableInterfaces = null; 
    273                 } else { 
    274                     editableInterfaces = new ArrayList<RemoteFrameworkElement>(); 
    275                     for (int i = 0; i < interfaces.getStaticParameterList().size(); i++) { 
    276                         RemoteFrameworkElement newElement = new RemoteFrameworkElement(0, interfaces.getStaticParameterList().get(i).getName()); 
    277                         editableInterfaces.add(newElement); 
    278                         newElement.flags = FrameworkElementFlags.INTERFACE | FrameworkElementFlags.EDGE_AGGREGATOR; 
    279                         newElement.classifyInterface(); 
    280                         if (isCompositeComponent()) { 
    281                             newElement.flags |= FrameworkElementFlags.PROXY_INTERFACE; 
    282                         } 
     261            for (int i = 0; i < getChildCount(); i++) { 
     262                RemoteFrameworkElement child = (RemoteFrameworkElement)this.getChildAt(i); 
     263                if (child.isEditableInterface()) { 
     264                    if (editableInterfaces == null) { 
     265                        editableInterfaces = new ArrayList<RemoteFrameworkElement>(); 
    283266                    } 
    284                 } 
    285             } catch (Exception e) { 
    286                 return null; 
     267                    child.classifyInterface(); 
     268                    if (isCompositeComponent()) { 
     269                        child.flags |= FrameworkElementFlags.PROXY_INTERFACE; 
     270                    } 
     271                    editableInterfaces.add(child); 
     272                } 
    287273            } 
    288         } 
    289  
    290         if (editableInterfaces == null) { 
    291             return null; 
    292         } 
    293         for (int i = 0; i < editableInterfaces.size(); i++) { 
    294             if (editableInterfaces.get(i).getRemoteHandle() == 0) { 
    295                 ModelNode child = this.getChildByName(editableInterfaces.get(i).getName()); 
    296                 if (child instanceof RemoteFrameworkElement && ((RemoteFrameworkElement)child).isInterface()) { 
    297                     editableInterfaces.set(i, (RemoteFrameworkElement)child); 
    298                 } else if (child != null) { 
    299                     Log.log(LogLevel.WARNING, "Non-interface with name that actually interface should have"); 
    300                 } 
    301             } 
    302         } 
     274            editableInterfacesChecked = true; 
     275        } 
     276 
    303277        return editableInterfaces; 
    304278    } 
     
    308282     * @throws Exception if receiving interfaces failed 
    309283     */ 
    310     public EditableInterfaces getEditableInterfacesObject() throws Exception { 
     284    public RemoteEditableInterfaces getEditableInterfacesObject() throws Exception { 
    311285        RemoteRuntime runtime = RemoteRuntime.find(this); 
    312286        if (runtime == null) { 
    313287            throw new Exception("No runtime found for this element"); 
    314288        } 
    315         return (EditableInterfaces)runtime.getAdminInterface().getAnnotation(getRemoteHandle(), EditableInterfaces.TYPE); 
     289        RemoteEditableInterfaces result = new RemoteEditableInterfaces(); 
     290        result.deserialize(runtime.getAdminInterface().getAnnotation(getRemoteHandle(), RemoteEditableInterfaces.TYPE_NAME, runtime)); 
     291        return result; 
    316292    } 
    317293 
     
    352328                        RemotePort remotePort = (RemotePort)getChildAt(i); 
    353329                        flags |= (remotePort.getFlags() & FrameworkElementFlags.IS_OUTPUT_PORT) != 0 ? FrameworkElementFlags.INTERFACE_FOR_OUTPUTS : FrameworkElementFlags.INTERFACE_FOR_INPUTS; 
    354                         if (FinrocTypeInfo.isMethodType(remotePort.getDataType())) { 
     330                        if ((remotePort.getDataType().getTypeTraits() & DataTypeBase.IS_RPC_TYPE) != 0) { 
    355331                            flags |= FrameworkElementFlags.INTERFACE_FOR_RPC_PORTS; 
    356                         } else if (FinrocTypeInfo.isCCType(remotePort.getDataType()) || FinrocTypeInfo.isStdType(remotePort.getDataType())) { 
     332                        } else if ((remotePort.getDataType().getTypeTraits() & DataTypeBase.IS_DATA_TYPE) != 0) { 
    357333                            flags |= FrameworkElementFlags.INTERFACE_FOR_DATA_PORTS; 
    358334                        } 
     
    365341        } 
    366342    } 
     343 
     344    @Override 
     345    public boolean isHidden(boolean checkAncestors) { 
     346        // Hide empty interfaces 
     347        if (isInterface() && getChildCount() == 0) { 
     348            return true; 
     349        } 
     350        return super.isHidden(checkAncestors); 
     351    } 
    367352} 
  • remote/RemotePort.java

    r256 r262  
    2222package org.finroc.core.remote; 
    2323 
    24 import java.util.ArrayList; 
    25 import java.util.Collection; 
    26 import java.util.HashSet; 
    27  
    2824import org.finroc.core.FinrocAnnotation; 
    2925import org.finroc.core.FrameworkElement; 
    3026import org.finroc.core.FrameworkElementFlags; 
    3127import org.finroc.core.port.AbstractPort; 
    32 import org.finroc.core.port.net.NetPort; 
    3328import org.rrlib.serialization.rtti.DataType; 
    3429import org.rrlib.serialization.rtti.DataTypeBase; 
     
    4237public class RemotePort extends RemoteFrameworkElement implements HasUid, PortWrapper { 
    4338 
    44  
    4539    /** Wrapped port link */ 
    4640    private final FrameworkElement.Link portLink; 
     41 
     42    /** Port data type */ 
     43    private final RemoteType dataType; 
     44 
     45    /** Index of 'portLink' */ 
     46    private final int linkNo; 
    4747 
    4848    public static final DataTypeBase TYPE = new DataType<RemotePortLink>(RemotePortLink.class); 
     
    5353     * @param port Port that is 
    5454     * @param linkNo Link number to specified port that this RemotePort wraps 
     55     * @param dataTypeEntry Port data type 
    5556     */ 
    56     public RemotePort(int remoteHandle, String name, AbstractPort port, int linkNo) { 
     57    public RemotePort(int remoteHandle, String name, AbstractPort port, int linkNo, RemoteType dataType) { 
    5758        super(remoteHandle, name); 
     59        this.linkNo = linkNo; 
    5860        this.portLink = port.getLink(linkNo); 
     61        this.dataType = dataType; 
    5962        RemotePortLink remotePortLink = port.getAnnotation(RemotePortLink.class); 
    6063        if (remotePortLink == null) { 
     
    115118    } 
    116119 
     120//    /** 
     121//     * @return Outgoing connections in remote runtime and also incoming network connections initiated by remote runtime 
     122//     */ 
     123//    public Collection<RemotePort> getOutgoingConnections() { 
     124//        ArrayList<RemotePort> result = new ArrayList<RemotePort>(); 
     125//        NetPort np = getPort().asNetPort(); 
     126//        if (np != null) { 
     127//            for (AbstractPort fe : np.getRemoteEdgeDestinations()) { 
     128//                for (RemotePort remotePort : RemotePort.get(fe)) { 
     129//                    result.add(remotePort); 
     130//                } 
     131//            } 
     132//        } 
     133//        return result; 
     134//    } 
     135// 
     136//    /** 
     137//     * (note: this can be quite computationally expensive - O(n) with n being the number of connections in the remote model (searches through all connections)) 
     138//     * 
     139//     * @return Incoming connections in remote runtime and also outgoing network connections initiated by some other remote runtime 
     140//     */ 
     141//    public Collection<RemotePort> getIncomingConnections() { 
     142//        final HashSet<RemotePort> result = new HashSet<RemotePort>(); 
     143//        getIncomingConnectionsHelper(result, this.getRoot()); 
     144//        return result; 
     145//    } 
     146// 
     147//    /** 
     148//     * Helper for getIncomingConnections() - called recursively 
     149//     * 
     150//     * @param result List with result 
     151//     * @param node Current node 
     152//     */ 
     153//    private void getIncomingConnectionsHelper(HashSet<RemotePort> result, ModelNode node) { 
     154//        if (node.getClass() == RemotePort.class) { 
     155//            AbstractPort otherPort = ((RemotePort)node).getPort(); 
     156//            NetPort netPort = otherPort.asNetPort(); 
     157//            if (netPort != null && otherPort != this.getPort()) { 
     158//                for (AbstractPort destPort : netPort.getRemoteEdgeDestinations()) { 
     159//                    if (destPort == this.getPort()) { 
     160//                        for (RemotePort remotePort : RemotePort.get(otherPort)) { 
     161//                            result.add(remotePort); 
     162//                        } 
     163//                    } 
     164//                } 
     165//            } 
     166//        } 
     167// 
     168//        for (int i = 0; i < node.getChildCount(); i++) { 
     169//            getIncomingConnectionsHelper(result, node.getChildAt(i)); 
     170//        } 
     171//    } 
     172// 
     173//    /** 
     174//     * It this remote port connected to other port in remote runtime? 
     175//     * 
     176//     * @param other Other port 
     177//     * @return Answer 
     178//     */ 
     179//    public boolean isConnectedTo(RemotePort other) { 
     180//        return (getOutgoingConnections().contains(other) || other.getOutgoingConnections().contains(this)); 
     181//    } 
     182 
    117183    /** 
    118      * @return Outgoing connections in remote runtime and also incoming network connections initiated by remote runtime 
     184     * @return Port data type 
    119185     */ 
    120     public Collection<RemotePort> getOutgoingConnections() { 
    121         ArrayList<RemotePort> result = new ArrayList<RemotePort>(); 
    122         NetPort np = getPort().asNetPort(); 
    123         if (np != null) { 
    124             for (AbstractPort fe : np.getRemoteEdgeDestinations()) { 
    125                 for (RemotePort remotePort : RemotePort.get(fe)) { 
    126                     result.add(remotePort); 
    127                 } 
    128             } 
    129         } 
    130         return result; 
     186    public RemoteType getDataType() { 
     187        return dataType; 
    131188    } 
    132189 
    133190    /** 
    134      * (note: this can be quite computationally expensive - O(n) with n being the number of connections in the remote model (searches through all connections)) 
    135      * 
    136      * @return Incoming connections in remote runtime and also outgoing network connections initiated by some other remote runtime 
     191     * @return Index of wrapped port link 
    137192     */ 
    138     public Collection<RemotePort> getIncomingConnections() { 
    139         final HashSet<RemotePort> result = new HashSet<RemotePort>(); 
    140         getIncomingConnectionsHelper(result, this.getRoot()); 
    141         return result; 
     193    public int getLinkIndex() { 
     194        return linkNo; 
    142195    } 
    143  
    144     /** 
    145      * Helper for getIncomingConnections() - called recursively 
    146      * 
    147      * @param result List with result 
    148      * @param node Current node 
    149      */ 
    150     private void getIncomingConnectionsHelper(HashSet<RemotePort> result, ModelNode node) { 
    151         if (node.getClass() == RemotePort.class) { 
    152             AbstractPort otherPort = ((RemotePort)node).getPort(); 
    153             NetPort netPort = otherPort.asNetPort(); 
    154             if (netPort != null && otherPort != this.getPort()) { 
    155                 for (AbstractPort destPort : netPort.getRemoteEdgeDestinations()) { 
    156                     if (destPort == this.getPort()) { 
    157                         for (RemotePort remotePort : RemotePort.get(otherPort)) { 
    158                             result.add(remotePort); 
    159                         } 
    160                     } 
    161                 } 
    162             } 
    163         } 
    164  
    165         for (int i = 0; i < node.getChildCount(); i++) { 
    166             getIncomingConnectionsHelper(result, node.getChildAt(i)); 
    167         } 
    168     } 
    169  
    170     /** 
    171      * It this remote port connected to other port in remote runtime? 
    172      * 
    173      * @param other Other port 
    174      * @return Answer 
    175      */ 
    176     public boolean isConnectedTo(RemotePort other) { 
    177         return (getOutgoingConnections().contains(other) || other.getOutgoingConnections().contains(this)); 
    178     } 
    179  
    180     /** 
    181      * @return Data type of remote port (possibly different from wrapped ports possibly adapted data type) 
    182      */ 
    183     public DataTypeBase getDataType() { 
    184         return getPort().asNetPort() != null && getPort().asNetPort().getRemoteType() != null ? getPort().asNetPort().getRemoteType() : getPort().getDataType(); 
    185     } 
    186  
    187196} 
  • remote/RemoteRuntime.java

    r243 r262  
    2222package org.finroc.core.remote; 
    2323 
    24 import java.util.HashMap; 
     24import java.util.ArrayList; 
     25import java.util.Collections; 
     26import java.util.List; 
    2527 
    2628import org.finroc.core.admin.AdminClient; 
    27 import org.finroc.core.port.net.NetPort; 
     29import org.finroc.core.port.AbstractPort; 
     30import org.finroc.core.remote.RemoteTypeConversion.SupportedTypeFilter; 
     31import org.finroc.core.remote.RemoteUriConnector.Status; 
     32import org.finroc.core.util.ConcurrentLookupTable; 
     33import org.rrlib.finroc_core_utils.jc.ArrayWrapper; 
     34import org.rrlib.finroc_core_utils.jc.container.SafeConcurrentlyIterableList; 
     35import org.rrlib.logging.Log; 
     36import org.rrlib.logging.LogLevel; 
     37import org.rrlib.serialization.BinaryInputStream; 
     38import org.rrlib.serialization.PublishedRegisters; 
     39import org.rrlib.serialization.Register; 
     40import org.rrlib.serialization.SerializationInfo; 
     41import org.rrlib.serialization.rtti.DataTypeBase; 
    2842 
    2943/** 
     
    3549public class RemoteRuntime extends RemoteFrameworkElement { 
    3650 
    37     /** Admin interface for remote runtime */ 
    38     private final AdminClient adminInterface; 
    39  
    40     /** Remote types */ 
    41     private RemoteTypes remoteTypes; 
    42  
    43     /** 
    44      * Lookup for remote framework elements: remote handle => remote framework element 
    45      * (should only be accessed by model thread) 
    46      */ 
    47     public final HashMap<Integer, RemoteFrameworkElement> elementLookup = new HashMap<Integer, RemoteFrameworkElement>(); 
    48  
    4951    /** Remote Runtime's UUID */ 
    5052    public final String uuid; 
    5153 
    52     public RemoteRuntime(String name, String uuid, AdminClient adminInterface, RemoteTypes remoteTypes) { 
     54    @SuppressWarnings({ "unchecked", "rawtypes" }) 
     55    public RemoteRuntime(String name, String uuid, AdminClient adminInterface, BinaryInputStream stream, int handleStampWidth) { 
    5356        super(0, name); 
     57        this.handleStampWidth = handleStampWidth; 
     58        int handleBitWidth = 32 - handleStampWidth; 
     59        int chunkSizeBits = handleBitWidth / 2; 
     60        int chunkCountBits = handleBitWidth - chunkSizeBits; 
     61        int chunkSize = 1 << chunkSizeBits; 
     62        int chunkCount = 1 << chunkCountBits; 
     63        elementLookup = new ConcurrentLookupTable<>(chunkCount, chunkSize); 
     64        connectorTable = new ConcurrentLookupTable<>(chunkCount, chunkSize); 
     65        remoteTypes = (Register<RemoteType>)(Register)PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.TYPE.ordinal()); 
     66        remoteStaticCasts = (Register<RemoteStaticCast>)(Register)PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.STATIC_CAST.ordinal()); 
     67        remoteTypeConversions = (Register<RemoteTypeConversion>)(Register)PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.CONVERSION_OPERATION.ordinal()); 
     68        remoteSchemeHandlers = (Register<RemoteUriSchemeHandler>)(Register)PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.SCHEME_HANDLER.ordinal()); 
     69        remoteCreateActions = (Register<RemoteCreateAction>)(Register)PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.CREATE_ACTION.ordinal()); 
     70        if (remoteStaticCasts == null) { 
     71            remoteStaticCasts = new Register<>(4, 4, 1); 
     72        } 
     73        if (remoteTypeConversions == null) { 
     74            remoteTypeConversions = new Register<>(4, 4, 1); 
     75        } 
     76        if (remoteSchemeHandlers == null) { 
     77            remoteSchemeHandlers = new Register<>(4, 4, 1); 
     78        } 
     79        if (remoteCreateActions == null) { 
     80            remoteCreateActions = new Register<>(128, 128, 4); 
     81        } 
     82        this.inputStream = stream; 
    5483        this.uuid = uuid; 
    5584        this.adminInterface = adminInterface; 
    56         this.remoteTypes = remoteTypes; 
    57         elementLookup.put(0, this); // Runtime lookup 
    58     } 
    59  
    60     /** 
    61      * @return Admin interface for remote runtime 
    62      */ 
    63     public AdminClient getAdminInterface() { 
    64         return adminInterface; 
    65     } 
    66  
    67     /** 
    68      * @param remoteTypes Remote types 
    69      */ 
    70     public void setRemoteTypes(RemoteTypes remoteTypes) { 
    71         this.remoteTypes = remoteTypes; 
    72     } 
    73  
    74     /** 
    75      * @return Remote types 
    76      */ 
    77     public RemoteTypes getRemoteTypes() { 
    78         return remoteTypes; 
    79     } 
    80  
    81     /** 
    82      * Find RemoteRuntime to which specified port belongs to 
    83      * 
    84      * @param np remote port 
    85      * @return RemoteRuntime object - or null if none could be found 
    86      */ 
    87     public static RemoteRuntime find(NetPort np) { 
    88         return find(RemotePort.get(np.getPort())[0]); 
     85        elementLookup.set(0, this); // Runtime lookup 
     86        this.serializationInfo = stream.getSourceInfo(); 
     87    } 
     88 
     89    /** 
     90     * Adds connector to runtime 
     91     * 
     92     * @param connector Connector to add 
     93     */ 
     94    public void addConnector(RemoteConnector connector) { 
     95        connector.ownerRuntime = this; 
     96        if (connector instanceof RemoteUriConnector) { 
     97            uriConnectors.add((RemoteUriConnector)connector, false); 
     98        } else { 
     99            for (int i = 0; i < 2; i++) { 
     100                int index = (int)(((i == 0 ? connector.getSourceHandle() : connector.getDestinationHandle()) & 0xFFFFFFFFL) >> handleStampWidth); 
     101                AbstractPort.EdgeList<RemoteConnector> list = connectorTable.get(index); 
     102                if (list == null) { 
     103                    list = new AbstractPort.EdgeList<RemoteConnector>(); 
     104                    connectorTable.set(index, list); 
     105                } 
     106 
     107                // Check whether edge has already been added 
     108                ArrayWrapper<RemoteConnector> iterable = list.getIterable(); 
     109                for (int j = 0, n = iterable.size(); j < n; j++) { 
     110                    RemoteConnector existingConnector = iterable.get(j); 
     111                    if (existingConnector.getSourceHandle() == connector.getSourceHandle() && existingConnector.getDestinationHandle() == connector.getDestinationHandle()) { 
     112                        Log.log(LogLevel.WARNING, "The same connector was added again. Discarding new connector."); 
     113                        return; 
     114                    } 
     115                } 
     116 
     117 
     118                list.add(connector, false); 
     119            } 
     120        } 
     121    } 
     122 
     123    /** 
     124     * @param port1 Port 1 
     125     * @param port2 Port 2 
     126     * @return Whether Port 1 and Port 2 are connected 
     127     */ 
     128    public static boolean arePortsConnected(RemotePort port1, RemotePort port2) { 
     129        RemoteRuntime runtime1 = RemoteRuntime.find(port1); 
     130        RemoteRuntime runtime2 = RemoteRuntime.find(port2); 
     131 
     132        if (runtime1 == null || runtime2 == null) { 
     133            return false; 
     134        } 
     135 
     136        if (runtime1 == runtime2) { 
     137            int index = (int)((port1.getRemoteHandle() & 0xFFFFFFFFL) >> runtime1.handleStampWidth); 
     138            AbstractPort.EdgeList<RemoteConnector> connectors = runtime1.connectorTable.get(index); 
     139            if (connectors != null) { 
     140                ArrayWrapper<RemoteConnector> iterable = connectors.getIterable(); 
     141                for (int i = 0, n = iterable.size(); i < n; i++) { 
     142                    RemoteConnector connector = iterable.get(i); 
     143                    if (connector != null && (connector.sourceHandle == port2.getRemoteHandle() || connector.destinationHandle == port2.getRemoteHandle())) { 
     144                        return true; 
     145                    } 
     146                } 
     147            } 
     148 
     149            ArrayWrapper<RemoteUriConnector> iterable = runtime1.uriConnectors.getIterable(); 
     150            for (int i = 0, n = iterable.size(); i < n; i++) { 
     151                RemoteUriConnector connector = iterable.get(i); 
     152                if (connector != null && connector.getOwnerRuntime() == runtime1 && (connector.getOwnerPortHandle() == port1.getRemoteHandle() && connector.currentPartner == port2) || (connector.getOwnerPortHandle() == port2.getRemoteHandle() && connector.currentPartner == port1)) { 
     153                    return true; 
     154                } 
     155            } 
     156        } else { 
     157            ArrayWrapper<RemoteUriConnector> iterable = runtime1.uriConnectors.getIterable(); 
     158            for (int i = 0, n = iterable.size(); i < n; i++) { 
     159                RemoteUriConnector connector = iterable.get(i); 
     160                if (connector != null && (connector.getOwnerPortHandle() == port1.getRemoteHandle() && connector.currentPartner == port2)) { 
     161                    return true; 
     162                } 
     163            } 
     164            iterable = runtime2.uriConnectors.getIterable(); 
     165            for (int i = 0, n = iterable.size(); i < n; i++) { 
     166                RemoteUriConnector connector = iterable.get(i); 
     167                if (connector != null && (connector.getOwnerPortHandle() == port2.getRemoteHandle() && connector.currentPartner == port1)) { 
     168                    return true; 
     169                } 
     170            } 
     171        } 
     172 
     173        return false; 
    89174    } 
    90175 
     
    108193    } 
    109194 
    110     /** 
    111      * @param handle Remote handle 
    112      * @return Framework element that represents remote framework element with this remote handle 
    113      */ 
    114     public RemoteFrameworkElement getRemoteElement(int handle) { 
    115         return elementLookup.get(handle); 
    116     } 
    117  
    118     /** 
    119      * Find other remote runtime environment with the specified UUID 
    120      * 
    121      * @param uuid uuid of other runtime environment 
    122      * @return Other runtime - or null if no runtime environment with specified id could be found 
    123      */ 
    124     public RemoteRuntime findOther(String uuid) { 
    125  
    126         // A more sophisticated search might be necessary in the future 
     195//    /** 
     196//     * Find other remote runtime environment with the specified UUID 
     197//     * 
     198//     * @param uuid uuid of other runtime environment 
     199//     * @return Other runtime - or null if no runtime environment with specified id could be found 
     200//     */ 
     201//    public RemoteRuntime findOther(String uuid) { 
     202// 
     203//        // A more sophisticated search might be necessary in the future 
     204//        ModelNode parent = this.getParent(); 
     205//        if (parent != null) { 
     206//            for (int i = 0; i < parent.getChildCount(); i++) { 
     207//                ModelNode child = parent.getChildAt(i); 
     208//                if (child instanceof RemoteRuntime && ((RemoteRuntime)child).uuid.equals(uuid)) { 
     209//                    return (RemoteRuntime)child; 
     210//                } 
     211//            } 
     212//        } 
     213//        return null; 
     214//    } 
     215 
     216    /** 
     217     * @return Admin interface for remote runtime 
     218     */ 
     219    public AdminClient getAdminInterface() { 
     220        return adminInterface; 
     221    } 
     222 
     223    /** 
     224     * @param result List to write result (all connectors) to. Will be cleared in this call. 
     225     * @param port Remote port whose connectors to get 
     226     */ 
     227    public void getConnectors(ArrayList<RemoteConnector> result, RemotePort port) { 
     228        result.clear(); 
     229        int index = (int)((port.getRemoteHandle() & 0xFFFFFFFFL) >> handleStampWidth); 
     230        AbstractPort.EdgeList<RemoteConnector> connectors = connectorTable.get(index); 
     231        if (connectors != null) { 
     232            ArrayWrapper<RemoteConnector> iterable = connectors.getIterable(); 
     233            for (int i = 0, n = iterable.size(); i < n; i++) { 
     234                RemoteConnector connector = iterable.get(i); 
     235                if (connector != null) { 
     236                    result.add(connector); 
     237                } 
     238            } 
     239        } 
     240 
     241        // Search for URI connectors in all remote runtimes 
    127242        ModelNode parent = this.getParent(); 
    128243        if (parent != null) { 
    129244            for (int i = 0; i < parent.getChildCount(); i++) { 
    130245                ModelNode child = parent.getChildAt(i); 
    131                 if (child instanceof RemoteRuntime && ((RemoteRuntime)child).uuid.equals(uuid)) { 
    132                     return (RemoteRuntime)child; 
    133                 } 
     246                if (child instanceof RemoteRuntime) { 
     247                    ArrayWrapper<RemoteUriConnector> iterable = ((RemoteRuntime)child).uriConnectors.getIterable(); 
     248                    for (int j = 0, n = iterable.size(); j < n; j++) { 
     249                        RemoteUriConnector connector = iterable.get(j); 
     250                        if (connector != null && connector.currentPartner == port) { 
     251                            result.add(connector); 
     252                        } 
     253                    } 
     254                } 
     255            } 
     256        } 
     257    } 
     258 
     259    /** 
     260     * Get conversion options from source to destination type. 
     261     * 
     262     * @param sourceType Source type 
     263     * @param destinationType Destination type 
     264     * @param singleOperationsOnly Only return single operations (no sequences) 
     265     * @return List with all available conversion options 
     266     */ 
     267    public ArrayList<RemoteConnectOptions> getConversionOptions(RemoteType sourceType, RemoteType destinationType, boolean singleOperationsOnly) { 
     268        ArrayList<RemoteConnectOptions> result = new ArrayList<RemoteConnectOptions>(); 
     269        if (sourceType == destinationType) { 
     270            result.add(new RemoteConnectOptions()); 
     271            return result; 
     272        } 
     273        ArrayList<GetCastOperationEntry> fromSourceType = new ArrayList<GetCastOperationEntry>(); 
     274        ArrayList<GetCastOperationEntry> fromDestinationType = new ArrayList<GetCastOperationEntry>(); 
     275        short sourceUid = (short)sourceType.getHandle(); 
     276        short destinationUid = (short)destinationType.getHandle(); 
     277 
     278        // Collect all static casts 
     279        RemoteTypeConversion staticCast = getTypeConversionOperation(RemoteTypeConversion.STATIC_CAST); 
     280        if (sourceType.getUnderlyingType() > 0) { 
     281            fromSourceType.add(new GetCastOperationEntry(staticCast, remoteTypes.get(sourceType.getUnderlyingType()), (sourceType.getTypeTraits() & DataTypeBase.IS_CAST_TO_UNDERLYING_TYPE_IMPLICIT) != 0)); 
     282        } 
     283        for (int i = 0, n = remoteTypes.size(); i < n; i++) { 
     284            RemoteType type = remoteTypes.get(i); 
     285            if (type.getUnderlyingType() == sourceUid && (type.getTypeTraits() & DataTypeBase.IS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID) != 0) { 
     286                fromSourceType.add(new GetCastOperationEntry(staticCast, type, (sourceType.getTypeTraits() & DataTypeBase.IS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT) != 0)); 
     287            } 
     288        } 
     289        for (int i = 0, n = remoteStaticCasts.size(); i < n; i++) { 
     290            RemoteStaticCast cast = remoteStaticCasts.get(i); 
     291            if (cast.getSourceType() == sourceType) { 
     292                fromSourceType.add(new GetCastOperationEntry(staticCast, cast.getDestinationType(), cast.isImplicit())); 
     293            } 
     294        } 
     295        if (destinationType.getUnderlyingType() > 0 && (destinationType.getTypeTraits() & DataTypeBase.IS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID) != 0) { 
     296            fromDestinationType.add(new GetCastOperationEntry(staticCast, remoteTypes.get(destinationType.getUnderlyingType()), (sourceType.getTypeTraits() & DataTypeBase.IS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT) != 0)); 
     297        } 
     298        for (int i = 0, n = remoteTypes.size(); i < n; i++) { 
     299            RemoteType type = remoteTypes.get(i); 
     300            if (type.getUnderlyingType() == destinationUid) { 
     301                fromDestinationType.add(new GetCastOperationEntry(staticCast, type, (sourceType.getTypeTraits() & DataTypeBase.IS_CAST_TO_UNDERLYING_TYPE_IMPLICIT) != 0)); 
     302            } 
     303        } 
     304        for (int i = 0, n = remoteStaticCasts.size(); i < n; i++) { 
     305            RemoteStaticCast cast = remoteStaticCasts.get(i); 
     306            if (cast.getDestinationType() == destinationType) { 
     307                fromDestinationType.add(new GetCastOperationEntry(staticCast, cast.getSourceType(), cast.isImplicit())); 
     308            } 
     309        } 
     310 
     311        // Collect all operations from source type 
     312        for (int i = 0, n = remoteTypeConversions.size(); i < n; i++) { 
     313            RemoteTypeConversion conversion = remoteTypeConversions.get(i); 
     314            if (isTypeSupported(sourceType, conversion.getSupportedSourceTypes(), conversion.getSupportedSourceType())) { 
     315                addAllTypes(fromSourceType, conversion, conversion.getSupportedDestinationTypes(), conversion.getSupportedDestinationType()); 
     316            } 
     317        } 
     318        RemoteTypeConversion getListElementOperation = getTypeConversionOperation(RemoteTypeConversion.GET_LIST_ELEMENT); 
     319        if ((sourceType.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) != 0) { 
     320            fromSourceType.add(new GetCastOperationEntry(getListElementOperation, remoteTypes.get(sourceUid - 1), false)); 
     321        } 
     322 
     323        // Collect all operations from destination type 
     324        for (int i = 0, n = remoteTypeConversions.size(); i < n; i++) { 
     325            RemoteTypeConversion conversion = remoteTypeConversions.get(i); 
     326            if (isTypeSupported(destinationType, conversion.getSupportedDestinationTypes(), conversion.getSupportedDestinationType())) { 
     327                addAllTypes(fromDestinationType, conversion, conversion.getSupportedSourceTypes(), conversion.getSupportedSourceType()); 
     328            } 
     329        } 
     330 
     331        // Sort results 
     332        Collections.sort(fromSourceType); 
     333        Collections.sort(fromDestinationType); 
     334 
     335        // Scan for single operation 
     336        for (int i = 0; i < 2; i++) { 
     337            RemoteType relevantType = i == 0 ? destinationType : sourceType; 
     338            for (GetCastOperationEntry entry : (i == 0 ? fromSourceType : fromDestinationType)) { 
     339                if (entry.intermediateType == relevantType) { 
     340                    boolean exists = false; 
     341                    for (RemoteConnectOptions existing : result) { 
     342                        if (existing.operation1 == entry.operation) { 
     343                            exists = true; 
     344                            break; 
     345                        } 
     346                    } 
     347                    if (!exists) { 
     348                        result.add(new RemoteConnectOptions(entry.implicitCast ? Definitions.TypeConversionRating.IMPLICIT_CAST : Definitions.TypeConversionRating.EXPLICIT_CONVERSION, entry.operation)); 
     349                    } 
     350                } 
     351            } 
     352        } 
     353 
     354        // Scan for operation sequences 
     355        if (singleOperationsOnly) { 
     356            return result; 
     357        } 
     358 
     359        int fromSourceIndex = 0, fromDestinationIndex = 0; 
     360        while (fromSourceIndex < fromSourceType.size() && fromDestinationIndex < fromDestinationType.size()) { 
     361            RemoteType fromSourceIntermediateType = fromSourceType.get(fromSourceIndex).intermediateType; 
     362            RemoteType fromDestinationIntermediateType = fromDestinationType.get(fromDestinationIndex).intermediateType; 
     363            if (fromSourceIntermediateType.getHandle() < fromDestinationIntermediateType.getHandle()) { 
     364                fromSourceIndex++; 
     365            } else if (fromSourceIntermediateType.getHandle() > fromDestinationIntermediateType.getHandle()) { 
     366                fromDestinationIndex++; 
     367            } else { 
     368                RemoteType matchingType = fromSourceIntermediateType; 
     369                while (fromSourceIndex < fromSourceType.size() && fromSourceType.get(fromSourceIndex).intermediateType == matchingType) { 
     370                    int fromDestinationIndexTemp = fromDestinationIndex; 
     371                    while (fromDestinationIndexTemp < fromDestinationType.size() && fromDestinationType.get(fromDestinationIndexTemp).intermediateType == matchingType) { 
     372                        boolean exists = false; 
     373                        for (RemoteConnectOptions existing : result) { 
     374                            if (existing.operation1 == fromSourceType.get(fromSourceIndex).operation && existing.operation2 == fromDestinationType.get(fromDestinationIndexTemp).operation && existing.intermediateType == matchingType) { 
     375                                exists = true; 
     376                                break; 
     377                            } 
     378                        } 
     379                        if (!exists) { 
     380                            int implicitConversions = (fromSourceType.get(fromSourceIndex).implicitCast ? 1 : 0) + (fromDestinationType.get(fromDestinationIndexTemp).implicitCast ? 1 : 0); 
     381                            result.add(new RemoteConnectOptions(implicitConversions == 2 ? Definitions.TypeConversionRating.TWO_IMPLICIT_CASTS : (implicitConversions == 1 ? Definitions.TypeConversionRating.EXPLICIT_CONVERSION_AND_IMPLICIT_CAST : Definitions.TypeConversionRating.TWO_EXPLICIT_CONVERSIONS), 
     382                                                                fromSourceType.get(fromSourceIndex).operation, matchingType, fromDestinationType.get(fromDestinationIndexTemp).operation)); 
     383                        } 
     384                        fromDestinationIndexTemp++; 
     385                    } 
     386                    fromSourceIndex++; 
     387                } 
     388            } 
     389        } 
     390 
     391        // Try for-each and get elements operations 
     392        boolean sourceIsListType = (sourceType.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) != 0; 
     393        boolean destinationIsListType = (destinationType.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) != 0; 
     394        if (sourceIsListType && destinationIsListType) { 
     395            RemoteTypeConversion forEachOperation = getTypeConversionOperation(RemoteTypeConversion.FOR_EACH); 
     396            RemoteType sourceElementType = remoteTypes.get(sourceType.getHandle() - 1); 
     397            RemoteType destinationElementType = remoteTypes.get(destinationType.getHandle() - 1); 
     398            for (RemoteConnectOptions operation : getConversionOptions(sourceElementType, destinationElementType, true)) { 
     399                result.add(new RemoteConnectOptions(operation.conversionRating == Definitions.TypeConversionRating.IMPLICIT_CAST ? Definitions.TypeConversionRating.EXPLICIT_CONVERSION : Definitions.TypeConversionRating.TWO_EXPLICIT_CONVERSIONS, forEachOperation, sourceElementType, operation.operation1)); 
     400            } 
     401        } 
     402 
     403        // Mark deprecated casts 
     404        RemoteTypeConversion toStringOperation = getTypeConversionOperation(RemoteTypeConversion.TO_STRING); 
     405        RemoteTypeConversion stringDeserializationOperation = getTypeConversionOperation(RemoteTypeConversion.STRING_DESERIALIZATION); 
     406        RemoteTypeConversion binarySerializationOperation = getTypeConversionOperation(RemoteTypeConversion.BINARY_SERIALIZATION); 
     407        RemoteTypeConversion binaryDeserializationOperation = getTypeConversionOperation(RemoteTypeConversion.BINARY_DESERIALIZATION); 
     408        for (RemoteConnectOptions operation : result) { 
     409            if (operation.operation1 == toStringOperation && operation.operation2 == stringDeserializationOperation || 
     410                    operation.operation1 == binarySerializationOperation && operation.operation2 == binaryDeserializationOperation) { 
     411                operation.conversionRating = Definitions.TypeConversionRating.DEPRECATED_CONVERSION; 
     412            } 
     413        } 
     414 
     415        Collections.sort(result); 
     416 
     417        return result; 
     418    } 
     419 
     420    /** 
     421     * @return Create actions in runtime 
     422     */ 
     423    public Register<RemoteCreateAction> getCreateActions() { 
     424        if (serializationInfo.getRevision() == 0) { 
     425            ArrayList<RemoteCreateAction> actions = getAdminInterface().getRemoteModuleTypes(this); 
     426            for (int i = remoteCreateActions.size(); i < actions.size(); i++) { 
     427                remoteCreateActions.add(actions.get(i)); 
     428            } 
     429        } else { 
     430            adminInterface.getRegisterUpdates(Definitions.RegisterUIDs.CREATE_ACTION.ordinal()); 
     431        } 
     432        return remoteCreateActions; 
     433    } 
     434 
     435    /** 
     436     * @return Retruns any elements in error state in this runtime. May only be accessed by thread that builds model. 
     437     */ 
     438    public ArrayList<RemoteFrameworkElement> getElementsInErrorState() { 
     439        return elementsInErrorState; 
     440    } 
     441 
     442    /** 
     443     * @return Input stream that contains e.g. all shared registers 
     444     */ 
     445    public BinaryInputStream getInputStream() { 
     446        return inputStream; 
     447    } 
     448 
     449    /** 
     450     * @param handle Remote framework element handle 
     451     * @return Returns object that represents remote framework element with this remote handle 
     452     */ 
     453    public RemoteFrameworkElement getRemoteElement(int handle) { 
     454        int index = (int)((handle & 0xFFFFFFFFL) >> handleStampWidth); 
     455        return elementLookup.get(index); 
     456    } 
     457 
     458    /** 
     459     * @param handle Remote port handle 
     460     * @return Returns object that represents remote port with this remote handle 
     461     */ 
     462    public RemotePort getRemotePort(int handle) { 
     463        RemoteFrameworkElement element = getRemoteElement(handle); 
     464        return element != null && (element instanceof RemotePort) ? (RemotePort)element : null; 
     465    } 
     466 
     467    /** 
     468     * @return List with all remote ports 
     469     */ 
     470    public ArrayList<RemotePort> getRemotePorts() { 
     471        ArrayList<RemoteFrameworkElement> temp = new ArrayList<>(); 
     472        elementLookup.getAll(temp); 
     473        ArrayList<RemotePort> result = new ArrayList<>(temp.size()); 
     474        for (RemoteFrameworkElement element : temp) { 
     475            if (element instanceof RemotePort) { 
     476                result.add((RemotePort)element); 
     477            } 
     478        } 
     479        return result; 
     480    } 
     481 
     482    /** 
     483     * @param name Type name 
     484     * @return Type with specified name in remote runtime. null if no type with specified name exists. 
     485     */ 
     486    public RemoteType getRemoteType(String name) { 
     487        for (int i = 0, n = remoteTypes.size(); i < n; i++) { 
     488            if (remoteTypes.get(i).getName().equals(name)) { 
     489                return remoteTypes.get(i); 
    134490            } 
    135491        } 
    136492        return null; 
    137493    } 
     494 
     495    /** 
     496     * @return Returns (thread-safe) register with remote types 
     497     */ 
     498    public Register<RemoteType> getRemoteTypes() { 
     499        return remoteTypes; 
     500    } 
     501 
     502    /** 
     503     * @return URI scheme handlers in runtime 
     504     */ 
     505    public Register<RemoteUriSchemeHandler> getSchemeHandlers() { 
     506        return remoteSchemeHandlers; 
     507    } 
     508 
     509    /** 
     510     * @return Serialization info from remote runtime 
     511     */ 
     512    public SerializationInfo getSerializationInfo() { 
     513        return serializationInfo; 
     514    } 
     515 
     516    /** 
     517     * @return Static casts in runtime 
     518     */ 
     519    public Register<RemoteStaticCast> getStaticCasts() { 
     520        return remoteStaticCasts; 
     521    } 
     522 
     523    /** 
     524     * @param name Name of remote type conversion operation 
     525     * @return Return type conversion operation with specified name - or null if no type conversion operation with this name exists 
     526     */ 
     527    public RemoteTypeConversion getTypeConversionOperation(String name) { 
     528        for (int i = 0, n = remoteTypeConversions.size(); i < n; i++) { 
     529            if (remoteTypeConversions.get(i).getName().equals(name)) { 
     530                return remoteTypeConversions.get(i); 
     531            } 
     532        } 
     533        return null; 
     534    } 
     535 
     536    /** 
     537     * @param sourceType Source type 
     538     * @param destinationType Destination type 
     539     * @return Rating of 'best' possibility to convert source type to destination type in this runtime environment 
     540     */ 
     541    public Definitions.TypeConversionRating getTypeConversionRating(RemoteType sourceType, RemoteType destinationType) { 
     542        return getTypeConversionRatings(sourceType).getRating(destinationType); 
     543    } 
     544 
     545    /** 
     546     * Returns type conversion ratings for specified type. 
     547     * This method cashes results in RemoteType and updates cached results when required. 
     548     * (Implementation note: as complete cached results are replaced atomically with the old ones remaining intact, this is thread-safe) 
     549     * 
     550     * @param type Type whose ratings to update 
     551     * @param Returns type conversion ratings 
     552     */ 
     553    public RemoteType.CachedConversionRatings getTypeConversionRatings(RemoteType type) { 
     554 
     555        RemoteType.CachedConversionRatings currentRatings = type.cachedConversionRatings.get(); 
     556        if (currentRatings != null && currentRatings.typeCount == remoteTypes.size() && currentRatings.staticCastCount == remoteStaticCasts.size() && currentRatings.typeConversionOperationCount == remoteTypeConversions.size() && (!currentRatings.singleOperationsResultsOnly)) { 
     557            return currentRatings; 
     558        } 
     559 
     560        // Init new result 
     561        RemoteType.CachedConversionRatings singleRatings = getTypeSingleConversionRatings(type); 
     562        RemoteType.CachedConversionRatings ratings = new RemoteType.CachedConversionRatings(); 
     563        ratings.typeCount = singleRatings.typeCount; 
     564        ratings.staticCastCount = singleRatings.staticCastCount; 
     565        ratings.typeConversionOperationCount = singleRatings.typeConversionOperationCount; 
     566        ratings.singleOperationsResultsOnly = false; 
     567        ratings.cachedConversionRatings = new byte[ratings.typeCount]; 
     568        System.arraycopy(singleRatings.cachedConversionRatings, 0, ratings.cachedConversionRatings, 0, singleRatings.cachedConversionRatings.length); 
     569        for (int i = 0; i < ratings.cachedConversionRatings.length; i++) { 
     570            if (ratings.cachedConversionRatings[i] == 0) { 
     571                ratings.cachedConversionRatings[i] = 1; // Deprecated binary conversion works for all types 
     572            } 
     573        } 
     574 
     575        // Continue from all single operation entries 
     576        for (int i = 0; i < ratings.cachedConversionRatings.length; i++) { 
     577            byte rating = ratings.cachedConversionRatings[i]; 
     578            if (isSingleOperationRating(rating)) { 
     579                RemoteType.CachedConversionRatings intermediateRatings = getTypeSingleConversionRatings(remoteTypes.get(i)); 
     580                for (int j = 0; j < ratings.cachedConversionRatings.length; j++) { 
     581                    byte rating2 = intermediateRatings.cachedConversionRatings[j]; 
     582                    if (isSingleOperationRating(rating2)) { 
     583                        int implicitCasts = (rating == Definitions.TypeConversionRating.IMPLICIT_CAST.ordinal() ? 1 : 0) + (rating2 == Definitions.TypeConversionRating.IMPLICIT_CAST.ordinal() ? 1 : 0); 
     584                        boolean deprecatedConversion = ((rating == Definitions.TypeConversionRating.EXPLICIT_CONVERSION_FROM_GENERIC_TYPE.ordinal()) && (rating2 == Definitions.TypeConversionRating.EXPLICIT_CONVERSION_TO_GENERIC_TYPE.ordinal())) || 
     585                                                       ((rating2 == Definitions.TypeConversionRating.EXPLICIT_CONVERSION_FROM_GENERIC_TYPE.ordinal()) && (rating == Definitions.TypeConversionRating.EXPLICIT_CONVERSION_TO_GENERIC_TYPE.ordinal())); 
     586                        updateConversionRating(ratings.cachedConversionRatings, j, deprecatedConversion ? Definitions.TypeConversionRating.DEPRECATED_CONVERSION : (implicitCasts == 2 ? Definitions.TypeConversionRating.TWO_IMPLICIT_CASTS : (implicitCasts == 1 ? Definitions.TypeConversionRating.EXPLICIT_CONVERSION_AND_IMPLICIT_CAST : Definitions.TypeConversionRating.TWO_EXPLICIT_CONVERSIONS))); 
     587                    } 
     588                } 
     589            } 
     590        } 
     591 
     592        // For/each operation 
     593        if ((type.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) != 0) { 
     594            RemoteType elementType = remoteTypes.get(type.getHandle() - 1); 
     595            RemoteType.CachedConversionRatings intermediateRatings = getTypeSingleConversionRatings(elementType); 
     596            for (int i = 0; i < ratings.cachedConversionRatings.length; i++) { 
     597                byte rating = intermediateRatings.cachedConversionRatings[i]; 
     598                if (isSingleOperationRating(rating)) { 
     599                    RemoteType destinationElementType = remoteTypes.get(i); 
     600                    if ((destinationElementType.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) == 0 && (destinationElementType.getTypeTraits() & DataTypeBase.HAS_LIST_TYPE) == 1) { 
     601                        updateConversionRating(ratings.cachedConversionRatings, i + 1, rating == Definitions.TypeConversionRating.IMPLICIT_CAST.ordinal() ? Definitions.TypeConversionRating.EXPLICIT_CONVERSION : Definitions.TypeConversionRating.TWO_EXPLICIT_CONVERSIONS); 
     602                    } 
     603                } 
     604            } 
     605        } 
     606 
     607        // Replace result if it has not changed 
     608        if (type.cachedConversionRatings.compareAndSet(singleRatings, ratings)) { 
     609            return ratings; 
     610        } 
     611        return getTypeConversionRatings(type); 
     612    } 
     613 
     614 
     615    /** 
     616     * @return Type conversion operations in runtime 
     617     */ 
     618    public Register<RemoteTypeConversion> getTypeConversions() { 
     619        return remoteTypeConversions; 
     620    } 
     621 
     622    /** 
     623     * @return Types in runtime 
     624     */ 
     625    public Register<RemoteType> getTypes() { 
     626        return remoteTypes; 
     627    } 
     628 
     629    /** 
     630     * @param sourceType Source type 
     631     * @param destinationType Destination type 
     632     * @return Whether there is a static cast from sourceType to destinationType in remote runtime that is implicit 
     633     */ 
     634    public boolean isStaticCastImplicit(RemoteType sourceType, RemoteType destinationType) { 
     635        if ((sourceType.getTypeTraits() & DataTypeBase.HAS_UNDERLYING_TYPE) != 0 && sourceType.getUnderlyingType() == destinationType.getHandle() && (sourceType.getTypeTraits() & DataTypeBase.IS_CAST_TO_UNDERLYING_TYPE_IMPLICIT) != 0) { 
     636            return true; 
     637        } 
     638        if ((destinationType.getTypeTraits() & DataTypeBase.HAS_UNDERLYING_TYPE) != 0 && (destinationType.getTypeTraits() & DataTypeBase.IS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID) != 0 && destinationType.getUnderlyingType() == sourceType.getHandle() && (destinationType.getTypeTraits() & DataTypeBase.IS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT) != 0) { 
     639            return true; 
     640        } 
     641        int size = remoteStaticCasts.size(); 
     642        for (int i = 0; i < size; i++) { 
     643            RemoteStaticCast cast = remoteStaticCasts.get(i); 
     644            if (cast.isImplicit() && cast.getSourceType() == sourceType && cast.getDestinationType() == destinationType) { 
     645                return true; 
     646            } 
     647        } 
     648        return false; 
     649    } 
     650 
     651    /** 
     652     * @param sourceType Source type 
     653     * @param destinationType Destination type 
     654     * @return Whether there is a static cast from sourceType to destinationType in remote runtime 
     655     */ 
     656    public boolean isStaticCastSupported(RemoteType sourceType, RemoteType destinationType) { 
     657        if ((sourceType.getTypeTraits() & DataTypeBase.HAS_UNDERLYING_TYPE) != 0 && sourceType.getUnderlyingType() == destinationType.getHandle()) { 
     658            return true; 
     659        } 
     660        if ((destinationType.getTypeTraits() & DataTypeBase.HAS_UNDERLYING_TYPE) != 0 && (destinationType.getTypeTraits() & DataTypeBase.IS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID) != 0 && destinationType.getUnderlyingType() == sourceType.getHandle()) { 
     661            return true; 
     662        } 
     663        int size = remoteStaticCasts.size(); 
     664        for (int i = 0; i < size; i++) { 
     665            RemoteStaticCast cast = remoteStaticCasts.get(i); 
     666            if (cast.getSourceType() == sourceType && cast.getDestinationType() == destinationType) { 
     667                return true; 
     668            } 
     669        } 
     670        return false; 
     671    } 
     672 
     673    /** 
     674     * Load module library in external runtime 
     675     * 
     676     * @param load module library to load 
     677     * @return Updated list of remote create module actions 
     678     */ 
     679    public Register<RemoteCreateAction> loadModuleLibrary(String load) { 
     680        List<RemoteCreateAction> createActions = adminInterface.loadModuleLibrary(load, this); 
     681        if (serializationInfo.getRevision() == 0) { 
     682            for (int i = remoteCreateActions.size(); i < createActions.size(); i++) { 
     683                remoteCreateActions.add(createActions.get(i)); 
     684            } 
     685        } else { 
     686            adminInterface.getRegisterUpdates(Definitions.RegisterUIDs.CREATE_ACTION.ordinal()); 
     687        } 
     688        return remoteCreateActions; 
     689    } 
     690 
     691    /** 
     692     * Returns framework element with specified handle. 
     693     * Creates one if it doesn't exist. 
     694     * 
     695     * @param handle Remote handle of framework element 
     696     * @return Framework element. 
     697     */ 
     698    public RemoteFrameworkElement obtainFrameworkElement(int handle) { 
     699        int index = (int)((handle & 0xFFFFFFFFL) >> handleStampWidth); 
     700        RemoteFrameworkElement remoteElement = elementLookup.get(index); 
     701        if (remoteElement == null) { 
     702            remoteElement = new RemoteFrameworkElement(handle, "(unknown)"); 
     703            setElementLookupEntry(handle, remoteElement); 
     704        } 
     705        return remoteElement; 
     706    } 
     707 
     708    /** 
     709     * Removes connector from connector table 
     710     * 
     711     * @param connector Connector to remove 
     712     */ 
     713    public void removeConnector(RemoteConnector connector) { 
     714        if (connector instanceof RemoteUriConnector) { 
     715            uriConnectors.remove((RemoteUriConnector)connector); 
     716        } else { 
     717            for (int i = 0; i < 2; i++) { 
     718                int index = (int)(((i == 0 ? connector.getSourceHandle() : connector.getDestinationHandle()) & 0xFFFFFFFFL) >> handleStampWidth); 
     719                AbstractPort.EdgeList<RemoteConnector> list = connectorTable.get(index); 
     720                if (list != null) { 
     721                    list.remove(connector); 
     722                } 
     723            } 
     724        } 
     725    } 
     726 
     727    /** 
     728     * Removes connector from connector table 
     729     * 
     730     * @param sourceHandle Handle of source port 
     731     * @param destinationHandle Handle of destination port 
     732     */ 
     733    public void removeConnector(int sourceHandle, int destinationHandle) { 
     734        for (int i = 0; i < 2; i++) { 
     735            int index = (int)(((i == 0 ? sourceHandle : destinationHandle) & 0xFFFFFFFFL) >> handleStampWidth); 
     736            AbstractPort.EdgeList<RemoteConnector> list = connectorTable.get(index); 
     737            if (list != null) { 
     738                ArrayWrapper<RemoteConnector> iterable = list.getIterable(); 
     739                for (int j = 0, n = iterable.size(); j < n; j++) { 
     740                    RemoteConnector connector = iterable.get(j); 
     741                    if ((connector.sourceHandle == sourceHandle && connector.destinationHandle == destinationHandle) || (connector.sourceHandle == destinationHandle && connector.destinationHandle == sourceHandle)) { 
     742                        list.remove(connector); 
     743                    } 
     744                } 
     745            } 
     746        } 
     747    } 
     748 
     749    /** 
     750     * Removes all connectors owned by port with specified handle 
     751     * 
     752     * @param portHandle Handle of port 
     753     */ 
     754    public void removePortConnectors(int portHandle) { 
     755        int index = (int)((portHandle & 0xFFFFFFFFL) >> handleStampWidth); 
     756        AbstractPort.EdgeList<RemoteConnector> list = connectorTable.get(index); 
     757        if (list != null) { 
     758            list.clear(); 
     759        } 
     760 
     761        ArrayWrapper<RemoteUriConnector> iterable = uriConnectors.getIterable(); 
     762        for (int i = 0, n = iterable.size(); i < n; i++) { 
     763            RemoteUriConnector connector = iterable.get(i); 
     764            if (connector != null && connector.getOwnerPortHandle() == portHandle) { 
     765                uriConnectors.remove(connector); 
     766            } 
     767        } 
     768    } 
     769 
     770    /** 
     771     * Removes URI connector 
     772     * 
     773     * @param ownerHandle Handle of owner port 
     774     * @param index Index of URI connector in owner port list 
     775     */ 
     776    public void removeUriConnector(int ownerHandle, byte index) { 
     777        ArrayWrapper<RemoteUriConnector> iterable = uriConnectors.getIterable(); 
     778        for (int i = 0, n = iterable.size(); i < n; i++) { 
     779            RemoteUriConnector connector = iterable.get(i); 
     780            if (connector != null && connector.getOwnerPortHandle() == ownerHandle && connector.getIndex() == index) { 
     781                uriConnectors.remove(connector); 
     782            } 
     783        } 
     784    } 
     785 
     786    /** 
     787     * Resolves local data types if this has not been done yet 
     788     * Should be done when static cast operations are also available 
     789     */ 
     790    public synchronized void resolveDefaultLocalTypes() { 
     791        int typeCount = this.remoteTypes.size(); 
     792        if (resolvedTypes < typeCount) { 
     793            for (int i = resolvedTypes; i < typeCount; i++) { 
     794                this.remoteTypes.get(i).resolveDefaultLocalType(this); 
     795            } 
     796            resolvedTypes = typeCount; 
     797        } 
     798    } 
     799 
     800    /** 
     801     * Sets entry in element lookup table (thread-safe) 
     802     * 
     803     * @param handle Handle of element 
     804     * @param element Element 
     805     */ 
     806    public void setElementLookupEntry(int handle, RemoteFrameworkElement element) { 
     807        int index = (int)((handle & 0xFFFFFFFFL) >> handleStampWidth); 
     808        if (element != null && elementLookup.get(index) != null) { 
     809            Log.log(LogLevel.WARNING, "Lookup entry overwritten"); 
     810        } 
     811        elementLookup.set(index, element); 
     812    } 
     813 
     814    /** 
     815     * Sets status of remote URI connector 
     816     * 
     817     * @param ownerHandle Handle of owner port 
     818     * @param index Index of URI connector in owner port list 
     819     * @param status New Status 
     820     */ 
     821    public void setUriConnectorStatus(int ownerHandle, byte index, Status status) { 
     822        ArrayWrapper<RemoteUriConnector> iterable = uriConnectors.getIterable(); 
     823        for (int i = 0, n = iterable.size(); i < n; i++) { 
     824            RemoteUriConnector connector = iterable.get(i); 
     825            if (connector != null && connector.getOwnerPortHandle() == ownerHandle && connector.getIndex() == index) { 
     826                connector.setStatus(status); 
     827            } 
     828        } 
     829    } 
     830 
     831    /** 
     832     * Update/resolve URI connector connection partners using current model. 
     833     * When model changes, this needs to be computed again (suggestion: do before redraw) 
     834     * May only be called by thread that builds remote model 
     835     */ 
     836    public void updateUriConnectors() { 
     837        ArrayList<RemoteRuntime> otherRuntimes = new ArrayList<RemoteRuntime>(); 
     838        elementsInErrorState.clear(); 
     839        ArrayWrapper<RemoteUriConnector> iterable = uriConnectors.getIterable(); 
     840        for (int j = 0, n = iterable.size(); j < n; j++) { 
     841            RemoteUriConnector connector = iterable.get(j); 
     842            if (connector == null) { 
     843                continue; 
     844            } 
     845            if (connector.getStatus() != RemoteUriConnector.Status.CONNECTED) { 
     846                connector.currentPartner = null; 
     847                RemotePort errorPort = getRemotePort(connector.getOwnerPortHandle()); 
     848                if (errorPort != null) { 
     849                    elementsInErrorState.add(errorPort); 
     850                } 
     851                continue; 
     852            } 
     853            if (connector.currentPartner != null && connector.currentPartner.getRoot() == this.getRoot()) {  // still connected 
     854                continue; 
     855            } 
     856            connector.currentPartner = null; 
     857 
     858            // Resolve runtimes that match scheme handler and authority (needs to be more sophisticated for supporting additional network transports) 
     859            otherRuntimes.clear(); 
     860            if (connector.getSchemeHandler().getSchemeName().equals("")) { 
     861                otherRuntimes.add(this); 
     862            } else { 
     863                ModelNode parent = this.getParent(); 
     864                if (parent != null) { 
     865                    for (int i = 0; i < parent.getChildCount(); i++) { 
     866                        ModelNode child = parent.getChildAt(i); 
     867                        if (child instanceof RemoteRuntime && connector.currentConnectionMayGoTo((RemoteRuntime)child)) { 
     868                            otherRuntimes.add((RemoteRuntime)child); 
     869                        } 
     870                    } 
     871                } 
     872            } 
     873 
     874            // Look for port in runtimes 
     875            for (RemoteRuntime runtime : otherRuntimes) { 
     876                RemotePort port = connector.getRemoteConnectedPort(runtime); 
     877                if (port != null) { 
     878                    connector.currentPartner = port; 
     879                    break; 
     880                } 
     881            } 
     882        } 
     883    } 
     884 
     885//    /** 
     886//     * Find RemoteRuntime to which specified port belongs to 
     887//     * 
     888//     * @param np remote port 
     889//     * @return RemoteRuntime object - or null if none could be found 
     890//     */ 
     891//    public static RemoteRuntime find(NetPort np) { 
     892//        return find(RemotePort.get(np.getPort())[0]); 
     893//    } 
     894 
     895 
     896    /** Admin interface for remote runtime */ 
     897    private final AdminClient adminInterface; 
     898 
     899    /** Remote registers */ 
     900    private final Register<RemoteType> remoteTypes; 
     901    private Register<RemoteStaticCast> remoteStaticCasts; 
     902    private Register<RemoteTypeConversion> remoteTypeConversions; 
     903    private Register<RemoteUriSchemeHandler> remoteSchemeHandlers; 
     904    private Register<RemoteCreateAction> remoteCreateActions; 
     905 
     906    /** Input stream containing all registers */ 
     907    private final BinaryInputStream inputStream; 
     908 
     909    /** Number of resolved remote types */ 
     910    private int resolvedTypes; 
     911 
     912    /** Thread-safe lookup for remote framework elements: remote handle => remote framework element */ 
     913    private final ConcurrentLookupTable<RemoteFrameworkElement> elementLookup; 
     914 
     915    /** Stamp Width of framework element handles */ 
     916    private final int handleStampWidth; 
     917 
     918    /** Thread-safe table/lookup for remote connectors: remote handle => remote connectors */ 
     919    private final ConcurrentLookupTable<AbstractPort.EdgeList<RemoteConnector>> connectorTable; 
     920 
     921    /** List with all URI connectors */ 
     922    private final SafeConcurrentlyIterableList<RemoteUriConnector> uriConnectors = new SafeConcurrentlyIterableList<RemoteUriConnector>(128, 4); 
     923 
     924    /** Serialization info from remote runtime */ 
     925    private final SerializationInfo serializationInfo; 
     926 
     927    /** Contains any elements in error state in this runtime. May only be accessed by thread that builds model. */ 
     928    private final ArrayList<RemoteFrameworkElement> elementsInErrorState = new ArrayList<>(); 
     929 
     930    /** Internal helper type for getConversionOptions() methods */ 
     931    private static class GetCastOperationEntry implements Comparable<GetCastOperationEntry> { 
     932 
     933        final RemoteType intermediateType; 
     934        final RemoteTypeConversion operation; 
     935        final boolean implicitCast; 
     936 
     937        public GetCastOperationEntry(RemoteTypeConversion operation, RemoteType intermediateType, boolean implicitCast) { 
     938            this.operation = operation; 
     939            this.intermediateType = intermediateType; 
     940            this.implicitCast = implicitCast; 
     941        } 
     942 
     943        @Override 
     944        public int compareTo(GetCastOperationEntry o) { 
     945            if (intermediateType != o.intermediateType) { 
     946                return Integer.compare(intermediateType.getHandle(), o.intermediateType.getHandle()); 
     947            } 
     948            return operation.getName().compareTo(o.operation.getName()); 
     949        } 
     950    } 
     951 
     952    /** 
     953     * Helper function for getConversionOptions() 
     954     * 
     955     * @param type Type to check 
     956     * @param filter Type filter to apply 
     957     * @param singleType Single type for type filter 'SINGLE' 
     958     * @return Whether 'type' is supported by non-special function 
     959     */ 
     960    private boolean isTypeSupported(RemoteType type, SupportedTypeFilter filter, RemoteType singleType) { 
     961        return (filter == SupportedTypeFilter.ALL) || 
     962               (filter == SupportedTypeFilter.BINARY_SERIALIZABLE && (type.getTypeTraits() & DataTypeBase.IS_BINARY_SERIALIZABLE) != 0) || 
     963               (filter == SupportedTypeFilter.SINGLE && singleType == type) || 
     964               (filter == SupportedTypeFilter.STRING_SERIALIZABLE && (type.getTypeTraits() & DataTypeBase.IS_STRING_SERIALIZABLE) != 0); 
     965    } 
     966 
     967    /** 
     968     * Helper function for getConversionOptions() 
     969     * 
     970     * @param result List to store result in 
     971     * @param operation Type conversion operation in question 
     972     * @param filter Type filter to apply 
     973     * @param singleType Single type for type filter 'SINGLE' 
     974     */ 
     975    private void addAllTypes(ArrayList<GetCastOperationEntry> result, RemoteTypeConversion operation, SupportedTypeFilter filter, RemoteType singleType) { 
     976        if (filter == SupportedTypeFilter.SINGLE) { 
     977            result.add(new GetCastOperationEntry(operation, singleType, false)); 
     978        } else if (filter == SupportedTypeFilter.ALL || filter == SupportedTypeFilter.BINARY_SERIALIZABLE || filter == SupportedTypeFilter.STRING_SERIALIZABLE) { 
     979            int requiredFlag = filter == SupportedTypeFilter.ALL ? 0 : (filter == SupportedTypeFilter.BINARY_SERIALIZABLE ? DataTypeBase.IS_BINARY_SERIALIZABLE : DataTypeBase.IS_STRING_SERIALIZABLE); 
     980            for (int i = 0, n = remoteTypes.size(); i < n; i++) { 
     981                RemoteType type = remoteTypes.get(i); 
     982                if ((type.getTypeTraits() & requiredFlag) == requiredFlag) { 
     983                    result.add(new GetCastOperationEntry(operation, type, false)); 
     984                } 
     985            } 
     986        } 
     987    } 
     988 
     989    /** 
     990     * Helper function for getTypeConversionRatings() 
     991     * 
     992     * @param result Object to store result in 
     993     * @param operation Type conversion operation in question 
     994     * @param filter Type filter to apply 
     995     * @param singleType Single type for type filter 'SINGLE' 
     996     * @param sourceFilter Whether this is the source filter 
     997     */ 
     998    private void addAllDestinationTypes(RemoteType.CachedConversionRatings result, RemoteTypeConversion operation) { 
     999        RemoteTypeConversion.SupportedTypeFilter filter = operation.getSupportedDestinationTypes(); 
     1000        if (operation.getSupportedDestinationTypes() == SupportedTypeFilter.SINGLE) { 
     1001            Definitions.TypeConversionRating rating = (operation.getSupportedSourceTypes() == SupportedTypeFilter.ALL || operation.getSupportedSourceTypes() == SupportedTypeFilter.BINARY_SERIALIZABLE || operation.getSupportedSourceTypes() == SupportedTypeFilter.STRING_SERIALIZABLE) ? Definitions.TypeConversionRating.EXPLICIT_CONVERSION_TO_GENERIC_TYPE : Definitions.TypeConversionRating.EXPLICIT_CONVERSION; 
     1002            updateConversionRating(result.cachedConversionRatings, operation.getSupportedDestinationType().getHandle(), rating); 
     1003        } else if (filter == SupportedTypeFilter.ALL || filter == SupportedTypeFilter.BINARY_SERIALIZABLE || filter == SupportedTypeFilter.STRING_SERIALIZABLE) { 
     1004            int requiredFlag = filter == SupportedTypeFilter.ALL ? 0 : (filter == SupportedTypeFilter.BINARY_SERIALIZABLE ? DataTypeBase.IS_BINARY_SERIALIZABLE : DataTypeBase.IS_STRING_SERIALIZABLE); 
     1005            for (int i = 0; i < result.typeCount; i++) { 
     1006                RemoteType type = remoteTypes.get(i); 
     1007                if ((type.getTypeTraits() & requiredFlag) == requiredFlag) { 
     1008                    updateConversionRating(result.cachedConversionRatings, type.getHandle(), Definitions.TypeConversionRating.EXPLICIT_CONVERSION_FROM_GENERIC_TYPE); 
     1009                } 
     1010            } 
     1011        } 
     1012    } 
     1013 
     1014    /** 
     1015     * Helper function for getTypeConversionRatings() 
     1016     * 
     1017     * @param ratingArray Array with cached results. Stores provided rating value if it is better than the current value. 
     1018     * @param index Index (== remote handle) of type of interest 
     1019     * @param rating Rating to possibly set array entry to 
     1020     */ 
     1021    private void updateConversionRating(byte[] ratingArray, int index, Definitions.TypeConversionRating rating) { 
     1022        byte value = (byte)rating.ordinal(); 
     1023        if (value > ratingArray[index]) { 
     1024            ratingArray[index] = value; 
     1025        } 
     1026    } 
     1027 
     1028    /** 
     1029     * Helper function for getTypeConversionRatings() 
     1030     * Returns type conversion ratings for specified type if only a single type conversion is used. 
     1031     * Returned object may also include ratings for type conversion sequences. 
     1032     * This method cashes results in RemoteType and updates cached results when required. 
     1033     * (Implementation note: as complete cached results are replaced atomically with the old ones remaining intact, this is thread-safe) 
     1034     * 
     1035     * @param type Type whose ratings to update 
     1036     * @param Returns type conversion ratings 
     1037     */ 
     1038    private RemoteType.CachedConversionRatings getTypeSingleConversionRatings(RemoteType type) { 
     1039        RemoteType.CachedConversionRatings currentRatings = type.cachedConversionRatings.get(); 
     1040        if (currentRatings != null && currentRatings.typeCount == remoteTypes.size() && currentRatings.staticCastCount == remoteStaticCasts.size() && currentRatings.typeConversionOperationCount == remoteTypeConversions.size()) { 
     1041            return currentRatings; 
     1042        } 
     1043 
     1044        // Init new result 
     1045        RemoteType.CachedConversionRatings ratings = new RemoteType.CachedConversionRatings(); 
     1046        ratings.typeCount = remoteTypes.size(); 
     1047        ratings.staticCastCount = remoteStaticCasts.size(); 
     1048        ratings.typeConversionOperationCount = remoteTypeConversions.size(); 
     1049        ratings.singleOperationsResultsOnly = true; 
     1050        ratings.cachedConversionRatings = new byte[ratings.typeCount]; 
     1051        ratings.cachedConversionRatings[type.getHandle()] = (byte)Definitions.TypeConversionRating.NO_CONVERSION.ordinal(); 
     1052 
     1053        // Process static casts 
     1054        if (type.getUnderlyingType() > 0) { 
     1055            updateConversionRating(ratings.cachedConversionRatings, type.getUnderlyingType(), ((type.getTypeTraits() & DataTypeBase.IS_CAST_TO_UNDERLYING_TYPE_IMPLICIT) != 0) ? Definitions.TypeConversionRating.IMPLICIT_CAST : Definitions.TypeConversionRating.EXPLICIT_CONVERSION); 
     1056        } 
     1057        for (int i = 0; i < ratings.typeCount; i++) { 
     1058            RemoteType type2 = remoteTypes.get(i); 
     1059            if (type2.getUnderlyingType() == type.getHandle() && (type2.getTypeTraits() & DataTypeBase.IS_REINTERPRET_CAST_FROM_UNDERLYING_TYPE_VALID) != 0) { 
     1060                updateConversionRating(ratings.cachedConversionRatings, i, ((type.getTypeTraits() & DataTypeBase.IS_CAST_FROM_UNDERLYING_TYPE_IMPLICIT) != 0) ? Definitions.TypeConversionRating.IMPLICIT_CAST : Definitions.TypeConversionRating.EXPLICIT_CONVERSION); 
     1061            } 
     1062        } 
     1063        for (int i = 0; i < ratings.staticCastCount; i++) { 
     1064            RemoteStaticCast cast = remoteStaticCasts.get(i); 
     1065            if (cast.getSourceType() == type) { 
     1066                updateConversionRating(ratings.cachedConversionRatings, cast.getDestinationType().getHandle(), cast.isImplicit() ? Definitions.TypeConversionRating.IMPLICIT_CAST : Definitions.TypeConversionRating.EXPLICIT_CONVERSION); 
     1067            } 
     1068        } 
     1069 
     1070        // Process type conversion operations 
     1071        for (int i = 0; i < ratings.typeConversionOperationCount; i++) { 
     1072            RemoteTypeConversion conversion = remoteTypeConversions.get(i); 
     1073            if (isTypeSupported(type, conversion.getSupportedSourceTypes(), conversion.getSupportedSourceType())) { 
     1074                addAllDestinationTypes(ratings, conversion); 
     1075            } 
     1076        } 
     1077 
     1078        // Get list elements operation 
     1079        if ((type.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) != 0) { 
     1080            updateConversionRating(ratings.cachedConversionRatings, type.getHandle() - 1, Definitions.TypeConversionRating.EXPLICIT_CONVERSION); 
     1081        } 
     1082 
     1083        // Replace result if it has not changed 
     1084        if (type.cachedConversionRatings.compareAndSet(currentRatings, ratings)) { 
     1085            return ratings; 
     1086        } 
     1087        return getTypeSingleConversionRatings(type); 
     1088    } 
     1089 
     1090    /** 
     1091     * Helper function for getTypeConversionRatings() 
     1092     * 
     1093     * @param rating Rating to check 
     1094     * @return Whether this is a rating for a single operation 
     1095     */ 
     1096    private static boolean isSingleOperationRating(byte rating) { 
     1097        return rating == Definitions.TypeConversionRating.IMPLICIT_CAST.ordinal() || rating == Definitions.TypeConversionRating.EXPLICIT_CONVERSION.ordinal() || rating == Definitions.TypeConversionRating.EXPLICIT_CONVERSION_FROM_GENERIC_TYPE.ordinal() || rating == Definitions.TypeConversionRating.EXPLICIT_CONVERSION_TO_GENERIC_TYPE.ordinal(); 
     1098    } 
    1381099} 
  • remote/RemoteType.java

    r240 r262  
    11// 
    2 // You received this file as part of RRLib 
    3 // Robotics Research Library 
     2// You received this file as part of Finroc 
     3// A framework for intelligent robot control 
    44// 
    55// Copyright (C) Finroc GbR (finroc.org) 
     
    2222package org.finroc.core.remote; 
    2323 
    24 import java.util.ArrayList; 
    25  
     24import java.util.concurrent.atomic.AtomicReference; 
     25 
     26import org.finroc.core.datatype.CoreString; 
     27import org.finroc.core.datatype.Event; 
     28import org.finroc.core.datatype.XML; 
    2629import org.rrlib.serialization.BinaryInputStream; 
    2730import org.rrlib.serialization.BinaryOutputStream; 
    28 import org.rrlib.serialization.EnumValue; 
    29 import org.rrlib.serialization.Serialization.DataEncoding; 
     31import org.rrlib.serialization.PublishedRegisters; 
     32import org.rrlib.serialization.Register; 
     33import org.rrlib.serialization.Serialization; 
     34import org.rrlib.serialization.PublishedRegisters.RemoteEntryBase; 
    3035import org.rrlib.serialization.rtti.DataTypeBase; 
    3136import org.rrlib.serialization.rtti.GenericObject; 
     
    3439 * @author Max Reichardt 
    3540 * 
    36  * Data type whose implementation is only available in remote runtime environment. 
    37  * It may be possible to adapt/map it to a local data type. 
    38  * Adapters for this purpose may be added by creating and instantiating subclasses of RemoteTypeAdapter. 
     41 * Remote data type 
     42 * 
     43 * Represents type in remote runtime environment. 
     44 * To be used with rrlib::serialization::PublishedRegisters (handles serialization etc.). 
    3945 */ 
    40 public class RemoteType extends DataTypeBase { 
    41  
    42     /** Type adapter for this type. null if type cannot be adapted */ 
    43     private RemoteTypeAdapter typeAdapter; 
    44  
    45     /** Info from type adapter */ 
    46     private RemoteTypeAdapter.Info adapterInfo = new RemoteTypeAdapter.Info(); 
    47  
    48     /** Listener for new unknown types */ 
    49     private static final ArrayList<RemoteType.Listener> listener = new ArrayList<RemoteType.Listener>(); 
    50  
    51     /** 
    52      * @param name Name of remote type 
    53      * @param enumConstants Enum constants if this is a (remote) enum type - otherwise NULL (may be an array of strings) 
    54      * @param enumValues Enum value - if this is a remote enum type with non-standard values 
    55      * @param Relevant type traits of remote type 
    56      */ 
    57     public RemoteType(String name, Object[] enumConstants, long[] enumValues, byte traits) { 
    58         super(name); 
    59         this.typeTraits = traits; 
    60         this.enumConstants = enumConstants; 
    61         this.enumValues = enumValues; 
    62         this.type = Classification.PLAIN; // we might need to changes this some time 
    63  
     46public class RemoteType extends PublishedRegisters.RemoteEntryBase<DataTypeBase> { 
     47 
     48    /** How deafault local data type was resolved (sorted by preference) */ 
     49    public enum LocalTypeMatch { 
     50        EXACT,     // Option 1: Local type is the exact counterpart to remote type 
     51        ADAPTED,   // Option 2: Local type is adapted via a type adapter 
     52        CAST,      // Option 3: Local type is obtained via static cast from and to remote type 
     53        STRING,    // Option 4: Type's string representation is used 
     54        XML,       // Option 5: Type's XML representation is used 
     55        EVENT,     // Option 6: Event type is used 
     56        NONE       // Local type has not yet been resolved 
     57    } 
     58 
     59    /** 
     60     * Searches for type with specified name in remote type registers used in input stream 
     61     * 
     62     * @param stream Input stream whose type register to search in 
     63     * @param name Type name 
     64     * @param alternativeName Alternative name (e.g. with namespace) (optional) 
     65     * @param throwExceptionOnUnavailability Whether to throw an exception if type is not available 
     66     * @return Returns RemoteType with specified name - or null if no type with specified name could be found 
     67     */ 
     68    public static RemoteType find(BinaryInputStream stream, String name, String alternativeName, boolean throwExceptionOnUnavailability) throws Exception { 
     69        Register<RemoteEntryBase<?>> typeRegister = PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.TYPE.ordinal()); 
     70        if (typeRegister != null) { 
     71            for (int i = 0, n = typeRegister.size(); i < n; i++) { 
     72                RemoteType type = (RemoteType)typeRegister.get(i); 
     73                if (type.getName().equals(name) || (type.getName().equals(alternativeName))) { 
     74                    return type; 
     75                } 
     76            } 
     77            if (throwExceptionOnUnavailability) { 
     78                throw new Exception("Type '" + name  + "' not found"); 
     79            } 
     80        } 
     81        return null; 
     82    } 
     83 
     84    /** 
     85     * @return If default local type is obtained via casting: the number of chained casts. Otherwise 0. 
     86     */ 
     87    public int getCastCountForDefaultLocalType() { 
     88        return localTypeMatch == LocalTypeMatch.CAST ? castedFrom.getCastCountForDefaultLocalType() : 0; 
     89    } 
     90 
     91    /** 
     92     * @return Default local data type that represents the same type (null if type has not been resolved) 
     93     */ 
     94    public DataTypeBase getDefaultLocalDataType() { 
     95        return localDataType; 
     96    } 
     97 
     98    /** 
     99     * @return If default local type is obtained via casting: the type this type is casted from - otherwise null. 
     100     */ 
     101    public RemoteType getDefaultLocalTypeIsCastedFrom() { 
     102        return castedFrom; 
     103    } 
     104 
     105    /** 
     106     * @return Data encoding to use in binary streams 
     107     */ 
     108    public Serialization.DataEncoding getEncodingForDefaultLocalType() { 
     109        return localTypeMatch == LocalTypeMatch.XML ? Serialization.DataEncoding.XML : (localTypeMatch == LocalTypeMatch.STRING ? Serialization.DataEncoding.STRING : Serialization.DataEncoding.BINARY); 
     110    } 
     111 
     112    /** 
     113     * @return If this a remote enum type: Remote enum strings - otherwise nullptr 
     114     */ 
     115    public String[] getEnumConstants() { 
     116        return enumConstants; 
     117    } 
     118 
     119    /** 
     120     * @return If this a remote enum type with non-standard values: Values - otherwise nullptr 
     121     */ 
     122    public long[] getEnumValues() { 
     123        return enumValues; 
     124    } 
     125 
     126    /** 
     127     * @return Name of remote type 
     128     */ 
     129    public String getName() { 
     130        return name; 
     131    } 
     132// 
     133//    /** 
     134//     * @return Data Encoding to use when subscribing and sending data over the network (must be set in handlesType) 
     135//     */ 
     136//    public Serialization.DataEncoding getNetworkEncoding() { 
     137//        return adapterInfo.networkEncoding; 
     138//    } 
     139 
     140    /** 
     141     * @return Type traits of remote type 
     142     */ 
     143    public int getTypeTraits() { 
     144        return typeTraits; 
     145    } 
     146 
     147    /** 
     148     * @return Uid of underlying type. 0 if this type has no underlying type. 
     149     */ 
     150    public short getUnderlyingType() { 
     151        return underlyingType; 
     152    } 
     153 
     154    /** 
     155     * @return Whether this is a cheap-copy type in remote runtime environment 
     156     */ 
     157    public boolean isCheapCopyType() { 
     158        return (typeTraits & (DataTypeBase.HAS_TRIVIAL_DESTRUCTOR | DataTypeBase.IS_DATA_TYPE)) == (DataTypeBase.HAS_TRIVIAL_DESTRUCTOR | DataTypeBase.IS_DATA_TYPE) && size <= 256; 
     159    } 
     160 
     161    /** 
     162     * @return Whether this is a remote enum type 
     163     */ 
     164    public boolean isEnum() { 
     165        return (typeTraits & DataTypeBase.IS_ENUM) != 0; 
     166    } 
     167 
     168//    /** 
     169//     * @return Can type be adapted/mapped to a local data type? 
     170//     */ 
     171//    public boolean isAdaptable() { 
     172//        return typeAdapter != null; 
     173//    } 
     174 
     175    /** 
     176     * Resolves local data type if this has not been done yet 
     177     * Should be done when static cast operations are also available 
     178     */ 
     179    public void resolveDefaultLocalType(RemoteRuntime runtime) { 
     180        if (localDataType != null) { 
     181            return; 
     182        } 
     183 
     184        // Option 1: There is an equivalent local type 
     185        if (!isEnum()) { 
     186            localDataType = DataTypeBase.findType(name); 
     187            if (localDataType != null) { 
     188                localTypeMatch = LocalTypeMatch.EXACT; 
     189                return; 
     190            } 
     191        } 
     192 
     193        // Option 2: There is a type adapter for this type 
    64194        synchronized (RemoteTypeAdapter.adapters) { 
     195            RemoteTypeAdapter.Info info = new RemoteTypeAdapter.Info(); 
    65196            for (RemoteTypeAdapter adapter : RemoteTypeAdapter.adapters) { 
    66                 if (adapter.handlesType(this, adapterInfo)) { 
     197                if (adapter.handlesType(this, info)) { 
    67198                    typeAdapter = adapter; 
     199                    adapterInfo = info; 
    68200                    if (adapterInfo.localType == null || adapterInfo.networkEncoding == null) { 
    69201                        throw new RuntimeException("Network adapter did not set all mandatory info"); 
    70202                    } 
    71                     javaClass = adapterInfo.localType; 
    72                     break; 
     203                    //javaClass = adapterInfo.localType; 
     204                    localTypeMatch = LocalTypeMatch.ADAPTED; 
     205                    localDataType = adapterInfo.localType; 
     206                    return; 
    73207                } 
    74208            } 
    75209        } 
    76210 
    77         synchronized (listener) { 
    78             for (Listener remoteTypeListener : listener) { 
    79                 remoteTypeListener.remoteTypeAdded(this); 
    80             } 
    81         } 
    82     } 
    83  
    84     /** 
    85      * @return Can type be adapted/mapped to a local data type? 
    86      */ 
    87     public boolean isAdaptable() { 
    88         return typeAdapter != null; 
    89     } 
    90  
    91     /** 
    92      * @return Data Encoding to use when subscribing and sending data over the network (must be set in handlesType) 
    93      */ 
    94     public DataEncoding getNetworkEncoding() { 
    95         return adapterInfo.networkEncoding; 
    96     } 
    97  
    98     /** 
    99      * @param remoteTypeListener Listener to add 
    100      */ 
    101     public static void addRemoteTypeListener(RemoteType.Listener remoteTypeListener) { 
    102         synchronized (listener) { 
    103             if (!listener.contains(remoteTypeListener)) { 
    104                 listener.add(remoteTypeListener); 
    105             } 
    106         } 
    107     } 
    108  
    109     /** 
    110      * @param remoteTypeListener Listener to remove 
    111      */ 
    112     public static void removeUnknownTypeListener(RemoteType.Listener remoteTypeListener) { 
    113         synchronized (listener) { 
    114             listener.remove(remoteTypeListener); 
    115         } 
     211        // Option 3: Type has a static cast operation to and from known type (underlying type is preferred, next choices are types with the maximum size <= this type's size) 
     212        if ((typeTraits & DataTypeBase.HAS_UNDERLYING_TYPE) != 0) { 
     213            castedFrom = runtime.getTypes().get(underlyingType); 
     214            if (castedFrom.getCastCountForDefaultLocalType() > 1 || (!runtime.isStaticCastSupported(castedFrom, this))) { 
     215                castedFrom = null; 
     216            } 
     217        } 
     218        if (castedFrom == null) { 
     219            int castsSize = runtime.getStaticCasts().size(); 
     220            for (int i = 0; i < castsSize; i++) { 
     221                RemoteStaticCast cast = runtime.getStaticCasts().get(i); 
     222                if (cast.getSourceType() == this && runtime.isStaticCastSupported(cast.getDestinationType(), this)) { 
     223                    RemoteType candidate = cast.getDestinationType(); 
     224                    candidate.resolveDefaultLocalType(runtime); 
     225                    if (castedFrom.getCastCountForDefaultLocalType() <= 1 && (castedFrom == null || (candidate.localTypeMatch.ordinal() < castedFrom.localTypeMatch.ordinal()) || (candidate.localTypeMatch == castedFrom.localTypeMatch && candidate.size <= this.size && candidate.size > castedFrom.size))) { 
     226                        castedFrom = candidate; 
     227                    } 
     228                } 
     229            } 
     230        } 
     231 
     232        if (castedFrom != null) { 
     233            castedFrom.resolveDefaultLocalType(runtime); 
     234            localDataType = castedFrom.localDataType; 
     235            localTypeMatch = LocalTypeMatch.CAST; 
     236            return; 
     237        } 
     238 
     239        // Option 4: Type has a string representation 
     240        if ((typeTraits & DataTypeBase.IS_STRING_SERIALIZABLE) != 0) { 
     241            localDataType = CoreString.TYPE; 
     242            localTypeMatch = LocalTypeMatch.STRING; 
     243            return; 
     244        } 
     245 
     246        // Option 6: Type has an XML representation 
     247        if ((typeTraits & DataTypeBase.IS_XML_SERIALIZABLE) != 0) { 
     248            localDataType = XML.TYPE; 
     249            localTypeMatch = LocalTypeMatch.XML; 
     250            return; 
     251        } 
     252 
     253        // Option 7: Use empty (event) type 
     254        localDataType = Event.TYPE; 
     255        localTypeMatch = LocalTypeMatch.EVENT; 
     256    } 
     257 
     258    /** 
     259     * @param stream Stream to deserialize remote type from 
     260     * @return Deserialized remote type (reference to register entry) 
     261     */ 
     262    public static RemoteType deserialize(BinaryInputStream stream) throws Exception { 
     263        return (RemoteType)stream.readRegisterEntry(Definitions.RegisterUIDs.TYPE.ordinal()); 
    116264    } 
    117265 
    118266    @Override 
    119     public Object createInstance() { 
    120         try { 
    121             if (enumConstants != null) { 
    122                 return new EnumValue(this); 
    123             } 
    124             return javaClass.newInstance(); 
    125         } catch (Exception e) { 
    126             throw new RuntimeException(e); 
    127         } 
    128     } 
    129  
    130     @Override 
    131     protected GenericObject createInstanceGeneric() { 
    132         return new GenericObject(createInstance(), this, null); 
    133     } 
    134  
    135     /** 
    136      * Listener that gets notified whenever an unknown type is added 
    137      */ 
    138     public static interface Listener { 
    139  
    140         /** 
    141          * Called whenever a remote type is added 
    142          * 
    143          * @param type Type that was added 
    144          */ 
    145         public void remoteTypeAdded(RemoteType type); 
    146     } 
    147  
    148     /** 
    149      * Deserialize adaptable data from stream and place result in provided object 
     267    public String toString() { 
     268        return name; 
     269    } 
     270 
     271    /** 
     272     * Deserialize data from stream and place result in provided object of default local type. 
    150273     * 
    151274     * @param stream Stream to deserialize from 
    152275     * @param object Object to put result in 
    153276     */ 
    154     public void deserialize(BinaryInputStream stream, GenericObject object) throws Exception { 
    155         typeAdapter.deserialize(stream, object, this, adapterInfo); 
    156     } 
    157  
    158     /** 
    159      * Serialize provided object to stream in the correct data format 
     277    public void deserializeData(BinaryInputStream stream, GenericObject object) throws Exception { 
     278        switch (localTypeMatch) { 
     279        case ADAPTED: 
     280            typeAdapter.deserialize(stream, object, this, adapterInfo); 
     281            break; 
     282        case EVENT: 
     283        case NONE: 
     284            break; 
     285        default: 
     286            object.deserialize(stream, getEncodingForDefaultLocalType()); 
     287            break; 
     288        } 
     289    } 
     290 
     291    /** 
     292     * Serialize provided object (of default local type) to stream in the correct data format 
    160293     * 
    161294     * @param stream Stream to serialize to 
    162295     * @param object Object containing data to adapt and serialize 
    163296     */ 
    164     public void serialize(BinaryOutputStream stream, GenericObject object) { 
    165         typeAdapter.serialize(stream, object, this, adapterInfo); 
    166     } 
     297    public void serializeData(BinaryOutputStream stream, GenericObject object) { 
     298        switch (localTypeMatch) { 
     299        case ADAPTED: 
     300            typeAdapter.serialize(stream, object, this, adapterInfo); 
     301            break; 
     302        case EVENT: 
     303        case NONE: 
     304            break; 
     305        default: 
     306            object.serialize(stream, getEncodingForDefaultLocalType()); 
     307            break; 
     308        } 
     309    } 
     310 
     311    @Override 
     312    public void deserializeRegisterEntry(BinaryInputStream stream) throws Exception { 
     313        boolean legacyProtocol = stream.getSourceInfo().getRevision() == 0; 
     314 
     315        enumConstants = null; 
     316        enumValues = null; 
     317        size = 0; 
     318        localDataType = null; 
     319        typeAdapter = null; 
     320        adapterInfo = null; 
     321        castedFrom = null; 
     322 
     323        if (legacyProtocol) { 
     324 
     325            stream.readShort(); // default update time 
     326            TypeClassificationLegacy classification = stream.readEnum(TypeClassificationLegacy.class);  // type classification 
     327 
     328            name = stream.readString(); 
     329 
     330            // read additional data we do not need in c++ (remote type traits and enum ant names) 
     331            typeTraits = stream.readByte() << 8; // type traits 
     332            if (classification == TypeClassificationLegacy.RPC_INTERFACE) { 
     333                typeTraits |= DataTypeBase.IS_RPC_TYPE; 
     334            } else { 
     335                typeTraits |= DataTypeBase.IS_DATA_TYPE; 
     336            } 
     337 
     338            if ((typeTraits & DataTypeBase.IS_ENUM) != 0) { 
     339                short n = stream.readShort(); 
     340                enumConstants = new String[n]; 
     341                for (short i = 0; i < n; i++) { 
     342                    String s = stream.readString(); 
     343                    if (s.contains("|")) { 
     344                        if (enumValues == null) { 
     345                            enumValues = new long[n]; 
     346                        } 
     347                        String[] strings = s.split("\\|"); 
     348                        enumConstants[i] = strings[0]; 
     349                        enumValues[i] = Long.parseLong(strings[1]); 
     350                    } else { 
     351                        enumConstants[i] = s; 
     352                    } 
     353                } 
     354            } 
     355 
     356        } else { 
     357 
     358            //auto reg = *rrlib.serialization.PublishedRegisters.GetRemoteRegister<RemoteType>(stream); 
     359            typeTraits = stream.readShort() << 8; 
     360            if ((typeTraits & DataTypeBase.IS_LIST_TYPE) != 0) { 
     361                Register<?> reg = PublishedRegisters.getRemoteRegister(stream, Definitions.RegisterUIDs.TYPE.ordinal()); 
     362                RemoteType lastType = (RemoteType)reg.get(reg.size() - 1); 
     363                name = "List<" + lastType.name + ">"; 
     364                underlyingType = (short)((typeTraits & DataTypeBase.HAS_UNDERLYING_TYPE) != 0 ? (lastType.underlyingType + 1) : 0); 
     365            } else { 
     366                name = stream.readString(); 
     367                size = stream.readInt(); 
     368                underlyingType = (short)((typeTraits & DataTypeBase.HAS_UNDERLYING_TYPE) != 0 ? stream.readShort() : 0); 
     369                if ((typeTraits & DataTypeBase.IS_ENUM) != 0) { 
     370                    // discard enum info 
     371                    short n = stream.readShort(); 
     372                    int valueSize = stream.readByte(); 
     373                    enumConstants = new String[n]; 
     374                    enumValues = valueSize > 0 ? new long[n] : null; 
     375                    for (short i = 0; i < n; i++) { 
     376                        enumConstants[i] = stream.readString(); 
     377                        if (valueSize > 0) { 
     378                            enumValues[i] = stream.readInt(valueSize); 
     379                        } 
     380                    } 
     381                } 
     382            } 
     383        } 
     384    } 
     385 
     386    @Override 
     387    public void serializeLocalRegisterEntry(BinaryOutputStream stream, Object entry) { 
     388        boolean legacyProcotol = stream.getTargetInfo().getRevision() == 0; 
     389        DataTypeBase type = (DataTypeBase)entry; 
     390 
     391        if (legacyProcotol) { 
     392            stream.writeShort(type.getUid()); 
     393            stream.writeShort(-1); // default update time (legacy, unused in c++) 
     394            stream.writeByte(0); // type classification (legacy, unused in c++) 
     395            stream.writeString(type.getName()); 
     396            stream.writeByte(0); // type traits (legacy, unused in c++) 
     397        } else { 
     398            stream.writeShort((short)((type.getTypeTraits() >> 8) & 0xFFFF)); 
     399            if ((type.getTypeTraits() & DataTypeBase.IS_LIST_TYPE) != 0) { 
     400                return; 
     401            } 
     402            stream.writeString(type.getName()); 
     403            if ((stream.getTargetInfo().getCustomInfo() & Definitions.INFO_FLAG_JAVA_CLIENT) != 0) { 
     404                stream.writeInt(0); // Java type size is difficult to obtain and currently irrelevant 
     405            } 
     406            if ((type.getTypeTraits() & DataTypeBase.HAS_UNDERLYING_TYPE) != 0) { 
     407                throw new RuntimeException("Underlying types not supported for Java types"); 
     408                //stream.writeShort(type.getUnderlyingType().getHandle()); 
     409            } 
     410            if ((type.getTypeTraits() & DataTypeBase.IS_ENUM) != 0) { 
     411                Object[] enumConstants = type.getEnumConstants(); 
     412                stream.writeShort(enumConstants.length); 
     413                stream.writeByte(0); // note that sendValues is no type trait (flag) as it not a compile-time ant (at least not straight-forward) 
     414                for (Object enumContants : enumConstants) { 
     415                    stream.writeString(enumContants.toString()); 
     416                } 
     417            } 
     418        } 
     419    } 
     420 
     421    @Override 
     422    public int getHandleSize() { 
     423        return 2; 
     424    } 
     425 
     426 
     427    /** Type traits of remote type */ 
     428    private int typeTraits; 
     429 
     430    /** Local data type that represents the same type; null-type if there is no such type in local runtime environment */ 
     431    private DataTypeBase localDataType; 
     432 
     433    /** Name of remote type */ 
     434    private String name; 
     435 
     436    /** Uid of underlying type */ 
     437    private short underlyingType; 
     438 
     439    /** If this a remote enum type: Remote enum strings - otherwise nullptr */ 
     440    private String[] enumConstants = null; 
     441 
     442    /** If this a remote enum type with non-standard values: Values - otherwise nullptr */ 
     443    private long[] enumValues = null; 
     444 
     445    /** Type adapter for this type. null if type cannot be adapted */ 
     446    private RemoteTypeAdapter typeAdapter; 
     447 
     448    /** Info from type adapter */ 
     449    private RemoteTypeAdapter.Info adapterInfo = new RemoteTypeAdapter.Info(); 
     450 
     451    /** Size of remote type (not set for list types (identical) and legacy types (no casts anyway)) */ 
     452    private int size; 
     453 
     454    /** How default local data type was resolved  */ 
     455    private LocalTypeMatch localTypeMatch = LocalTypeMatch.NONE; 
     456 
     457    /** If default local type is obtained via casting: the type this type is casted from - otherwise null. */ 
     458    private RemoteType castedFrom; 
     459 
     460    /** Create legacy remote null type */ 
     461    static RemoteType createLegacyRemoteNullTypeInstance() { 
     462        RemoteType type = new RemoteType(); 
     463        type.name = DataTypeBase.NULL_TYPE.getName(); 
     464        type.localDataType = DataTypeBase.NULL_TYPE; 
     465        type.localTypeMatch = LocalTypeMatch.EXACT; 
     466        return type; 
     467    } 
     468 
     469    /** Stores cached conversion ratings */ 
     470    public static class CachedConversionRatings { 
     471 
     472        /** 
     473         * @param destinationType Destination Type 
     474         * @return Rating converting this type to destination type 
     475         */ 
     476        public Definitions.TypeConversionRating getRating(RemoteType destinationType) { 
     477            return Definitions.TypeConversionRating.values()[cachedConversionRatings[destinationType.getHandle()]]; 
     478        } 
     479 
     480        /** 
     481         * @return Conversion to how many types are stored in this object 
     482         */ 
     483        public int size() { 
     484            return cachedConversionRatings.length; 
     485        } 
     486 
     487        /** 
     488         * Number of types, static_casts, and type conversion operations when cached ratings were calculated 
     489         * If any of these has increased, ratings need to be recalculated 
     490         */ 
     491        int typeCount, staticCastCount, typeConversionOperationCount; 
     492 
     493        /** Whether only single operation results are stored in this object */ 
     494        boolean singleOperationsResultsOnly; 
     495 
     496        /** 
     497         * Cached conversion ratings to all other remote types in runtime environment. 
     498         * All other types in runtime have an entry in this array. The entry's value is the type conversion rating numeric value. 
     499         */ 
     500        byte[] cachedConversionRatings; 
     501    } 
     502 
     503    /** 
     504     * Cached conversion ratings. 
     505     * This lazily created/updated by RemoteRuntime.getTypeConversionRatings() 
     506     */ 
     507    AtomicReference<CachedConversionRatings> cachedConversionRatings = new AtomicReference<CachedConversionRatings>(); 
     508 
     509    /** 
     510     * Type of data type (legacy) - relevant only for tooling 
     511     */ 
     512    private enum TypeClassificationLegacy { 
     513        DATA_FLOW_STANDARD, 
     514        DATA_FLOW_CHEAP_COPY, 
     515        RPC_INTERFACE 
     516    }; 
    167517} 
  • remote/RemoteTypeAdapter.java

    r235 r262  
    11// 
    2 // You received this file as part of RRLib 
    3 // Robotics Research Library 
     2// You received this file as part of Finroc 
     3// A framework for intelligent robot control 
    44// 
    55// Copyright (C) Finroc GbR (finroc.org) 
     
    2929import org.rrlib.serialization.BinaryInputStream; 
    3030import org.rrlib.serialization.BinaryOutputStream; 
    31 import org.rrlib.serialization.EnumValue; 
    3231import org.rrlib.serialization.Serialization; 
    3332import org.rrlib.serialization.rtti.DataTypeBase; 
     
    5655 
    5756        /** Local type that this data type is adapted to (must be set in handlesType) */ 
    58         public Class<?> localType; 
     57        public DataTypeBase localType; 
    5958 
    6059        /** Data Encoding to use when subscribing and sending data over the network (must be set in handlesType) */ 
     
    123122        @Override 
    124123        public boolean handlesType(RemoteType remoteType, Info adapterInfo) { 
    125             if ((remoteType.getTypeTraits() & DataTypeBase.IS_ENUM) != 0) { 
    126                 adapterInfo.localType = EnumValue.class; 
     124            if (remoteType.isEnum()) { 
     125                adapterInfo.localType = RemoteEnumValue.TYPE; 
    127126                adapterInfo.networkEncoding = Serialization.DataEncoding.BINARY; 
    128127            } else if ((remoteType.getTypeTraits() & DataTypeBase.IS_STRING_SERIALIZABLE) != 0) { 
    129                 adapterInfo.localType = CoreString.class; 
     128                adapterInfo.localType = CoreString.TYPE; 
    130129                adapterInfo.networkEncoding = Serialization.DataEncoding.STRING; 
    131130            } else if ((remoteType.getTypeTraits() & DataTypeBase.IS_XML_SERIALIZABLE) != 0) { 
    132                 adapterInfo.localType = XML.class; 
     131                adapterInfo.localType = XML.TYPE; 
    133132                adapterInfo.networkEncoding = Serialization.DataEncoding.XML; 
    134133            } else { 
     
    140139        @Override 
    141140        public void deserialize(BinaryInputStream stream, GenericObject object, RemoteType type, Info adapterInfo) throws Exception { 
    142             if (adapterInfo.localType == XML.class) { 
     141            if (adapterInfo.localType == RemoteEnumValue.TYPE) { 
     142                String[] strings = type.getEnumConstants(); 
     143                long[] values = type.getEnumValues(); 
     144                int index = -1; 
     145                if (strings.length <= 0x100) { 
     146                    index = stream.readByte(); 
     147                } else if (strings.length <= 0x10000) { 
     148                    index = stream.readShort(); 
     149                } else { 
     150                    assert(strings.length < 0x7FFFFFFF); 
     151                    index = stream.readInt(); 
     152                } 
     153                long value = values != null ? values[index] : index; 
     154                ((RemoteEnumValue)object.getData()).set(value, index, strings[index]); 
     155            } else if (adapterInfo.localType == XML.TYPE) { 
    143156                object.deserialize(stream, Serialization.DataEncoding.BINARY); 
    144157            } else { 
     
    149162        @Override 
    150163        public void serialize(BinaryOutputStream stream, GenericObject object, RemoteType type, Info adapterInfo) { 
    151             if (adapterInfo.localType == XML.class) { 
     164            if (adapterInfo.localType == RemoteEnumValue.TYPE) { 
     165                RemoteEnumValue value = (RemoteEnumValue)object.getData(); 
     166                int index = value.getOrdinal(); 
     167                String[] strings = type.getEnumConstants(); 
     168                if (index < 0 && value.getValue() >= 0) { 
     169                    long[] values = type.getEnumValues(); 
     170                    for (int i = 0; i < values.length; i++) { 
     171                        if (values[i] == value.getValue()) { 
     172                            index = i; 
     173                            break; 
     174                        } 
     175                    } 
     176                } 
     177                if (index < 0 && value.getString() != null) { 
     178                    for (int i = 0; i < strings.length; i++) { 
     179                        if (strings[i].equals(value.getString())) { 
     180                            index = i; 
     181                            break; 
     182                        } 
     183                    } 
     184                } 
     185                if (index < 0) { 
     186                    throw new RuntimeException("Cannot resolve enum index"); 
     187                } 
     188                if (strings.length <= 0x100) { 
     189                    stream.writeByte(index); 
     190                } else if (strings.length <= 0x10000) { 
     191                    stream.writeShort(index); 
     192                } else { 
     193                    stream.writeInt(index); 
     194                } 
     195            } else if (adapterInfo.localType == XML.TYPE) { 
    152196                object.serialize(stream, Serialization.DataEncoding.BINARY); 
    153197            } else { 
Note: See TracChangeset for help on using the changeset viewer.