function constructor(mParameters = {}) {
		var oGroupProperties,
			sLanguageTag = Localization.getLanguageTag().toString(),
			sODataVersion,
			sParameter,
			mQueryParams,
			sServiceUrl,
			oUri,
			mUriParameters,
			that = this;

		// do not pass any parameters to Model
		Model.call(this);

		/** @deprecated As of version 1.110.0 */
		if ("synchronizationMode" in mParameters && mParameters.synchronizationMode !== "None") {
			throw new Error("Synchronization mode must be 'None'");
		}
		sODataVersion = mParameters.odataVersion || "4.0";
		this.sODataVersion = sODataVersion;
		if (sODataVersion !== "4.0" && sODataVersion !== "2.0") {
			throw new Error("Unsupported value for parameter odataVersion: " + sODataVersion);
		}
		for (sParameter in mParameters) {
			if (!(sParameter in mSupportedParameters)) {
				throw new Error("Unsupported parameter: " + sParameter);
			}
		}
		sServiceUrl = mParameters.serviceUrl;
		if (!sServiceUrl) {
			throw new Error("Missing service root URL");
		}
		oUri = new URI(sServiceUrl);
		if (oUri.path()[oUri.path().length - 1] !== "/") {
			throw new Error("Service root URL must end with '/'");
		}
		if (mParameters.operationMode && mParameters.operationMode !== OperationMode.Server) {
			throw new Error("Unsupported operation mode: "
				+ mParameters.operationMode);
		}
		this.sOperationMode = mParameters.operationMode;
		// Note: strict checking for model's URI parameters, but "sap-*" is allowed
		mUriParameters = this.buildQueryOptions(oUri.query(true), false, true);
		// BEWARE: these are shared across all bindings!
		this.mUriParameters = mUriParameters;
		if (Supportability.isStatisticsEnabled()) {
			// Note: this way, "sap-statistics" is not sent within $batch
			mUriParameters = Object.assign({"sap-statistics" : true}, mUriParameters);
		}
		this.sServiceUrl = oUri.query("").toString();
		this.sGroupId = mParameters.groupId;
		if (this.sGroupId === undefined) {
			this.sGroupId = "$auto";
		}
		if (this.sGroupId !== "$auto" && this.sGroupId !== "$direct") {
			throw new Error("Group ID must be '$auto' or '$direct'");
		}
		_Helper.checkGroupId(mParameters.updateGroupId, false, false, "Invalid update group ID: ");
		this.sUpdateGroupId = mParameters.updateGroupId || this.getGroupId();
		this.mGroupProperties = {};
		for (const sGroupId in mParameters.groupProperties) {
			_Helper.checkGroupId(sGroupId, true);
			oGroupProperties = mParameters.groupProperties[sGroupId];
			if (typeof oGroupProperties !== "object"
					|| Object.keys(oGroupProperties).length !== 1
					|| !(oGroupProperties.submit in SubmitMode)) {
				throw new Error("Group '" + sGroupId + "' has invalid properties: '"
					+ oGroupProperties + "'");
			}
		}
		this.mGroupProperties = _Helper.clone(mParameters.groupProperties) || {};
		this.mGroupProperties.$auto = {submit : SubmitMode.Auto};
		this.mGroupProperties.$direct = {submit : SubmitMode.Direct};
		if (mParameters.autoExpandSelect !== undefined
				&& typeof mParameters.autoExpandSelect !== "boolean") {
			throw new Error("Value for autoExpandSelect must be true or false");
		}
		this.bAutoExpandSelect = mParameters.autoExpandSelect === true;
		if ("sharedRequests" in mParameters && mParameters.sharedRequests !== true) {
			throw new Error("Value for sharedRequests must be true");
		}
		this.bSharedRequests = mParameters.sharedRequests === true;
		this.bIgnoreETag = false;
		if ("ignoreAnnotationsFromMetadata" in mParameters
			&& mParameters.ignoreAnnotationsFromMetadata !== true) {
			throw new Error("Value for ignoreAnnotationsFromMetadata must be true");
		}

		// BEWARE: do not share mHeaders between _MetadataRequestor and _Requestor!
		this.mHeaders = {"Accept-Language" : sLanguageTag};
		this.mMetadataHeaders = {"Accept-Language" : sLanguageTag};

		mQueryParams = Object.assign({}, mUriParameters, mParameters.metadataUrlParams);
		const fnGetOrCreateRetryAfterPromise = this.getOrCreateRetryAfterPromise.bind(this);
		this.oMetaModel = new ODataMetaModel(
			_MetadataRequestor.create(this.mMetadataHeaders, sODataVersion,
				mParameters.ignoreAnnotationsFromMetadata, mQueryParams,
				mParameters.withCredentials, fnGetOrCreateRetryAfterPromise),
			this.sServiceUrl + "$metadata", mParameters.annotationURI, this,
			mParameters.supportReferences, mQueryParams["sap-language"]);
		this.oInterface = {
			fetchEntityContainer : this.oMetaModel.fetchEntityContainer.bind(this.oMetaModel),
			fetchMetadata : this.oMetaModel.fetchObject.bind(this.oMetaModel),
			fireDataReceived : this.fireDataReceived.bind(this),
			fireDataRequested : this.fireDataRequested.bind(this),
			fireSessionTimeout : function () {
				that.fireEvent("sessionTimeout");
			},
			getGroupProperty : this.getGroupProperty.bind(this),
			getMessagesByPath : this.getMessagesByPath.bind(this),
			getOptimisticBatchEnabler : this.getOptimisticBatchEnabler.bind(this),
			getOrCreateRetryAfterPromise : fnGetOrCreateRetryAfterPromise,
			getReporter : this.getReporter.bind(this),
			isIgnoreETag : function () {
				return that.bIgnoreETag;
			},
			onCreateGroup : function (sGroupId) {
				if (that.isAutoGroup(sGroupId)) {
					that.addPrerenderingTask(that._submitBatch.bind(that, sGroupId, true));
				}
			},
			onHttpResponse : function (mHeaders) {
				const fnHttpListener = that.fnHttpListener; // avoid "this" when calling
				fnHttpListener?.({responseHeaders : mHeaders});
			},
			reportError : this.reportError.bind(this),
			reportStateMessages : this.reportStateMessages.bind(this),
			reportTransitionMessages : this.reportTransitionMessages.bind(this),
			updateMessages : function (aOldMessages, aNewMessages) {
				Messaging.updateMessages(aOldMessages, aNewMessages);
			}
		};
		this.oRequestor = _Requestor.create(this.sServiceUrl, this.oInterface, this.mHeaders,
			mUriParameters, sODataVersion, mParameters.withCredentials);
		this.changeHttpHeaders(mParameters.httpHeaders);
		this.bEarlyRequests = mParameters.earlyRequests;
		if (this.bEarlyRequests) {
			this.oMetaModel.fetchEntityContainer(true);
			this.initializeSecurityToken();
			this.oRequestor.sendOptimisticBatch();
		}

		this.aAllBindings = [];
		this.oAnnotationChangePromise = null; // @see #_requestAnnotationChanges
		// The bindings holding keep-alive contexts without a $$getKeepAlive binding
		this.mKeepAliveBindingsByPath = {};
		this.mSupportedBindingModes = {
			OneTime : true,
			OneWay : true
		};
		if (mParameters.sharedRequests) {
			this.sDefaultBindingMode = BindingMode.OneWay;
		} else {
			this.sDefaultBindingMode = BindingMode.TwoWay;
			this.mSupportedBindingModes.TwoWay = true;
		}
		this.aPrerenderingTasks = null; // @see #addPrerenderingTask
		this.fnHttpListener = null;
		this.fnOptimisticBatchEnabler = null;
		// maps the path to the error for the next dataReceived event
		this.mPath2DataReceivedError = {};
		// maps a path to the difference between fireDataRequested and fireDataReceived calls, to
		// ensure the events are respectively fired once for a GET request
		this.mPath2DataRequestedCount = {};
		this.fnRetryAfter = null;
		this.oRetryAfterPromise = null;
	}
******************************************************************************************
	// ODataModel
	//*********************************************************************************************

	/**
Constructor for a new ODataModel.

@param {object} mParameters
  The parameters
@throws {Error} If an unsupported synchronization mode is given, if the given service root
  URL does not end with a forward slash, if an unsupported parameter is given, if OData
  system query options or parameter aliases are specified as parameters, if an invalid group
  ID or update group ID is given, if the given operation mode is not supported, if an
  annotation file cannot be merged into the service metadata, if an unsupported value for
  <code>odataVersion</code> is given.