blob: c619d79c74e99d0123676c94755ac0d62456de01 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sling.distribution.journal.impl.subscriber;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static java.util.Objects.requireNonNull;
import static org.apache.sling.api.resource.ResourceResolverFactory.SUBSERVICE;
@ParametersAreNonnullByDefault
public class LocalStore {
private static final String ROOT_PATH = "/var/sling/distribution/journal/stores";
private static final Logger LOG = LoggerFactory.getLogger(LocalStore.class);
private final ResourceResolverFactory resolverFactory;
private final String storeId;
private final String rootPath;
public LocalStore(ResourceResolverFactory resolverFactory, String storeType,
String storeId) {
this.resolverFactory = Objects.requireNonNull(resolverFactory);
this.rootPath = String.format("%s/%s", ROOT_PATH, Objects.requireNonNull(storeType));
this.storeId = Objects.requireNonNull(storeId);
createParent();
}
public synchronized void store(ResourceResolver serviceResolver, String key, Object value)
throws PersistenceException {
store(serviceResolver, Collections.singletonMap(key, value));
}
public synchronized void store(ResourceResolver serviceResolver, Map<String, Object> map) throws PersistenceException {
Resource parent = getParent(serviceResolver);
Resource store = parent.getChild(storeId);
if (store != null) {
store.adaptTo(ModifiableValueMap.class).putAll(map);
} else {
serviceResolver.create(parent, storeId, map);
}
LOG.debug(String.format("Stored data %s for storeId %s", map.toString(), storeId));
}
public <T> T load(String key, T defaultValue) {
LOG.debug(String.format("Loading key %s for storeId %s with default value %s", key, storeId, defaultValue));
return load().get(key, defaultValue);
}
public ValueMap load() {
LOG.debug(String.format("Loading data for storeId %s", storeId));
try (ResourceResolver serviceResolver = requireNonNull(getBookKeeperServiceResolver())) {
Resource parent = getParent(serviceResolver);
Resource store = parent.getChild(storeId);
Map<String, Object> properties = (store != null) ? filterJcrProperties(store.getValueMap()) : emptyMap();
LOG.debug(String.format("Loaded data %s for storeId %s", properties.toString(), storeId));
return new ValueMapDecorator(properties);
} catch (LoginException e) {
throw new RuntimeException("Failed to load data from the repository." + e.getMessage(), e);
}
}
@Nonnull
private Resource getParent(ResourceResolver resolver) {
String msg = "Parent path " + rootPath + " must be created during provisioning.";
return requireNonNull(resolver.getResource(rootPath), msg);
}
private void createParent() {
try (ResourceResolver resolver = getBookKeeperServiceResolver()) {
ResourceUtil.getOrCreateResource(resolver,
rootPath, "sling:Folder", "sling:Folder", true);
} catch (Exception e) {
throw new RuntimeException("Failed to create parent path " + rootPath + ". " + e.getMessage(), e);
}
}
private Map<String, Object> filterJcrProperties(ValueMap map) {
return map.entrySet().stream()
.filter(e -> ! e.getKey().startsWith("jcr:"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private ResourceResolver getBookKeeperServiceResolver() throws LoginException {
return resolverFactory.getServiceResourceResolver(singletonMap(SUBSERVICE, "bookkeeper"));
}
}