ParsysConfigManagerImpl.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2014 wcm.io
* %%
* 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 io.wcm.wcm.parsys.componentinfo.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.osgi.Order;
import org.apache.sling.commons.osgi.RankedServices;
import org.jetbrains.annotations.NotNull;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import io.wcm.sling.commons.resource.ResourceType;
import io.wcm.wcm.parsys.componentinfo.ParsysConfig;
import io.wcm.wcm.parsys.componentinfo.ParsysConfigManager;
/**
* Collects paragraph system configurations from repository and OSGi configuration.
* Apply super resource type based inheritance to both configuration types.
*/
@Component(service = ParsysConfigManager.class, immediate = true, reference = {
@Reference(service = ParsysConfig.class, name = "parsysConfig",
bind = "bindParsysConfig", unbind = "unbindParsysConfig",
cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
})
public final class ParsysConfigManagerImpl implements ParsysConfigManager {
private final RankedServices<ParsysConfig> osgiParsysConfigs = new RankedServices<>(Order.ASCENDING);
@Override
public @NotNull Iterable<ParsysConfig> getParsysConfigs(@NotNull String pageComponentPath, @NotNull ResourceResolver resolver) {
Resource pageComponentResource = resolver.getResource(pageComponentPath);
if (pageComponentResource != null) {
return Collections.unmodifiableCollection(getParsysConfigsWithInheritance(pageComponentResource, resolver));
}
else {
return Collections.emptyList();
}
}
@Override
public @NotNull Iterable<ParsysConfig> getParsysConfigs(@NotNull final String pageComponentPath, @NotNull final String relativePath,
@NotNull final ResourceResolver resolver) {
Iterable<ParsysConfig> configs = getParsysConfigs(pageComponentPath, resolver);
return IterableUtils.filteredIterable(configs, parsysConfig -> {
// sanity check
if (parsysConfig == null || parsysConfig.getPathPattern() == null) {
return false;
}
Pattern pathPattern = parsysConfig.getPathPattern();
if (pathPattern == null) {
return false;
}
return pathPattern.matcher(relativePath).matches();
});
}
private Collection<ParsysConfig> getParsysConfigs(Resource pageComponentResource) {
List<ParsysConfig> configs = new ArrayList<>();
// get first jcr parsys configurations for this page component
ResourceParsysConfigProvider resourceParsysConfigProvider = new ResourceParsysConfigProvider(pageComponentResource);
configs.addAll(resourceParsysConfigProvider.getPathDefs());
// add osgi parsys configurations
for (ParsysConfig osgiParsysConfig : osgiParsysConfigs) {
if (ResourceType.equals(pageComponentResource.getPath(), osgiParsysConfig.getPageComponentPath(), pageComponentResource.getResourceResolver())) {
configs.add(osgiParsysConfig);
}
}
return configs;
}
@SuppressWarnings("null")
private Collection<ParsysConfig> getParsysConfigsWithInheritance(Resource pageComponentResource, ResourceResolver resolver) {
List<ParsysConfig> configs = new ArrayList<>();
// get path definitions from this page component
configs.addAll(getParsysConfigs(pageComponentResource));
// add path definitions from for super page components
String resourceSuperType = pageComponentResource.getResourceSuperType();
if (StringUtils.isNotEmpty(resourceSuperType)) {
Resource superResource = resolver.getResource(resourceSuperType);
if (superResource != null) {
Collection<ParsysConfig> configsFromSupertype = getParsysConfigsWithInheritance(superResource, resolver);
List<ParsysConfig> inheritedConfigs = new ArrayList<>();
for (ParsysConfig configFromSupertype : configsFromSupertype) {
if (existingPathParentConfigAllowsInheritance(configFromSupertype, configs)) {
inheritedConfigs.add(configFromSupertype);
}
}
configs.addAll(inheritedConfigs);
}
}
return configs;
}
private boolean existingPathParentConfigAllowsInheritance(ParsysConfig item, List<ParsysConfig> existingItems) {
for (ParsysConfig existingItem : existingItems) {
if (matchesPathParent(item, existingItem) && !existingItem.isInherit()) {
return false;
}
}
return true;
}
private boolean matchesPathParent(ParsysConfig item1, ParsysConfig item2) {
Pattern pattern1 = item1.getPathPattern();
Pattern pattern2 = item2.getPathPattern();
String pathPattern1 = pattern1 != null ? pattern1.pattern() : "";
String pathPattern2 = pattern2 != null ? pattern2.pattern() : "";
return pathPattern1.equals(pathPattern2)
&& item1.getParentAncestorLevel() == item2.getParentAncestorLevel()
&& item1.getAllowedParents().equals(item2.getAllowedParents());
}
void bindParsysConfig(ParsysConfig service, Map<String, Object> props) {
osgiParsysConfigs.bind(service, props);
}
void unbindParsysConfig(ParsysConfig service, Map<String, Object> props) {
osgiParsysConfigs.unbind(service, props);
}
}