From aaf3836fec06c3ece12aa113881cd339fd5393f3 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Wed, 5 Jun 2024 10:49:15 -0400 Subject: [PATCH] Refactor dispatch pipeline in Swift (#2269) --- cpp/src/slice2swift/Gen.cpp | 38 +-- cpp/src/slice2swift/SwiftUtil.cpp | 184 +++++-------- cpp/src/slice2swift/SwiftUtil.h | 1 - swift/src/Ice/AdminFacetFactory.swift | 99 ++++--- swift/src/Ice/Blobject.swift | 16 +- swift/src/Ice/BlobjectAsync.swift | 15 +- swift/src/Ice/Communicator.swift | 12 +- swift/src/Ice/CommunicatorI.swift | 14 +- swift/src/Ice/CurrentExtensions.swift | 187 +++++++++++++ swift/src/Ice/Dispatcher.swift | 14 + swift/src/Ice/FacetMap.swift | 2 +- swift/src/Ice/Incoming.swift | 256 ------------------ swift/src/Ice/IncomingRequest.swift | 19 ++ swift/src/Ice/Initialize.swift | 3 +- swift/src/Ice/InputStream.swift | 2 +- swift/src/Ice/LocalExceptionDescription.swift | 2 +- swift/src/Ice/Object.swift | 106 ++++---- swift/src/Ice/ObjectAdapter.swift | 48 ++-- swift/src/Ice/ObjectAdapterI.swift | 81 +++--- swift/src/Ice/OutgoingResponse.swift | 41 +++ swift/src/Ice/OutputStream.swift | 17 +- swift/src/Ice/ReplyStatus.swift | 13 + swift/src/Ice/ServantLocator.swift | 12 +- swift/src/Ice/ServantManager.swift | 72 ++++- swift/src/IceImpl/AdminFacetFactory.h | 8 +- swift/src/IceImpl/BlobjectFacade.h | 57 ---- swift/src/IceImpl/BlobjectFacade.mm | 57 ---- swift/src/IceImpl/Communicator.h | 8 +- swift/src/IceImpl/Communicator.mm | 28 +- swift/src/IceImpl/DispatchAdapter.h | 54 ++++ swift/src/IceImpl/DispatchAdapter.mm | 54 ++++ swift/src/IceImpl/Exception.h | 39 --- swift/src/IceImpl/Exception.mm | 98 ------- swift/src/IceImpl/IceImpl.h | 2 +- swift/src/IceImpl/ObjectAdapter.h | 5 +- swift/src/IceImpl/ObjectAdapter.mm | 8 +- .../test/Ice/adapterDeactivation/TestI.swift | 4 +- swift/test/Ice/exceptions/AllTests.swift | 4 +- swift/test/Ice/invoke/Server.swift | 6 +- .../Ice/servantLocator/ServantLocatorI.swift | 4 +- 40 files changed, 785 insertions(+), 905 deletions(-) create mode 100644 swift/src/Ice/CurrentExtensions.swift create mode 100644 swift/src/Ice/Dispatcher.swift delete mode 100644 swift/src/Ice/Incoming.swift create mode 100644 swift/src/Ice/IncomingRequest.swift create mode 100644 swift/src/Ice/OutgoingResponse.swift create mode 100644 swift/src/Ice/ReplyStatus.swift delete mode 100644 swift/src/IceImpl/BlobjectFacade.h delete mode 100644 swift/src/IceImpl/BlobjectFacade.mm create mode 100644 swift/src/IceImpl/DispatchAdapter.h create mode 100644 swift/src/IceImpl/DispatchAdapter.mm delete mode 100644 swift/src/IceImpl/Exception.mm diff --git a/cpp/src/slice2swift/Gen.cpp b/cpp/src/slice2swift/Gen.cpp index 3cb95603b45..017db70eae1 100644 --- a/cpp/src/slice2swift/Gen.cpp +++ b/cpp/src/slice2swift/Gen.cpp @@ -1437,7 +1437,7 @@ Gen::ObjectVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p) out << sp; out << sp; out << nl << "/// Dispatcher for `" << servant << "` servants."; - out << nl << "public struct " << disp << ": " << getUnqualified("Ice.Disp", swiftModule); + out << nl << "public struct " << disp << ": Ice.Dispatcher"; out << sb; out << nl << "public let servant: " << servant; @@ -1468,42 +1468,33 @@ Gen::ObjectVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p) out << sp; out << nl; - out << "public func dispatch"; - out << spar; - out << ("request: " + getUnqualified("Ice.Request", swiftModule)); - out << ("current: " + getUnqualified("Ice.Current", swiftModule)); - out << epar; - out << " throws -> PromiseKit.Promise<" << getUnqualified("Ice.OutputStream", swiftModule) << ">?"; - + out << "public func dispatch(_ request: Ice.IncomingRequest) -> PromiseKit.Promise"; out << sb; - // Call startOver() so that dispatch interceptors can retry requests - out << nl << "request.startOver()"; - out << nl << "switch current.operation"; + out << nl; + out << "switch request.current.operation"; out << sb; out.dec(); // to align case with switch - for (StringList::const_iterator q = allOpNames.begin(); q != allOpNames.end(); ++q) + for (const auto& opName : allOpNames) { - const string opName = *q; out << nl << "case \"" << opName << "\":"; out.inc(); if (opName == "ice_id" || opName == "ice_ids" || opName == "ice_isA" || opName == "ice_ping") { - out << nl << "return try (servant as? Object ?? " << disp << ".defaultObject)._iceD_" << opName - << "(incoming: request, current: current)"; + out << nl << "(servant as? Ice.Object ?? " << disp << ".defaultObject)._iceD_" << opName << "(request)"; } else { - out << nl << "return try servant._iceD_" << opName << "(incoming: request, current: current)"; + out << nl << "servant._iceD_" << opName << "(request)"; } out.dec(); } out << nl << "default:"; out.inc(); - out << nl << "throw " << getUnqualified("Ice.OperationNotExistException", swiftModule) - << "(id: current.id, facet: current.facet, operation: current.operation)"; + out << nl << "PromiseKit.Promise(error: Ice.OperationNotExistException())"; // missing dec to compensate for the extra dec after switch sb out << eb; out << eb; + out << eb; // @@ -1604,7 +1595,7 @@ Gen::ObjectExtVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p) out << sp; writeServantDocSummary(out, p, swiftModule); - out << nl << "public extension " << fixIdent(name); + out << nl << "extension " << fixIdent(name); out << sb; return true; @@ -1619,12 +1610,5 @@ Gen::ObjectExtVisitor::visitInterfaceDefEnd(const InterfaceDefPtr&) void Gen::ObjectExtVisitor::visitOperation(const OperationPtr& op) { - if (operationIsAmd(op)) - { - writeDispatchAsyncOperation(out, op); - } - else - { - writeDispatchOperation(out, op); - } + writeDispatchOperation(out, op); } diff --git a/cpp/src/slice2swift/SwiftUtil.cpp b/cpp/src/slice2swift/SwiftUtil.cpp index 64bc8956a7e..73926bdf96d 100644 --- a/cpp/src/slice2swift/SwiftUtil.cpp +++ b/cpp/src/slice2swift/SwiftUtil.cpp @@ -2181,8 +2181,6 @@ SwiftGenerator::writeMarshalOutParams(::IceUtilInternal::Output& out, const Oper ParamInfoList requiredOutParams, optionalOutParams; getOutParams(op, requiredOutParams, optionalOutParams); - out << "{ ostr in"; - out.inc(); // // Marshal parameters // 1. required @@ -2203,9 +2201,6 @@ SwiftGenerator::writeMarshalOutParams(::IceUtilInternal::Output& out, const Oper { out << nl << "ostr.writePendingValues()"; } - - out.dec(); - out << nl << "}"; } void @@ -2214,8 +2209,7 @@ SwiftGenerator::writeMarshalAsyncOutParams(::IceUtilInternal::Output& out, const ParamInfoList requiredOutParams, optionalOutParams; getOutParams(op, requiredOutParams, optionalOutParams); - out << sb << " (ostr, retVals) in"; - out << nl << "let " << operationReturnDeclaration(op) << " = retVals"; + out << nl << "let " << operationReturnDeclaration(op) << " = value"; // // Marshal parameters // 1. required @@ -2236,8 +2230,6 @@ SwiftGenerator::writeMarshalAsyncOutParams(::IceUtilInternal::Output& out, const { out << nl << "ostr.writePendingValues()"; } - - out << eb; } void @@ -2330,8 +2322,6 @@ SwiftGenerator::writeUnmarshalInParams(::IceUtilInternal::Output& out, const Ope // 1. required // 3. optional // - out << "{ istr in"; - out.inc(); for (ParamInfoList::const_iterator q = requiredInParams.begin(); q != requiredInParams.end(); ++q) { if (q->param) @@ -2369,25 +2359,6 @@ SwiftGenerator::writeUnmarshalInParams(::IceUtilInternal::Output& out, const Ope { out << nl << "try istr.readPendingValues()"; } - - out << nl << "return "; - if (allInParams.size() > 1) - { - out << spar; - } - - for (ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) - { - out << ("iceP_" + q->name); - } - - if (allInParams.size() > 1) - { - out << epar; - } - - out.dec(); - out << nl << "}"; } void @@ -2610,111 +2581,98 @@ SwiftGenerator::writeDispatchOperation(::IceUtilInternal::Output& out, const Ope { const string opName = op->name(); - const ParamInfoList allInParams = getAllInParams(op); - const ParamInfoList allOutParams = getAllOutParams(op); - const ExceptionList allExceptions = op->throws(); + const ParamInfoList inParams = getAllInParams(op); + const ParamInfoList outParams = getAllOutParams(op); const string swiftModule = getSwiftModule(getTopLevelModule(dynamic_pointer_cast(op))); out << sp; - out << nl << "func _iceD_" << opName; - out << spar; - out << ("incoming inS: " + getUnqualified("Ice.Incoming", swiftModule)); - out << ("current: " + getUnqualified("Ice.Current", swiftModule)); - out << epar; - - out << " throws -> PromiseKit.Promise<" << getUnqualified("Ice.OutputStream", swiftModule) << ">?"; + out << nl << "public func _iceD_" << opName + << "(_ request: Ice.IncomingRequest) -> PromiseKit.Promise"; out << sb; - if (allInParams.empty()) - { - out << nl << "try inS.readEmptyParams()"; - } - else - { - out << nl << "let " << operationInParamsDeclaration(op) << " = try inS.read "; - writeUnmarshalInParams(out, op); - } - - if (op->format() != DefaultFormat) - { - out << nl << "inS.setFormat(" << opFormatTypeToString(op) << ")"; - } - out << sp; - out << nl; - if (!allOutParams.empty()) - { - out << "let " << operationReturnDeclaration(op) << " = "; - } - out << "try self." << fixIdent(opName); + out << nl << "do"; + out << sb; - out << spar; - for (ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) - { - out << (q->name + ": iceP_" + q->name); - } - out << "current: current"; - out << epar; + // TODO: check operation mode - out << sp << nl; - out << "return inS.setResult"; - if (allOutParams.empty()) + if (inParams.empty()) { - out << "()"; + out << nl << "_ = try request.inputStream.skipEmptyEncapsulation()"; } else { - writeMarshalOutParams(out, op); + out << nl << "let istr = request.inputStream"; + out << nl << "_ = try istr.startEncapsulation()"; + writeUnmarshalInParams(out, op); } - out << eb; -} - -void -SwiftGenerator::writeDispatchAsyncOperation(::IceUtilInternal::Output& out, const OperationPtr& op) -{ - const ParamInfoList allInParams = getAllInParams(op); - const ParamInfoList allOutParams = getAllOutParams(op); - - const string swiftModule = getSwiftModule(getTopLevelModule(dynamic_pointer_cast(op))); - - out << sp; - out << nl << "func _iceD_" << op->name(); - out << spar; - out << ("incoming inS: " + getUnqualified("Ice.Incoming", swiftModule)); - out << ("current: " + getUnqualified("Ice.Current", swiftModule)); - out << epar; - out << " throws -> PromiseKit.Promise<" << getUnqualified("Ice.OutputStream", swiftModule) << ">?"; - out << sb; - if (allInParams.empty()) + if (operationIsAmd(op)) { - out << nl << "try inS.readEmptyParams()"; + out << nl << "return self." << opName << "Async("; + out << nl << " "; // inc/dec doesn't work for an unknown reason + for (const auto& q : inParams) + { + out << q.name << ": iceP_" << q.name << ", "; + } + out << "current: request.current"; + out << nl; + out << ").map(on: nil)"; + out << sb; + if (outParams.empty()) + { + out << nl << "request.current.makeEmptyOutgoingResponse()"; + } + else + { + out << " result in "; + out << nl << "request.current.makeOutgoingResponse(result, formatType:" << opFormatTypeToString(op) << ")"; + out << sb; + out << " ostr, value in "; + writeMarshalAsyncOutParams(out, op); + out << eb; + } + out << eb; } else { - out << nl << "let " << operationInParamsDeclaration(op) << " = try inS.read "; - writeUnmarshalInParams(out, op); - } - - if (op->format() != DefaultFormat) - { - out << nl << "inS.setFormat(" << opFormatTypeToString(op) << ")"; - } + out << sp; + out << nl; + if (!outParams.empty()) + { + out << "let " << operationReturnDeclaration(op) << " = "; + } + out << "try self." << fixIdent(opName); + out << spar; + for (const auto& q : inParams) + { + out << (q.name + ": iceP_" + q.name); + } + out << "current: request.current"; + out << epar; - out << sp << nl; - out << "return inS.setResultPromise(" << fixIdent(op->name() + (operationIsAmd(op) ? "Async" : "")) << spar; - for (ParamInfoList::const_iterator q = allInParams.begin(); q != allInParams.end(); ++q) - { - out << (q->name + ": iceP_" + q->name); - } - out << "current: current" << epar; - out << ")"; - if (!allOutParams.empty()) - { - writeMarshalAsyncOutParams(out, op); + if (outParams.empty()) + { + out << nl << "return PromiseKit.Promise.value(request.current.makeEmptyOutgoingResponse())"; + } + else + { + out << nl << "let ostr = request.current.startReplyStream()"; + out << nl + << "ostr.startEncapsulation(encoding: request.current.encoding, format: " << opFormatTypeToString(op) + << ")"; + writeMarshalOutParams(out, op); + out << nl << "ostr.endEncapsulation()"; + out << nl << "return PromiseKit.Promise.value(Ice.OutgoingResponse(ostr))"; + } } out << eb; + out << " catch"; + out << sb; + out << nl << "return PromiseKit.Promise(error: error)"; + out << eb; + out << eb; } bool diff --git a/cpp/src/slice2swift/SwiftUtil.h b/cpp/src/slice2swift/SwiftUtil.h index 5105c7955c1..50e3e8c6e1b 100644 --- a/cpp/src/slice2swift/SwiftUtil.h +++ b/cpp/src/slice2swift/SwiftUtil.h @@ -153,7 +153,6 @@ namespace Slice void writeProxyOperation(::IceUtilInternal::Output&, const OperationPtr&); void writeProxyAsyncOperation(::IceUtilInternal::Output&, const OperationPtr&); void writeDispatchOperation(::IceUtilInternal::Output&, const OperationPtr&); - void writeDispatchAsyncOperation(::IceUtilInternal::Output&, const OperationPtr&); private: class MetaDataVisitor : public ParserVisitor diff --git a/swift/src/Ice/AdminFacetFactory.swift b/swift/src/Ice/AdminFacetFactory.swift index 11c15870b24..a8eb22860c3 100644 --- a/swift/src/Ice/AdminFacetFactory.swift +++ b/swift/src/Ice/AdminFacetFactory.swift @@ -1,19 +1,17 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// +// Copyright (c) ZeroC, Inc. import IceImpl -class AdminFacetFacade: ICEBlobjectFacade { +class AdminFacetFacade: ICEDispatchAdapter { private let communicator: Communicator - var disp: Disp + var dispatcher: Dispatcher - init(communicator: Communicator, disp: Disp) { + init(communicator: Communicator, dispatcher: Dispatcher) { self.communicator = communicator - self.disp = disp + self.dispatcher = dispatcher } - func facadeInvoke( + func dispatch( _ adapter: ICEObjectAdapter, inEncapsBytes: UnsafeMutableRawPointer, inEncapsCount: Int, @@ -27,7 +25,7 @@ class AdminFacetFacade: ICEBlobjectFacade { requestId: Int32, encodingMajor: UInt8, encodingMinor: UInt8, - sendResponse: @escaping ICESendResponse + completionHandler: @escaping ICEOutgoingResponse ) { let objectAdapter = adapter.getSwiftObject(ObjectAdapterI.self) { let oa = ObjectAdapterI(handle: adapter, communicator: communicator) @@ -39,7 +37,8 @@ class AdminFacetFacade: ICEBlobjectFacade { return oa } - let connection = con?.getSwiftObject(ConnectionI.self) { ConnectionI(handle: con!) } ?? nil + let connection = con?.getSwiftObject(ConnectionI.self) { ConnectionI(handle: con!) } + let encoding = EncodingVersion(major: encodingMajor, minor: encodingMinor) let current = Current( adapter: objectAdapter, @@ -50,40 +49,39 @@ class AdminFacetFacade: ICEBlobjectFacade { mode: OperationMode(rawValue: mode)!, ctx: context, requestId: requestId, - encoding: EncodingVersion(major: encodingMajor, minor: encodingMinor)) - - let incoming = Incoming( - istr: InputStream( - communicator: communicator, - encoding: EncodingVersion( - major: encodingMajor, - minor: encodingMinor), - bytes: Data( - bytesNoCopy: inEncapsBytes, count: inEncapsCount, - deallocator: .none)), - sendResponse: sendResponse, - current: current) - - // Dispatch directly to the servant. Do not call invoke on Incoming - do { - // Request was dispatched asynchronously if promise is non-nil - if let promise = try disp.dispatch(request: incoming, current: current) { - // Use the thread which fulfilled the promise (on: nil) - promise.done(on: nil) { ostr in - incoming.setResult(ostr) - incoming.response() - }.catch(on: nil) { error in - incoming.exception(error) - } - } else { - incoming.response() + encoding: encoding) + + let istr = InputStream( + communicator: communicator, + encoding: encoding, + bytes: Data(bytesNoCopy: inEncapsBytes, count: inEncapsCount, deallocator: .none)) + + let request = IncomingRequest(current: current, inputStream: istr) + + // Dispatch directly to the servant. + dispatcher.dispatch(request).map { response in + response.outputStream.finished().withUnsafeBytes { + completionHandler( + response.replyStatus.rawValue, + response.exceptionId, + response.exceptionMessage, + $0.baseAddress!, + $0.count) + } + }.catch { error in + let response = current.makeOutgoingResponse(error: error) + response.outputStream.finished().withUnsafeBytes { + completionHandler( + response.replyStatus.rawValue, + response.exceptionId, + response.exceptionMessage, + $0.baseAddress!, + $0.count) } - } catch { - incoming.exception(error) } } - func facadeRemoved() {} + func complete() {} } final class UnsupportedAdminFacet: LocalObject, Object { @@ -103,39 +101,34 @@ final class UnsupportedAdminFacet: LocalObject, Object } class AdminFacetFactory: ICEAdminFacetFactory { - static func createProcess(_ communicator: ICECommunicator, handle: ICEProcess) - -> ICEBlobjectFacade - { + static func createProcess(_ communicator: ICECommunicator, handle: ICEProcess) -> ICEDispatchAdapter { let c = communicator.getCachedSwiftObject(CommunicatorI.self) return AdminFacetFacade( communicator: c, - disp: ProcessDisp( + dispatcher: ProcessDisp( handle.getSwiftObject(ProcessI.self) { ProcessI(handle: handle) })) } - static func createProperties(_ communicator: ICECommunicator, handle: ICEPropertiesAdmin) - -> ICEBlobjectFacade - { + static func createProperties(_ communicator: ICECommunicator, handle: ICEPropertiesAdmin) -> ICEDispatchAdapter { let c = communicator.getCachedSwiftObject(CommunicatorI.self) return AdminFacetFacade( communicator: c, - disp: PropertiesAdminDisp( + dispatcher: PropertiesAdminDisp( handle.getSwiftObject(PropertiesAdminI.self) { PropertiesAdminI(communicator: c, handle: handle) })) } - static func createUnsupported( - _ communicator: ICECommunicator, - handle: ICEUnsupportedAdminFacet - ) -> ICEBlobjectFacade { + static func createUnsupported(_ communicator: ICECommunicator, handle: ICEUnsupportedAdminFacet) + -> ICEDispatchAdapter + { let c = communicator.getCachedSwiftObject(CommunicatorI.self) return AdminFacetFacade( communicator: c, - disp: ObjectDisp( + dispatcher: ObjectDisp( handle.getSwiftObject(UnsupportedAdminFacet.self) { UnsupportedAdminFacet(handle: handle) })) diff --git a/swift/src/Ice/Blobject.swift b/swift/src/Ice/Blobject.swift index d2739a5ce60..09f7b729f47 100644 --- a/swift/src/Ice/Blobject.swift +++ b/swift/src/Ice/Blobject.swift @@ -26,17 +26,21 @@ public protocol Blobject { } /// Request dispatcher for Blobject servants. -public struct BlobjectDisp: Disp { +public struct BlobjectDisp: Dispatcher { public let servant: Blobject public init(_ servant: Blobject) { self.servant = servant } - public func dispatch(request: Request, current: Current) throws -> Promise? { - let inEncaps = try request.readParamEncaps() - let invokeResult = try servant.ice_invoke(inEncaps: inEncaps, current: current) - return request.setResult( - request.writeParamEncaps(ok: invokeResult.ok, outParams: invokeResult.outParams)) + public func dispatch(_ request: IncomingRequest) -> Promise { + do { + let (inEncaps, _) = try request.inputStream.readEncapsulation() + let result = try servant.ice_invoke(inEncaps: inEncaps, current: request.current) + return Promise.value( + request.current.makeOutgoingResponse(ok: result.ok, encapsulation: result.outParams)) + } catch { + return Promise(error: error) + } } } diff --git a/swift/src/Ice/BlobjectAsync.swift b/swift/src/Ice/BlobjectAsync.swift index a3ce3a3fea2..098e6a06cf4 100644 --- a/swift/src/Ice/BlobjectAsync.swift +++ b/swift/src/Ice/BlobjectAsync.swift @@ -26,18 +26,21 @@ public protocol BlobjectAsync { } /// Request dispatcher for BlobjectAsync servants. -public struct BlobjectAsyncDisp: Disp { +public struct BlobjectAsyncDisp: Dispatcher { public let servant: BlobjectAsync public init(_ servant: BlobjectAsync) { self.servant = servant } - public func dispatch(request: Request, current: Current) throws -> Promise? { - let inEncaps = try request.readParamEncaps() - return servant.ice_invokeAsync(inEncaps: inEncaps, current: current).map(on: nil) { - invokeResult in - request.writeParamEncaps(ok: invokeResult.ok, outParams: invokeResult.outParams) + public func dispatch(_ request: IncomingRequest) -> Promise { + do { + let (inEncaps, _) = try request.inputStream.readEncapsulation() + return servant.ice_invokeAsync(inEncaps: inEncaps, current: request.current).map(on: nil) { result in + request.current.makeOutgoingResponse(ok: result.ok, encapsulation: result.outParams) + } + } catch { + return Promise(error: error) } } } diff --git a/swift/src/Ice/Communicator.swift b/swift/src/Ice/Communicator.swift index c9e431ccfcb..63c28cda9fb 100644 --- a/swift/src/Ice/Communicator.swift +++ b/swift/src/Ice/Communicator.swift @@ -301,27 +301,27 @@ public protocol Communicator: Swift.AnyObject { /// Add a new facet to the Admin object. Adding a servant with a facet that is already registered throws /// AlreadyRegisteredException. /// - /// - parameter servant: `Disp` The servant that implements the new Admin facet. + /// - parameter servant: `Dispatcher` The servant that implements the new Admin facet. /// /// - parameter facet: `Swift.String` The name of the new Admin facet. - func addAdminFacet(servant: Disp, facet: Swift.String) throws + func addAdminFacet(servant: Dispatcher, facet: Swift.String) throws /// Remove the following facet to the Admin object. Removing a facet that was not previously registered throws /// NotRegisteredException. /// /// - parameter _: `Swift.String` The name of the Admin facet. /// - /// - returns: `Disp` - The servant associated with this Admin facet. + /// - returns: `Dispatcher` - The servant associated with this Admin facet. @discardableResult - func removeAdminFacet(_ facet: Swift.String) throws -> Disp + func removeAdminFacet(_ facet: Swift.String) throws -> Dispatcher /// Returns a facet of the Admin object. /// /// - parameter _: `Swift.String` The name of the Admin facet. /// - /// - returns: `Disp?` - The servant associated with this Admin facet, or null if no facet is registered with the + /// - returns: `Dispatcher?` - The servant associated with this Admin facet, or null if no facet is registered with the /// given name. - func findAdminFacet(_ facet: Swift.String) -> Disp? + func findAdminFacet(_ facet: Swift.String) -> Dispatcher? /// Returns a map of all facets of the Admin object. /// diff --git a/swift/src/Ice/CommunicatorI.swift b/swift/src/Ice/CommunicatorI.swift index 0b4959f5478..ae49337de98 100644 --- a/swift/src/Ice/CommunicatorI.swift +++ b/swift/src/Ice/CommunicatorI.swift @@ -200,29 +200,29 @@ class CommunicatorI: LocalObject, Communicator { } } - func addAdminFacet(servant disp: Disp, facet: String) throws { + func addAdminFacet(servant dispatcher: Dispatcher, facet: String) throws { try autoreleasepool { - try handle.addAdminFacet(AdminFacetFacade(communicator: self, disp: disp), facet: facet) + try handle.addAdminFacet(AdminFacetFacade(communicator: self, dispatcher: dispatcher), facet: facet) } } - func removeAdminFacet(_ facet: String) throws -> Disp { + func removeAdminFacet(_ facet: String) throws -> Dispatcher { return try autoreleasepool { guard let facade = try handle.removeAdminFacet(facet) as? AdminFacetFacade else { preconditionFailure() } - return facade.disp + return facade.dispatcher } } - func findAdminFacet(_ facet: String) -> Disp? { + func findAdminFacet(_ facet: String) -> Dispatcher? { do { return try autoreleasepool { guard let facade = try handle.findAdminFacet(facet) as? AdminFacetFacade else { return nil } - return facade.disp + return facade.dispatcher } } catch is CommunicatorDestroyedException { // Ignored @@ -236,7 +236,7 @@ class CommunicatorI: LocalObject, Communicator { do { return try autoreleasepool { try handle.findAllAdminFacets().mapValues { facade in - (facade as! AdminFacetFacade).disp + (facade as! AdminFacetFacade).dispatcher } } } catch is CommunicatorDestroyedException { diff --git a/swift/src/Ice/CurrentExtensions.swift b/swift/src/Ice/CurrentExtensions.swift new file mode 100644 index 00000000000..588c3e844b5 --- /dev/null +++ b/swift/src/Ice/CurrentExtensions.swift @@ -0,0 +1,187 @@ +// Copyright (c) ZeroC, Inc. + +import Foundation + +extension Current { + /// Creates an outgoing response with reply status `ok`. + /// - Parameters: + /// - result: The result to marshal into the response payload. + /// - formatType: The class format. + /// - marshal: The action that marshals result into an output stream. + /// - Returns: The outgoing response. + public func makeOutgoingResponse(_ result: T, formatType: FormatType, marshal: (OutputStream, T) -> Void) + -> OutgoingResponse + { + precondition(requestId != 0, "A one-way request cannot return a response") + let ostr = startReplyStream() + ostr.startEncapsulation(encoding: encoding, format: formatType) + marshal(ostr, result) + ostr.endEncapsulation() + return OutgoingResponse(ostr) + } + + /// Creates an empty outgoing response with reply status `ok`. + /// - Returns: The outgoing response. + public func makeEmptyOutgoingResponse() -> OutgoingResponse { + let ostr = startReplyStream() + if requestId != 0 { + ostr.writeEmptyEncapsulation(encoding) + } + return OutgoingResponse(ostr) + } + + /// Creates an outgoing response with the specified payload. + /// - Parameters: + /// - ok: When true, the reply status of the response is `ok`; otherwise, it's `userException`. + /// - encapsulation: The payload of the response. + /// - Returns: The outgoing response. + public func makeOutgoingResponse(ok: Bool, encapsulation: Data) -> OutgoingResponse { + let ostr = startReplyStream(replyStatus: ok ? .ok : .userException) + + if requestId != 0 { + if encapsulation.isEmpty { + ostr.writeEmptyEncapsulation(encoding) + } else { + ostr.writeEncapsulation(encapsulation) + } + } + return OutgoingResponse(ostr) + } + + /// Creates an outgoing response that marshals an exception. + /// - Parameter error: The exception to marshal into the response payload. + /// - Returns: The outgoing response. + public func makeOutgoingResponse(error: Error) -> OutgoingResponse { + let ostr = OutputStream(communicator: adapter.getCommunicator(), encoding: currentProtocolEncoding) + + if requestId != 0 { + ostr.writeBlob(replyHdr) + ostr.write(requestId) + } + + var replyStatus: ReplyStatus + var exceptionId: String? + var exceptionMessage: String? + + switch error { + case let rfe as RequestFailedException: + exceptionId = rfe.ice_id() + + replyStatus = + switch rfe { + case is ObjectNotExistException: + .objectNotExist + case is FacetNotExistException: + .facetNotExist + case is OperationNotExistException: + .operationNotExist + default: + fatalError("Unexpected RequestFailedException subclass") + } + + if rfe.id.name.isEmpty { + rfe.id = id + } + + if rfe.facet.isEmpty { + rfe.facet = facet + } + + if rfe.operation.isEmpty { + rfe.operation = operation + } + + // We must call ice_print _after_ setting the properties above. + exceptionMessage = rfe.ice_print() + + if requestId != 0 { + ostr.write(replyStatus.rawValue) + ostr.write(rfe.id) + if rfe.facet.isEmpty { + ostr.write(size: 0) + } else { + ostr.write([rfe.facet]) + } + ostr.write(rfe.operation) + } + + case let ex as UserException: + exceptionId = ex.ice_id() + exceptionMessage = "\(ex)" + replyStatus = .userException + + if requestId != 0 { + ostr.write(replyStatus.rawValue) + ostr.startEncapsulation(encoding: encoding, format: .SlicedFormat) + ostr.write(ex) + ostr.endEncapsulation() + } + + case let ex as UnknownLocalException: + exceptionId = ex.ice_id() + replyStatus = .unknownLocalException + exceptionMessage = ex.unknown + + case let ex as UnknownUserException: + exceptionId = ex.ice_id() + replyStatus = .unknownUserException + exceptionMessage = ex.unknown + + case let ex as UnknownException: + exceptionId = ex.ice_id() + replyStatus = .unknownException + exceptionMessage = ex.unknown + + case let ex as LocalException: + exceptionId = ex.ice_id() + replyStatus = .unknownLocalException + exceptionMessage = "\(ex)" + + case let ex as Exception: + exceptionId = ex.ice_id() + replyStatus = .unknownException + exceptionMessage = "\(ex)" + + default: + replyStatus = .unknownException + exceptionId = "\(type(of: error))" + exceptionMessage = "\(error)" + } + + if requestId != 0, + replyStatus == .unknownUserException || replyStatus == .unknownLocalException + || replyStatus == .unknownException + { + ostr.write(replyStatus.rawValue) + ostr.write(exceptionMessage!) + } + + return OutgoingResponse( + replyStatus: replyStatus, exceptionId: exceptionId, exceptionMessage: exceptionMessage, outputStream: ostr) + } + + /// Starts the output stream for a reply, with everything up to and including the reply status. When the request ID + /// is 0 (one-way request), the returned output stream is empty. + /// - Parameter replyStatus: The reply status. + /// - Returns: The output stream. + public func startReplyStream(replyStatus: ReplyStatus = .ok) -> OutputStream { + let ostr = OutputStream(communicator: adapter.getCommunicator(), encoding: currentProtocolEncoding) + if requestId != 0 { + ostr.writeBlob(replyHdr) + ostr.write(requestId) + ostr.write(replyStatus.rawValue) + } + return ostr + } +} + +private let currentProtocolEncoding = EncodingVersion(major: 1, minor: 0) + +private let replyHdr: [UInt8] = [ + 0x49, 0x63, 0x65, 0x50, // IceP magic + 1, 0, // Protocol version (1.0) + 1, 0, // Protocol encoding version (1.0) + 2, // Reply message + 0, // Compression status (not compressed) + 0, 0, 0, 0, // Message size (placeholder) +] diff --git a/swift/src/Ice/Dispatcher.swift b/swift/src/Ice/Dispatcher.swift new file mode 100644 index 00000000000..3db1c813d42 --- /dev/null +++ b/swift/src/Ice/Dispatcher.swift @@ -0,0 +1,14 @@ +// Copyright (c) ZeroC, Inc. + +import PromiseKit + +/// A dispatcher accepts incoming requests and returns outgoing responses. +public protocol Dispatcher { + /// Dispatches an incoming request and returns the corresponding outgoing response. + /// - Parameter request: The incoming request. + /// - Returns: The outgoing response, wrapped in a Promise. + func dispatch(_ request: IncomingRequest) -> Promise +} + +@available(*, deprecated, renamed: "Dispatcher") +public typealias Disp = Dispatcher diff --git a/swift/src/Ice/FacetMap.swift b/swift/src/Ice/FacetMap.swift index ae8e41978ce..259236d649d 100644 --- a/swift/src/Ice/FacetMap.swift +++ b/swift/src/Ice/FacetMap.swift @@ -16,4 +16,4 @@ import Foundation /// A mapping from facet name to servant. -public typealias FacetMap = [Swift.String: Disp] +public typealias FacetMap = [Swift.String: Dispatcher] diff --git a/swift/src/Ice/Incoming.swift b/swift/src/Ice/Incoming.swift deleted file mode 100644 index 4ceba0984b2..00000000000 --- a/swift/src/Ice/Incoming.swift +++ /dev/null @@ -1,256 +0,0 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// - -import Foundation -import IceImpl -import PromiseKit - -public final class Incoming { - private let current: Current - private var format: FormatType - private let istr: InputStream - - // sendResponse must be called exactly once. It's likely the current implementation does not guarantee it. - private let sendResponse: ICESendResponse - - private var servant: Disp? - private var locator: ServantLocator? - private var cookie: AnyObject? - - private var ostr: OutputStream! // must be set before calling sendResponse - private var ok: Bool // false if response contains a UserException - - init( - istr: InputStream, sendResponse: @escaping ICESendResponse, - current: Current - ) { - self.istr = istr - format = .DefaultFormat - ok = true - self.sendResponse = sendResponse - self.current = current - } - - public func readEmptyParams() throws { - let encoding = try istr.startEncapsulation() - assert(encoding == current.encoding) - } - - public func readParamEncaps() throws -> Data { - let params = try istr.readEncapsulation() - assert(params.encoding == current.encoding) - return params.bytes - } - - public func read(_ cb: (InputStream) throws -> T) throws -> T { - let encoding = try istr.startEncapsulation() - assert(encoding == current.encoding) - let l = try cb(istr) - try istr.endEncapsulation() - return l - } - - public func startOver() { - istr.startOver() - ostr = nil - } - - public func writeParamEncaps(ok: Bool, outParams: Data) -> OutputStream { - let ostr = OutputStream(communicator: istr.communicator, encoding: current.encoding) - if outParams.isEmpty { - ostr.writeEmptyEncapsulation(current.encoding) - } else { - ostr.writeEncapsulation(outParams) - } - self.ok = ok - - return ostr - } - - public func response() { - guard locator == nil || servantLocatorFinished() else { - return - } - precondition(ostr != nil, "OutputStream was not set before calling response()") - ostr.finished().withUnsafeBytes { - sendResponse(ok, $0.baseAddress!, $0.count, nil) - } - } - - public func exception(_ ex: Error) { - guard locator == nil || servantLocatorFinished() else { - return - } - handleException(ex) - } - - public func setFormat(_ format: FormatType) { - self.format = format - } - - @discardableResult - public func setResult(_ os: OutputStream) -> Promise? { - ostr = os - return nil // Response is cached in the Incoming to not have to create unnecessary promise - } - - public func setResult() -> Promise? { - let ostr = OutputStream(communicator: istr.communicator) - ostr.writeEmptyEncapsulation(current.encoding) - self.ostr = ostr - return nil // Response is cached in the Incoming to not have to create unnecessary future - } - - public func setResult(_ cb: (OutputStream) -> Void) -> Promise? { - let ostr = OutputStream(communicator: istr.communicator) - ostr.startEncapsulation(encoding: current.encoding, format: format) - cb(ostr) - ostr.endEncapsulation() - self.ostr = ostr - return nil // Response is cached in the Incoming to not have to create unnecessary future - } - - public func setResultPromise(_ p: Promise) -> Promise { - // Use the thread which fulfilled the promise (on: nil) - return p.map(on: nil) { - let ostr = OutputStream(communicator: self.istr.communicator) - ostr.writeEmptyEncapsulation(self.current.encoding) - return ostr - } - } - - public func setResultPromise( - _ p: Promise, - _ cb: @escaping (OutputStream, T) -> Void - ) -> Promise { - // Use the thread which fulfilled the promise (on: nil) - return p.map(on: nil) { t in - let ostr = OutputStream(communicator: self.istr.communicator) - ostr.startEncapsulation(encoding: self.current.encoding, format: self.format) - cb(ostr, t) - ostr.endEncapsulation() - return ostr - } - } - - func servantLocatorFinished() -> Bool { - guard let locator = locator, let servant = servant else { - preconditionFailure() - } - - do { - try locator.finished(curr: current, servant: servant, cookie: cookie) - return true - } catch { - handleException(error) - } - - return false - } - - func invoke(_ servantManager: ServantManager) { - servant = servantManager.findServant(id: current.id, facet: current.facet) - - if servant == nil { - locator = servantManager.findServantLocator(category: current.id.category) - - if locator == nil, !current.id.category.isEmpty { - locator = servantManager.findServantLocator(category: "") - } - - if let locator = locator { - do { - let locatorReturn = try locator.locate(current) - (servant, cookie) = (locatorReturn.returnValue, locatorReturn.cookie) - } catch { - handleException(error) - return - } - } - } - - guard let s = servant else { - do { - if servantManager.hasServant(id: current.id) || servantManager.isAdminId(current.id) { - throw FacetNotExistException( - id: current.id, facet: current.facet, operation: current.operation) - } else { - throw ObjectNotExistException( - id: current.id, facet: current.facet, operation: current.operation) - } - } catch { - sendResponse(false, nil, 0, convertIntoDispatchException(error)) - return - } - } - - // - // Dispatch in the incoming call - // - do { - // Request was dispatched asynchronously if promise is non-nil - if let promise = try s.dispatch(request: self, current: current) { - // Use the thread which fulfilled the promise (on: nil) - promise.done(on: nil) { ostr in - self.ostr = ostr - self.response() - }.catch(on: nil) { error in - self.exception(error) - } - } else { - response() - } - } catch { - exception(error) - } - } - - func handleException(_ exception: Error) { - guard let e = exception as? UserException else { - sendResponse(false, nil, 0, convertIntoDispatchException(exception)) - return - } - ok = false // response will contain a UserException - let ostr = OutputStream(communicator: istr.communicator) - ostr.startEncapsulation(encoding: current.encoding, format: format) - ostr.write(e) - ostr.endEncapsulation() - ostr.finished().withUnsafeBytes { - sendResponse(ok, $0.baseAddress!, $0.count, nil) - } - } - - // This code is temporary: we should give a fully marshaled response back to the Objective-C++ code. - func convertIntoDispatchException(_ exception: Error) -> ICEDispatchException { - switch exception { - // OperationNotExistException and friends - case let e as ObjectNotExistException: - ICEDispatchException.objectNotExistException( - e.id.name, category: e.id.category, facet: e.facet, operation: e.operation, file: e.file, - line: e.line) - case let e as FacetNotExistException: - ICEDispatchException.facetNotExistException( - e.id.name, category: e.id.category, facet: e.facet, operation: e.operation, file: e.file, - line: e.line) - case let e as OperationNotExistException: - ICEDispatchException.operationNotExistException( - e.id.name, category: e.id.category, facet: e.facet, operation: e.operation, file: e.file, - line: e.line) - // Unknown exceptions - case let e as UnknownUserException: - ICEDispatchException.unknownUserException(e.unknown, file: e.file, line: e.line) - case let e as UnknownLocalException: - ICEDispatchException.unknownLocalException(e.unknown, file: e.file, line: e.line) - case let e as UnknownException: - ICEDispatchException.unknownException(e.unknown, file: e.file, line: e.line) - // Other exceptions mapped to Unknown exceptions - case let e as LocalException: - ICEDispatchException.unknownLocalException("\(e)", file: e.file, line: e.line) - case let e as UserException: - ICEDispatchException.unknownUserException("\(e.ice_id())", file: #file, line: #line) - default: - ICEDispatchException.unknownException("\(exception)", file: #file, line: #line) - } - } -} diff --git a/swift/src/Ice/IncomingRequest.swift b/swift/src/Ice/IncomingRequest.swift new file mode 100644 index 00000000000..870db573baa --- /dev/null +++ b/swift/src/Ice/IncomingRequest.swift @@ -0,0 +1,19 @@ +// Copyright (c) ZeroC, Inc. + +/// Represents a request received by a connection. It's the argument given to `Dispatcher.dispatch`. +public final class IncomingRequest { + /// Gets the current object for the request. + public let current: Current + + /// Gets the incoming stream buffer of the request. + public let inputStream: InputStream + + /// Constructs an incoming request. + /// - parameter current: The current object for the request. + /// - parameter inputStream: The input stream buffer over the incoming Ice protocol request message. The stream is + /// positioned at the beginning of the encapsulation in the request. + public init(current: Current, inputStream: InputStream) { + self.current = current + self.inputStream = inputStream + } +} diff --git a/swift/src/Ice/Initialize.swift b/swift/src/Ice/Initialize.swift index 18a20689b4c..35b56a14a7c 100644 --- a/swift/src/Ice/Initialize.swift +++ b/swift/src/Ice/Initialize.swift @@ -265,7 +265,7 @@ public let currentEncoding = Encoding_1_1 /// - returns: `Ice.Identity` - The converted object identity. public func stringToIdentity(_ string: String) throws -> Identity { guard factoriesRegistered else { - fatalError("Unable to initialie Ice") + fatalError("Unable to initialize Ice") } return try autoreleasepool { var name = NSString() @@ -284,6 +284,7 @@ public func stringToIdentity(_ string: String) throws -> Identity { /// /// - returns: `String` - The string representation of the object identity. public func identityToString(id: Identity, mode: ToStringMode = ToStringMode.Unicode) -> String { + precondition(!id.name.isEmpty, "Invalid identity with an empty name") return ICEUtil.identityToString(name: id.name, category: id.category, mode: mode.rawValue) } diff --git a/swift/src/Ice/InputStream.swift b/swift/src/Ice/InputStream.swift index 4aec3adbdef..a9bb27e2356 100644 --- a/swift/src/Ice/InputStream.swift +++ b/swift/src/Ice/InputStream.swift @@ -130,7 +130,7 @@ public class InputStream { /// /// - returns: `Ice.EncodingVersion` - The encapsulation's encoding version. @discardableResult - func skipEmptyEncapsulation() throws -> EncodingVersion { + public func skipEmptyEncapsulation() throws -> EncodingVersion { let sz: Int32 = try read() if sz < 6 { diff --git a/swift/src/Ice/LocalExceptionDescription.swift b/swift/src/Ice/LocalExceptionDescription.swift index cdc1015e203..a39809c0131 100644 --- a/swift/src/Ice/LocalExceptionDescription.swift +++ b/swift/src/Ice/LocalExceptionDescription.swift @@ -20,7 +20,7 @@ extension String { } fileprivate mutating func failedRequest(_ ex: RequestFailedException) { - let id: String = identityToString(id: ex.id, mode: .Unicode) + let id = ex.id.name.isEmpty ? "" : identityToString(id: ex.id, mode: .Unicode) sep("identity: `\(id)'") nl("facet: \(ex.facet)") nl("operation: \(ex.operation)") diff --git a/swift/src/Ice/Object.swift b/swift/src/Ice/Object.swift index 6370d529f67..8bfb1f56bf6 100644 --- a/swift/src/Ice/Object.swift +++ b/swift/src/Ice/Object.swift @@ -5,20 +5,6 @@ import IceImpl import PromiseKit -/// Request is an opaque type that represents an incoming request. -public typealias Request = Incoming - -/// A request dispatcher (Disp) is a helper struct used by object adapters to dispatch -/// requests to servants. -public protocol Disp { - /// Dispatch request to servant. - /// - /// - parameter request: `Ice.Request` - The incoming request. - /// - /// - parameter current: `Ice.Current` - The Current object for the dispatch. - func dispatch(request: Request, current: Current) throws -> Promise? -} - /// A SliceTraits struct describes a Slice interface, class or exception. public protocol SliceTraits { /// List of all type-ids. @@ -61,50 +47,55 @@ public protocol Object { } extension Object { - public func _iceD_ice_id(incoming inS: Incoming, current: Current) throws -> Promise< - OutputStream - >? { - try inS.readEmptyParams() - - let returnValue = try ice_id(current: current) - - return inS.setResult { ostr in - ostr.write(returnValue) + public func _iceD_ice_id(_ request: IncomingRequest) -> Promise { + do { + _ = try request.inputStream.skipEmptyEncapsulation() + let returnValue = try ice_id(current: request.current) + return Promise.value( + request.current.makeOutgoingResponse(returnValue, formatType: .DefaultFormat) { ostr, value in + ostr.write(value) + }) + } catch { + return Promise(error: error) } } - public func _iceD_ice_ids(incoming inS: Incoming, current: Current) throws -> Promise< - OutputStream - >? { - try inS.readEmptyParams() - - let returnValue = try ice_ids(current: current) - - return inS.setResult { ostr in - ostr.write(returnValue) + public func _iceD_ice_ids(_ request: IncomingRequest) -> Promise { + do { + _ = try request.inputStream.skipEmptyEncapsulation() + let returnValue = try ice_ids(current: request.current) + return Promise.value( + request.current.makeOutgoingResponse(returnValue, formatType: .DefaultFormat) { ostr, value in + ostr.write(value) + }) + } catch { + return Promise(error: error) } } - public func _iceD_ice_isA(incoming inS: Incoming, current: Current) throws -> Promise< - OutputStream - >? { - let ident: String = try inS.read { istr in - try istr.read() - } - - let returnValue = try ice_isA(id: ident, current: current) - - return inS.setResult { ostr in - ostr.write(returnValue) + public func _iceD_ice_isA(_ request: IncomingRequest) -> Promise { + do { + let istr = request.inputStream + _ = try istr.startEncapsulation() + let identity: String = try istr.read() + let returnValue = try ice_isA(id: identity, current: request.current) + return Promise.value( + request.current.makeOutgoingResponse(returnValue, formatType: .DefaultFormat) { ostr, value in + ostr.write(value) + }) + } catch { + return Promise(error: error) } } - public func _iceD_ice_ping(incoming inS: Incoming, current: Current) throws -> Promise< - OutputStream - >? { - try inS.readEmptyParams() - try ice_ping(current: current) - return inS.setResult() + public func _iceD_ice_ping(_ request: IncomingRequest) -> Promise { + do { + _ = try request.inputStream.skipEmptyEncapsulation() + try ice_ping(current: request.current) + return Promise.value(request.current.makeEmptyOutgoingResponse()) + } catch { + return Promise(error: error) + } } } @@ -137,26 +128,25 @@ open class ObjectI: Object { } /// Request dispatcher for plain Object servants. -public struct ObjectDisp: Disp { +public struct ObjectDisp: Dispatcher { public let servant: Object public init(_ servant: Object) { self.servant = servant } - public func dispatch(request: Request, current: Current) throws -> Promise? { - switch current.operation { + public func dispatch(_ request: IncomingRequest) -> Promise { + switch request.current.operation { case "ice_id": - return try servant._iceD_ice_id(incoming: request, current: current) + servant._iceD_ice_id(request) case "ice_ids": - return try servant._iceD_ice_ids(incoming: request, current: current) + servant._iceD_ice_ids(request) case "ice_isA": - return try servant._iceD_ice_isA(incoming: request, current: current) + servant._iceD_ice_isA(request) case "ice_ping": - return try servant._iceD_ice_ping(incoming: request, current: current) + servant._iceD_ice_ping(request) default: - throw OperationNotExistException( - id: current.id, facet: current.facet, operation: current.operation) + Promise(error: OperationNotExistException()) } } } diff --git a/swift/src/Ice/ObjectAdapter.swift b/swift/src/Ice/ObjectAdapter.swift index 6f59dc0647e..5a3330cd670 100644 --- a/swift/src/Ice/ObjectAdapter.swift +++ b/swift/src/Ice/ObjectAdapter.swift @@ -73,18 +73,18 @@ public protocol ObjectAdapter: Swift.AnyObject { /// objects by registering the servant with multiple identities. Adding a servant with an identity that is in the /// map already throws AlreadyRegisteredException. /// - /// - parameter servant: `Disp` The servant to add. + /// - parameter servant: `Dispatcher` The servant to add. /// /// - parameter id: `Identity` The identity of the Ice object that is implemented by the servant. /// /// - returns: `ObjectPrx` - A proxy that matches the given identity and this object adapter. @discardableResult - func add(servant: Disp, id: Identity) throws -> ObjectPrx + func add(servant: Dispatcher, id: Identity) throws -> ObjectPrx /// Like add, but with a facet. Calling add(servant, id) is equivalent to calling /// addFacet with an empty facet. /// - /// - parameter servant: `Disp` The servant to add. + /// - parameter servant: `Dispatcher` The servant to add. /// /// - parameter id: `Identity` The identity of the Ice object that is implemented by the servant. /// @@ -92,28 +92,28 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - returns: `ObjectPrx` - A proxy that matches the given identity, facet, and this object adapter. @discardableResult - func addFacet(servant: Disp, id: Identity, facet: Swift.String) throws -> ObjectPrx + func addFacet(servant: Dispatcher, id: Identity, facet: Swift.String) throws -> ObjectPrx /// Add a servant to this object adapter's Active Servant Map, using an automatically generated UUID as its /// identity. Note that the generated UUID identity can be accessed using the proxy's ice_getIdentity /// operation. /// - /// - parameter _: `Disp` The servant to add. + /// - parameter _: `Dispatcher` The servant to add. /// /// - returns: `ObjectPrx` - A proxy that matches the generated UUID identity and this object adapter. @discardableResult - func addWithUUID(_ servant: Disp) throws -> ObjectPrx + func addWithUUID(_ servant: Dispatcher) throws -> ObjectPrx /// Like addWithUUID, but with a facet. Calling addWithUUID(servant) is equivalent to calling /// addFacetWithUUID with an empty facet. /// - /// - parameter servant: `Disp` The servant to add. + /// - parameter servant: `Dispatcher` The servant to add. /// /// - parameter facet: `Swift.String` The facet. An empty facet means the default facet. /// /// - returns: `ObjectPrx` - A proxy that matches the generated UUID identity, facet, and this object adapter. @discardableResult - func addFacetWithUUID(servant: Disp, facet: Swift.String) throws -> ObjectPrx + func addFacetWithUUID(servant: Dispatcher, facet: Swift.String) throws -> ObjectPrx /// Add a default servant to handle requests for a specific category. Adding a default servant for a category for /// which a default servant is already registered throws AlreadyRegisteredException. To dispatch operation @@ -128,11 +128,11 @@ public protocol ObjectAdapter: Swift.AnyObject { /// If no servant has been found by any of the preceding steps, the object adapter gives up and the caller /// receives ObjectNotExistException or FacetNotExistException. /// - /// - parameter servant: `Disp` The default servant. + /// - parameter servant: `Dispatcher` The default servant. /// /// - parameter category: `Swift.String` The category for which the default servant is registered. An empty /// category means it will handle all categories. - func addDefaultServant(servant: Disp, category: Swift.String) throws + func addDefaultServant(servant: Dispatcher, category: Swift.String) throws /// Remove a servant (that is, the default facet) from the object adapter's Active Servant Map. /// @@ -140,9 +140,9 @@ public protocol ObjectAdapter: Swift.AnyObject { /// implements multiple Ice objects, remove has to be called for all those Ice objects. Removing an identity /// that is not in the map throws NotRegisteredException. /// - /// - returns: `Disp` - The removed servant. + /// - returns: `Dispatcher` - The removed servant. @discardableResult - func remove(_ id: Identity) throws -> Disp + func remove(_ id: Identity) throws -> Dispatcher /// Like remove, but with a facet. Calling remove(id) is equivalent to calling /// removeFacet with an empty facet. @@ -151,9 +151,9 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - parameter facet: `Swift.String` The facet. An empty facet means the default facet. /// - /// - returns: `Disp` - The removed servant. + /// - returns: `Dispatcher` - The removed servant. @discardableResult - func removeFacet(id: Identity, facet: Swift.String) throws -> Disp + func removeFacet(id: Identity, facet: Swift.String) throws -> Dispatcher /// Remove all facets with the given identity from the Active Servant Map. The operation completely removes the Ice /// object, including its default facet. Removing an identity that is not in the map throws @@ -170,9 +170,9 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - parameter _: `Swift.String` The category of the default servant to remove. /// - /// - returns: `Disp` - The default servant. + /// - returns: `Dispatcher` - The default servant. @discardableResult - func removeDefaultServant(_ category: Swift.String) throws -> Disp + func removeDefaultServant(_ category: Swift.String) throws -> Dispatcher /// Look up a servant in this object adapter's Active Servant Map by the identity of the Ice object it implements. /// This operation only tries to look up a servant in the Active Servant Map. It does not attempt @@ -180,9 +180,9 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - parameter _: `Identity` The identity of the Ice object for which the servant should be returned. /// - /// - returns: `Disp?` - The servant that implements the Ice object with the given identity, or null if no such + /// - returns: `Dispatcher?` - The servant that implements the Ice object with the given identity, or null if no such /// servant has been found. - func find(_ id: Identity) -> Disp? + func find(_ id: Identity) -> Dispatcher? /// Like find, but with a facet. Calling find(id) is equivalent to calling findFacet /// with an empty facet. @@ -191,9 +191,9 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - parameter facet: `Swift.String` The facet. An empty facet means the default facet. /// - /// - returns: `Disp?` - The servant that implements the Ice object with the given identity and facet, or null if + /// - returns: `Dispatcher?` - The servant that implements the Ice object with the given identity and facet, or null if /// no such servant has been found. - func findFacet(id: Identity, facet: Swift.String) -> Disp? + func findFacet(id: Identity, facet: Swift.String) -> Dispatcher? /// Find all facets with the given identity in the Active Servant Map. /// @@ -209,8 +209,8 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - parameter _: `ObjectPrx` The proxy for which the servant should be returned. /// - /// - returns: `Disp?` - The servant that matches the proxy, or null if no such servant has been found. - func findByProxy(_ proxy: ObjectPrx) -> Disp? + /// - returns: `Dispatcher?` - The servant that matches the proxy, or null if no such servant has been found. + func findByProxy(_ proxy: ObjectPrx) -> Dispatcher? /// Add a Servant Locator to this object adapter. Adding a servant locator for a category for which a servant /// locator is already registered throws AlreadyRegisteredException. To dispatch operation calls on @@ -258,8 +258,8 @@ public protocol ObjectAdapter: Swift.AnyObject { /// /// - parameter _: `Swift.String` The category of the default servant to find. /// - /// - returns: `Disp?` - The default servant or null if no default servant was registered for the category. - func findDefaultServant(_ category: Swift.String) -> Disp? + /// - returns: `Dispatcher?` - The default servant or null if no default servant was registered for the category. + func findDefaultServant(_ category: Swift.String) -> Dispatcher? /// Create a proxy for the object with the given identity. If this object adapter is configured with an adapter id, /// the return value is an indirect proxy that refers to the adapter id. If a replica group id is also defined, the diff --git a/swift/src/Ice/ObjectAdapterI.swift b/swift/src/Ice/ObjectAdapterI.swift index 6a3a8bb1df4..2d5b7bb584d 100644 --- a/swift/src/Ice/ObjectAdapterI.swift +++ b/swift/src/Ice/ObjectAdapterI.swift @@ -4,7 +4,7 @@ import IceImpl -class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectFacade, Hashable { +class ObjectAdapterI: LocalObject, ObjectAdapter, ICEDispatchAdapter, Hashable { private let communicator: Communicator let servantManager: ServantManager @@ -13,7 +13,7 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF servantManager = ServantManager(adapterName: handle.getName(), communicator: communicator) super.init(handle: handle) - handle.registerDefaultServant(self) + handle.registerDispatchAdapter(self) } func hash(into hasher: inout Hasher) { @@ -62,34 +62,34 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF return handle.destroy() } - func add(servant: Disp, id: Identity) throws -> ObjectPrx { + func add(servant: Dispatcher, id: Identity) throws -> ObjectPrx { return try addFacet(servant: servant, id: id, facet: "") } - func addFacet(servant: Disp, id: Identity, facet: String) throws -> ObjectPrx { + func addFacet(servant: Dispatcher, id: Identity, facet: String) throws -> ObjectPrx { precondition(!id.name.isEmpty, "Identity cannot have an empty name") try servantManager.addServant(servant: servant, id: id, facet: facet) return try createProxy(id).ice_facet(facet) } - func addWithUUID(_ servant: Disp) throws -> ObjectPrx { + func addWithUUID(_ servant: Dispatcher) throws -> ObjectPrx { return try addFacetWithUUID(servant: servant, facet: "") } - func addFacetWithUUID(servant: Disp, facet: String) throws -> ObjectPrx { + func addFacetWithUUID(servant: Dispatcher, facet: String) throws -> ObjectPrx { return try addFacet( servant: servant, id: Identity(name: UUID().uuidString, category: ""), facet: facet) } - func addDefaultServant(servant: Disp, category: String) throws { + func addDefaultServant(servant: Dispatcher, category: String) throws { try servantManager.addDefaultServant(servant: servant, category: category) } - func remove(_ id: Identity) throws -> Disp { + func remove(_ id: Identity) throws -> Dispatcher { return try removeFacet(id: id, facet: "") } - func removeFacet(id: Identity, facet: String) throws -> Disp { + func removeFacet(id: Identity, facet: String) throws -> Dispatcher { precondition(!id.name.isEmpty, "Identity cannot have an empty name") return try servantManager.removeServant(id: id, facet: facet) } @@ -99,15 +99,15 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF return try servantManager.removeAllFacets(id: id) } - func removeDefaultServant(_ category: String) throws -> Disp { + func removeDefaultServant(_ category: String) throws -> Dispatcher { return try servantManager.removeDefaultServant(category: category) } - func find(_ id: Identity) -> Disp? { + func find(_ id: Identity) -> Dispatcher? { return findFacet(id: id, facet: "") } - func findFacet(id: Identity, facet: String) -> Disp? { + func findFacet(id: Identity, facet: String) -> Dispatcher? { return servantManager.findServant(id: id, facet: facet) } @@ -115,7 +115,7 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF return servantManager.findAllFacets(id: id) } - func findByProxy(_ proxy: ObjectPrx) -> Disp? { + func findByProxy(_ proxy: ObjectPrx) -> Dispatcher? { return findFacet(id: proxy.ice_getIdentity(), facet: proxy.ice_getFacet()) } @@ -131,7 +131,7 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF return servantManager.findServantLocator(category: category) } - func findDefaultServant(_ category: String) -> Disp? { + func findDefaultServant(_ category: String) -> Dispatcher? { return servantManager.findDefaultServant(category: category) } @@ -200,7 +200,7 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF } } - func facadeInvoke( + func dispatch( _ adapter: ICEObjectAdapter, inEncapsBytes: UnsafeMutableRawPointer, inEncapsCount: Int, @@ -214,11 +214,12 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF requestId: Int32, encodingMajor: UInt8, encodingMinor: UInt8, - sendResponse: @escaping ICESendResponse + completionHandler: @escaping ICEOutgoingResponse ) { precondition(handle == adapter) - let connection = con?.getSwiftObject(ConnectionI.self) { ConnectionI(handle: con!) } ?? nil + let connection = con?.getSwiftObject(ConnectionI.self) { ConnectionI(handle: con!) } + let encoding = EncodingVersion(major: encodingMajor, minor: encodingMinor) let current = Current( adapter: self, @@ -229,24 +230,38 @@ class ObjectAdapterI: LocalObject, ObjectAdapter, ICEBlobjectF mode: OperationMode(rawValue: mode)!, ctx: context, requestId: requestId, - encoding: EncodingVersion(major: encodingMajor, minor: encodingMinor)) - - let incoming = Incoming( - istr: InputStream( - communicator: communicator, - encoding: EncodingVersion( - major: encodingMajor, - minor: encodingMinor), - bytes: Data( - bytesNoCopy: inEncapsBytes, count: inEncapsCount, - deallocator: .none)), - sendResponse: sendResponse, - current: current) - - incoming.invoke(servantManager) + encoding: encoding) + + let istr = InputStream( + communicator: communicator, + encoding: encoding, + bytes: Data(bytesNoCopy: inEncapsBytes, count: inEncapsCount, deallocator: .none)) + + let request = IncomingRequest(current: current, inputStream: istr) + + servantManager.dispatch(request).map { response in + response.outputStream.finished().withUnsafeBytes { + completionHandler( + response.replyStatus.rawValue, + response.exceptionId, + response.exceptionMessage, + $0.baseAddress!, + $0.count) + } + }.catch { error in + let response = current.makeOutgoingResponse(error: error) + response.outputStream.finished().withUnsafeBytes { + completionHandler( + response.replyStatus.rawValue, + response.exceptionId, + response.exceptionMessage, + $0.baseAddress!, + $0.count) + } + } } - func facadeRemoved() { + func complete() { servantManager.destroy() } } diff --git a/swift/src/Ice/OutgoingResponse.swift b/swift/src/Ice/OutgoingResponse.swift new file mode 100644 index 00000000000..09989c7ab35 --- /dev/null +++ b/swift/src/Ice/OutgoingResponse.swift @@ -0,0 +1,41 @@ +// Copyright (c) ZeroC, Inc. + +import Foundation + +/// Represents the response to an incoming request. It's returned by Dispatcher.dispatch. +public final class OutgoingResponse { + /// Gets the exception ID of the response. + /// It's nil when replyStatus is ok. Otherwise, this ID is the Slice type ID of the exception marshaled into this + /// response if this exception was defined in Slice or is derived from LocalException. + /// For other exceptions, this ID is the full name of the exception's type. + public let exceptionId: String? + + /// Gets the exception message of the response. + /// It's nil when replyStatus is ok. + public let exceptionMessage: String? + + /// Gets the output stream buffer of the response. This output stream should not be written to after construction. + public let outputStream: OutputStream + + /// Gets the reply status of the response. + public let replyStatus: ReplyStatus + + /// Constructs an OutgoingResponse object. + /// - Parameters: + /// - replyStatus: The reply status. + /// - exceptionId: The ID of the exception, when the response carries an exception. + /// - exceptionMessage: The message of the exception, when the response carries an exception. + /// - outputStream: The output stream that holds the response. + public init(replyStatus: ReplyStatus, exceptionId: String?, exceptionMessage: String?, outputStream: OutputStream) { + self.replyStatus = replyStatus + self.exceptionId = exceptionId + self.exceptionMessage = exceptionMessage + self.outputStream = outputStream + } + + /// Constructs an OutgoingResponse object with the ok status. + /// - Parameter outputStream: The output stream that holds the response. + public convenience init(_ outputStream: OutputStream) { + self.init(replyStatus: .ok, exceptionId: nil, exceptionMessage: nil, outputStream: outputStream) + } +} diff --git a/swift/src/Ice/OutputStream.swift b/swift/src/Ice/OutputStream.swift index 43674965a5b..e6cd810a497 100644 --- a/swift/src/Ice/OutputStream.swift +++ b/swift/src/Ice/OutputStream.swift @@ -10,7 +10,6 @@ public class OutputStream { private var data: Data = .init(capacity: 240) private let communicator: Communicator private let encoding: EncodingVersion - private let encoding_1_0: Bool private let format: FormatType private var encaps: Encaps! @@ -28,7 +27,6 @@ public class OutputStream { public init(communicator: Communicator, encoding: EncodingVersion) { self.communicator = communicator self.encoding = encoding - encoding_1_0 = encoding == Encoding_1_0 format = (communicator as! CommunicatorI).defaultsAndOverrides.defaultFormat } @@ -134,7 +132,7 @@ public class OutputStream { public func writePendingValues() { if encaps != nil, encaps.encoder != nil { encaps.encoder.writePendingValues() - } else if encoding_1_0 { + } else if currentEncoding == Encoding_1_0 { // If using the 1.0 encoding and no instances were written, we // still write an empty sequence for pending instances if // requested (i.e.: if this is called). @@ -237,7 +235,16 @@ extension OutputStream { data.append(v) } - /// Writes a sequence of bytes to the stream. + /// Writes bytes to the stream. + /// + /// - parameter _: `[UInt8]` - The bytes to write. + public func writeBlob(_ v: [UInt8]) { + if v.count > 0 { + data.append(contentsOf: v) + } + } + + /// Writes a sequence of bytes to the stream (including the size). /// /// - parameter _: `[UInt8]` - The sequence of bytes to write. public func write(_ v: [UInt8]) { @@ -247,7 +254,7 @@ extension OutputStream { } } - /// Writes a sequence of bytes to the stream. + /// Writes a sequence of bytes to the stream (including the size). /// /// - parameter _: `Data` - The sequence of bytes to write. public func write(_ v: Data) { diff --git a/swift/src/Ice/ReplyStatus.swift b/swift/src/Ice/ReplyStatus.swift new file mode 100644 index 00000000000..d849e54b5eb --- /dev/null +++ b/swift/src/Ice/ReplyStatus.swift @@ -0,0 +1,13 @@ +// Copyright (c) ZeroC, Inc. + +/// Represents the status of a reply. +public enum ReplyStatus: UInt8 { + case ok = 0 + case userException = 1 + case objectNotExist = 2 + case facetNotExist = 3 + case operationNotExist = 4 + case unknownLocalException = 5 + case unknownUserException = 6 + case unknownException = 7 +} diff --git a/swift/src/Ice/ServantLocator.swift b/swift/src/Ice/ServantLocator.swift index 4137cc54357..0f012207676 100644 --- a/swift/src/Ice/ServantLocator.swift +++ b/swift/src/Ice/ServantLocator.swift @@ -23,16 +23,16 @@ public protocol ServantLocator: Swift.AnyObject { /// user exception. If it does, that exception is marshaled back to the client. If the Slice definition for the /// corresponding operation includes that user exception, the client receives that user exception; otherwise, the /// client receives UnknownUserException. - /// If locate throws any exception, the Ice run time does notcall finished. + /// If locate throws any exception, the Ice run time does not call finished. /// If you call locate from your own code, you must also call finished /// when you have finished using the servant, provided that locate returned a non-null servant; /// otherwise, you will get undefined behavior if you use servant locators such as the Freeze Evictor. /// /// - parameter _: `Current` Information about the current operation for which a servant is required. /// - /// - returns: `(returnValue: Disp?, cookie: Swift.AnyObject?)`: + /// - returns: `(returnValue: Dispatcher?, cookie: Swift.AnyObject?)`: /// - /// - returnValue: `Disp?` - The located servant, or null if no suitable servant has been found. + /// - returnValue: `Dispatcher?` - The located servant, or null if no suitable servant has been found. /// /// - cookie: `Swift.AnyObject?` - A "cookie" that will be passed to finished. /// @@ -40,7 +40,7 @@ public protocol ServantLocator: Swift.AnyObject { /// /// - UserException - The implementation can raise a UserException and the run time will marshal it as the /// result of the invocation. - func locate(_ curr: Current) throws -> (returnValue: Disp?, cookie: Swift.AnyObject?) + func locate(_ curr: Current) throws -> (returnValue: Dispatcher?, cookie: Swift.AnyObject?) /// Called by the object adapter after a request has been made. This operation is only called if /// locate was called prior to the request and returned a non-null servant. This operation can be used @@ -54,7 +54,7 @@ public protocol ServantLocator: Swift.AnyObject { /// - parameter curr: `Current` Information about the current operation call for which a servant was located by /// locate. /// - /// - parameter servant: `Disp` The servant that was returned by locate. + /// - parameter servant: `Dispatcher` The servant that was returned by locate. /// /// - parameter cookie: `Swift.AnyObject?` The cookie that was returned by locate. /// @@ -62,7 +62,7 @@ public protocol ServantLocator: Swift.AnyObject { /// /// - UserException - The implementation can raise a UserException and the run time will marshal it as the /// result of the invocation. - func finished(curr: Current, servant: Disp, cookie: Swift.AnyObject?) throws + func finished(curr: Current, servant: Dispatcher, cookie: Swift.AnyObject?) throws /// Called when the object adapter in which this servant locator is installed is destroyed. /// diff --git a/swift/src/Ice/ServantManager.swift b/swift/src/Ice/ServantManager.swift index e37b102c68f..bad21dfa20d 100644 --- a/swift/src/Ice/ServantManager.swift +++ b/swift/src/Ice/ServantManager.swift @@ -2,15 +2,17 @@ // Copyright (c) ZeroC, Inc. All rights reserved. // -class ServantManager { +import PromiseKit + +class ServantManager: Dispatcher { private let adapterName: String private let communicator: Communicator - private var servantMapMap = [Identity: [String: Disp]]() - private var defaultServantMap = [String: Disp]() + private var servantMapMap = [Identity: [String: Dispatcher]]() + private var defaultServantMap = [String: Dispatcher]() private var locatorMap = [String: ServantLocator]() - // This is used to distingish between ObjectNotExistException and FacetNotExistException + // This is used to distinguish between ObjectNotExistException and FacetNotExistException // when a servant is not found on a Swift Admin OA. private var adminId: Identity? @@ -21,7 +23,7 @@ class ServantManager { self.communicator = communicator } - func addServant(servant: Disp, id ident: Identity, facet: String) throws { + func addServant(servant: Dispatcher, id ident: Identity, facet: String) throws { try mutex.sync { if var m = servantMapMap[ident] { if m[facet] != nil { @@ -39,7 +41,7 @@ class ServantManager { } } - func addDefaultServant(servant: Disp, category: String) throws { + func addDefaultServant(servant: Dispatcher, category: String) throws { try mutex.sync { guard defaultServantMap[category] == nil else { throw AlreadyRegisteredException(kindOfObject: "default servant", id: category) @@ -49,7 +51,7 @@ class ServantManager { } } - func removeServant(id ident: Identity, facet: String) throws -> Disp { + func removeServant(id ident: Identity, facet: String) throws -> Dispatcher { return try mutex.sync { guard var m = servantMapMap[ident], let obj = m.removeValue(forKey: facet) else { var id = communicator.identityToString(ident) @@ -68,7 +70,7 @@ class ServantManager { } } - func removeDefaultServant(category: String) throws -> Disp { + func removeDefaultServant(category: String) throws -> Dispatcher { return try mutex.sync { guard let obj = defaultServantMap.removeValue(forKey: category) else { throw NotRegisteredException(kindOfObject: "default servant", id: category) @@ -88,7 +90,7 @@ class ServantManager { } } - func findServant(id: Identity, facet: String) -> Disp? { + func findServant(id: Identity, facet: String) -> Dispatcher? { return mutex.sync { guard let m = servantMapMap[id] else { guard let obj = defaultServantMap[id.category] else { @@ -102,7 +104,7 @@ class ServantManager { } } - func findDefaultServant(category: String) -> Disp? { + func findDefaultServant(category: String) -> Dispatcher? { return mutex.sync { defaultServantMap[category] } @@ -177,4 +179,54 @@ class ServantManager { locator.deactivate(category) } } + + func dispatch(_ request: IncomingRequest) -> Promise { + let current = request.current + var servant = findServant(id: current.id, facet: current.facet) + + if let servant = servant { + // the simple, common path + return servant.dispatch(request) + } + + // Else, check servant locators + + var locator = findServantLocator(category: current.id.category) + if locator == nil, !current.id.category.isEmpty { + locator = findServantLocator(category: "") + } + + if let locator = locator { + do { + var cookie: AnyObject? + (servant, cookie) = try locator.locate(current) + + if let servant = servant { + // If locator returned a servant, we must execute finished once no matter what. + return servant.dispatch(request).map(on: nil) { response in + do { + try locator.finished(curr: current, servant: servant, cookie: cookie) + } catch { + // Can't return a rejected promise here; otherwise recover will execute finished a second + // time. + return current.makeOutgoingResponse(error: error) + } + return response + }.recover(on: nil) { error in + // This can throw and return a rejected promise. + try locator.finished(curr: current, servant: servant, cookie: cookie) + return Promise(error: error) + } + } + } catch { + return Promise(error: error) + } + } + + if hasServant(id: current.id) || isAdminId(current.id) { + return Promise(error: FacetNotExistException()) + } else { + return Promise(error: ObjectNotExistException()) + } + } } diff --git a/swift/src/IceImpl/AdminFacetFactory.h b/swift/src/IceImpl/AdminFacetFactory.h index f8bf4e957ed..0a8017e980a 100644 --- a/swift/src/IceImpl/AdminFacetFactory.h +++ b/swift/src/IceImpl/AdminFacetFactory.h @@ -8,14 +8,14 @@ @class ICEProcess; @class ICEPropertiesAdmin; @class ICEUnsupportedAdminFacet; -@protocol ICEBlobjectFacade; +@protocol ICEDispatchAdapter; NS_ASSUME_NONNULL_BEGIN ICEIMPL_API @protocol ICEAdminFacetFactory -+ (id)createProcess:(ICECommunicator*)communicator handle:(ICEProcess*)handle; -+ (id)createProperties:(ICECommunicator*)communicator handle:(ICEPropertiesAdmin*)handle; -+ (id)createUnsupported:(ICECommunicator*)communicator handle:(ICEUnsupportedAdminFacet*)handle; ++ (id)createProcess:(ICECommunicator*)communicator handle:(ICEProcess*)handle; ++ (id)createProperties:(ICECommunicator*)communicator handle:(ICEPropertiesAdmin*)handle; ++ (id)createUnsupported:(ICECommunicator*)communicator handle:(ICEUnsupportedAdminFacet*)handle; @end NS_ASSUME_NONNULL_END diff --git a/swift/src/IceImpl/BlobjectFacade.h b/swift/src/IceImpl/BlobjectFacade.h deleted file mode 100644 index 597d67e7b21..00000000000 --- a/swift/src/IceImpl/BlobjectFacade.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// - -#import "Config.h" - -@class ICEConnection; -@class ICEObjectAdapter; -@class ICEDispatchException; - -NS_ASSUME_NONNULL_BEGIN - -// Sends the outgoing response. The first 3 parameters are ignored when the last parameter is not null. -// TODO: this code is temporary. The completion handler should look more like the main constructor of -// Ice::OutgoingResponse. -typedef void (^ICESendResponse)(bool, const void* _Nullable, size_t, ICEDispatchException* _Nullable); - -// The implementation must call sendResponse exactly once. -ICEIMPL_API @protocol ICEBlobjectFacade -- (void)facadeInvoke:(ICEObjectAdapter*)adapter - inEncapsBytes:(void*)inEncapsBytes - inEncapsCount:(long)inEncapsCount - con:(ICEConnection* _Nullable)con - name:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - mode:(uint8_t)mode - context:(NSDictionary*)context - requestId:(int32_t)requestId - encodingMajor:(uint8_t)encodingMajor - encodingMinor:(uint8_t)encodingMinor - sendResponse:(ICESendResponse)sendResponse; -- (void)facadeRemoved; -@end - -#ifdef __cplusplus - -/// A C++ dispatcher that dispatches requests to a Swift object via an ObjC/Swift "facade". -class SwiftDispatcher final : public Ice::Object -{ -public: - SwiftDispatcher(id facade) : _facade(facade) {} - - ~SwiftDispatcher() final { [_facade facadeRemoved]; } - - void dispatch(Ice::IncomingRequest&, std::function sendResponse) final; - - id getFacade() const { return _facade; } - -private: - id _facade; -}; - -#endif - -NS_ASSUME_NONNULL_END diff --git a/swift/src/IceImpl/BlobjectFacade.mm b/swift/src/IceImpl/BlobjectFacade.mm deleted file mode 100644 index 1aff929dfbe..00000000000 --- a/swift/src/IceImpl/BlobjectFacade.mm +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// - -#import "BlobjectFacade.h" -#import "Convert.h" -#import "Exception.h" -#import "Ice/AsyncResponseHandler.h" -#import "ObjectAdapter.h" - -#import "Connection.h" - -void -SwiftDispatcher::dispatch(Ice::IncomingRequest& request, std::function sendResponse) -{ - // Captured as a const copy by the block according to https://clang.llvm.org/docs/BlockLanguageSpec.html - Ice::Current current = request.current(); - - ICESendResponse sendResponseBlock = - ^(bool ok, const void* outEncaps, size_t count, ICEDispatchException* dispatchException) { - if (dispatchException) - { - sendResponse(Ice::makeOutgoingResponse(dispatchException.cppExceptionPtr, current)); - } - else - { - assert(outEncaps); - const std::byte* bytes = static_cast(outEncaps); - sendResponse(Ice::makeOutgoingResponse(ok, std::make_pair(bytes, bytes + count), current)); - } - }; - - int32_t sz; - const std::byte* inEncaps; - request.inputStream().readEncapsulation(inEncaps, sz); - - ICEObjectAdapter* adapter = [ICEObjectAdapter getHandle:current.adapter]; - ICEConnection* con = [ICEConnection getHandle:current.con]; - - @autoreleasepool - { - [_facade facadeInvoke:adapter - inEncapsBytes:const_cast(inEncaps) - inEncapsCount:static_cast(sz) - con:con - name:toNSString(current.id.name) - category:toNSString(current.id.category) - facet:toNSString(current.facet) - operation:toNSString(current.operation) - mode:static_cast(current.mode) - context:toNSDictionary(current.ctx) - requestId:current.requestId - encodingMajor:current.encoding.major - encodingMinor:current.encoding.minor - sendResponse:sendResponseBlock]; - } -} diff --git a/swift/src/IceImpl/Communicator.h b/swift/src/IceImpl/Communicator.h index 8e43ae63edc..cbd214f6585 100644 --- a/swift/src/IceImpl/Communicator.h +++ b/swift/src/IceImpl/Communicator.h @@ -9,7 +9,7 @@ @class ICEProperties; @class ICEObjectAdapter; @protocol ICELoggerProtocol; -@protocol ICEBlobjectFacade; +@protocol ICEDispatchAdapter; NS_ASSUME_NONNULL_BEGIN @@ -51,10 +51,10 @@ ICEIMPL_API @interface ICECommunicator : ICELocalObject category:(NSString*)category error:(NSError**)error; - (nullable id)getAdmin:(NSError**)error; -- (BOOL)addAdminFacet:(id)servant facet:(NSString*)facet error:(NSError**)error; -- (nullable id)removeAdminFacet:(NSString*)facet error:(NSError* _Nullable* _Nullable)error; +- (BOOL)addAdminFacet:(id)servant facet:(NSString*)facet error:(NSError**)error; +- (nullable id)removeAdminFacet:(NSString*)facet error:(NSError* _Nullable* _Nullable)error; - (nullable id)findAdminFacet:(NSString*)facet error:(NSError* _Nullable* _Nullable)error; -- (nullable NSDictionary>*)findAllAdminFacets:(NSError* _Nullable* _Nullable)error; +- (nullable NSDictionary>*)findAllAdminFacets:(NSError* _Nullable* _Nullable)error; - (ICEProperties*)getProperties; - (nullable dispatch_queue_t)getClientDispatchQueue:(NSError* _Nullable* _Nullable)error; - (nullable dispatch_queue_t)getServerDispatchQueue:(NSError* _Nullable* _Nullable)error; diff --git a/swift/src/IceImpl/Communicator.mm b/swift/src/IceImpl/Communicator.mm index 30d61153bd2..2fb9523ded5 100644 --- a/swift/src/IceImpl/Communicator.mm +++ b/swift/src/IceImpl/Communicator.mm @@ -3,7 +3,7 @@ // #import "Communicator.h" -#import "BlobjectFacade.h" +#import "DispatchAdapter.h" #import "IceUtil.h" #import "ImplicitContext.h" #import "Logger.h" @@ -302,12 +302,12 @@ - (nullable id)getAdmin:(NSError**)error } } -- (BOOL)addAdminFacet:(id)facade facet:(NSString*)facet error:(NSError**)error +- (BOOL)addAdminFacet:(id)dispatchAdapter facet:(NSString*)facet error:(NSError**)error { try { - auto swiftDispatcher = std::make_shared(facade); - self.communicator->addAdminFacet(swiftDispatcher, fromNSString(facet)); + auto cppDispatcher = std::make_shared(dispatchAdapter); + self.communicator->addAdminFacet(cppDispatcher, fromNSString(facet)); return YES; } catch (...) @@ -317,12 +317,12 @@ - (BOOL)addAdminFacet:(id)facade facet:(NSString*)facet error } } -- (id)removeAdminFacet:(NSString*)facet error:(NSError**)error +- (id)removeAdminFacet:(NSString*)facet error:(NSError**)error { try { // servant can either be a Swift wrapped facet or a builtin admin facet - return [self facetToFacade:self.communicator->removeAdminFacet(fromNSString(facet))]; + return [self facetToDispatchAdapter:self.communicator->removeAdminFacet(fromNSString(facet))]; } catch (...) { @@ -343,7 +343,7 @@ - (nullable id)findAdminFacet:(NSString*)facet error:(NSError**)error return [NSNull null]; } - return [self facetToFacade:servant]; + return [self facetToDispatchAdapter:servant]; } catch (...) { @@ -352,15 +352,15 @@ - (nullable id)findAdminFacet:(NSString*)facet error:(NSError**)error } } -- (nullable NSDictionary>*)findAllAdminFacets:(NSError**)error +- (nullable NSDictionary>*)findAllAdminFacets:(NSError**)error { try { - NSMutableDictionary>* facets = [NSMutableDictionary dictionary]; + NSMutableDictionary>* facets = [NSMutableDictionary dictionary]; for (const auto& d : self.communicator->findAllAdminFacets()) { - [facets setObject:[self facetToFacade:d.second] forKey:toNSString(d.first)]; + [facets setObject:[self facetToDispatchAdapter:d.second] forKey:toNSString(d.first)]; } return facets; @@ -417,17 +417,17 @@ - (void)getDefaultEncoding:(std::uint8_t*)major minor:(std::uint8_t*)minor IceInternal::getInstance(self.communicator)->defaultsAndOverrides()->defaultFormat); } -- (id)facetToFacade:(const Ice::ObjectPtr&)servant +- (id)facetToDispatchAdapter:(const Ice::ObjectPtr&)servant { if (!servant) { return nil; } - auto swiftDispatcher = std::dynamic_pointer_cast(servant); - if (swiftDispatcher) + auto cppDispatcher = std::dynamic_pointer_cast(servant); + if (cppDispatcher) { - return swiftDispatcher->getFacade(); + return cppDispatcher->dispatchAdapter(); } Class factory = [ICEUtil adminFacetFactory]; diff --git a/swift/src/IceImpl/DispatchAdapter.h b/swift/src/IceImpl/DispatchAdapter.h new file mode 100644 index 00000000000..0de33b7569a --- /dev/null +++ b/swift/src/IceImpl/DispatchAdapter.h @@ -0,0 +1,54 @@ +// Copyright (c) ZeroC, Inc. + +#import "Config.h" + +@class ICEConnection; +@class ICEObjectAdapter; + +NS_ASSUME_NONNULL_BEGIN + +// Provides the reply status, the exception ID, the exception message, and bytes of the reply message (including the +// header). +typedef void (^ICEOutgoingResponse)(uint8_t, NSString* _Nullable, NSString* _Nullable, const void*, long); + +// The implementation must call the completion handler exactly once. +ICEIMPL_API @protocol ICEDispatchAdapter +- (void)dispatch:(ICEObjectAdapter*)adapter + inEncapsBytes:(void*)inEncapsBytes + inEncapsCount:(long)inEncapsCount + con:(ICEConnection* _Nullable)con + name:(NSString*)name + category:(NSString*)category + facet:(NSString*)facet + operation:(NSString*)operation + mode:(uint8_t)mode + context:(NSDictionary*)context + requestId:(int32_t)requestId + encodingMajor:(uint8_t)encodingMajor + encodingMinor:(uint8_t)encodingMinor + completionHandler:(ICEOutgoingResponse)completionHandler; + +- (void)complete; +@end + +#ifdef __cplusplus + +/// A C++ dispatcher that dispatches requests to a Swift object via an ObjC/Swift dispatch adapter. +class CppDispatcher final : public Ice::Object +{ +public: + CppDispatcher(id dispatchAdapter) : _dispatchAdapter(dispatchAdapter) {} + + ~CppDispatcher() final { [_dispatchAdapter complete]; } + + void dispatch(Ice::IncomingRequest&, std::function sendResponse) final; + + id dispatchAdapter() const noexcept { return _dispatchAdapter; } + +private: + id _dispatchAdapter; +}; + +#endif + +NS_ASSUME_NONNULL_END diff --git a/swift/src/IceImpl/DispatchAdapter.mm b/swift/src/IceImpl/DispatchAdapter.mm new file mode 100644 index 00000000000..206bdadcfc3 --- /dev/null +++ b/swift/src/IceImpl/DispatchAdapter.mm @@ -0,0 +1,54 @@ +// Copyright (c) ZeroC, Inc. + +#import "DispatchAdapter.h" +#import "Connection.h" +#import "Convert.h" +#import "Exception.h" +#import "Ice/AsyncResponseHandler.h" +#import "ObjectAdapter.h" + +void +CppDispatcher::dispatch(Ice::IncomingRequest& request, std::function sendResponse) +{ + // Captured as a const copy by the block according to https://clang.llvm.org/docs/BlockLanguageSpec.html + Ice::Current current{request.current()}; + + ICEOutgoingResponse outgoingResponse = + ^(uint8_t replyStatus, NSString* exceptionId, NSString* exceptionMessage, const void* message, long count) { + // We need to copy the message here as we don't own the memory and it can be sent asynchronously. + Ice::OutputStream ostr(current.adapter->getCommunicator()); + ostr.writeBlob(static_cast(message), static_cast(count)); + + sendResponse(Ice::OutgoingResponse{ + static_cast(replyStatus), + fromNSString(exceptionId), + fromNSString(exceptionMessage), + std::move(ostr), + current}); + }; + + int32_t sz; + const std::byte* inEncaps; + request.inputStream().readEncapsulation(inEncaps, sz); + + ICEObjectAdapter* adapter = [ICEObjectAdapter getHandle:current.adapter]; + ICEConnection* con = [ICEConnection getHandle:current.con]; + + @autoreleasepool + { + [_dispatchAdapter dispatch:adapter + inEncapsBytes:const_cast(inEncaps) + inEncapsCount:static_cast(sz) + con:con + name:toNSString(current.id.name) + category:toNSString(current.id.category) + facet:toNSString(current.facet) + operation:toNSString(current.operation) + mode:static_cast(current.mode) + context:toNSDictionary(current.ctx) + requestId:current.requestId + encodingMajor:current.encoding.major + encodingMinor:current.encoding.minor + completionHandler:outgoingResponse]; + } +} diff --git a/swift/src/IceImpl/Exception.h b/swift/src/IceImpl/Exception.h index 80f91456bfe..8a726f0ba36 100644 --- a/swift/src/IceImpl/Exception.h +++ b/swift/src/IceImpl/Exception.h @@ -132,43 +132,4 @@ ICEIMPL_API @protocol ICEExceptionFactory + (NSError*)runtimeError:(NSString*)message; @end -ICEIMPL_API @interface ICEDispatchException : NSObject - -+ (instancetype)objectNotExistException:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - file:(NSString*)file - line:(int32_t)line - NS_SWIFT_NAME(objectNotExistException(_:category:facet:operation:file:line:)); - -+ (instancetype)facetNotExistException:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - file:(NSString*)file - line:(int32_t)line - NS_SWIFT_NAME(facetNotExistException(_:category:facet:operation:file:line:)); - -+ (instancetype)operationNotExistException:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - file:(NSString*)file - line:(int32_t)line - NS_SWIFT_NAME(operationNotExistException(_:category:facet:operation:file:line:)); - -+ (instancetype)unknownLocalException:(NSString*)unknown file:(NSString*)file line:(int32_t)line; -+ (instancetype)unknownUserException:(NSString*)unknown file:(NSString*)file line:(int32_t)line; -+ (instancetype)unknownException:(NSString*)unknown file:(NSString*)file line:(int32_t)line; -@end - -#ifdef __cplusplus -@interface -ICEDispatchException () -@property(nonatomic, readonly) std::exception_ptr cppExceptionPtr; -- (instancetype)initWithCppExceptionPtr:(std::exception_ptr)cppExceptionPtr; -@end -#endif - NS_ASSUME_NONNULL_END diff --git a/swift/src/IceImpl/Exception.mm b/swift/src/IceImpl/Exception.mm deleted file mode 100644 index 5d036e9c122..00000000000 --- a/swift/src/IceImpl/Exception.mm +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// - -#import "Exception.h" -#import "Convert.h" - -@implementation ICEDispatchException - -- (instancetype)initWithCppExceptionPtr:(std::exception_ptr)cppExceptionPtr -{ - assert(cppExceptionPtr); - self = [super init]; - if (!self) - { - return nil; - } - - _cppExceptionPtr = cppExceptionPtr; - - return self; -} - -+ (instancetype)objectNotExistException:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - file:(NSString*)file - line:(int32_t)line -{ - auto epr = std::make_exception_ptr(Ice::ObjectNotExistException{ - fromNSString(file).c_str(), - line, - Ice::Identity{fromNSString(name), fromNSString(category)}, - fromNSString(facet), - fromNSString(operation)}); - - return [[ICEDispatchException alloc] initWithCppExceptionPtr:epr]; -} - -+ (instancetype)facetNotExistException:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - file:(NSString*)file - line:(int32_t)line -{ - auto epr = std::make_exception_ptr(Ice::FacetNotExistException{ - fromNSString(file).c_str(), - line, - Ice::Identity{fromNSString(name), fromNSString(category)}, - fromNSString(facet), - fromNSString(operation)}); - - return [[ICEDispatchException alloc] initWithCppExceptionPtr:epr]; -} - -+ (instancetype)operationNotExistException:(NSString*)name - category:(NSString*)category - facet:(NSString*)facet - operation:(NSString*)operation - file:(NSString*)file - line:(int32_t)line -{ - auto epr = std::make_exception_ptr(Ice::OperationNotExistException{ - fromNSString(file).c_str(), - line, - Ice::Identity{fromNSString(name), fromNSString(category)}, - fromNSString(facet), - fromNSString(operation)}); - - return [[ICEDispatchException alloc] initWithCppExceptionPtr:epr]; -} - -+ (instancetype)unknownLocalException:(NSString*)unknown file:(NSString*)file line:(int32_t)line -{ - auto epr = - std::make_exception_ptr(Ice::UnknownLocalException{fromNSString(file).c_str(), line, fromNSString(unknown)}); - - return [[ICEDispatchException alloc] initWithCppExceptionPtr:epr]; -} - -+ (instancetype)unknownUserException:(NSString*)unknown file:(NSString*)file line:(int32_t)line -{ - auto epr = - std::make_exception_ptr(Ice::UnknownUserException{fromNSString(file).c_str(), line, fromNSString(unknown)}); - - return [[ICEDispatchException alloc] initWithCppExceptionPtr:epr]; -} - -+ (instancetype)unknownException:(NSString*)unknown file:(NSString*)file line:(int32_t)line -{ - auto epr = std::make_exception_ptr(Ice::UnknownException{fromNSString(file).c_str(), line, fromNSString(unknown)}); - - return [[ICEDispatchException alloc] initWithCppExceptionPtr:epr]; -} - -@end diff --git a/swift/src/IceImpl/IceImpl.h b/swift/src/IceImpl/IceImpl.h index c4b371219d0..8543bdf82ef 100644 --- a/swift/src/IceImpl/IceImpl.h +++ b/swift/src/IceImpl/IceImpl.h @@ -1,8 +1,8 @@ #import "AdminFacetFactory.h" -#import "BlobjectFacade.h" #import "Communicator.h" #import "Config.h" #import "Connection.h" +#import "DispatchAdapter.h" #import "Endpoint.h" #import "Exception.h" #import "IceUtil.h" diff --git a/swift/src/IceImpl/ObjectAdapter.h b/swift/src/IceImpl/ObjectAdapter.h index 6864ab21934..1445112d9c3 100644 --- a/swift/src/IceImpl/ObjectAdapter.h +++ b/swift/src/IceImpl/ObjectAdapter.h @@ -8,7 +8,7 @@ @class ICEObjectPrx; @class ICEEndpoint; @class ICEConnection; -@protocol ICEBlobjectFacade; +@protocol ICEDispatchAdapter; NS_ASSUME_NONNULL_BEGIN @@ -40,8 +40,7 @@ ICEIMPL_API @interface ICEObjectAdapter : ICELocalObject - (NSArray*)getPublishedEndpoints; - (BOOL)setPublishedEndpoints:(NSArray*)newEndpoints error:(NSError* _Nullable* _Nullable)error; - (nullable dispatch_queue_t)getDispatchQueue:(NSError* _Nullable* _Nullable)error; - -- (void)registerDefaultServant:(id)facade NS_SWIFT_NAME(registerDefaultServant(_:)); +- (void)registerDispatchAdapter:(id)dispatchAdapter NS_SWIFT_NAME(registerDispatchAdapter(_:)); @end #ifdef __cplusplus diff --git a/swift/src/IceImpl/ObjectAdapter.mm b/swift/src/IceImpl/ObjectAdapter.mm index ebea89bdfb3..f41a4f37df2 100644 --- a/swift/src/IceImpl/ObjectAdapter.mm +++ b/swift/src/IceImpl/ObjectAdapter.mm @@ -3,11 +3,11 @@ // #import "ObjectAdapter.h" -#import "BlobjectFacade.h" #import "Communicator.h" #import "Config.h" #import "Connection.h" #import "Convert.h" +#import "DispatchAdapter.h" #import "ObjectPrx.h" @implementation ICEObjectAdapter @@ -234,10 +234,10 @@ - (dispatch_queue_t)getDispatchQueue:(NSError* _Nullable* _Nullable)error } } -- (void)registerDefaultServant:(id)facade +- (void)registerDispatchAdapter:(id)dispatchAdapter { - auto swiftDispatcher = std::make_shared(facade); - self.objectAdapter->addDefaultServant(swiftDispatcher, ""); + auto cppDispatcher = std::make_shared(dispatchAdapter); + self.objectAdapter->addDefaultServant(cppDispatcher, ""); } @end diff --git a/swift/test/Ice/adapterDeactivation/TestI.swift b/swift/test/Ice/adapterDeactivation/TestI.swift index 88338329217..77e057e562e 100644 --- a/swift/test/Ice/adapterDeactivation/TestI.swift +++ b/swift/test/Ice/adapterDeactivation/TestI.swift @@ -68,7 +68,7 @@ class ServantLocatorI: Ice.ServantLocator { precondition(_deactivated) } - func locate(_ current: Ice.Current) throws -> (returnValue: Disp?, cookie: AnyObject?) { + func locate(_ current: Ice.Current) throws -> (returnValue: Dispatcher?, cookie: AnyObject?) { try withLock(&_lock) { try _helper.test(!_deactivated) } @@ -83,7 +83,7 @@ class ServantLocatorI: Ice.ServantLocator { return (TestIntfDisp(TestI()), Cookie()) } - func finished(curr current: Ice.Current, servant _: Ice.Disp, cookie: Swift.AnyObject?) throws { + func finished(curr current: Ice.Current, servant _: Ice.Dispatcher, cookie: Swift.AnyObject?) throws { try withLock(&_lock) { try _helper.test(!_deactivated) } diff --git a/swift/test/Ice/exceptions/AllTests.swift b/swift/test/Ice/exceptions/AllTests.swift index c3a8703002f..b1a356e4a55 100644 --- a/swift/test/Ice/exceptions/AllTests.swift +++ b/swift/test/Ice/exceptions/AllTests.swift @@ -7,11 +7,11 @@ import PromiseKit import TestCommon class ServantLocatorI: Ice.ServantLocator { - func locate(_: Current) throws -> (returnValue: Disp?, cookie: AnyObject?) { + func locate(_: Current) throws -> (returnValue: Dispatcher?, cookie: AnyObject?) { return (nil, nil) } - func finished(curr _: Current, servant _: Disp, cookie _: AnyObject?) throws {} + func finished(curr _: Current, servant _: Dispatcher, cookie _: AnyObject?) throws {} func deactivate(_: String) {} } diff --git a/swift/test/Ice/invoke/Server.swift b/swift/test/Ice/invoke/Server.swift index 442e1c76e0e..2cb921853cd 100644 --- a/swift/test/Ice/invoke/Server.swift +++ b/swift/test/Ice/invoke/Server.swift @@ -7,7 +7,7 @@ import Ice import TestCommon class ServantLocatorI: Ice.ServantLocator { - var _blobject: Ice.Disp + var _blobject: Ice.Dispatcher init(_ async: Bool) { if async { @@ -17,11 +17,11 @@ class ServantLocatorI: Ice.ServantLocator { } } - func locate(_: Ice.Current) -> (returnValue: Ice.Disp?, cookie: AnyObject?) { + func locate(_: Ice.Current) -> (returnValue: Ice.Dispatcher?, cookie: AnyObject?) { return (_blobject, nil) } - func finished(curr _: Ice.Current, servant _: Ice.Disp, cookie _: AnyObject?) {} + func finished(curr _: Ice.Current, servant _: Ice.Dispatcher, cookie _: AnyObject?) {} func deactivate(_: String) {} } diff --git a/swift/test/Ice/servantLocator/ServantLocatorI.swift b/swift/test/Ice/servantLocator/ServantLocatorI.swift index 690238faed8..e4f572831ca 100644 --- a/swift/test/Ice/servantLocator/ServantLocatorI.swift +++ b/swift/test/Ice/servantLocator/ServantLocatorI.swift @@ -32,7 +32,7 @@ class ServantLocatorI: Ice.ServantLocator { } } - func locate(_ curr: Ice.Current) throws -> (returnValue: Ice.Disp?, cookie: AnyObject?) { + func locate(_ curr: Ice.Current) throws -> (returnValue: Ice.Dispatcher?, cookie: AnyObject?) { try withLock(&_lock) { try _helper.test(!_deactivated) } @@ -62,7 +62,7 @@ class ServantLocatorI: Ice.ServantLocator { return (TestIntfDisp(TestI()), Cookie()) } - func finished(curr: Ice.Current, servant _: Ice.Disp, cookie: AnyObject?) throws { + func finished(curr: Ice.Current, servant _: Ice.Dispatcher, cookie: AnyObject?) throws { try withLock(&_lock) { try _helper.test(!_deactivated) }