blob: 534f9cca52ab3a0acd9106e882fb4c0661b86fe4 [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.serialization.impl;
import java.io.InputStream;
import java.util.Dictionary;
import java.util.Hashtable;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.commons.scheduler.Scheduler;
import org.apache.sling.distribution.DistributionRequest;
import org.apache.sling.distribution.common.DistributionException;
import org.apache.sling.distribution.component.impl.SettingsUtils;
import org.apache.sling.distribution.monitor.impl.MonitoringDistributionPackageBuilder;
import org.apache.sling.distribution.packaging.DistributionPackage;
import org.apache.sling.distribution.packaging.DistributionPackageBuilder;
import org.apache.sling.distribution.packaging.DistributionPackageInfo;
import org.apache.sling.distribution.packaging.impl.FileDistributionPackageBuilder;
import org.apache.sling.distribution.packaging.impl.InMemoryDistributionPackageBuilder;
import org.apache.sling.distribution.packaging.impl.ResourceDistributionPackageBuilder;
import org.apache.sling.distribution.packaging.impl.ResourceDistributionPackageCleanup;
import org.apache.sling.distribution.serialization.DistributionContentSerializer;
import org.apache.sling.distribution.util.impl.FileBackedMemoryOutputStream.MemoryUnit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.Option;
/**
* A factory for package builders
*/
@Component(
configurationPolicy = ConfigurationPolicy.REQUIRE,
service=DistributionPackageBuilder.class,
property= {
"webconsole.configurationFactory.nameHint=Builder name: {name}"
})
@Designate(ocd=DistributionPackageBuilderFactory.Config.class, factory=true)
public class DistributionPackageBuilderFactory implements DistributionPackageBuilder {
@ObjectClassDefinition(name="Apache Sling Distribution Packaging - Package Builder Factory",
description = "OSGi configuration for package builders")
public @interface Config {
@AttributeDefinition(name="name", description = "The name of the package builder.")
String name();
@AttributeDefinition(name="type",description = "The persistence type used by this package builder",
options = {
@Option(label = "resource", value="resource package"),
@Option(label="file", value="file package"),
@Option(label="inmemory", value="in memory packages")
})
String type() default "resource"; // persistence
@AttributeDefinition(name="Content Serializer",description = "The target reference for the DistributionSerializationFormat used to (de)serialize packages, " +
"e.g. use target=(name=...) to bind to services by name.")
String format_target() default SettingsUtils.COMPONENT_NAME_DEFAULT;
@AttributeDefinition(name="Temp Filesystem Folder", description = "The filesystem folder where the temporary files should be saved.")
String tempFsFolder();
@AttributeDefinition(name="File threshold",description = "Once the data reaches the configurable size value, buffering to memory switches to file buffering.")
int fileThreshold() default DEFAULT_FILE_THRESHOLD_VALUE;
@AttributeDefinition(name="The memory unit for the file threshold",
description = "The memory unit for the file threshold, Megabytes by default",
options = {
@Option(label = "BYTES", value = "Bytes"),
@Option(label = "KILO_BYTES", value = "Kilobytes"),
@Option(label = "MEGA_BYTES", value = "Megabytes"),
@Option(label = "GIGA_BYTES", value = "Gigabytes")
})
String memoryUnit() default DEFAULT_MEMORY_UNIT;
@AttributeDefinition(name="Flag to enable/disable the off-heap memory", description="Flag to enable/disable the off-heap memory, false by default")
boolean useOffHeapMemory() default DEFAULT_USE_OFF_HEAP_MEMORY;
@AttributeDefinition(
name = "The digest algorithm to calculate the package checksum",
description = "The digest algorithm to calculate the package checksum, Megabytes by default",
options = {
@Option(label = "NONE", value = "Do not send digest"),
@Option(label = "MD2", value = "md2"),
@Option(label = "MD5", value = "md5"),
@Option(label = "SHA-1", value = "sha1"),
@Option(label = "SHA-256", value = "sha256"),
@Option(label = "SHA-384", value = "sha384"),
@Option(label = "SHA-512", value = "sha512")
})
String digestAlgorithm() default DEFAULT_DIGEST_ALGORITHM;
@AttributeDefinition(
name="The number of items for monitoring distribution packages creation/installation",
description = "The number of items for monitoring distribution packages creation/installation, 100 by default")
int monitoringQueueSize() default DEFAULT_MONITORING_QUEUE_SIZE;
@AttributeDefinition(
name="The delay in seconds between two runs of the cleanup phase for resource persisted packages.",
description = "The resource persisted packages are cleaned up periodically (asynchronously) since SLING-6503." +
"The delay between two runs of the cleanup phase can be configured with this setting. 60 seconds by default")
long cleanupDelay() default DEFAULT_PACKAGE_CLEANUP_DELAY;
@AttributeDefinition(
name = "Package Node Filters",
description = "The package node path filters. Filter format: path|+include|-exclude",
cardinality = 100)
String[] package_filters();
@AttributeDefinition(
name = "Package Property Filters",
description = "The package property path filters. Filter format: path|+include|-exclude",
cardinality = Integer.MAX_VALUE)
String[] property_filters();
}
private MonitoringDistributionPackageBuilder packageBuilder;
private ServiceRegistration<Runnable> packageCleanup = null;
@Reference(name = "format")
private DistributionContentSerializer contentSerializer;
@Reference
private ResourceResolverFactory resolverFactory;
// 1M
private static final int DEFAULT_FILE_THRESHOLD_VALUE = 1;
private static final String DEFAULT_MEMORY_UNIT = "MEGA_BYTES";
private static final boolean DEFAULT_USE_OFF_HEAP_MEMORY = false;
private static final String DEFAULT_DIGEST_ALGORITHM = "NONE";
private static final int DEFAULT_MONITORING_QUEUE_SIZE = 0;
private static final long DEFAULT_PACKAGE_CLEANUP_DELAY = 60L;
@Activate
public void activate(BundleContext context,
Config conf) {
String[] nodeFilters = SettingsUtils.removeEmptyEntries(conf.package_filters());
String[] propertyFilters = SettingsUtils.removeEmptyEntries(conf.property_filters());
String persistenceType = conf.type();
String tempFsFolder = SettingsUtils.removeEmptyEntry(conf.tempFsFolder());
String digestAlgorithm = conf.digestAlgorithm();
long cleanupDelay = conf.cleanupDelay();
if (DEFAULT_DIGEST_ALGORITHM.equals(digestAlgorithm)) {
digestAlgorithm = null;
}
DistributionPackageBuilder wrapped;
if ("file".equals(persistenceType)) {
wrapped = new FileDistributionPackageBuilder(contentSerializer.getName(), contentSerializer, tempFsFolder, digestAlgorithm, nodeFilters, propertyFilters);
} else if ("inmemory".equals(persistenceType)) {
wrapped = new InMemoryDistributionPackageBuilder(contentSerializer.getName(), contentSerializer, nodeFilters, propertyFilters);
} else {
final int fileThreshold = conf.fileThreshold();
String memoryUnitName = conf.memoryUnit();
final MemoryUnit memoryUnit = MemoryUnit.valueOf(memoryUnitName);
final boolean useOffHeapMemory = conf.useOffHeapMemory();
ResourceDistributionPackageBuilder resourceDistributionPackageBuilder = new ResourceDistributionPackageBuilder(contentSerializer.getName(), contentSerializer, tempFsFolder, fileThreshold, memoryUnit, useOffHeapMemory, digestAlgorithm, nodeFilters, propertyFilters);
Runnable cleanup = new ResourceDistributionPackageCleanup(resolverFactory, resourceDistributionPackageBuilder);
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put(Scheduler.PROPERTY_SCHEDULER_CONCURRENT, false);
props.put(Scheduler.PROPERTY_SCHEDULER_PERIOD, cleanupDelay);
packageCleanup = context.registerService(Runnable.class, cleanup, props);
wrapped = resourceDistributionPackageBuilder;
}
int monitoringQueueSize = conf.monitoringQueueSize();
packageBuilder = new MonitoringDistributionPackageBuilder(monitoringQueueSize, wrapped, context);
}
@Deactivate
public void deactivate() {
packageBuilder.clear();
if (packageCleanup != null) {
packageCleanup.unregister();
}
}
public String getType() {
return packageBuilder.getType();
}
@NotNull
public DistributionPackage createPackage(@NotNull ResourceResolver resourceResolver, @NotNull DistributionRequest request) throws DistributionException {
return packageBuilder.createPackage(resourceResolver, request);
}
@NotNull
public DistributionPackage readPackage(@NotNull ResourceResolver resourceResolver, @NotNull InputStream stream) throws DistributionException {
return packageBuilder.readPackage(resourceResolver, stream);
}
@Nullable
public DistributionPackage getPackage(@NotNull ResourceResolver resourceResolver, @NotNull String id) throws DistributionException {
return packageBuilder.getPackage(resourceResolver, id);
}
public boolean installPackage(@NotNull ResourceResolver resourceResolver, @NotNull DistributionPackage distributionPackage) throws DistributionException {
return packageBuilder.installPackage(resourceResolver, distributionPackage);
}
@NotNull
@Override
public DistributionPackageInfo installPackage(@NotNull ResourceResolver resourceResolver, @NotNull InputStream stream) throws DistributionException {
return packageBuilder.installPackage(resourceResolver, stream);
}
}