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</code>. */
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 with any results encoded in
* {@code outParams}; {@code false} if a user exception occurred with the exception
* encoded in {@code outParams}.
* @param outParams The encoded results.
*/
public Ice_invokeResult(boolean returnValue, byte[] outParams) {
this.returnValue = returnValue;
this.outParams = outParams;
}
/**
* If the operation completed successfully, the return value is <code>true</code>. If the
* operation raises a user exception, the return value is <code>false</code>; in this case,
* <code>outParams</code> 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. The return value follows
* any out-parameters.
*/
public byte[] outParams;
}
/**
* Tests whether this object supports a specific Slice interface.
*
* @param s The type ID of the Slice interface to test against.
* @param current The {@link Current} object for the invocation.
* @return <code>true</code> if this object has the interface specified by <code>s</code> or
* derives from the interface specified by <code>s</code>.
*/
default boolean ice_isA(String s, Current current) {
return isA(this.getClass(), s);
}
/**
* Tests whether this object can be reached.
*
* @param current The {@link Current} object for the invocation.
*/
default void ice_ping(Current current) {
// Nothing to do.
}
/**
* Returns the Slice type IDs of the interfaces supported by this object.
*
* @param current The {@link Current} object for the invocation.
* @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 Slice type ID of the most-derived interface supported by this object.
*
* @param current The {@link Current} object for the invocation.
* @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 Slice type ID of the interface supported by this object.
*
* @return The return value is always ::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 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 the corresponding outgoing response
* for the {@code 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 the corresponding outgoing response
* for the {@code 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 the corresponding outgoing response
* for the {@code 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 the corresponding outgoing response
* for the {@code 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 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);
}
}
}