/*
* 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.pipes.internal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
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.distribution.DistributionRequest;
import org.apache.sling.distribution.DistributionRequestType;
import org.apache.sling.distribution.DistributionResponse;
import org.apache.sling.distribution.Distributor;
import org.apache.sling.distribution.SimpleDistributionRequest;
import org.apache.sling.pipes.BasePipe;
import org.apache.sling.pipes.ContainerPipe;
import org.apache.sling.pipes.Pipe;
import org.apache.sling.pipes.Plumber;
import org.apache.sling.pipes.ReferencePipe;
import org.osgi.service.component.annotations.Activate;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* implements plumber interface, and registers default pipes
*/
@Component(service = {Plumber.class})
public class PlumberImpl implements Plumber {
private final Logger log = LoggerFactory.getLogger(this.getClass());
Map<String, Class<? extends BasePipe>> registry;
@Reference(policy= ReferencePolicy.DYNAMIC, cardinality= ReferenceCardinality.OPTIONAL)
protected volatile Distributor distributor = null;
@Activate
public void activate(){
registry = new HashMap<>();
registerPipe(BasePipe.RESOURCE_TYPE, BasePipe.class);
registerPipe(ContainerPipe.RESOURCE_TYPE, ContainerPipe.class);
registerPipe(SlingQueryPipe.RESOURCE_TYPE, SlingQueryPipe.class);
registerPipe(WritePipe.RESOURCE_TYPE, WritePipe.class);
registerPipe(JsonPipe.RESOURCE_TYPE, JsonPipe.class);
registerPipe(MultiPropertyPipe.RESOURCE_TYPE, MultiPropertyPipe.class);
registerPipe(AuthorizablePipe.RESOURCE_TYPE, AuthorizablePipe.class);
registerPipe(XPathPipe.RESOURCE_TYPE, XPathPipe.class);
registerPipe(ReferencePipe.RESOURCE_TYPE, ReferencePipe.class);
registerPipe(RemovePipe.RESOURCE_TYPE, RemovePipe.class);
registerPipe(ParentPipe.RESOURCE_TYPE, ParentPipe.class);
registerPipe(MovePipe.RESOURCE_TYPE, MovePipe.class);
registerPipe(PathPipe.RESOURCE_TYPE, PathPipe.class);
registerPipe(FilterPipe.RESOURCE_TYPE, FilterPipe.class);
registerPipe(NotPipe.RESOURCE_TYPE, NotPipe.class);
}
@Override
public Pipe getPipe(Resource resource) {
if ((resource == null) || !registry.containsKey(resource.getResourceType())) {
log.error("Pipe configuration resource is either null, or its type is not registered");
} else {
try {
Class<? extends Pipe> pipeClass = registry.get(resource.getResourceType());
return pipeClass.getDeclaredConstructor(Plumber.class, Resource.class).newInstance(this, resource);
} catch (Exception e) {
log.error("Unable to properly instantiate the pipe configured in {}", resource.getPath(), e);
}
}
return null;
}
@Override
public Set<String> execute(ResourceResolver resolver, String path, Map additionalBindings, boolean save) throws Exception {
Resource pipeResource = resolver.getResource(path);
Pipe pipe = getPipe(pipeResource);
if (pipe == null) {
throw new Exception("unable to build pipe based on configuration at " + path);
}
return execute(resolver, pipe, additionalBindings, save);
}
@Override
public Set<String> execute(ResourceResolver resolver, Pipe pipe, Map additionalBindings, boolean save) throws Exception {
if (additionalBindings != null && pipe instanceof ContainerPipe){
pipe.getBindings().addBindings(additionalBindings);
}
log.info("[{}] execution starts, save ({})", pipe, save);
Set<String> set = new HashSet<>();
for (Iterator<Resource> it = pipe.getOutput(); it.hasNext();){
Resource resource = it.next();
if (resource != null) {
log.debug("[{}] retrieved {}", pipe.getName(), resource.getPath());
set.add(resource.getPath());
}
}
if (save) {
persist(resolver, pipe, set);
}
log.info("[{}] done executing.", pipe.getName());
return set;
}
@Override
public void persist(ResourceResolver resolver, Pipe pipe, Set<String> paths) throws PersistenceException {
if (pipe.modifiesContent() && resolver.hasChanges() && !pipe.isDryRun()){
log.info("[{}] saving changes...", pipe.getName());
resolver.commit();
if (distributor != null && StringUtils.isNotBlank(pipe.getDistributionAgent())) {
log.info("a distribution agent is configured, will try to distribute the changes");
DistributionRequest request = new SimpleDistributionRequest(DistributionRequestType.ADD, true, paths.toArray(new String[paths.size()]));
DistributionResponse response = distributor.distribute(pipe.getDistributionAgent(), resolver, request);
log.info("distribution response : {}", response);
}
}
}
@Override
public void registerPipe(String type, Class<? extends BasePipe> pipeClass) {
registry.put(type, pipeClass);
}
}