Example usage ‒ Creating a service interface
This section contains a few examples for the usage of the Java RSC API.
The Java RSC API will soon be replaced by a better solution. Therefore the support for this tool is already discontinued. If you decide to use the Java RSC API anyway you'll be on your own.
See section RSC (Remote Service Calls) for further information of available RSC services and their usage.
If you want to provide your RSC service through Java the following points must be taken into consideration.
Service
The first step to provide a service in Java is to create an interface file for the service. Afterwards you must add the com.phoenixcontact.ade.commonremoting.RemotingService
annotation. This is required to identify the associated RSC service.
The namespace of the Java service interface file may differ from the namespace on the PLCnext device. In this case you have to define the service name in the RemotingService
annotation.
The service provider name can be defined by the serviceProviderName
field of the RemotingService
annotation.
@RemotingService(fullName = "Ade.CommonRemoting.Security.Services.IPasswordAuthenticationService",
serviceProviderName = "Security")
public interface IPasswordAuthenticationService {
...
}
Service method
The methods should have the com.phoenixcontact.ade.commonremoting.RemotingMethod
annotation. The annotation allows to specify the method index which is required to identify the method on the PLCnext Control device.
@RemotingMethod(index = 1)
void start();
@RemotingMethod(index = 2)
void stop();
If the return value of the method is an unsigned type the AdeMarshalAs
annotation must be added to the method. If parameters are unsigned the AdeMarshalAs
annotation must be placed right before the parameter. See for more info the sections “Data Types” and “AdeMarshalAs” below.
@RemotingMethod(index = 1) @AdeMarshalAs(coreType = CoreType.U4) long exampleOne(int arg0);
@RemotingMethod(index = 2) int example(@AdeMarshalAs(coreType = CoreType.U4) long arg0);
Data types
The following table lists the data types used in Java. For unsigned data types the next larger datatype is used e.g. for the data type uint16 the data type int32 will be used in Java.
Exception: There are many cases where it does not matter whether a byte or byte array is signed or unsigned. Therefore unsigned bytes are allowed to be passed as signed bytes in the Java implementation. As a result unsigned byte arrays can be passed as signed short array or signed byte array.
RSC Type | ID | C++ | C# | JAVA | Note |
Void | 1 | void | System.Void | void | |
Bool | 2 | Arp::boolean | System.Boolean | boolean | |
Int8 | 4 | Arp::int8 | System.SByte | byte | |
Uint8 | 5 | Arp::uint8 | System.Byte | short (or) byte | |
Int16 | 6 | Arp::int16 | System.Int16 | short | |
Uint16 | 7 | Arp::uint16 | System.Uint16 | int | |
Int32 | 8 | Arp::int32 | System.Int32 | int | |
Uint32 | 9 | Arp::uint32 | System.Uint32 | long | |
Int64 | 10 | Arp::int64 | System.Int64 | long | |
Uint64 | 11 | Arp::uint64 | System.Uint64 | BigInteger | |
Real32 | 12 | Arp::float32 | System.Single | float | IEEE 754 |
Real64 | 13 | Arp::float64 | System.Double | double | IEEE 754 |
String | 14 | RscString | System.String | String | |
Struct | 18 | IRscSerializable | struct | class | |
Utf8string | 19 | RscString | System.String | String | |
Array | 20 | std::vector<T> IRscReadEnumerator IRscWriteEnumerator | T[] | T[] | |
DateTime | 23 | Arp::DateTime | System.DateTime | java.time.Instant | |
Object | 28 | RscVariant | System.Object | com.phoenixcontact.ade.commonremoting.utils.AdeObject Wrapper object to pass the type information. Required for unsigned data types. | |
Stream | 34 | RscStream | System.IO.Stream | java.io.InputStream | |
Enumerator | 35 | IRscReadEnumerator IRscWriteEnumerator | System.Collections.IEnumerator | java.util.List<T> | |
SecureString |
36 | SecureString | System.Security.SecureString | char[] | |
System.Version | com.phoenixcontact.ade.commonremoting.Version | ||||
System.Guid | java.util.UUID |
Structs
There are no structs in Java. Therefore structs are converted to Java as classes. The fields are marked as private and provided with getters and setters for access. To recognize that the class is a conversion of a struct object, the Struct annotation must be added to the class.
@com.phoenixcontact.ade.commonremoting.utils.Struct public class ReadItem {
private DataAccessError error;
private AdeObject value;
public DataAccessError getError() { return error; }
public void setError(DataAccessError error) { this.error = error; }
public AdeObject getValue() { if (value == null) { value = new AdeObject(null, CoreType.VOID); } return value; }
public void setValue(AdeObject value) { this.value = value; } }
The annotation com.phoenixcontact.ade.commonremoting.StructField(ignore = true)
allows you to exclude fields for the serialization.
If a field is an unsigned type, you have to add the AdeMarhsalAs
to the field with the corresponding CoreType
.
The API implementation com.phoenixcontact.commonremoting.implementation
uses reflection to access the fields.
Enums
All enums must be able to be converted to a numeric value for communication. If zero is passed as value for an enum, the enum class should contain an enum constant NONE or an enum constant with the value 0 which will be used as default value.
The enums which shall be used in the communication must implement the interface com.phoenixcontact.ade.commonremoting.utils.NumericEnum
@AdeMarshalAs(coreType = CoreType.U4)
public enum ExampleEnum implements NumericEnum<Long> { NONE(0);
private long value;
private ExampleEnum(long value) { this.value = value; }
@Override public Long getValue() { return value; } }
AdeMarshalAs
The com.phoenixcontact.ade.commonremoting.AdeMarshalAs
annotation allows you
- to define the marshal type of a string (ASCII, UTF-8, UTF-16) (Default is UTF-8)
- to define the max length in bytes for a string
- to define the core type of a field, parameter and return value. This is necessary for unsigned types.
@AdeMarshalAs(marshalType = AdeMarshalType.ANSI) String asciiString;
@AdeMarshalAs(marshalType = AdeMarshalType.UTF_8, stringLength = 256) String utf8String;
@AdeMarshalAs(marshalType = AdeMarshalType.UTF_16) String utf16String;
boolean valueBoolean;
byte valueInt8;
@AdeMarshalAs(coreType = CoreType.U1) byte valueUInt8
@AdeMarshalAs(coreType = CoreType.U1) short valueUInt8
short valueInt16;
@AdeMarshalAs(coreType = CoreType.U2) int valueUInt16
int valueInt32;
@AdeMarshalAs(coreType = CoreType.U4) long valueUInt32
long valueInt64;
@AdeMarshalAs(coreType = CoreType.U8) BigInteger valueUInt64
float valueReal32;
double valueReal64;
AdeObject valueObject;
@AdeMarshalAs(coreType = CoreType.U1) byte[] byteArray;
@AdeMarshalAs(coreType = CoreType.U1) short[] byteArray;
int[] valueInt32Array;
@AdeMarshalAs(componentCoreType = CoreType.U4) long[] valueUInt32Array;
List<Short> valueInt16List;
List<@AdeMarshalAs(coreType = CoreType.U2) Integer> valueUInt16List;
InputStream valueStream;
Instant valueDateTime;
@AdeMarshalAs(marshalType = AdeMarshalType.LOCAL_DATE_TIME) Instant valueLocalDateTime;
OutParam
The com.phoenixcontact.ade.commonremoting.utils.OutParam
class provides you with the possibility to define methods, e.g.:
void example(OutParam<Integer> param);
void example(OutParam<@AdeMarshalAs(coreType = CoreType.U4)> Long param);
void example(OutParam<@AdeMarshalAs(coreType = CoreType.U1)> short[] param);
void example(OutParam<@AdeMarshalAs(coreType = CoreType.U1)> byte[] param);
RefParam
The com.phoenixcontact.ade.commonremoting.utils.RefParam
class provides you with possibility to define methods, e.g.:
void example(RefParam<Integer> param);
void example(RefParam<@AdeMarshalAs(coreType = CoreType.U4) Long> param);