1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2024-09-29 23:10:52 +00:00

XOMW: Add more implementation for XomwServiceContainer [#632]

This commit is contained in:
gnosygnu 2020-05-08 09:18:46 -04:00
parent 6663b769d5
commit ee68162a4a
6 changed files with 342 additions and 190 deletions

View File

@ -71,7 +71,7 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
} }
return rv; return rv;
} }
public XophpArray Add(Object val) { public XophpArray Add(T val) {
int key = newMemberIdx++; int key = newMemberIdx++;
Set(XophpArrayItm.New_int(key, val)); Set(XophpArrayItm.New_int(key, val));
return this; return this;
@ -110,8 +110,8 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
} }
return this; return this;
} }
public XophpArray Add_many(Object... val) { public XophpArray Add_many(T... val) {
for (Object itm : val) { for (T itm : val) {
Add(itm); Add(itm);
} }
return this; return this;
@ -165,9 +165,9 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
public String Get_by_str(int key) {return (String)this.Get_by(Int_.To_str(key));} public String Get_by_str(int key) {return (String)this.Get_by(Int_.To_str(key));}
public String Get_by_str_or(String key, String or) {Object rv = this.Get_by(key); return rv == null ? or : (String)rv;} public String Get_by_str_or(String key, String or) {Object rv = this.Get_by(key); return rv == null ? or : (String)rv;}
public String Get_by_str(String key) {return (String)this.Get_by(key);} public String Get_by_str(String key) {return (String)this.Get_by(key);}
public Object Get_by(String key) { public T Get_by(String key) {
XophpArrayItm itm = (XophpArrayItm)hash.Get_by(key); XophpArrayItm itm = (XophpArrayItm)hash.Get_by(key);
return itm == null ? null : itm.Val(); return itm == null ? null : (T)itm.Val();
} }
public void Set(int key, Object val) { public void Set(int key, Object val) {
this.Set(XophpArrayItm.New_int(key, val)); this.Set(XophpArrayItm.New_int(key, val));

View File

@ -0,0 +1,37 @@
/*
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;
import gplx.String_;
import gplx.xowa.mediawiki.XophpException;
import gplx.xowa.mediawiki.XophpRuntimeException;
// MW.SRC:1.33.1
/**
* Exception thrown when trying to replace an already active service.
*/
public class XomwCannotReplaceActiveServiceException extends XophpRuntimeException {
/**
* @param string $serviceName
* @param Exception|null $previous
*/
public XomwCannotReplaceActiveServiceException(String serviceName) {this(serviceName, null);}
public XomwCannotReplaceActiveServiceException(String serviceName, XophpException previous) {
super(String_.Format("Cannot replace an active service: {0}", serviceName), 0, previous);
}
}

View File

@ -0,0 +1,35 @@
/*
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;
import gplx.xowa.mediawiki.XophpException;
import gplx.xowa.mediawiki.XophpRuntimeException;
// MW.SRC:1.33.1
/**
* Exception thrown when trying to access a service on a disabled container or factory.
*/
public class XomwContainerDisabledException extends XophpRuntimeException {
/**
* @param Exception|null $previous
*/
public XomwContainerDisabledException(){this(null);}
public XomwContainerDisabledException(XophpException previous) {
super("Container disabled!", 0, previous);
}
}

View File

@ -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;
import gplx.String_;
import gplx.xowa.mediawiki.XophpException;
import gplx.xowa.mediawiki.XophpRuntimeException;
// MW.SRC:1.33.1
/**
* Exception thrown when a service was already defined, but the
* caller expected it to not exist.
*/
public class XomwServiceAlreadyDefinedException extends XophpRuntimeException {
/**
* @param string $serviceName
* @param Exception|null $previous
*/
public XomwServiceAlreadyDefinedException(String serviceName) {this(serviceName, null);}
public XomwServiceAlreadyDefinedException(String serviceName, XophpException previous) {
super(String_.Format("Service already defined: {0}", serviceName), 0, previous);
}
}

View File

@ -15,15 +15,18 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/ */
package gplx.xowa.mediawiki.includes.libs.services; 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.XophpArray_; import gplx.xowa.mediawiki.XophpArray_;
import gplx.xowa.mediawiki.XophpCallbackOwner; import gplx.xowa.mediawiki.XophpCallback;
import gplx.xowa.mediawiki.XophpObject_; import gplx.xowa.mediawiki.XophpObject_;
import gplx.xowa.mediawiki.XophpType_; import gplx.xowa.mediawiki.XophpType_;
/*
XOTODO:
* array_diff: https://www.php.net/manual/en/function.array-diff.php
* array_diff_key: https://www.php.net/manual/en/function.array-diff-key
* XomwAssert: /vendor/wikimedia/Assert/src
*/
// MW.SRC:1.33.1
/** /**
* ServiceContainer provides a generic service to manage named services using * ServiceContainer provides a generic service to manage named services using
* lazy instantiation based on instantiator callback functions. * lazy instantiation based on instantiator callback functions.
@ -49,12 +52,12 @@ public class XomwServiceContainer implements XomwDestructibleService {
/** /**
* @var callable[] * @var callable[]
*/ */
private XophpArray<XophpCallbackOwner> serviceInstantiators = new XophpArray(); private XophpArray<XophpCallback> serviceInstantiators = new XophpArray();
/** /**
* @var callable[][] * @var callable[][]
*/ */
private XophpArray<XophpCallbackOwner[]> serviceManipulators = new XophpArray(); private XophpArray<XophpArray<XophpCallback>> serviceManipulators = new XophpArray();
/** /**
* @var bool[] disabled status, per service name * @var bool[] disabled status, per service name
@ -106,76 +109,77 @@ public class XomwServiceContainer implements XomwDestructibleService {
this.destroyed = true; this.destroyed = true;
} }
// /** /**
// * @param array $wiringFiles A list of PHP files to load wiring information from. * @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 * 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. * return an associative array that maps service names to instantiator functions.
// */ */
// public function loadWiringFiles(array $wiringFiles) { public void loadWiringFiles(XophpArray wiringFiles) {
// foreach ($wiringFiles as $file) { // foreach ($wiringFiles as $file) {
// // the wiring file is required to return an array of instantiators. // // the wiring file is required to return an array of instantiators.
// $wiring = require $file; // $wiring = require $file;
// //
// Assert::postcondition( // // Assert::postcondition(
// is_array($wiring), // // is_array($wiring),
// "Wiring file $file is expected to return an array!" // // "Wiring file $file is expected to return an array!"
// ); // // );
// //
// this.applyWiring($wiring); // this.applyWiring($wiring);
// } // }
// } }
/**
* Registers multiple services (aka a "wiring").
*
* @param array $serviceInstantiators An associative array mapping service names to
* instantiator functions.
*/
public void applyWiring(XophpArray $serviceInstantiators) {
// Assert::parameterElementType('callable', $serviceInstantiators, '$serviceInstantiators');
// /**
// * 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) { // foreach ($serviceInstantiators as $name => $instantiator) {
// this.defineService($name, $instantiator); // this.defineService($name, $instantiator);
// } // }
// } }
// /** /**
// * Imports all wiring defined in $container. Wiring defined in $container * Imports all wiring defined in $container. Wiring defined in $container
// * will override any wiring already defined locally. However, already * will override any wiring already defined locally. However, already
// * existing service instances will be preserved. * existing service instances will be preserved.
// * *
// * @since 1.28 * @since 1.28
// * *
// * @param ServiceContainer $container * @param ServiceContainer $container
// * @param string[] $skip A list of service names to skip during import * @param string[] $skip A list of service names to skip during import
// */ */
// public function importWiring(ServiceContainer $container, $skip = []) { public void importWiring(XomwServiceContainer container) {this.importWiring(container, new XophpArray<>());}
// $newInstantiators = array_diff_key( public void importWiring(XomwServiceContainer container, XophpArray<String> skip) {
// $container.serviceInstantiators, // XophpArray<String> newInstantiators = XophpArray_.array_diff_key(
// array_flip($skip) // container.serviceInstantiators,
// ); // XophpArray_.array_flip(skip)
// );
// //
// this.serviceInstantiators = array_merge( // this.serviceInstantiators = XophpArray_.array_merge(
// this.serviceInstantiators, // this.serviceInstantiators,
// $newInstantiators // newInstantiators
// ); // );
// //
// $newManipulators = array_diff( // XophpArray<String> newManipulators = XophpArray_.array_diff(
// array_keys($container.serviceManipulators), // XophpArray_.array_keys(container.serviceManipulators),
// $skip // skip
// ); // );
// //
// foreach ($newManipulators as $name) { // for (String name : newManipulators) {
// if (isset(this.serviceManipulators[$name])) { // if (XophpArray_.isset(this.serviceManipulators, name)) {
// this.serviceManipulators[$name] = array_merge( // this.serviceManipulators.Set(name, XophpArray_.array_merge(
// this.serviceManipulators[$name], // this.serviceManipulators.Get_by(name),
// $container.serviceManipulators[$name] // container.serviceManipulators.Get_by(name)
// ); // ));
// } else { // } else {
// this.serviceManipulators[$name] = $container.serviceManipulators[$name]; // this.serviceManipulators.Set(name, container.serviceManipulators.Get_by(name));
// } // }
// } // }
// } }
/** /**
* Returns true if a service is defined for $name, that is, if a call to getService($name) * Returns true if a service is defined for $name, that is, if a call to getService($name)
@ -219,103 +223,103 @@ public class XomwServiceContainer implements XomwDestructibleService {
return XophpArray_.array_keys(this.serviceInstantiators); return XophpArray_.array_keys(this.serviceInstantiators);
} }
// /** /**
// * Define a new service. The service must not be known already. * Define a new service. The service must not be known already.
// * *
// * @see getService(). * @see getService().
// * @see redefineService(). * @see redefineService().
// * *
// * @param string $name The name of the service to register, for use with getService(). * @param string $name The name of the service to register, for use with getService().
// * @param callable $instantiator Callback that returns a service instance. * @param callable $instantiator Callback that returns a service instance.
// * Will be called with this ServiceContainer instance as the only parameter. * Will be called with this ServiceContainer instance as the only parameter.
// * Any extra instantiation parameters provided to the constructor will be * Any extra instantiation parameters provided to the constructor will be
// * passed as subsequent parameters when invoking the instantiator. * passed as subsequent parameters when invoking the instantiator.
// * *
// * @throws RuntimeException if there is already a service registered as $name. * @throws RuntimeException if there is already a service registered as $name.
// */ */
// public function defineService($name, callable $instantiator) { public void defineService(String name, XophpCallback instantiator) {
// Assert::parameterType('string', $name, '$name'); // Assert::parameterType('string', $name, '$name');
//
// if (this.hasService($name)) {
// throw new ServiceAlreadyDefinedException($name);
// }
//
// this.serviceInstantiators[$name] = $instantiator;
// }
// /** if (this.hasService(name)) {
// * Replace an already defined service. throw new XomwServiceAlreadyDefinedException(name);
// * }
// * @see defineService().
// * this.serviceInstantiators.Set(name, instantiator);
// * @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. /**
// * * Replace an already defined service.
// * @param string $name The name of the service to register. *
// * @param callable $instantiator Callback function that returns a service instance. * @see defineService().
// * Will be called with this ServiceContainer instance as the only parameter. *
// * The instantiator must return a service compatible with the originally defined service. * @note This will fail if the service was already instantiated. If the service was previously
// * Any extra instantiation parameters provided to the constructor will be * disabled, it will be re-enabled by this call. Any manipulators registered for the service
// * passed as subsequent parameters when invoking the instantiator. * will remain in place.
// * *
// * @throws NoSuchServiceException if $name is not a known service. * @param string $name The name of the service to register.
// * @throws CannotReplaceActiveServiceException if the service was already instantiated. * @param callable $instantiator Callback function that returns a service instance.
// */ * Will be called with this ServiceContainer instance as the only parameter.
// public function redefineService($name, callable $instantiator) { * The instantiator must return a service compatible with the originally defined service.
// Assert::parameterType('string', $name, '$name'); * Any extra instantiation parameters provided to the constructor will be
// * passed as subsequent parameters when invoking the instantiator.
// if (!this.hasService($name)) { *
// throw new NoSuchServiceException($name); * @throws NoSuchServiceException if $name is not a known service.
// } * @throws CannotReplaceActiveServiceException if the service was already instantiated.
// */
// if (isset(this.services[$name])) { public void redefineService(String name, XophpCallback instantiator) {
// throw new CannotReplaceActiveServiceException($name); // Assert::parameterType('string', $name, '$name');
// }
// if (!this.hasService(name)) {
// this.serviceInstantiators[$name] = $instantiator; throw new XomwNoSuchServiceException(name);
// unset(this.disabled[$name]); }
// }
// if (XophpArray_.isset(this.services, name)) {
// /** throw new XomwCannotReplaceActiveServiceException(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. this.serviceInstantiators.Set(name, instantiator);
// * XophpArray_.unset(this.disabled, name);
// * 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. /**
// * * Add a service manipulator callback for the given service.
// * @see defineService(). * This method may be used by extensions that need to wrap, replace, or re-configure a
// * @see redefineService(). * service. It would typically be called from a MediaWikiServices hook handler.
// * *
// * @note This will fail if the service was already instantiated. * 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
// * @since 1.32 * replace it.
// * *
// * @param string $name The name of the service to manipulate. * @see defineService().
// * @param callable $manipulator Callback function that manipulates, wraps or replaces a * @see redefineService().
// * service instance. The callback receives the new service instance and this *
// * ServiceContainer as parameters, as well as any extra instantiation parameters specified * @note This will fail if the service was already instantiated.
// * when constructing this ServiceContainer. If the callback returns a value, that *
// * value replaces the original service instance. * @since 1.32
// * *
// * @throws NoSuchServiceException if $name is not a known service. * @param string $name The name of the service to manipulate.
// * @throws CannotReplaceActiveServiceException if the service was already instantiated. * @param callable $manipulator Callback function that manipulates, wraps or replaces a
// */ * service instance. The callback receives the new service instance and this
// public function addServiceManipulator($name, callable $manipulator) { * ServiceContainer as parameters, as well as any extra instantiation parameters specified
// Assert::parameterType('string', $name, '$name'); * when constructing this ServiceContainer. If the callback returns a value, that
// * value replaces the original service instance.
// if (!this.hasService($name)) { *
// throw new NoSuchServiceException($name); * @throws NoSuchServiceException if $name is not a known service.
// } * @throws CannotReplaceActiveServiceException if the service was already instantiated.
// */
// if (isset(this.services[$name])) { public void addServiceManipulator(String name, XophpCallback manipulator) {
// throw new CannotReplaceActiveServiceException($name); // Assert::parameterType('string', $name, '$name');
// }
// if (!this.hasService(name)) {
// this.serviceManipulators[$name][] = $manipulator; throw new XomwNoSuchServiceException(name);
// } }
if (XophpArray_.isset(this.services, name)) {
throw new XomwCannotReplaceActiveServiceException(name);
}
this.serviceManipulators.Xet_by_ary(name).Add(manipulator);
}
/** /**
* Disables a service. * Disables a service.
@ -401,11 +405,11 @@ public class XomwServiceContainer implements XomwDestructibleService {
*/ */
public Object getService(String name) { public Object getService(String name) {
if (this.destroyed) { if (this.destroyed) {
// throw new XomwContainerDisabledException(); throw new XomwContainerDisabledException();
} }
if (XophpArray_.isset(this.disabled, name)) { if (XophpArray_.isset(this.disabled, name)) {
// throw new XomwServiceDisabledException($name); throw new XomwServiceDisabledException(name);
} }
if (!XophpArray_.isset(this.services, name)) { if (!XophpArray_.isset(this.services, name)) {
@ -422,35 +426,36 @@ public class XomwServiceContainer implements XomwDestructibleService {
* @return object * @return object
*/ */
private Object createService(String name) { private Object createService(String name) {
// if (isset(this.serviceInstantiators[$name])) { Object service;
// $service = (this.serviceInstantiators[$name])( if (XophpArray_.isset(this.serviceInstantiators, name)) {
// this, service = (this.serviceInstantiators.Get_by(name)).Call(
// ...this.extraInstantiationParams this,
// ); this.extraInstantiationParams
// );
// if (isset(this.serviceManipulators[$name])) {
// foreach (this.serviceManipulators[$name] as $callback) { if (XophpArray_.isset(this.serviceManipulators, name)) {
// $ret = call_user_func_array( Object ret;
// $callback, for (XophpCallback callback : this.serviceManipulators.Get_by(name)) {
// array_merge([ $service, this ], this.extraInstantiationParams) ret = XophpCallback.call_user_func_array(
// ); callback,
// XophpArray_.array_merge(XophpArray.New(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 the manipulator callback returns an object, that object replaces
// if ($ret !== null) { // the original service instance. This allows the manipulator to wrap
// $service = $ret; // 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); // NOTE: when adding more wiring logic here, make sure importWiring() is kept in sync!
// } } else {
// throw new XomwNoSuchServiceException(name);
// return $service; }
return null;
return service;
} }
/** /**

View File

@ -0,0 +1,37 @@
/*
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;
import gplx.String_;
import gplx.xowa.mediawiki.XophpException;
import gplx.xowa.mediawiki.XophpRuntimeException;
// MW.SRC:1.33.1
/**
* Exception thrown when trying to access a disabled service.
*/
public class XomwServiceDisabledException extends XophpRuntimeException {
/**
* @param string $serviceName
* @param Exception|null $previous
*/
public XomwServiceDisabledException(String serviceName) {this(serviceName, null);}
public XomwServiceDisabledException(String serviceName, XophpException previous) {
super(String_.Format("Service disabled: {0}", serviceName), 0, previous);
}
}