mirror of https://github.com/gnosygnu/xowa
XOMW: Start XomwServiceContainer [#632]
parent
b0e02979ac
commit
2dab6a90be
File diff suppressed because it is too large
Load Diff
@ -1,49 +1,68 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.xowa.mediawiki.includes.dao; import gplx.*; import gplx.xowa.*; import gplx.xowa.mediawiki.*; import gplx.xowa.mediawiki.includes.*;
|
||||
/**
|
||||
* Interface for database access objects.
|
||||
*
|
||||
* Classes using this support a set of constants in a bitfield argument to their data loading
|
||||
* functions. In general, objects should assume READ_NORMAL if no flags are explicitly given,
|
||||
* though certain objects may assume READ_LATEST for common use case or legacy reasons.
|
||||
*
|
||||
* There are four types of reads:
|
||||
* - READ_NORMAL : Potentially cached read of data (e.g. from a replica DB or stale replica)
|
||||
* - READ_LATEST : Up-to-date read as of transaction start (e.g. from master or a quorum read)
|
||||
* - READ_LOCKING : Up-to-date read as of now, that locks (shared) the records
|
||||
* - READ_EXCLUSIVE : Up-to-date read as of now, that locks (exclusive) the records
|
||||
* All record locks persist for the duration of the transaction.
|
||||
*
|
||||
* A special constant READ_LATEST_IMMUTABLE can be used for fetching append-only data. Such
|
||||
* data is either (a) on a replica DB and up-to-date or (b) not yet there, but on the master/quorum.
|
||||
* Because the data is append-only, it can never be stale on a replica DB if present.
|
||||
*
|
||||
* Callers should use READ_NORMAL (or pass in no flags) unless the read determines a write.
|
||||
* In theory, such cases may require READ_LOCKING, though to avoid contention, READ_LATEST is
|
||||
* often good enough. If UPDATE race condition checks are required on a row and expensive code
|
||||
* must run after the row is fetched to determine the UPDATE, it may help to do something like:
|
||||
* - a) Start transaction
|
||||
* - b) Read the current row with READ_LATEST
|
||||
* - c) Determine the new row (expensive, so we don't want to hold locks now)
|
||||
* - d) Re-read the current row with READ_LOCKING; if it changed then bail out
|
||||
* - e) otherwise, do the updates
|
||||
* - f) Commit transaction
|
||||
*
|
||||
* @since 1.20
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.xowa.mediawiki.includes.dao;
|
||||
|
||||
/**
|
||||
* Interface for database access objects.
|
||||
*
|
||||
* Classes using this support a set of constants in a bitfield argument to their data loading
|
||||
* functions. In general, objects should assume READ_NORMAL if no flags are explicitly given,
|
||||
* though certain objects may assume READ_LATEST for common use case or legacy reasons.
|
||||
*
|
||||
* There are four types of reads:
|
||||
* - READ_NORMAL : Potentially cached read of data (e.g. from a replica DB or stale replica)
|
||||
* - READ_LATEST : Up-to-date read as of transaction start (e.g. from master or a quorum read)
|
||||
* - READ_LOCKING : Up-to-date read as of now, that locks (shared) the records
|
||||
* - READ_EXCLUSIVE : Up-to-date read as of now, that locks (exclusive) the records
|
||||
* All record locks persist for the duration of the transaction.
|
||||
*
|
||||
* A special constant READ_LATEST_IMMUTABLE can be used for fetching append-only data. Such
|
||||
* data is either (a) on a replica DB and up-to-date or (b) not yet there, but on the master/quorum.
|
||||
* Because the data is append-only, it can never be stale on a replica DB if present.
|
||||
*
|
||||
* Callers should use READ_NORMAL (or pass in no flags) unless the read determines a write.
|
||||
* In theory, such cases may require READ_LOCKING, though to avoid contention, READ_LATEST is
|
||||
* often good enough. If UPDATE race condition checks are required on a row and expensive code
|
||||
* must run after the row is fetched to determine the UPDATE, it may help to do something like:
|
||||
* - a) Start transaction
|
||||
* - b) Read the current row with READ_LATEST
|
||||
* - c) Determine the new row (expensive, so we don't want to hold locks now)
|
||||
* - d) Re-read the current row with READ_LOCKING; if it changed then bail out
|
||||
* - e) otherwise, do the updates
|
||||
* - f) Commit transaction
|
||||
*
|
||||
* @since 1.20
|
||||
*/
|
||||
public interface XomwIDBAccessObject {
|
||||
/** Constants for object loading bitfield flags (higher => higher QoS) */
|
||||
/** @var int Read from a replica DB/non-quorum */
|
||||
public static int READ_NORMAL = 0;
|
||||
|
||||
/** @var int Read from the master/quorum */
|
||||
public static int READ_LATEST = 1;
|
||||
|
||||
/* @var int Read from the master/quorum and lock out other writers */
|
||||
public static int READ_LOCKING = READ_LATEST | 2; // READ_LATEST (1) and "LOCK IN SHARE MODE" (2)
|
||||
|
||||
/** @var int Read from the master/quorum and lock out other writers and locking readers */
|
||||
public static int READ_EXCLUSIVE = READ_LOCKING | 4; // READ_LOCKING (3) and "FOR UPDATE" (4)
|
||||
|
||||
/** @var int Read from a replica DB or without a quorum, using the master/quorum on miss */
|
||||
public static int READ_LATEST_IMMUTABLE = 8;
|
||||
|
||||
// Convenience constant for tracking how data was loaded (higher => higher QoS)
|
||||
public static int READ_NONE = -1; // not loaded yet (or the object was cleared)
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.xowa.mediawiki.includes.libs.services;
|
||||
|
||||
|
||||
// MW.SRC:1.33.1
|
||||
/**
|
||||
* DestructibleService defines a standard interface for shutting down a service instance.
|
||||
* The intended use is for a service container to be able to shut down services that should
|
||||
* no longer be used, and allow such services to release any system resources.
|
||||
*
|
||||
* @note There is no expectation that services will be destroyed when the process (or web request)
|
||||
* terminates.
|
||||
*/
|
||||
public interface XomwDestructibleService {
|
||||
|
||||
/**
|
||||
* Notifies the service object that it should expect to no longer be used, and should release
|
||||
* any system resources it may own. The behavior of all service methods becomes undefined after
|
||||
* destroy() has been called. It is recommended that implementing classes should throw an
|
||||
* exception when service methods are accessed after destroy() has been called.
|
||||
*/
|
||||
public void destroy();
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package gplx.xowa.mediawiki.includes.libs.services;
|
||||
|
||||
import gplx.String_;
|
||||
import gplx.xowa.mediawiki.XophpException;
|
||||
import gplx.xowa.mediawiki.XophpRuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when the requested service is not known.
|
||||
*/
|
||||
class XomwNoSuchServiceException extends XophpRuntimeException {
|
||||
|
||||
/**
|
||||
* @param string $serviceName
|
||||
* @param Exception|null $previous
|
||||
*/
|
||||
public XomwNoSuchServiceException(String serviceName) {this(serviceName, null);}
|
||||
public XomwNoSuchServiceException(String serviceName, XophpException previous) {
|
||||
super(String_.Format("No such service: {0}", serviceName), 0, previous);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,464 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012-2020 gnosygnu@gmail.com
|
||||
|
||||
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
||||
or alternatively under the terms of the Apache License Version 2.0.
|
||||
|
||||
You may use XOWA according to either of these licenses as is most appropriate
|
||||
for your project on a case-by-case basis.
|
||||
|
||||
The terms of each license can be found in the source code repository:
|
||||
|
||||
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
||||
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
||||
*/
|
||||
package gplx.xowa.mediawiki.includes.libs.services;
|
||||
|
||||
|
||||
// MW.SRC:1.33.1
|
||||
|
||||
import gplx.xowa.mediawiki.XophpArray;
|
||||
import gplx.xowa.mediawiki.XophpArray_;
|
||||
import gplx.xowa.mediawiki.XophpCallbackOwner;
|
||||
import gplx.xowa.mediawiki.XophpObject_;
|
||||
import gplx.xowa.mediawiki.XophpType_;
|
||||
|
||||
/**
|
||||
* ServiceContainer provides a generic service to manage named services using
|
||||
* lazy instantiation based on instantiator callback functions.
|
||||
*
|
||||
* Services managed by an instance of ServiceContainer may or may not implement
|
||||
* a common interface.
|
||||
*
|
||||
* @note When using ServiceContainer to manage a set of services, consider
|
||||
* creating a wrapper or a subclass that provides access to the services via
|
||||
* getter methods with more meaningful names and more specific return type
|
||||
* declarations.
|
||||
*
|
||||
* @see docs/injection.txt for an overview of using dependency injection in the
|
||||
* MediaWiki code base.
|
||||
*/
|
||||
public class XomwServiceContainer implements XomwDestructibleService {
|
||||
|
||||
/**
|
||||
* @var object[]
|
||||
*/
|
||||
private XophpArray<Object> services = new XophpArray();
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
*/
|
||||
private XophpArray<XophpCallbackOwner> serviceInstantiators = new XophpArray();
|
||||
|
||||
/**
|
||||
* @var callable[][]
|
||||
*/
|
||||
private XophpArray<XophpCallbackOwner[]> serviceManipulators = new XophpArray();
|
||||
|
||||
/**
|
||||
* @var bool[] disabled status, per service name
|
||||
*/
|
||||
private XophpArray<Boolean> disabled = new XophpArray();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private XophpArray extraInstantiationParams;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private boolean destroyed = false;
|
||||
|
||||
/**
|
||||
* @param array $extraInstantiationParams Any additional parameters to be passed to the
|
||||
* instantiator function when creating a service. This is typically used to provide
|
||||
* access to additional ServiceContainers or Config objects.
|
||||
*/
|
||||
public XomwServiceContainer() {this(new XophpArray());}
|
||||
public XomwServiceContainer(XophpArray extraInstantiationParams) {
|
||||
this.extraInstantiationParams = extraInstantiationParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys all contained service instances that implement the DestructibleService
|
||||
* interface. This will render all services obtained from this ServiceContainer
|
||||
* instance unusable. In particular, this will disable access to the storage backend
|
||||
* via any of these services. Any future call to getService() will throw an exception.
|
||||
*
|
||||
* @see resetGlobalInstance()
|
||||
*/
|
||||
public void destroy() {
|
||||
for (String name : this.getServiceNames()) {
|
||||
Object service = this.peekService(name);
|
||||
if (service != null && XophpType_.instance_of(service, XomwDestructibleService.class)) {
|
||||
((XomwDestructibleService)service).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// Break circular references due to the this reference in closures, by
|
||||
// erasing the instantiator array. This allows the ServiceContainer to
|
||||
// be deleted when it goes out of scope.
|
||||
this.serviceInstantiators = new XophpArray();
|
||||
// Also remove the services themselves, to avoid confusion.
|
||||
this.services = new XophpArray();
|
||||
this.destroyed = true;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @param array $wiringFiles A list of PHP files to load wiring information from.
|
||||
// * Each file is loaded using PHP's include mechanism. Each file is expected to
|
||||
// * return an associative array that maps service names to instantiator functions.
|
||||
// */
|
||||
// public function loadWiringFiles(array $wiringFiles) {
|
||||
// foreach ($wiringFiles as $file) {
|
||||
// // the wiring file is required to return an array of instantiators.
|
||||
// $wiring = require $file;
|
||||
//
|
||||
// Assert::postcondition(
|
||||
// is_array($wiring),
|
||||
// "Wiring file $file is expected to return an array!"
|
||||
// );
|
||||
//
|
||||
// this.applyWiring($wiring);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Registers multiple services (aka a "wiring").
|
||||
// *
|
||||
// * @param array $serviceInstantiators An associative array mapping service names to
|
||||
// * instantiator functions.
|
||||
// */
|
||||
// public function applyWiring(array $serviceInstantiators) {
|
||||
// Assert::parameterElementType('callable', $serviceInstantiators, '$serviceInstantiators');
|
||||
//
|
||||
// foreach ($serviceInstantiators as $name => $instantiator) {
|
||||
// this.defineService($name, $instantiator);
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Imports all wiring defined in $container. Wiring defined in $container
|
||||
// * will override any wiring already defined locally. However, already
|
||||
// * existing service instances will be preserved.
|
||||
// *
|
||||
// * @since 1.28
|
||||
// *
|
||||
// * @param ServiceContainer $container
|
||||
// * @param string[] $skip A list of service names to skip during import
|
||||
// */
|
||||
// public function importWiring(ServiceContainer $container, $skip = []) {
|
||||
// $newInstantiators = array_diff_key(
|
||||
// $container.serviceInstantiators,
|
||||
// array_flip($skip)
|
||||
// );
|
||||
//
|
||||
// this.serviceInstantiators = array_merge(
|
||||
// this.serviceInstantiators,
|
||||
// $newInstantiators
|
||||
// );
|
||||
//
|
||||
// $newManipulators = array_diff(
|
||||
// array_keys($container.serviceManipulators),
|
||||
// $skip
|
||||
// );
|
||||
//
|
||||
// foreach ($newManipulators as $name) {
|
||||
// if (isset(this.serviceManipulators[$name])) {
|
||||
// this.serviceManipulators[$name] = array_merge(
|
||||
// this.serviceManipulators[$name],
|
||||
// $container.serviceManipulators[$name]
|
||||
// );
|
||||
// } else {
|
||||
// this.serviceManipulators[$name] = $container.serviceManipulators[$name];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns true if a service is defined for $name, that is, if a call to getService($name)
|
||||
* would return a service instance.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public boolean hasService(String name) {
|
||||
return XophpArray_.isset(this.serviceInstantiators, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the service instance for $name only if that service has already been instantiated.
|
||||
* This is intended for situations where services get destroyed/cleaned up, so we can
|
||||
* avoid creating a service just to destroy it again.
|
||||
*
|
||||
* @note This is intended for internal use and for test fixtures.
|
||||
* Application logic should use getService() instead.
|
||||
*
|
||||
* @see getService().
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return object|null The service instance, or null if the service has not yet been instantiated.
|
||||
* @throws RuntimeException if $name does not refer to a known service.
|
||||
*/
|
||||
public Object peekService(String name) {
|
||||
if (!this.hasService(name)) {
|
||||
throw new XomwNoSuchServiceException(name);
|
||||
}
|
||||
|
||||
return XophpObject_.Coalesce(this.services.Get_by(name), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public XophpArray<String> getServiceNames() {
|
||||
return XophpArray_.array_keys(this.serviceInstantiators);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Define a new service. The service must not be known already.
|
||||
// *
|
||||
// * @see getService().
|
||||
// * @see redefineService().
|
||||
// *
|
||||
// * @param string $name The name of the service to register, for use with getService().
|
||||
// * @param callable $instantiator Callback that returns a service instance.
|
||||
// * Will be called with this ServiceContainer instance as the only parameter.
|
||||
// * Any extra instantiation parameters provided to the constructor will be
|
||||
// * passed as subsequent parameters when invoking the instantiator.
|
||||
// *
|
||||
// * @throws RuntimeException if there is already a service registered as $name.
|
||||
// */
|
||||
// public function defineService($name, callable $instantiator) {
|
||||
// Assert::parameterType('string', $name, '$name');
|
||||
//
|
||||
// if (this.hasService($name)) {
|
||||
// throw new ServiceAlreadyDefinedException($name);
|
||||
// }
|
||||
//
|
||||
// this.serviceInstantiators[$name] = $instantiator;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Replace an already defined service.
|
||||
// *
|
||||
// * @see defineService().
|
||||
// *
|
||||
// * @note This will fail if the service was already instantiated. If the service was previously
|
||||
// * disabled, it will be re-enabled by this call. Any manipulators registered for the service
|
||||
// * will remain in place.
|
||||
// *
|
||||
// * @param string $name The name of the service to register.
|
||||
// * @param callable $instantiator Callback function that returns a service instance.
|
||||
// * Will be called with this ServiceContainer instance as the only parameter.
|
||||
// * The instantiator must return a service compatible with the originally defined service.
|
||||
// * Any extra instantiation parameters provided to the constructor will be
|
||||
// * passed as subsequent parameters when invoking the instantiator.
|
||||
// *
|
||||
// * @throws NoSuchServiceException if $name is not a known service.
|
||||
// * @throws CannotReplaceActiveServiceException if the service was already instantiated.
|
||||
// */
|
||||
// public function redefineService($name, callable $instantiator) {
|
||||
// Assert::parameterType('string', $name, '$name');
|
||||
//
|
||||
// if (!this.hasService($name)) {
|
||||
// throw new NoSuchServiceException($name);
|
||||
// }
|
||||
//
|
||||
// if (isset(this.services[$name])) {
|
||||
// throw new CannotReplaceActiveServiceException($name);
|
||||
// }
|
||||
//
|
||||
// this.serviceInstantiators[$name] = $instantiator;
|
||||
// unset(this.disabled[$name]);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Add a service manipulator callback for the given service.
|
||||
// * This method may be used by extensions that need to wrap, replace, or re-configure a
|
||||
// * service. It would typically be called from a MediaWikiServices hook handler.
|
||||
// *
|
||||
// * The manipulator callback is called just after the service is instantiated.
|
||||
// * It can call methods on the service to change configuration, or wrap or otherwise
|
||||
// * replace it.
|
||||
// *
|
||||
// * @see defineService().
|
||||
// * @see redefineService().
|
||||
// *
|
||||
// * @note This will fail if the service was already instantiated.
|
||||
// *
|
||||
// * @since 1.32
|
||||
// *
|
||||
// * @param string $name The name of the service to manipulate.
|
||||
// * @param callable $manipulator Callback function that manipulates, wraps or replaces a
|
||||
// * service instance. The callback receives the new service instance and this
|
||||
// * ServiceContainer as parameters, as well as any extra instantiation parameters specified
|
||||
// * when constructing this ServiceContainer. If the callback returns a value, that
|
||||
// * value replaces the original service instance.
|
||||
// *
|
||||
// * @throws NoSuchServiceException if $name is not a known service.
|
||||
// * @throws CannotReplaceActiveServiceException if the service was already instantiated.
|
||||
// */
|
||||
// public function addServiceManipulator($name, callable $manipulator) {
|
||||
// Assert::parameterType('string', $name, '$name');
|
||||
//
|
||||
// if (!this.hasService($name)) {
|
||||
// throw new NoSuchServiceException($name);
|
||||
// }
|
||||
//
|
||||
// if (isset(this.services[$name])) {
|
||||
// throw new CannotReplaceActiveServiceException($name);
|
||||
// }
|
||||
//
|
||||
// this.serviceManipulators[$name][] = $manipulator;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Disables a service.
|
||||
*
|
||||
* @note Attempts to call getService() for a disabled service will result
|
||||
* in a DisabledServiceException. Calling peekService for a disabled service will
|
||||
* return null. Disabled services are listed by getServiceNames(). A disabled service
|
||||
* can be enabled again using redefineService().
|
||||
*
|
||||
* @note If the service was already active (that is, instantiated) when getting disabled,
|
||||
* and the service instance implements DestructibleService, destroy() is called on the
|
||||
* service instance.
|
||||
*
|
||||
* @see redefineService()
|
||||
* @see resetService()
|
||||
*
|
||||
* @param string $name The name of the service to disable.
|
||||
*
|
||||
* @throws RuntimeException if $name is not a known service.
|
||||
*/
|
||||
public void disableService(String name) {
|
||||
this.resetService(name);
|
||||
|
||||
this.disabled.Set(name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a service by dropping the service instance.
|
||||
* If the service instances implements DestructibleService, destroy()
|
||||
* is called on the service instance.
|
||||
*
|
||||
* @warning This is generally unsafe! Other services may still retain references
|
||||
* to the stale service instance, leading to failures and inconsistencies. Subclasses
|
||||
* may use this method to reset specific services under specific instances, but
|
||||
* it should not be exposed to application logic.
|
||||
*
|
||||
* @note This is declared final so subclasses can not interfere with the expectations
|
||||
* disableService() has when calling resetService().
|
||||
*
|
||||
* @see redefineService()
|
||||
* @see disableService().
|
||||
*
|
||||
* @param string $name The name of the service to reset.
|
||||
* @param bool $destroy Whether the service instance should be destroyed if it exists.
|
||||
* When set to false, any existing service instance will effectively be detached
|
||||
* from the container.
|
||||
*
|
||||
* @throws RuntimeException if $name is not a known service.
|
||||
*/
|
||||
protected void resetService(String name) {this.resetService(name, true);}
|
||||
protected void resetService(String name, boolean destroy) {
|
||||
// Assert::parameterType('string', $name, '$name');
|
||||
|
||||
Object instance = this.peekService(name);
|
||||
|
||||
if (destroy && XophpType_.instance_of(instance, XomwDestructibleService.class)) {
|
||||
((XomwDestructibleService)instance).destroy();
|
||||
}
|
||||
|
||||
XophpArray_.unset(this.services, name);
|
||||
XophpArray_.unset(this.disabled, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a service object of the kind associated with $name.
|
||||
* Services instances are instantiated lazily, on demand.
|
||||
* This method may or may not return the same service instance
|
||||
* when called multiple times with the same $name.
|
||||
*
|
||||
* @note Rather than calling this method directly, it is recommended to provide
|
||||
* getters with more meaningful names and more specific return types, using
|
||||
* a subclass or wrapper.
|
||||
*
|
||||
* @see redefineService().
|
||||
*
|
||||
* @param string $name The service name
|
||||
*
|
||||
* @throws NoSuchServiceException if $name is not a known service.
|
||||
* @throws ContainerDisabledException if this container has already been destroyed.
|
||||
* @throws ServiceDisabledException if the requested service has been disabled.
|
||||
*
|
||||
* @return object The service instance
|
||||
*/
|
||||
public Object getService(String name) {
|
||||
if (this.destroyed) {
|
||||
// throw new XomwContainerDisabledException();
|
||||
}
|
||||
|
||||
if (XophpArray_.isset(this.disabled, name)) {
|
||||
// throw new XomwServiceDisabledException($name);
|
||||
}
|
||||
|
||||
if (!XophpArray_.isset(this.services, name)) {
|
||||
this.services.Set(name, this.createService(name));
|
||||
}
|
||||
|
||||
return this.services.Get_by(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @throws InvalidArgumentException if $name is not a known service.
|
||||
* @return object
|
||||
*/
|
||||
private Object createService(String name) {
|
||||
// if (isset(this.serviceInstantiators[$name])) {
|
||||
// $service = (this.serviceInstantiators[$name])(
|
||||
// this,
|
||||
// ...this.extraInstantiationParams
|
||||
// );
|
||||
//
|
||||
// if (isset(this.serviceManipulators[$name])) {
|
||||
// foreach (this.serviceManipulators[$name] as $callback) {
|
||||
// $ret = call_user_func_array(
|
||||
// $callback,
|
||||
// array_merge([ $service, this ], this.extraInstantiationParams)
|
||||
// );
|
||||
//
|
||||
// // If the manipulator callback returns an object, that object replaces
|
||||
// // the original service instance. This allows the manipulator to wrap
|
||||
// // or fully replace the service.
|
||||
// if ($ret !== null) {
|
||||
// $service = $ret;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // NOTE: when adding more wiring logic here, make sure importWiring() is kept in sync!
|
||||
// } else {
|
||||
// throw new NoSuchServiceException($name);
|
||||
// }
|
||||
//
|
||||
// return $service;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool Whether the service is disabled
|
||||
* @since 1.28
|
||||
*/
|
||||
public boolean isServiceDisabled(String name) {
|
||||
return XophpArray_.isset(this.disabled, name);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue