blob: 110cac1af41035ac34179cdef4f50920c4a0c1b1 [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.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.resourceresolver.impl.tree.ProviderHandler;
import org.apache.sling.resourceresolver.impl.tree.ResourceProviderFactoryHandler;
import org.apache.sling.resourceresolver.impl.tree.ResourceProviderHandler;
/**
* Helper class to get a sorted list of resource providers which implement
* a specific feature interface.
*/
public class SortedProviderList<T> {
/** The feature interface class. */
private final Class<T> genericClass;
/** Sorted list of providers and factories. */
private Entry[] sortedList = new Entry[0];
/**
* We need the class to do the instanceof test for providers
* returned by the factory.
*/
public SortedProviderList(final Class<T> genericClass) {
this.genericClass = genericClass;
}
public interface Filter<T> {
boolean select(ProviderHandler handler, T provider);
}
/**
* Return an iterator for the current sorted list of providers
* implementing the feature interface.
*/
public Iterator<T> getProviders(final ResourceResolverContext ctx, final Filter<T> filter) {
return new Iterator<T>() {
private final Entry[] list = sortedList;
private int index = 0;
private Object nextObject = seek();
private Object seek() {
Object result;
if ( this.index < list.length ) {
final Entry entry = list[this.index];
result = entry.object;
this.index++;
if ( result instanceof ResourceProviderFactoryHandler ) {
result = ((ResourceProviderFactoryHandler)result).getResourceProvider(ctx);
if ( !genericClass.isAssignableFrom(result.getClass())) {
result = null;
}
}
if ( result != null && filter != null && !filter.select(entry.handler, (T)result)) {
result = null;
}
if ( result == null ) {
result = seek();
}
} else {
result = null;
}
return result;
}
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return this.nextObject != null;
}
/**
* @see java.util.Iterator#next()
*/
@SuppressWarnings("unchecked")
public T next() {
if ( this.nextObject == null ) {
throw new NoSuchElementException();
}
final Object result = this.nextObject;
this.nextObject = seek();
return (T)result;
}
/**
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Add an object to the list
*/
private synchronized void addToList(final Object obj,
final ProviderHandler handler) {
final List<Entry> list = new ArrayList<Entry>();
list.addAll(Arrays.asList(this.sortedList));
list.add(new Entry(obj, handler));
Collections.sort(list);
this.sortedList = list.toArray(new Entry[list.size()]);
}
/**
* Remove an object from the list
*/
private synchronized void removeFromList(final Object obj) {
final List<Entry> list = new ArrayList<Entry>();
list.addAll(Arrays.asList(this.sortedList));
final Iterator<Entry> i = list.iterator();
while ( i.hasNext() ) {
final Entry entry = i.next();
if ( entry.object.equals(obj) ) {
i.remove();
break;
}
}
this.sortedList = list.toArray(new Entry[list.size()]);
}
/**
* Add a resource provider
* This first checks if it implements the feature interface.
*/
public void add(final ResourceProviderHandler rpHandler) {
if ( genericClass.isAssignableFrom(rpHandler.getResourceProvider().getClass())) {
this.addToList(rpHandler.getResourceProvider(), rpHandler);
}
}
/**
* Add a resource provider factory. We don't know yet if the
* resource provider implements the feature interface.
* This will be checked on demand.
*/
public void add(final ResourceProviderFactoryHandler factory) {
this.addToList(factory, factory);
}
/**
* Remove a resource provider.
*/
public void remove(final ResourceProviderHandler rpHandler) {
if ( genericClass.isAssignableFrom(rpHandler.getResourceProvider().getClass())) {
this.removeFromList(rpHandler.getResourceProvider());
}
}
/**
* Remove a resource provider factory.
*/
public void remove(final ResourceProviderFactoryHandler factory) {
this.removeFromList(factory);
}
/**
* returns the ProviderHandler for a specific resource provider
*/
public ProviderHandler getProviderHandler ( ResourceResolverContext ctx, ResourceProvider resourceProvider )
{
ProviderHandler returnValue = null;
final List<Entry> list = new ArrayList<Entry>();
list.addAll(Arrays.asList(this.sortedList));
final Iterator<Entry> i = list.iterator();
while ( i.hasNext() ) {
final Entry entry = i.next();
if ( entry.handler.getResourceProvider(ctx).equals(resourceProvider) ) {
returnValue = entry.handler;
break;
}
}
return returnValue;
}
private static final class Entry implements Comparable<Entry> {
private final String path;
public final ProviderHandler handler;
public final Object object;
public Entry(final Object object,
final ProviderHandler handler) {
this.object = object;
if ( handler.getRoots() != null ) {
this.path = handler.getRoots()[0];
} else {
this.path = "";
}
this.handler = handler;
}
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(final Entry other) {
int result = this.path.compareTo(other.path);
if ( result == 0 ) {
result = this.handler.getServiceId().compareTo(other.handler.getServiceId());
}
return result;
}
}
}