blob: 460f912190b3da40eb63a3d11d7a74f3651cd14a [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.resourceresolver.impl.helper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceDecorator;
import org.apache.sling.commons.osgi.ServiceUtil;
/**
* Helper class to track the resource decorators and keep them sorted by their
* service ranking.
*/
public class ResourceDecoratorTracker {
private static final ResourceDecorator[] EMPTY_ARRAY = new ResourceDecorator[0];
/**
* The (optional) resource decorators, working copy.
*/
protected final List<ResourceDecoratorEntry> resourceDecorators = new ArrayList<ResourceDecoratorEntry>();
/**
* An array of the above, updates when changes are created.
*/
private volatile ResourceDecorator[] resourceDecoratorsArray = EMPTY_ARRAY;
public void close() {
synchronized (this.resourceDecorators) {
this.resourceDecorators.clear();
this.resourceDecoratorsArray = EMPTY_ARRAY;
}
}
/**
* Decorate a resource.
*/
public Resource decorate(final Resource resource) {
Resource result = resource;
final ResourceDecorator[] decorators = this.resourceDecoratorsArray;
for (final ResourceDecorator decorator : decorators) {
final Resource original = result;
result = decorator.decorate(original);
if (result == null) {
result = original;
}
}
// make resource metadata read-only
result.getResourceMetadata().lock();
return result;
}
/**
* Bind a resource decorator.
*/
public void bindResourceDecorator(final ResourceDecorator decorator,
final Map<String, Object> props) {
synchronized (this.resourceDecorators) {
this.resourceDecorators.add(new ResourceDecoratorEntry(decorator,
ServiceUtil.getComparableForServiceRanking(props)));
Collections.sort(this.resourceDecorators);
updateResourceDecoratorsArray();
}
}
/**
* Unbind a resouce decorator.
*/
public void unbindResourceDecorator(final ResourceDecorator decorator,
final Map<String, Object> props) {
synchronized (this.resourceDecorators) {
final Iterator<ResourceDecoratorEntry> i = this.resourceDecorators
.iterator();
while (i.hasNext()) {
final ResourceDecoratorEntry current = i.next();
if (current.decorator == decorator) {
i.remove();
break;
}
}
updateResourceDecoratorsArray();
}
}
/**
* Updates the ResourceDecorators array, this method is not thread safe and
* should only be called from a synchronized block.
*/
private void updateResourceDecoratorsArray() {
final ResourceDecorator[] decorators;
if (this.resourceDecorators.size() > 0) {
decorators = new ResourceDecorator[this.resourceDecorators.size()];
int index = 0;
final Iterator<ResourceDecoratorEntry> i = this.resourceDecorators
.iterator();
while (i.hasNext()) {
decorators[index] = i.next().decorator;
index++;
}
} else {
decorators = EMPTY_ARRAY;
}
this.resourceDecoratorsArray = decorators;
}
/**
* Internal class to keep track of the resource decorators.
*/
private static final class ResourceDecoratorEntry implements
Comparable<ResourceDecoratorEntry> {
final Comparable<Object> comparable;
final ResourceDecorator decorator;
public ResourceDecoratorEntry(final ResourceDecorator d,
final Comparable<Object> comparable) {
this.comparable = comparable;
this.decorator = d;
}
public int compareTo(final ResourceDecoratorEntry o) {
return comparable.compareTo(o.comparable);
}
}
}