Object.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
/** The base interface for servants. */
@SliceTypeId(value = "::Ice::Object")
public interface Object {
/**
* Holds the results of a call to {@code ice_invoke}.
*
* @see Blobject#ice_invoke
* @see ObjectPrx#ice_invoke
*/
public class Ice_invokeResult {
/** Default initializes the fields. */
public Ice_invokeResult() {}
/**
* Primary constructor to initialize the fields.
*
* @param returnValue {@code true} for a successful invocation (any results are encoded in {@code outParams});
* {@code false} if a user exception occurred (the exception is encoded in {@code outParams}).
* @param outParams the encoded results of the operation
*/
public Ice_invokeResult(boolean returnValue, byte[] outParams) {
this.returnValue = returnValue;
this.outParams = outParams;
}
/**
* {@code true} if the operation completed successfully, {@code false} if the operation threw a user exception.
* If {@code false}, {@code outParams} contains the encoded user exception.
* If the operation raises a run-time exception, it throws it directly.
*/
public boolean returnValue;
/**
* The encoded out-parameters and return value for the operation (in that order).
*/
public byte[] outParams;
}
/**
* Tests whether this object supports a specific Slice interface.
*
* @param typeId the type ID of the Slice interface to test against
* @param current the {@link Current} object of the incoming request
* @return {@code true} if this object implements the Slice interface specified by {@code typeId} or
* implements a derived interface, {@code false} otherwise
*/
default boolean ice_isA(String typeId, Current current) {
return isA(this.getClass(), typeId);
}
/**
* Tests whether this object can be reached.
*
* @param current the {@link Current} object of the incoming request
*/
default void ice_ping(Current current) {
// Nothing to do.
}
/**
* Returns the Slice interfaces supported by this object as a list of Slice type IDs.
*
* @param current the {@link Current} object of the incoming request
* @return the Slice type IDs of the interfaces supported by this object, in alphabetical order
*/
default String[] ice_ids(Current current) {
var typeIds = new TreeSet<String>();
addTypeIds(this.getClass(), typeIds);
return typeIds.toArray(new String[0]);
}
/**
* Returns the type ID of the most-derived Slice interface supported by this object.
*
* @param current the {@link Current} object of the incoming request
* @return the Slice type ID of the most-derived interface
*/
default String ice_id(Current current) {
// The first direct interface with a type ID is necessarily the most derived interface.
for (var directInterface : this.getClass().getInterfaces()) {
var sliceTypeIdAnnotation = directInterface.getAnnotation(SliceTypeId.class);
if (sliceTypeIdAnnotation != null) {
return sliceTypeIdAnnotation.value();
}
}
return ice_staticId();
}
/**
* Returns the type ID of the associated Slice interface.
*
* @return The return value is always {@code "::Ice::Object"}.
*/
public static String ice_staticId() {
return "::Ice::Object";
}
/**
* Dispatches an incoming request and returns the corresponding outgoing response.
*
* @param request the incoming request
* @return a {@link CompletionStage} that will complete with the outgoing response
* @throws UserException If a {@code UserException} is thrown, Ice will marshal it as the response payload.
*/
default CompletionStage<OutgoingResponse> dispatch(IncomingRequest request) throws UserException {
return switch (request.current.operation) {
case "ice_id" -> _iceD_ice_id(this, request);
case "ice_ids" -> _iceD_ice_ids(this, request);
case "ice_isA" -> _iceD_ice_isA(this, request);
case "ice_ping" -> _iceD_ice_ping(this, request);
default -> throw new OperationNotExistException();
};
}
/**
* Dispatches an incoming request and returns a corresponding outgoing response for the {@link ice_isA} operation.
*
* @param obj the object to dispatch the request to
* @param request the incoming request
* @return a {@link CompletionStage} that will complete with the outgoing response
* @hidden
*/
static CompletionStage<OutgoingResponse> _iceD_ice_isA(Object obj, IncomingRequest request) {
InputStream istr = request.inputStream;
istr.startEncapsulation();
String iceP_id = istr.readString();
istr.endEncapsulation();
boolean ret = obj.ice_isA(iceP_id, request.current);
return CompletableFuture.completedFuture(
request.current.createOutgoingResponse(
ret, (ostr, value) -> ostr.writeBool(value), FormatType.CompactFormat));
}
/**
* Dispatches an incoming request and returns a corresponding outgoing response for the {@link ice_ping} operation.
*
* @param obj the object to dispatch the request to
* @param request the incoming request
* @return a {@link CompletionStage} that will complete with the outgoing response
* @hidden
*/
static CompletionStage<OutgoingResponse> _iceD_ice_ping(Object obj, IncomingRequest request) {
request.inputStream.skipEmptyEncapsulation();
obj.ice_ping(request.current);
return CompletableFuture.completedFuture(request.current.createEmptyOutgoingResponse());
}
/**
* Dispatches an incoming request and returns a corresponding outgoing response for the {@link ice_ids} operation.
*
* @param obj the object to dispatch the request to
* @param request the incoming request
* @return a {@link CompletionStage} that will complete with the outgoing response
* @hidden
*/
static CompletionStage<OutgoingResponse> _iceD_ice_ids(Object obj, IncomingRequest request) {
request.inputStream.skipEmptyEncapsulation();
String[] ret = obj.ice_ids(request.current);
return CompletableFuture.completedFuture(
request.current.createOutgoingResponse(
ret,
(ostr, value) -> ostr.writeStringSeq(value),
FormatType.CompactFormat));
}
/**
* Dispatches an incoming request and returns a corresponding outgoing response for the {@link ice_id} operation.
*
* @param obj the object to dispatch the request to
* @param request the incoming request
* @return a {@link CompletionStage} that will complete with the outgoing response
* @hidden
*/
static CompletionStage<OutgoingResponse> _iceD_ice_id(Object obj, IncomingRequest request) {
request.inputStream.skipEmptyEncapsulation();
String ret = obj.ice_id(request.current);
return CompletableFuture.completedFuture(
request.current.createOutgoingResponse(
ret, (ostr, value) -> ostr.writeString(value), FormatType.CompactFormat));
}
/** Implements {@link ice_isA} by checking all interfaces recursively. */
private static boolean isA(Class<?> type, String typeId) {
for (var directInterface : type.getInterfaces()) {
var sliceTypeIdAnnotation = directInterface.getAnnotation(SliceTypeId.class);
if (sliceTypeIdAnnotation != null) {
if (sliceTypeIdAnnotation.value().equals(typeId)) {
return true;
}
}
// Check the interfaces of this interface, if any.
if (isA(directInterface, typeId)) {
return true;
}
}
return false;
}
/** Helper for ice_ids. */
private static void addTypeIds(Class<?> type, SortedSet<String> typeIds) {
for (var directInterface : type.getInterfaces()) {
var sliceTypeIdAnnotation = directInterface.getAnnotation(SliceTypeId.class);
if (sliceTypeIdAnnotation != null) {
typeIds.add(sliceTypeIdAnnotation.value());
}
// Recursively add the type IDs of the interfaces of this interface, if any.
addTypeIds(directInterface, typeIds);
}
}
}