New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider impact of Configuration interface on non-compliant implementations. #252
Comments
Why can't a non-compliant implementation simply return Object.class for key and value, and boolean for the true false ones and null for the listeners etc. And then on the MutableConfiguration side, thy can throw an UnsupportedMethodException when methods that they do not support a called. This seems straight forward to me. |
The challenge is that the Configuration interface is used for/serves two purposes. Purpose 1. Providing Configuration to an implementation. Purpose 1: Let's consider a hypothetical case for say Memcached that doesn't support read-through, write-through, expiry etc. Such a vendor is required by contract (of the Configuration interface) to provide implementations of all of the getters, even though they don't make sense. public class MemcachedConfiguration<K, V> implements Configuration<K, V> {
... all of the Configuration methods (read-through, write-through et al) need to be implemented here, even though they don't make sense ...
} What I'm saying is that the minimum interface for defining/configuring a cache could be, as you point out, as simple as key type, value type and whether it's by reference / by value. Everything else is mostly not required by an application wanting to do just simple caching. Purpose 2: It's also not clear for developers (looking at the Javadoc API say for the hypothetical MemcachedConfiguration, what is supported). What's interesting is that we've gone to the trouble of cleanly isolating each of the features (like integration, events etc) into separate packages, but we've not done so at the Configuration level. I'm not saying we should relax the requirements for TCK compliants here, but if we follow the same pattern of separating out Configuration, into separate interfaces (like ObservableConfiguration, IntegrationConfiguration etc as an idea), it leads to a very clean API that allows both compliant and non-compliant implementations to clearly express what they support and don't necessarily support without ever having to throw an UnsupportedOperationException. The impact on the RI and TCK would effectively be zero as the MutableConfiguration class would implement all of the interfaces and the SPEC would clearly say that all are mandatory (as they are now). In the future, should we require it, we can relax that requirement without changing the API, to allow currently non-compliant implementations (like a hypothetic Memcached implementation) to be compliant. We'd simply change the wording in the SPEC document and update the TCK. |
After discussion, we can see the advantages, to encourage non TCK compliant API usage. It would work as follows:
e.g. Cache<String, Integer> cache = cacheManager.createCache("my-cache", new MutableConfiguration<>());
cache.getConfiguration(Configuration.class); |
Implemented. Have some new tests and spec changes to do. |
Tests done and spec changed. |
Currently all implementations that provide their own configurations are forced to implement all of the methods of the Configuration interface.
This implies that all implementations must provide configuration for: read-through, listeners, writers, loaders, expiry etc, regardless of whether they can provide said support.
eg: If an implementation simply wants to make use of the Cache interface (in a non-compliant manner) say for get/put etc operations, the implementation is forced to provide/return values for read-through, loaders, writers, expiry policy configurations, even if they don't make sense.
While it's very important the compliant implementations provide support for these features, it's equally important to allow for custom implementations (that may be non-compliant or may be configured differently yet still be compliant).
One solution would be to refactor the interface into separate parts, say for each feature "area", then provide a minimal part that all implementations (compliant and non-compliant) could support. This "minimal part" would only supply the type information and store-by-reference/value semantics for configuration. eg: Change the Configuration interface to look something like this.
Once this is in place we could introduce a few other sub-interfaces to define the configuration of specific specialized features.
eg 1: an IntegrationConfiguration sub-interface that would contain all of the read-through, loader, writer configuration.
eg 2: a ManagementConfiguration sub-interface that would contain the management / statistics configuration.
eg 3: an ObservableConfiguration sub-interface that would contain the listener configuration.
Lastly, the MutableConfiguration class would actually remain the same, but simply implement all of these interfaces. All TCK tests and the RI would remain unchanged.
Importantly this would pave the way for allowing non-compliant but eventually compliant implementations for products like Memcached without us ever having to change the specification API. We'd simply choose to relax some of the TCK requirements - and only test certain configuration interface implementations.
This would also allow us to avoid introducing the concept of "profiles" or changing the API radically in the future.
The impact on existing implementations would be almost nil.
The text was updated successfully, but these errors were encountered: