/**
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package io.neba.api.resourcemodels;
import org.apache.sling.api.resource.Resource;
/**
* <h2>Function of the resource model cache</h2>
* Implementations cache the result of {@link Resource#adaptTo(Class) resource adaptations} to a specific target type.
* They are invoked by the generic NEBA adapter factory prior to the lookup and mapping of
* a {@link io.neba.api.annotations.ResourceModel}. If the model is not contained
* in any cache, it is obtained from its spring bean factory, mapped and afterwards
* {@link #put(Resource, Object, Object) added} to all known {@link ResourceModelCache resource model caches}.
*
* <h2>Providing a cache implementation</h2>
* To provide a cache implementation, publish an OSGi service with this interface.
* It will automatically be detected by NEBA. You may provide any number of caches. NEBA
* will always attempt to retrieve a cached model from all of them. The first cache
* {@link #get(Object) providing} a non-<code>null</code> model wins.
* There is no guarantee concerning the order in which caches are invoked.<br />
* Likewise, a model will be {@link #put(Resource, Object, Object) stored} in all available caches.
*
* <h2>Default implementations shipped with NEBA</h2>
* NEBA comes with a sensible default implementation of this cache, the <em>request-scoped resource model cache</em>,
* which is configurable via the Apache Felix console.<br />
*
* <h2>Architecture considerations when providing a custom cache implementation</h2>
* Caching is hard. You must be aware that correctly scoping, i.e. expiring objects
* from this cache is crucial for both system stability and semantic correctness. Specifically,
* items in the cache <em>must never ever</em>:
*
* <ul>
* <li>Live longer than the resources they represent, including any subsequent resources mapped to
* the resource model</li>
* <li>Live longer than the {@link io.neba.api.annotations.ResourceModel resource model}
* represented by the model type and any subsequent resource models mapped to it</li>
* </ul>
*
* @author Olaf Otto
*/
public interface ResourceModelCache {
/**
* Retrieve a cached model.
*
* @param key The key used to identify the stored model. Never <code>null</code>.
* @return The cached model, or <code>null</code>.
*/
<T> T get(Object key);
/**
* @param resource The resource {@link Resource#adaptTo(Class) adapted} to the target type. Never <code>null</code>.
* @param model the model representing the mapped result of the adaptation. Can be <code>null</code>.
* @param key the key by which the model is identified and {@link #get(Object) retrieved}. Never <code>null</code>.
*/
<T> void put(Resource resource, T model, Object key);
}