From 1bb11679aff501eded169de6045949fbba7b08fc Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 26 Jun 2024 23:32:51 +0200 Subject: [PATCH] Move JavaScript reference factory to its own file (#2354) --- js/src/Ice/InstanceExtensions.js | 2 +- js/src/Ice/Reference.js | 733 +------------------------------ js/src/Ice/ReferenceFactory.js | 730 ++++++++++++++++++++++++++++++ js/test/Ice/optional/Client.ts | 2 +- 4 files changed, 735 insertions(+), 732 deletions(-) create mode 100644 js/src/Ice/ReferenceFactory.js diff --git a/js/src/Ice/InstanceExtensions.js b/js/src/Ice/InstanceExtensions.js index ff2bd753296..fcae7bd311e 100644 --- a/js/src/Ice/InstanceExtensions.js +++ b/js/src/Ice/InstanceExtensions.js @@ -11,7 +11,7 @@ import { LocatorManager } from "./LocatorManager.js"; import { ObjectAdapterFactory } from "./ObjectAdapterFactory.js"; import { OutgoingConnectionFactory } from "./OutgoingConnectionFactory.js"; import { Properties } from "./Properties.js"; -import { ReferenceFactory } from "./Reference.js"; +import { ReferenceFactory } from "./ReferenceFactory.js"; import { RetryQueue } from "./RetryQueue.js"; import { RouterManager } from "./RouterManager.js"; import { Timer } from "./Timer.js"; diff --git a/js/src/Ice/Reference.js b/js/src/Ice/Reference.js index aea90ef374d..3f1e1fd71a9 100644 --- a/js/src/Ice/Reference.js +++ b/js/src/Ice/Reference.js @@ -9,744 +9,17 @@ import { EndpointSelectionType } from "./EndpointSelectionType.js"; import { HashUtil } from "./HashUtil.js"; import { Ice as Ice_Identity } from "./Identity.js"; const { Identity } = Ice_Identity; -import { identityToString, stringToIdentity } from "./IdentityUtil.js"; -import { Ice as Ice_Locator } from "./Locator.js"; -const { LocatorPrx } = Ice_Locator; +import { identityToString } from "./IdentityUtil.js"; import { MapUtil } from "./MapUtil.js"; import { OpaqueEndpointI } from "./OpaqueEndpoint.js"; -import { PropertyNames } from "./PropertyNames.js"; import { ReferenceMode } from "./ReferenceMode.js"; -import { Ice as Ice_Router } from "./Router.js"; -const { RouterPrx } = Ice_Router; -import { Ice as Ice_BuiltinSequences } from "./BuiltinSequences.js"; -const { StringSeqHelper } = Ice_BuiltinSequences; import { StringUtil } from "./StringUtil.js"; -import { - Encoding_1_0, - Protocol_1_0, - encodingVersionToString, - protocolVersionToString, - stringToEncodingVersion, - stringToProtocolVersion, -} from "./Protocol.js"; -import { - EndpointSelectionTypeParseException, - EndpointParseException, - FixedProxyException, - IllegalIdentityException, - NoEndpointException, - ProxyParseException, - ProxyUnmarshalException, -} from "./LocalException.js"; -import { Ice as Ice_Version } from "./Version.js"; -const { ProtocolVersion, EncodingVersion } = Ice_Version; +import { Encoding_1_0, Protocol_1_0, encodingVersionToString, protocolVersionToString } from "./Protocol.js"; +import { FixedProxyException, NoEndpointException } from "./LocalException.js"; import { Promise } from "./Promise.js"; import { Debug } from "./Debug.js"; import { ConnectRequestHandler } from "./ConnectRequestHandler.js"; -const suffixes = [ - "EndpointSelection", - "ConnectionCached", - "PreferSecure", - "EncodingVersion", - "LocatorCacheTimeout", - "InvocationTimeout", - "Locator", - "Router", - "CollocationOptimized", -]; - -// -// Only for use by Instance -// -export class ReferenceFactory { - constructor(instance, communicator) { - this._instance = instance; - this._communicator = communicator; - this._defaultRouter = null; - this._defaultLocator = null; - } - - create(ident, facet, template, endpoints) { - if (ident.name.length === 0 && ident.category.length === 0) { - return null; - } - - return this.createImpl( - ident, - facet, - template.getMode(), - template.getSecure(), - template.getProtocol(), - template.getEncoding(), - endpoints, - null, - null, - ); - } - - createWithAdapterId(ident, facet, template, adapterId) { - if (ident.name.length === 0 && ident.category.length === 0) { - return null; - } - - return this.createImpl( - ident, - facet, - template.getMode(), - template.getSecure(), - template.getProtocol(), - template.getEncoding(), - null, - adapterId, - null, - ); - } - - createFixed(ident, fixedConnection) { - if (ident.name.length === 0 && ident.category.length === 0) { - return null; - } - - // - // Create new reference - // - return new FixedReference( - this._instance, - this._communicator, - ident, - "", // Facet - fixedConnection.endpoint().datagram() ? ReferenceMode.ModeDatagram : ReferenceMode.ModeTwoway, - fixedConnection.endpoint().secure(), - Protocol_1_0, - this._instance.defaultsAndOverrides().defaultEncoding, - fixedConnection, - -1, - null, - ); - } - - copy(r) { - const ident = r.getIdentity(); - if (ident.name.length === 0 && ident.category.length === 0) { - return null; - } - return r.clone(); - } - - createFromString(s, propertyPrefix) { - if (s === undefined || s === null || s.length === 0) { - return null; - } - - const delim = " \t\n\r"; - - let end = 0; - let beg = StringUtil.findFirstNotOf(s, delim, end); - if (beg == -1) { - throw new ProxyParseException("no non-whitespace characters found in `" + s + "'"); - } - - // - // Extract the identity, which may be enclosed in single - // or double quotation marks. - // - let idstr = null; - end = StringUtil.checkQuote(s, beg); - if (end === -1) { - throw new ProxyParseException("mismatched quotes around identity in `" + s + "'"); - } else if (end === 0) { - end = StringUtil.findFirstOf(s, delim + ":@", beg); - if (end === -1) { - end = s.length; - } - idstr = s.substring(beg, end); - } else { - beg++; // Skip leading quote - idstr = s.substring(beg, end); - end++; // Skip trailing quote - } - - if (beg === end) { - throw new ProxyParseException("no identity in `" + s + "'"); - } - - // - // Parsing the identity may raise IdentityParseException. - // - const ident = stringToIdentity(idstr); - - if (ident.name.length === 0) { - // - // An identity with an empty name and a non-empty - // category is illegal. - // - if (ident.category.length > 0) { - throw new IllegalIdentityException(); - } - // - // Treat a stringified proxy containing two double - // quotes ("") the same as an empty string, i.e., - // a null proxy, but only if nothing follows the - // quotes. - // - else if (StringUtil.findFirstNotOf(s, delim, end) != -1) { - throw new ProxyParseException("invalid characters after identity in `" + s + "'"); - } else { - return null; - } - } - - let facet = ""; - let mode = ReferenceMode.ModeTwoway; - let secure = false; - let encoding = this._instance.defaultsAndOverrides().defaultEncoding; - let protocol = Protocol_1_0; - let adapter = ""; - - while (true) { - beg = StringUtil.findFirstNotOf(s, delim, end); - if (beg === -1) { - break; - } - - if (s.charAt(beg) == ":" || s.charAt(beg) == "@") { - break; - } - - end = StringUtil.findFirstOf(s, delim + ":@", beg); - if (end == -1) { - end = s.length; - } - - if (beg == end) { - break; - } - - const option = s.substring(beg, end); - if (option.length != 2 || option.charAt(0) != "-") { - throw new ProxyParseException("expected a proxy option but found `" + option + "' in `" + s + "'"); - } - - // - // Check for the presence of an option argument. The - // argument may be enclosed in single or double - // quotation marks. - // - let argument = null; - const argumentBeg = StringUtil.findFirstNotOf(s, delim, end); - if (argumentBeg != -1) { - const ch = s.charAt(argumentBeg); - if (ch != "@" && ch != ":" && ch != "-") { - beg = argumentBeg; - end = StringUtil.checkQuote(s, beg); - if (end == -1) { - throw new ProxyParseException( - "mismatched quotes around value for " + option + " option in `" + s + "'", - ); - } else if (end === 0) { - end = StringUtil.findFirstOf(s, delim + ":@", beg); - if (end === -1) { - end = s.length; - } - argument = s.substring(beg, end); - } else { - beg++; // Skip leading quote - argument = s.substring(beg, end); - end++; // Skip trailing quote - } - } - } - - // - // If any new options are added here, - // IceInternal::Reference::toString() and its derived classes must be updated as well. - // - switch (option.charAt(1)) { - case "f": { - if (argument === null) { - throw new ProxyParseException("no argument provided for -f option in `" + s + "'"); - } - - try { - facet = StringUtil.unescapeString(argument, 0, argument.length); - } catch (ex) { - throw new ProxyParseException("invalid facet in `" + s + "': " + ex.message); - } - - break; - } - - case "t": { - if (argument !== null) { - throw new ProxyParseException( - "unexpected argument `" + argument + "' provided for -t option in `" + s + "'", - ); - } - mode = ReferenceMode.ModeTwoway; - break; - } - - case "o": { - if (argument !== null) { - throw new ProxyParseException( - "unexpected argument `" + argument + "' provided for -o option in `" + s + "'", - ); - } - mode = ReferenceMode.ModeOneway; - break; - } - - case "O": { - if (argument !== null) { - throw new ProxyParseException( - "unexpected argument `" + argument + "' provided for -O option in `" + s + "'", - ); - } - mode = ReferenceMode.ModeBatchOneway; - break; - } - - case "d": { - if (argument !== null) { - throw new ProxyParseException( - "unexpected argument `" + argument + "' provided for -d option in `" + s + "'", - ); - } - mode = ReferenceMode.ModeDatagram; - break; - } - - case "D": { - if (argument !== null) { - throw new ProxyParseException( - "unexpected argument `" + argument + "' provided for -D option in `" + s + "'", - ); - } - mode = ReferenceMode.ModeBatchDatagram; - break; - } - - case "s": { - if (argument !== null) { - throw new ProxyParseException( - "unexpected argument `" + argument + "' provided for -s option in `" + s + "'", - ); - } - secure = true; - break; - } - - case "e": { - if (argument === null) { - throw new ProxyParseException("no argument provided for -e option in `" + s + "'"); - } - - try { - encoding = stringToEncodingVersion(argument); - } catch ( - e // VersionParseException - ) { - throw new ProxyParseException( - "invalid encoding version `" + argument + "' in `" + s + "':\n" + e.str, - ); - } - break; - } - - case "p": { - if (argument === null) { - throw new ProxyParseException("no argument provided for -p option in `" + s + "'"); - } - - try { - protocol = stringToProtocolVersion(argument); - } catch ( - e // VersionParseException - ) { - throw new ProxyParseException( - "invalid protocol version `" + argument + "' in `" + s + "':\n" + e.str, - ); - } - break; - } - - default: { - throw new ProxyParseException("unknown option `" + option + "' in `" + s + "'"); - } - } - } - - if (beg === -1) { - return this.createImpl(ident, facet, mode, secure, protocol, encoding, null, null, propertyPrefix); - } - - const endpoints = []; - - if (s.charAt(beg) == ":") { - const unknownEndpoints = []; - end = beg; - - while (end < s.length && s.charAt(end) == ":") { - beg = end + 1; - - end = beg; - while (true) { - end = s.indexOf(":", end); - if (end == -1) { - end = s.length; - break; - } else { - let quoted = false; - let quote = beg; - while (true) { - quote = s.indexOf('"', quote); - if (quote == -1 || end < quote) { - break; - } else { - quote = s.indexOf('"', ++quote); - if (quote == -1) { - break; - } else if (end < quote) { - quoted = true; - break; - } - ++quote; - } - } - if (!quoted) { - break; - } - ++end; - } - } - - const es = s.substring(beg, end); - const endp = this._instance.endpointFactoryManager().create(es, false); - if (endp !== null) { - endpoints.push(endp); - } else { - unknownEndpoints.push(es); - } - } - if (endpoints.length === 0) { - Debug.assert(unknownEndpoints.length > 0); - throw new EndpointParseException("invalid endpoint `" + unknownEndpoints[0] + "' in `" + s + "'"); - } else if ( - unknownEndpoints.length !== 0 && - this._instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Endpoints", 1) > 0 - ) { - const msg = []; - msg.push("Proxy contains unknown endpoints:"); - unknownEndpoints.forEach((unknownEndpoint) => { - msg.push(" `"); - msg.push(unknownEndpoint); - msg.push("'"); - }); - this._instance.initializationData().logger.warning(msg.join("")); - } - - return this.createImpl(ident, facet, mode, secure, protocol, encoding, endpoints, null, propertyPrefix); - } else if (s.charAt(beg) == "@") { - beg = StringUtil.findFirstNotOf(s, delim, beg + 1); - if (beg == -1) { - throw new ProxyParseException("missing adapter id in `" + s + "'"); - } - - let adapterstr = null; - end = StringUtil.checkQuote(s, beg); - if (end === -1) { - throw new ProxyParseException("mismatched quotes around adapter id in `" + s + "'"); - } else if (end === 0) { - end = StringUtil.findFirstOf(s, delim, beg); - if (end === -1) { - end = s.length; - } - adapterstr = s.substring(beg, end); - } else { - beg++; // Skip leading quote - adapterstr = s.substring(beg, end); - end++; // Skip trailing quote - } - - if (end !== s.length && StringUtil.findFirstNotOf(s, delim, end) !== -1) { - throw new ProxyParseException( - "invalid trailing characters after `" + s.substring(0, end + 1) + "' in `" + s + "'", - ); - } - - try { - adapter = StringUtil.unescapeString(adapterstr, 0, adapterstr.length); - } catch (ex) { - throw new ProxyParseException("invalid adapter id in `" + s + "': " + ex.message); - } - if (adapter.length === 0) { - throw new ProxyParseException("empty adapter id in `" + s + "'"); - } - return this.createImpl(ident, facet, mode, secure, protocol, encoding, null, adapter, propertyPrefix); - } - - throw new ProxyParseException("malformed proxy `" + s + "'"); - } - - createFromStream(ident, s) { - // - // Don't read the identity here. Operations calling this - // constructor read the identity, and pass it as a parameter. - // - - if (ident.name.length === 0 && ident.category.length === 0) { - return null; - } - - // - // For compatibility with the old FacetPath. - // - const facetPath = StringSeqHelper.read(s); // String[] - let facet; - if (facetPath.length > 0) { - if (facetPath.length > 1) { - throw new ProxyUnmarshalException(); - } - facet = facetPath[0]; - } else { - facet = ""; - } - - const mode = s.readByte(); - if (mode < 0 || mode > ReferenceMode.ModeLast) { - throw new ProxyUnmarshalException(); - } - - const secure = s.readBool(); - - let protocol = null; - let encoding = null; - if (!s.getEncoding().equals(Encoding_1_0)) { - protocol = new ProtocolVersion(); - protocol._read(s); - encoding = new EncodingVersion(); - encoding._read(s); - } else { - protocol = Protocol_1_0; - encoding = Encoding_1_0; - } - - let endpoints = null; // EndpointI[] - let adapterId = null; - - const sz = s.readSize(); - if (sz > 0) { - endpoints = []; - for (let i = 0; i < sz; i++) { - endpoints[i] = this._instance.endpointFactoryManager().read(s); - } - } else { - adapterId = s.readString(); - } - - return this.createImpl(ident, facet, mode, secure, protocol, encoding, endpoints, adapterId, null); - } - - setDefaultRouter(defaultRouter) { - if (this._defaultRouter === null ? defaultRouter === null : this._defaultRouter.equals(defaultRouter)) { - return this; - } - - const factory = new ReferenceFactory(this._instance, this._communicator); - factory._defaultLocator = this._defaultLocator; - factory._defaultRouter = defaultRouter; - return factory; - } - - getDefaultRouter() { - return this._defaultRouter; - } - - setDefaultLocator(defaultLocator) { - if (this._defaultLocator === null ? defaultLocator === null : this._defaultLocator.equals(defaultLocator)) { - return this; - } - - const factory = new ReferenceFactory(this._instance, this._communicator); - factory._defaultRouter = this._defaultRouter; - factory._defaultLocator = defaultLocator; - return factory; - } - - getDefaultLocator() { - return this._defaultLocator; - } - - checkForUnknownProperties(prefix) { - let unknownProps = []; - // - // Do not warn about unknown properties for Ice prefixes (Ice, Glacier2, etc.) - // - for (let i = 0; i < PropertyNames.clPropNames.length; ++i) { - if (prefix.indexOf(PropertyNames.clPropNames[i] + ".") === 0) { - return; - } - } - - const properties = this._instance.initializationData().properties.getPropertiesForPrefix(prefix + "."); - unknownProps = unknownProps.concat( - Array.from(properties.keys()).filter((key) => !suffixes.some((suffix) => key === prefix + "." + suffix)), - ); - if (unknownProps.length > 0) { - const message = []; - message.push("found unknown properties for proxy '"); - message.push(prefix); - message.push("':"); - unknownProps.forEach((unknownProp) => message.push("\n ", unknownProp)); - this._instance.initializationData().logger.warning(message.join("")); - } - } - - createImpl(ident, facet, mode, secure, protocol, encoding, endpoints, adapterId, propertyPrefix) { - const defaultsAndOverrides = this._instance.defaultsAndOverrides(); - - // - // Default local proxy options. - // - let locatorInfo = null; - if (this._defaultLocator !== null) { - if (!this._defaultLocator._getReference().getEncoding().equals(encoding)) { - locatorInfo = this._instance.locatorManager().find(this._defaultLocator.ice_encodingVersion(encoding)); - } else { - locatorInfo = this._instance.locatorManager().find(this._defaultLocator); - } - } - let routerInfo = this._instance.routerManager().find(this._defaultRouter); - let cacheConnection = true; - let preferSecure = defaultsAndOverrides.defaultPreferSecure; - let endpointSelection = defaultsAndOverrides.defaultEndpointSelection; - let locatorCacheTimeout = defaultsAndOverrides.defaultLocatorCacheTimeout; - let invocationTimeout = defaultsAndOverrides.defaultInvocationTimeout; - - // - // Override the defaults with the proxy properties if a property prefix is defined. - // - if (propertyPrefix !== null && propertyPrefix.length > 0) { - const properties = this._instance.initializationData().properties; - - // - // Warn about unknown properties. - // - if (properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0) { - this.checkForUnknownProperties(propertyPrefix); - } - - let property = propertyPrefix + ".Locator"; - const locator = LocatorPrx.uncheckedCast(this._communicator.propertyToProxy(property)); - if (locator !== null) { - if (!locator._getReference().getEncoding().equals(encoding)) { - locatorInfo = this._instance.locatorManager().find(locator.ice_encodingVersion(encoding)); - } else { - locatorInfo = this._instance.locatorManager().find(locator); - } - } - - property = propertyPrefix + ".Router"; - const router = RouterPrx.uncheckedCast(this._communicator.propertyToProxy(property)); - if (router !== null) { - if (propertyPrefix.endsWith("Router")) { - this._instance - .initializationData() - .logger.warning( - "`" + - property + - "=" + - properties.getProperty(property) + - "': cannot set a router on a router; setting ignored", - ); - } else { - routerInfo = this._instance.routerManager().find(router); - } - } - - property = propertyPrefix + ".ConnectionCached"; - cacheConnection = properties.getPropertyAsIntWithDefault(property, cacheConnection ? 1 : 0) > 0; - - property = propertyPrefix + ".PreferSecure"; - preferSecure = properties.getPropertyAsIntWithDefault(property, preferSecure ? 1 : 0) > 0; - - property = propertyPrefix + ".EndpointSelection"; - if (properties.getProperty(property).length > 0) { - const type = properties.getProperty(property); - if (type == "Random") { - endpointSelection = EndpointSelectionType.Random; - } else if (type == "Ordered") { - endpointSelection = EndpointSelectionType.Ordered; - } else { - throw new EndpointSelectionTypeParseException( - "illegal value `" + type + "'; expected `Random' or `Ordered'", - ); - } - } - - property = propertyPrefix + ".LocatorCacheTimeout"; - let value = properties.getProperty(property); - if (value.length !== 0) { - locatorCacheTimeout = properties.getPropertyAsIntWithDefault(property, locatorCacheTimeout); - if (locatorCacheTimeout < -1) { - locatorCacheTimeout = -1; - this._instance - .initializationData() - .logger.warning( - "invalid value for" + - property + - "`" + - properties.getProperty(property) + - "': defaulting to -1", - ); - } - } - - property = propertyPrefix + ".InvocationTimeout"; - value = properties.getProperty(property); - if (value.length !== 0) { - invocationTimeout = properties.getPropertyAsIntWithDefault(property, invocationTimeout); - if (invocationTimeout < 1 && invocationTimeout !== -1) { - invocationTimeout = -1; - this._instance - .initializationData() - .logger.warning( - "invalid value for" + - property + - "`" + - properties.getProperty(property) + - "': defaulting to -1", - ); - } - } - } - - // - // Create new reference - // - return new RoutableReference( - this._instance, - this._communicator, - ident, - facet, - mode, - secure, - protocol, - encoding, - endpoints, - adapterId, - locatorInfo, - routerInfo, - cacheConnection, - preferSecure, - endpointSelection, - locatorCacheTimeout, - invocationTimeout, - ); - } -} - const _emptyContext = new Map(); const _emptyEndpoints = []; diff --git a/js/src/Ice/ReferenceFactory.js b/js/src/Ice/ReferenceFactory.js new file mode 100644 index 00000000000..6e672b3ce53 --- /dev/null +++ b/js/src/Ice/ReferenceFactory.js @@ -0,0 +1,730 @@ +// +// Copyright (c) ZeroC, Inc. All rights reserved. +// + +import { EndpointSelectionType } from "./EndpointSelectionType.js"; +import { Ice as Ice_Locator } from "./Locator.js"; +const { LocatorPrx } = Ice_Locator; +import { PropertyNames } from "./PropertyNames.js"; +import { ReferenceMode } from "./ReferenceMode.js"; +import { Ice as Ice_Router } from "./Router.js"; +const { RouterPrx } = Ice_Router; +import { Ice as Ice_BuiltinSequences } from "./BuiltinSequences.js"; +const { StringSeqHelper } = Ice_BuiltinSequences; +import { StringUtil } from "./StringUtil.js"; +import { Encoding_1_0, Protocol_1_0, stringToEncodingVersion, stringToProtocolVersion } from "./Protocol.js"; +import { + EndpointSelectionTypeParseException, + EndpointParseException, + IllegalIdentityException, + ProxyParseException, + ProxyUnmarshalException, +} from "./LocalException.js"; +import { Ice as Ice_Version } from "./Version.js"; +const { ProtocolVersion, EncodingVersion } = Ice_Version; +import { Debug } from "./Debug.js"; +import { stringToIdentity } from "./IdentityUtil.js"; +import { RoutableReference, FixedReference } from "./Reference.js"; + +const suffixes = [ + "EndpointSelection", + "ConnectionCached", + "PreferSecure", + "EncodingVersion", + "LocatorCacheTimeout", + "InvocationTimeout", + "Locator", + "Router", + "CollocationOptimized", +]; + +// +// Only for use by Instance +// +export class ReferenceFactory { + constructor(instance, communicator) { + this._instance = instance; + this._communicator = communicator; + this._defaultRouter = null; + this._defaultLocator = null; + } + + create(ident, facet, template, endpoints) { + if (ident.name.length === 0 && ident.category.length === 0) { + return null; + } + + return this.createImpl( + ident, + facet, + template.getMode(), + template.getSecure(), + template.getProtocol(), + template.getEncoding(), + endpoints, + null, + null, + ); + } + + createWithAdapterId(ident, facet, template, adapterId) { + if (ident.name.length === 0 && ident.category.length === 0) { + return null; + } + + return this.createImpl( + ident, + facet, + template.getMode(), + template.getSecure(), + template.getProtocol(), + template.getEncoding(), + null, + adapterId, + null, + ); + } + + createFixed(ident, fixedConnection) { + if (ident.name.length === 0 && ident.category.length === 0) { + return null; + } + + // + // Create new reference + // + return new FixedReference( + this._instance, + this._communicator, + ident, + "", // Facet + fixedConnection.endpoint().datagram() ? ReferenceMode.ModeDatagram : ReferenceMode.ModeTwoway, + fixedConnection.endpoint().secure(), + Protocol_1_0, + this._instance.defaultsAndOverrides().defaultEncoding, + fixedConnection, + -1, + null, + ); + } + + copy(r) { + const ident = r.getIdentity(); + if (ident.name.length === 0 && ident.category.length === 0) { + return null; + } + return r.clone(); + } + + createFromString(s, propertyPrefix) { + if (s === undefined || s === null || s.length === 0) { + return null; + } + + const delim = " \t\n\r"; + + let end = 0; + let beg = StringUtil.findFirstNotOf(s, delim, end); + if (beg == -1) { + throw new ProxyParseException("no non-whitespace characters found in `" + s + "'"); + } + + // + // Extract the identity, which may be enclosed in single + // or double quotation marks. + // + let idstr = null; + end = StringUtil.checkQuote(s, beg); + if (end === -1) { + throw new ProxyParseException("mismatched quotes around identity in `" + s + "'"); + } else if (end === 0) { + end = StringUtil.findFirstOf(s, delim + ":@", beg); + if (end === -1) { + end = s.length; + } + idstr = s.substring(beg, end); + } else { + beg++; // Skip leading quote + idstr = s.substring(beg, end); + end++; // Skip trailing quote + } + + if (beg === end) { + throw new ProxyParseException("no identity in `" + s + "'"); + } + + // + // Parsing the identity may raise IdentityParseException. + // + const ident = stringToIdentity(idstr); + + if (ident.name.length === 0) { + // + // An identity with an empty name and a non-empty + // category is illegal. + // + if (ident.category.length > 0) { + throw new IllegalIdentityException(); + } + // + // Treat a stringified proxy containing two double + // quotes ("") the same as an empty string, i.e., + // a null proxy, but only if nothing follows the + // quotes. + // + else if (StringUtil.findFirstNotOf(s, delim, end) != -1) { + throw new ProxyParseException("invalid characters after identity in `" + s + "'"); + } else { + return null; + } + } + + let facet = ""; + let mode = ReferenceMode.ModeTwoway; + let secure = false; + let encoding = this._instance.defaultsAndOverrides().defaultEncoding; + let protocol = Protocol_1_0; + let adapter = ""; + + while (true) { + beg = StringUtil.findFirstNotOf(s, delim, end); + if (beg === -1) { + break; + } + + if (s.charAt(beg) == ":" || s.charAt(beg) == "@") { + break; + } + + end = StringUtil.findFirstOf(s, delim + ":@", beg); + if (end == -1) { + end = s.length; + } + + if (beg == end) { + break; + } + + const option = s.substring(beg, end); + if (option.length != 2 || option.charAt(0) != "-") { + throw new ProxyParseException("expected a proxy option but found `" + option + "' in `" + s + "'"); + } + + // + // Check for the presence of an option argument. The + // argument may be enclosed in single or double + // quotation marks. + // + let argument = null; + const argumentBeg = StringUtil.findFirstNotOf(s, delim, end); + if (argumentBeg != -1) { + const ch = s.charAt(argumentBeg); + if (ch != "@" && ch != ":" && ch != "-") { + beg = argumentBeg; + end = StringUtil.checkQuote(s, beg); + if (end == -1) { + throw new ProxyParseException( + "mismatched quotes around value for " + option + " option in `" + s + "'", + ); + } else if (end === 0) { + end = StringUtil.findFirstOf(s, delim + ":@", beg); + if (end === -1) { + end = s.length; + } + argument = s.substring(beg, end); + } else { + beg++; // Skip leading quote + argument = s.substring(beg, end); + end++; // Skip trailing quote + } + } + } + + // + // If any new options are added here, + // IceInternal::Reference::toString() and its derived classes must be updated as well. + // + switch (option.charAt(1)) { + case "f": { + if (argument === null) { + throw new ProxyParseException("no argument provided for -f option in `" + s + "'"); + } + + try { + facet = StringUtil.unescapeString(argument, 0, argument.length); + } catch (ex) { + throw new ProxyParseException("invalid facet in `" + s + "': " + ex.message); + } + + break; + } + + case "t": { + if (argument !== null) { + throw new ProxyParseException( + "unexpected argument `" + argument + "' provided for -t option in `" + s + "'", + ); + } + mode = ReferenceMode.ModeTwoway; + break; + } + + case "o": { + if (argument !== null) { + throw new ProxyParseException( + "unexpected argument `" + argument + "' provided for -o option in `" + s + "'", + ); + } + mode = ReferenceMode.ModeOneway; + break; + } + + case "O": { + if (argument !== null) { + throw new ProxyParseException( + "unexpected argument `" + argument + "' provided for -O option in `" + s + "'", + ); + } + mode = ReferenceMode.ModeBatchOneway; + break; + } + + case "d": { + if (argument !== null) { + throw new ProxyParseException( + "unexpected argument `" + argument + "' provided for -d option in `" + s + "'", + ); + } + mode = ReferenceMode.ModeDatagram; + break; + } + + case "D": { + if (argument !== null) { + throw new ProxyParseException( + "unexpected argument `" + argument + "' provided for -D option in `" + s + "'", + ); + } + mode = ReferenceMode.ModeBatchDatagram; + break; + } + + case "s": { + if (argument !== null) { + throw new ProxyParseException( + "unexpected argument `" + argument + "' provided for -s option in `" + s + "'", + ); + } + secure = true; + break; + } + + case "e": { + if (argument === null) { + throw new ProxyParseException("no argument provided for -e option in `" + s + "'"); + } + + try { + encoding = stringToEncodingVersion(argument); + } catch ( + e // VersionParseException + ) { + throw new ProxyParseException( + "invalid encoding version `" + argument + "' in `" + s + "':\n" + e.str, + ); + } + break; + } + + case "p": { + if (argument === null) { + throw new ProxyParseException("no argument provided for -p option in `" + s + "'"); + } + + try { + protocol = stringToProtocolVersion(argument); + } catch ( + e // VersionParseException + ) { + throw new ProxyParseException( + "invalid protocol version `" + argument + "' in `" + s + "':\n" + e.str, + ); + } + break; + } + + default: { + throw new ProxyParseException("unknown option `" + option + "' in `" + s + "'"); + } + } + } + + if (beg === -1) { + return this.createImpl(ident, facet, mode, secure, protocol, encoding, null, null, propertyPrefix); + } + + const endpoints = []; + + if (s.charAt(beg) == ":") { + const unknownEndpoints = []; + end = beg; + + while (end < s.length && s.charAt(end) == ":") { + beg = end + 1; + + end = beg; + while (true) { + end = s.indexOf(":", end); + if (end == -1) { + end = s.length; + break; + } else { + let quoted = false; + let quote = beg; + while (true) { + quote = s.indexOf('"', quote); + if (quote == -1 || end < quote) { + break; + } else { + quote = s.indexOf('"', ++quote); + if (quote == -1) { + break; + } else if (end < quote) { + quoted = true; + break; + } + ++quote; + } + } + if (!quoted) { + break; + } + ++end; + } + } + + const es = s.substring(beg, end); + const endp = this._instance.endpointFactoryManager().create(es, false); + if (endp !== null) { + endpoints.push(endp); + } else { + unknownEndpoints.push(es); + } + } + if (endpoints.length === 0) { + Debug.assert(unknownEndpoints.length > 0); + throw new EndpointParseException("invalid endpoint `" + unknownEndpoints[0] + "' in `" + s + "'"); + } else if ( + unknownEndpoints.length !== 0 && + this._instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Endpoints", 1) > 0 + ) { + const msg = []; + msg.push("Proxy contains unknown endpoints:"); + unknownEndpoints.forEach((unknownEndpoint) => { + msg.push(" `"); + msg.push(unknownEndpoint); + msg.push("'"); + }); + this._instance.initializationData().logger.warning(msg.join("")); + } + + return this.createImpl(ident, facet, mode, secure, protocol, encoding, endpoints, null, propertyPrefix); + } else if (s.charAt(beg) == "@") { + beg = StringUtil.findFirstNotOf(s, delim, beg + 1); + if (beg == -1) { + throw new ProxyParseException("missing adapter id in `" + s + "'"); + } + + let adapterstr = null; + end = StringUtil.checkQuote(s, beg); + if (end === -1) { + throw new ProxyParseException("mismatched quotes around adapter id in `" + s + "'"); + } else if (end === 0) { + end = StringUtil.findFirstOf(s, delim, beg); + if (end === -1) { + end = s.length; + } + adapterstr = s.substring(beg, end); + } else { + beg++; // Skip leading quote + adapterstr = s.substring(beg, end); + end++; // Skip trailing quote + } + + if (end !== s.length && StringUtil.findFirstNotOf(s, delim, end) !== -1) { + throw new ProxyParseException( + "invalid trailing characters after `" + s.substring(0, end + 1) + "' in `" + s + "'", + ); + } + + try { + adapter = StringUtil.unescapeString(adapterstr, 0, adapterstr.length); + } catch (ex) { + throw new ProxyParseException("invalid adapter id in `" + s + "': " + ex.message); + } + if (adapter.length === 0) { + throw new ProxyParseException("empty adapter id in `" + s + "'"); + } + return this.createImpl(ident, facet, mode, secure, protocol, encoding, null, adapter, propertyPrefix); + } + + throw new ProxyParseException("malformed proxy `" + s + "'"); + } + + createFromStream(ident, s) { + // + // Don't read the identity here. Operations calling this + // constructor read the identity, and pass it as a parameter. + // + + if (ident.name.length === 0 && ident.category.length === 0) { + return null; + } + + // + // For compatibility with the old FacetPath. + // + const facetPath = StringSeqHelper.read(s); // String[] + let facet; + if (facetPath.length > 0) { + if (facetPath.length > 1) { + throw new ProxyUnmarshalException(); + } + facet = facetPath[0]; + } else { + facet = ""; + } + + const mode = s.readByte(); + if (mode < 0 || mode > ReferenceMode.ModeLast) { + throw new ProxyUnmarshalException(); + } + + const secure = s.readBool(); + + let protocol = null; + let encoding = null; + if (!s.getEncoding().equals(Encoding_1_0)) { + protocol = new ProtocolVersion(); + protocol._read(s); + encoding = new EncodingVersion(); + encoding._read(s); + } else { + protocol = Protocol_1_0; + encoding = Encoding_1_0; + } + + let endpoints = null; // EndpointI[] + let adapterId = null; + + const sz = s.readSize(); + if (sz > 0) { + endpoints = []; + for (let i = 0; i < sz; i++) { + endpoints[i] = this._instance.endpointFactoryManager().read(s); + } + } else { + adapterId = s.readString(); + } + + return this.createImpl(ident, facet, mode, secure, protocol, encoding, endpoints, adapterId, null); + } + + setDefaultRouter(defaultRouter) { + if (this._defaultRouter === null ? defaultRouter === null : this._defaultRouter.equals(defaultRouter)) { + return this; + } + + const factory = new ReferenceFactory(this._instance, this._communicator); + factory._defaultLocator = this._defaultLocator; + factory._defaultRouter = defaultRouter; + return factory; + } + + getDefaultRouter() { + return this._defaultRouter; + } + + setDefaultLocator(defaultLocator) { + if (this._defaultLocator === null ? defaultLocator === null : this._defaultLocator.equals(defaultLocator)) { + return this; + } + + const factory = new ReferenceFactory(this._instance, this._communicator); + factory._defaultRouter = this._defaultRouter; + factory._defaultLocator = defaultLocator; + return factory; + } + + getDefaultLocator() { + return this._defaultLocator; + } + + checkForUnknownProperties(prefix) { + let unknownProps = []; + // + // Do not warn about unknown properties for Ice prefixes (Ice, Glacier2, etc.) + // + for (let i = 0; i < PropertyNames.clPropNames.length; ++i) { + if (prefix.indexOf(PropertyNames.clPropNames[i] + ".") === 0) { + return; + } + } + + const properties = this._instance.initializationData().properties.getPropertiesForPrefix(prefix + "."); + unknownProps = unknownProps.concat( + Array.from(properties.keys()).filter((key) => !suffixes.some((suffix) => key === prefix + "." + suffix)), + ); + if (unknownProps.length > 0) { + const message = []; + message.push("found unknown properties for proxy '"); + message.push(prefix); + message.push("':"); + unknownProps.forEach((unknownProp) => message.push("\n ", unknownProp)); + this._instance.initializationData().logger.warning(message.join("")); + } + } + + createImpl(ident, facet, mode, secure, protocol, encoding, endpoints, adapterId, propertyPrefix) { + const defaultsAndOverrides = this._instance.defaultsAndOverrides(); + + // + // Default local proxy options. + // + let locatorInfo = null; + if (this._defaultLocator !== null) { + if (!this._defaultLocator._getReference().getEncoding().equals(encoding)) { + locatorInfo = this._instance.locatorManager().find(this._defaultLocator.ice_encodingVersion(encoding)); + } else { + locatorInfo = this._instance.locatorManager().find(this._defaultLocator); + } + } + let routerInfo = this._instance.routerManager().find(this._defaultRouter); + let cacheConnection = true; + let preferSecure = defaultsAndOverrides.defaultPreferSecure; + let endpointSelection = defaultsAndOverrides.defaultEndpointSelection; + let locatorCacheTimeout = defaultsAndOverrides.defaultLocatorCacheTimeout; + let invocationTimeout = defaultsAndOverrides.defaultInvocationTimeout; + + // + // Override the defaults with the proxy properties if a property prefix is defined. + // + if (propertyPrefix !== null && propertyPrefix.length > 0) { + const properties = this._instance.initializationData().properties; + + // + // Warn about unknown properties. + // + if (properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0) { + this.checkForUnknownProperties(propertyPrefix); + } + + let property = propertyPrefix + ".Locator"; + const locator = LocatorPrx.uncheckedCast(this._communicator.propertyToProxy(property)); + if (locator !== null) { + if (!locator._getReference().getEncoding().equals(encoding)) { + locatorInfo = this._instance.locatorManager().find(locator.ice_encodingVersion(encoding)); + } else { + locatorInfo = this._instance.locatorManager().find(locator); + } + } + + property = propertyPrefix + ".Router"; + const router = RouterPrx.uncheckedCast(this._communicator.propertyToProxy(property)); + if (router !== null) { + if (propertyPrefix.endsWith("Router")) { + this._instance + .initializationData() + .logger.warning( + "`" + + property + + "=" + + properties.getProperty(property) + + "': cannot set a router on a router; setting ignored", + ); + } else { + routerInfo = this._instance.routerManager().find(router); + } + } + + property = propertyPrefix + ".ConnectionCached"; + cacheConnection = properties.getPropertyAsIntWithDefault(property, cacheConnection ? 1 : 0) > 0; + + property = propertyPrefix + ".PreferSecure"; + preferSecure = properties.getPropertyAsIntWithDefault(property, preferSecure ? 1 : 0) > 0; + + property = propertyPrefix + ".EndpointSelection"; + if (properties.getProperty(property).length > 0) { + const type = properties.getProperty(property); + if (type == "Random") { + endpointSelection = EndpointSelectionType.Random; + } else if (type == "Ordered") { + endpointSelection = EndpointSelectionType.Ordered; + } else { + throw new EndpointSelectionTypeParseException( + "illegal value `" + type + "'; expected `Random' or `Ordered'", + ); + } + } + + property = propertyPrefix + ".LocatorCacheTimeout"; + let value = properties.getProperty(property); + if (value.length !== 0) { + locatorCacheTimeout = properties.getPropertyAsIntWithDefault(property, locatorCacheTimeout); + if (locatorCacheTimeout < -1) { + locatorCacheTimeout = -1; + this._instance + .initializationData() + .logger.warning( + "invalid value for" + + property + + "`" + + properties.getProperty(property) + + "': defaulting to -1", + ); + } + } + + property = propertyPrefix + ".InvocationTimeout"; + value = properties.getProperty(property); + if (value.length !== 0) { + invocationTimeout = properties.getPropertyAsIntWithDefault(property, invocationTimeout); + if (invocationTimeout < 1 && invocationTimeout !== -1) { + invocationTimeout = -1; + this._instance + .initializationData() + .logger.warning( + "invalid value for" + + property + + "`" + + properties.getProperty(property) + + "': defaulting to -1", + ); + } + } + } + + // + // Create new reference + // + return new RoutableReference( + this._instance, + this._communicator, + ident, + facet, + mode, + secure, + protocol, + encoding, + endpoints, + adapterId, + locatorInfo, + routerInfo, + cacheConnection, + preferSecure, + endpointSelection, + locatorCacheTimeout, + invocationTimeout, + ); + } +} diff --git a/js/test/Ice/optional/Client.ts b/js/test/Ice/optional/Client.ts index 3f55a40d113..4272d380729 100644 --- a/js/test/Ice/optional/Client.ts +++ b/js/test/Ice/optional/Client.ts @@ -547,7 +547,7 @@ export class Client extends TestHelper { let [p1, p2] = await initial.opFloatSeq(); test(p1 === undefined); test(p2 === undefined); - let data: number[] = []; + let data: number[] = []; for (let i = 0; i < 100; ++i) { data[i] = 1.0; }