/** * Copyright 2013 the original author or authors. * <p/> * 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 * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * 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.core.resourcemodels.tagsupport; import io.neba.api.resourcemodels.ResourceModelProvider; import io.neba.core.resourcemodels.caching.ResourceModelCaches; import io.neba.core.resourcemodels.mapping.ResourceToModelMapper; import io.neba.core.resourcemodels.registration.LookupResult; import io.neba.core.resourcemodels.registration.ModelRegistry; import io.neba.core.util.Key; import io.neba.core.util.OsgiBeanSource; import org.apache.sling.api.resource.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Collection; import static io.neba.api.Constants.SYNTHETIC_RESOURCETYPE_ROOT; import static io.neba.core.util.Key.toKey; /** * Resolves a {@link Resource} to a {@link io.neba.api.annotations.ResourceModel} * if a model is registered for the {@link Resource#getResourceType() resource type}. * <br /> * Serves as a source for generic models if the resource cannot be * {@link Resource#adaptTo(Class) adapted} to a specific target type.<br /> * If multiple generic models specifically target the type of the given resource through their * {@link io.neba.api.annotations.ResourceModel#types()}, this provider * may return <code>null</code> since there are no means to automatically resolve such ambiguities. * * @author Olaf Otto */ @Service public class ResourceModelProviderImpl implements ResourceModelProvider { @Autowired private ModelRegistry registry; @Autowired private ResourceToModelMapper mapper; @Autowired private ResourceModelCaches caches; @Override public Object resolveMostSpecificModelWithBeanName(Resource resource, String beanName) { if (resource == null) { throw new IllegalArgumentException("Method argument resource must not be null."); } if (beanName == null) { throw new IllegalArgumentException("Method argument beanName must not be null."); } return resolveMostSpecificModelForResource(resource, true, beanName); } @Override public Object resolveMostSpecificModel(Resource resource) { if (resource == null) { throw new IllegalArgumentException("Method argument resource must not be null."); } return resolveMostSpecificModelForResource(resource, false, null); } @Override public Object resolveMostSpecificModelIncludingModelsForBaseTypes(Resource resource) { if (resource == null) { throw new IllegalArgumentException("Method argument resource must not be null."); } return resolveMostSpecificModelForResource(resource, true, null); } private Object resolveMostSpecificModelForResource(Resource resource, boolean includeBaseTypes, String beanName) { final Key key = toKey(resource.getPath(), includeBaseTypes, beanName, resource.getResourceType()); Object model = this.caches.lookup(key); if (model == null) { Collection<LookupResult> models = (beanName == null) ? this.registry.lookupMostSpecificModels(resource) : this.registry.lookupMostSpecificModels(resource, beanName); if (models != null && models.size() == 1) { LookupResult lookupResult = models.iterator().next(); if (includeBaseTypes || !isMappedFromGenericBaseType(lookupResult)) { OsgiBeanSource<?> source = lookupResult.getSource(); model = this.mapper.map(resource, source); this.caches.store(resource, model, key); } } } return model; } private boolean isMappedFromGenericBaseType(LookupResult lookupResult) { final String resourceType = lookupResult.getResourceType(); return "nt:unstructured".equals(resourceType) || "nt:base".equals(resourceType) || SYNTHETIC_RESOURCETYPE_ROOT.equals(resourceType); } }