/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2016 Adobe
* %%
* 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.
* #L%
*/
package com.adobe.acs.commons.wcm.properties.shared.impl;
import com.adobe.acs.commons.wcm.PageRootProvider;
import com.adobe.acs.commons.wcm.properties.shared.SharedComponentProperties;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.components.Component;
import com.day.cq.wcm.commons.WCMUtils;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.scripting.api.BindingsValuesProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.Bindings;
import java.util.HashMap;
import java.util.Map;
/**
* Bindings Values Provider that adds bindings for globalProperties,
* sharedProperties, and mergedProperties maps.
* <p>
* globalProperties contains the shared properties accessible by
* all components.
* <p>
* sharedProperties contains the shared properties specific to the
* current component.
* <p>
* mergedProperties is a merge of the instance-level, shared, and
* global properties for the current component, giving preference
* to instance-level values, then shared values, and finally global
* values when properties exist at multiple levels with the same name.
*/
@org.apache.felix.scr.annotations.Component
@Service
public class SharedComponentPropertiesBindingsValuesProvider implements BindingsValuesProvider {
private static final Logger log = LoggerFactory.getLogger(SharedComponentPropertiesBindingsValuesProvider.class);
@Reference
private PageRootProvider pageRootProvider;
@Reference
private SharedComponentProperties sharedComponentProperties;
@Override
public void addBindings(Bindings bindings) {
Resource resource = (Resource) bindings.get("resource");
Component component = WCMUtils.getComponent(resource);
if (component != null) {
if (pageRootProvider != null) {
setSharedProperties(bindings, resource, component);
} else {
log.debug("Page Root Provider must be configured for shared component properties to be supported");
}
setMergedProperties(bindings, resource);
}
}
private void setSharedProperties(Bindings bindings, Resource resource, Component component) {
Page pageRoot = pageRootProvider.getRootPage(resource);
if (pageRoot != null) {
String globalPropsPath = pageRoot.getPath() + "/jcr:content/" + SharedComponentProperties.NN_GLOBAL_COMPONENT_PROPERTIES;
Resource globalPropsResource = resource.getResourceResolver().getResource(globalPropsPath);
if (globalPropsResource != null) {
bindings.put(SharedComponentProperties.GLOBAL_PROPERTIES, globalPropsResource.getValueMap());
}
String sharedPropsPath = pageRoot.getPath() + "/jcr:content/" + SharedComponentProperties.NN_SHARED_COMPONENT_PROPERTIES + "/"
+ component.getResourceType();
Resource sharedPropsResource = resource.getResourceResolver().getResource(sharedPropsPath);
if (sharedPropsResource != null) {
bindings.put(SharedComponentProperties.SHARED_PROPERTIES, sharedPropsResource.getValueMap());
}
} else {
log.debug("Could not determine shared properties root for resource {}", resource.getPath());
}
}
private void setMergedProperties(Bindings bindings, Resource resource) {
ValueMap globalPropertyMap = (ValueMap) bindings.get(SharedComponentProperties.GLOBAL_PROPERTIES);
ValueMap sharedPropertyMap = (ValueMap) bindings.get(SharedComponentProperties.SHARED_PROPERTIES);
ValueMap localPropertyMap = resource.getValueMap();
bindings.put(SharedComponentProperties.MERGED_PROPERTIES, mergeProperties(localPropertyMap, sharedPropertyMap, globalPropertyMap));
}
private ValueMap mergeProperties(ValueMap instanceProperties, ValueMap sharedProperties, ValueMap globalProperties) {
Map<String, Object> mergedProperties = new HashMap<String, Object>();
// Add Component Global Configs
if (globalProperties != null) {
mergedProperties.putAll(globalProperties);
}
// Add Component Shared Configs
if (sharedProperties != null) {
mergedProperties.putAll(sharedProperties);
}
// Merge in the Component Local Configs
if (instanceProperties != null) {
mergedProperties.putAll(instanceProperties);
}
return new ValueMapDecorator(mergedProperties);
}
}