Author: cziegeler
Date: Wed Oct 28 11:09:00 2015
New Revision: 1710993

URL: http://svn.apache.org/viewvc?rev=1710993&view=rev
Log:
SLING-5162 : Support for the new observation API in the resource resolver. 
Apply partial patch from Tomek Rekawek

Added:
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
   (with props)
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
   (with props)
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
   (with props)
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
   (with props)
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java
   (with props)
Modified:
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java
    
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java

Modified: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java?rev=1710993&r1=1710992&r2=1710993&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java
 Wed Oct 28 11:09:00 2015
@@ -18,7 +18,6 @@
  */
 package org.apache.sling.resourceresolver.impl;
 
-import org.apache.sling.api.SlingException;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
@@ -96,8 +95,6 @@ public class BasicResolveContext<T> impl
                             } catch ( final LoginException se) {
                                 // skip this, try next
                                 this.parentProvider = null;
-                            } catch ( final SlingException se) {
-                                // TODO we should rather catch LoginException 
from getStatefulResourceProvider
                             }
                             if ( this.parentProvider == null ) {
                                 path = ResourceUtil.getParent(path);

Added: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java?rev=1710993&view=auto
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
 (added)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
 Wed Oct 28 11:09:00 2015
@@ -0,0 +1,90 @@
+/*
+ * 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.observation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.sling.api.resource.observation.ResourceChange;
+import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.apache.sling.spi.resource.provider.ObservationReporter;
+import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+
+public class BasicObservationReporter implements ObservationReporter {
+
+    private final Map<ResourceChangeListener, ObserverConfiguration> listeners;
+
+    private final List<ObserverConfiguration> configs;
+
+    public BasicObservationReporter(Map<ResourceChangeListener, 
ObserverConfiguration> listeners) {
+        this.listeners = new HashMap<ResourceChangeListener, 
ObserverConfiguration>(listeners);
+        this.configs = new 
ArrayList<ObserverConfiguration>(listeners.values());
+    }
+
+    @Override
+    public List<ObserverConfiguration> getObserverConfigurations() {
+        return configs;
+    }
+
+    @Override
+    public void reportChanges(Iterable<ResourceChange> changes, boolean 
distribute) {
+        for (Entry<ResourceChangeListener, ObserverConfiguration> e : 
listeners.entrySet()) {
+            List<ResourceChange> filtered = filterChanges(changes, 
e.getValue());
+            e.getKey().onChange(filtered);
+        }
+    }
+
+    private List<ResourceChange> filterChanges(Iterable<ResourceChange> 
changes, ObserverConfiguration config) {
+        List<ResourceChange> filtered = new ArrayList<ResourceChange>();
+        for (ResourceChange c : changes) {
+            if (matches(c, config)) {
+                filtered.add(c);
+            }
+        }
+        return filtered;
+    }
+
+    private boolean matches(ResourceChange change, ObserverConfiguration 
config) {
+        if (!config.getChangeTypes().contains(change.getType())) {
+            return false;
+        }
+        if (!config.includeExternal() && change.isExternal()) {
+            return false;
+        }
+        for (String excludedPath : config.getExcludedPaths()) {
+            if (change.getPath().startsWith(excludedPath)) {
+                return false;
+            }
+        }
+        boolean included = false;
+        for (String includedPath : config.getPaths()) {
+            if (change.getPath().startsWith(includedPath)) {
+                included = true;
+                break;
+            }
+        }
+        if (!included) {
+            return false;
+        }
+        return true;
+    }
+}

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObservationReporter.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java?rev=1710993&view=auto
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
 (added)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
 Wed Oct 28 11:09:00 2015
@@ -0,0 +1,184 @@
+/*
+ * 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.observation;
+
+import static java.util.Arrays.asList;
+import static 
org.apache.sling.api.resource.observation.ResourceChangeListener.CHANGES;
+import static 
org.apache.sling.api.resource.observation.ResourceChangeListener.PATHS;
+import static org.apache.sling.commons.osgi.PropertiesUtil.toStringArray;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+
+public class BasicObserverConfiguration implements ObserverConfiguration {
+
+    private final boolean includeExternal;
+
+    private final Set<String> paths;
+
+    private final Set<String> excludedPaths;
+
+    private final Set<ChangeType> changeTypes;
+
+    private BasicObserverConfiguration(Builder builder) {
+        this.includeExternal = builder.isIncludeExternal();
+        this.paths = builder.getPaths();
+        this.excludedPaths = builder.getExludedPaths();
+        this.changeTypes = builder.getChangeTypes();
+    }
+
+    @Override
+    public boolean includeExternal() {
+        return includeExternal;
+    }
+
+    @Override
+    public Set<String> getPaths() {
+        return paths;
+    }
+
+    @Override
+    public Set<String> getExcludedPaths() {
+        return excludedPaths;
+    }
+
+    @Override
+    public Set<ChangeType> getChangeTypes() {
+        return changeTypes;
+    }
+
+    public static class Builder {
+        private boolean includeExternal;
+
+        private Set<String> paths = Collections.emptySet();
+
+        private Set<String> excludedPaths = Collections.emptySet();
+
+        private Set<ChangeType> changeTypes = Collections.emptySet();
+
+        private String[] searchPaths = new String[0];
+
+        public boolean isIncludeExternal() {
+            return includeExternal;
+        }
+
+        public Builder setIncludeExternal(boolean includeExternal) {
+            this.includeExternal = includeExternal;
+            return this;
+        }
+
+        public Set<String> getPaths() {
+            return normalizePaths(paths);
+        }
+
+        public Builder setPaths(Set<String> paths) {
+            this.paths = paths;
+            return this;
+        }
+
+        public Set<String> getExludedPaths() {
+            return normalizePaths(excludedPaths);
+        }
+
+        public Builder setExcludedPaths(Set<String> excludedPaths) {
+            this.excludedPaths = excludedPaths;
+            return this;
+        }
+
+        public Set<ChangeType> getChangeTypes() {
+            return changeTypes;
+        }
+
+        public Builder setChangeTypes(Set<ChangeType> changeTypes) {
+            this.changeTypes = changeTypes;
+            return this;
+        }
+
+        public Builder setFromProperties(Map<String, Object> properties) {
+            if (properties.containsKey(PATHS)) {
+                this.paths = new 
HashSet<String>(asList(toStringArray(properties.get(PATHS))));
+            } else {
+                this.paths = Collections.emptySet();
+            }
+            if (properties.containsKey(CHANGES)) {
+                this.changeTypes = EnumSet.noneOf(ChangeType.class);
+                for (String changeName : 
toStringArray(properties.get(CHANGES))) {
+                    this.changeTypes.add(ChangeType.valueOf(changeName));
+                }
+            } else {
+                this.changeTypes = EnumSet.allOf(ChangeType.class);
+            }
+            return this;
+        }
+
+        public Builder setSearchPaths(String[] searchPaths) {
+            this.searchPaths = searchPaths;
+            return this;
+        }
+
+        public ObserverConfiguration build() {
+            return new BasicObserverConfiguration(this);
+        }
+
+        private Set<String> normalizePaths(Set<String> relativePaths) {
+            Set<String> absolutePaths = getAbsolutePaths(relativePaths);
+            removeSubPaths(absolutePaths);
+            return absolutePaths;
+        }
+
+        private static void removeSubPaths(Set<String> absolutePaths) {
+            Iterator<String> it = absolutePaths.iterator();
+            while (it.hasNext()) {
+                String currentPath = it.next();
+                for (String p : absolutePaths) {
+                    if (!p.equals(currentPath) && currentPath.startsWith(p)) {
+                        it.remove();
+                        break;
+                    }
+                }
+            }
+        }
+
+        private Set<String> getAbsolutePaths(Set<String> relativePaths) {
+            Set<String> absolutePaths = new HashSet<String>();
+            if (relativePaths == null) {
+                return absolutePaths;
+            }
+            for (String path : relativePaths) {
+                if (path.startsWith("/")) {
+                    absolutePaths.add(path);
+                } else if (".".equals(path)) {
+                    absolutePaths.add("/");
+                } else {
+                    for (String searchPath : searchPaths) {
+                        absolutePaths.add(searchPath + path);
+                    }
+                }
+            }
+            return absolutePaths;
+        }
+    }
+}

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/BasicObserverConfiguration.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java?rev=1710993&view=auto
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
 (added)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
 Wed Oct 28 11:09:00 2015
@@ -0,0 +1,180 @@
+/*
+ * 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.observation;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+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.observation.ExternalResourceListener;
+import org.apache.sling.api.resource.observation.ResourceChange;
+import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(policy = ConfigurationPolicy.REQUIRE)
+@Service(ResourceChangeListener.class)
+@Properties({ @Property(name = ResourceChangeListener.CHANGES, value = { 
"ADDED", "CHANGED", "REMOVED" }),
+        @Property(name = ResourceChangeListener.PATHS, value = ".") })
+public class OsgiObservationBridge implements ResourceChangeListener, 
ExternalResourceListener {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(OsgiObservationBridge.class);
+
+    @Reference
+    private EventAdmin eventAdmin;
+
+    @Reference
+    private ResourceResolverFactory resolverFactory;
+
+    private ResourceResolver resolver;
+
+    private BlockingQueue<ResourceChange> changesQueue;
+
+    private EventSendingJob job;
+
+    @SuppressWarnings("deprecation")
+    protected void activate() throws LoginException {
+        resolver = resolverFactory.getAdministrativeResourceResolver(null);
+        changesQueue = new LinkedBlockingQueue<ResourceChange>();
+        job = new EventSendingJob(changesQueue);
+        Executors.newSingleThreadExecutor().submit(job);
+    }
+
+    protected void deactivate() {
+        changesQueue.clear();
+        job.stop();
+        resolver.close();
+    }
+
+    @Override
+    public void onChange(List<ResourceChange> changes) {
+        changesQueue.addAll(changes);
+    }
+
+    @SuppressWarnings("deprecation")
+    private void sendOsgiEvent(ResourceChange change) {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        String topic;
+        switch (change.getType()) {
+        case ADDED:
+            topic = SlingConstants.TOPIC_RESOURCE_ADDED;
+            break;
+
+        case CHANGED:
+            topic = SlingConstants.TOPIC_RESOURCE_CHANGED;
+            break;
+
+        case REMOVED:
+            topic = SlingConstants.TOPIC_RESOURCE_REMOVED;
+            break;
+
+        default:
+            return;
+        }
+
+        props.put(SlingConstants.PROPERTY_PATH, change.getPath());
+        if (change.getUserId() != null) {
+            props.put(SlingConstants.PROPERTY_USERID, change.getUserId());
+        }
+        if (change.getAddedPropertyNames() != null ) {
+            props.put(SlingConstants.PROPERTY_ADDED_ATTRIBUTES, 
change.getAddedPropertyNames().toArray(new 
String[change.getAddedPropertyNames().size()]));
+        }
+        if (change.getChangedPropertyNames() != null) {
+            props.put(SlingConstants.PROPERTY_CHANGED_ATTRIBUTES, 
change.getChangedPropertyNames().toArray(new 
String[change.getChangedPropertyNames().size()]));
+        }
+        if ( change.getRemovedPropertyNames() != null ) {
+            props.put(SlingConstants.PROPERTY_REMOVED_ATTRIBUTES, 
change.getRemovedPropertyNames().toArray(new 
String[change.getRemovedPropertyNames().size()]));
+        }
+        if (change.getType() != ChangeType.REMOVED) {
+            Resource resource = resolver.getResource(change.getPath());
+            if (resource == null) {
+                resolver.refresh();
+                resource = resolver.getResource(change.getPath());
+            }
+            if (resource != null) {
+                if (resource.getResourceType() != null) {
+                    props.put(SlingConstants.PROPERTY_RESOURCE_TYPE, 
resource.getResourceType());
+                }
+                if (resource.getResourceSuperType() != null) {
+                    props.put(SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE, 
resource.getResourceSuperType());
+                }
+            }
+        }
+        if (change.isExternal()) {
+            props.put("event.application", "unknown");
+        }
+
+        final Event event = new Event(topic, props);
+        eventAdmin.sendEvent(event);
+    }
+
+    private class EventSendingJob implements Runnable {
+
+        private final BlockingQueue<ResourceChange> changes;
+
+        private volatile boolean stop;
+
+        public EventSendingJob(BlockingQueue<ResourceChange> changes) {
+            this.changes = changes;
+        }
+
+        @Override
+        public void run() {
+            while (!stop) {
+                ResourceChange change = null;
+                try {
+                    change = changes.poll(100, TimeUnit.MILLISECONDS);
+                } catch (InterruptedException e) {
+                    logger.warn("Interrupted the OSGi runnable", e);
+                }
+                if (change == null) {
+                    continue;
+                }
+                try {
+                    sendOsgiEvent(change);
+                } catch (Exception e) {
+                    logger.error("processOsgiEventQueue: Unexpected problem 
processing resource change {}", change, e);
+                }
+            }
+        }
+
+        public void stop() {
+            stop = true;
+        }
+    }
+
+}

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/OsgiObservationBridge.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java?rev=1710993&view=auto
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
 (added)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
 Wed Oct 28 11:09:00 2015
@@ -0,0 +1,117 @@
+/*
+ * 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.observation;
+
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.References;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.observation.ResourceChangeListener;
+import 
org.apache.sling.resourceresolver.impl.observation.BasicObserverConfiguration.Builder;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.resource.observation.ExternalResourceListener;
+import org.apache.sling.spi.resource.provider.ObservationReporter;
+import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+@Component(immediate = true)
+@Service(ResourceChangeListenerWhiteboard.class)
+@References({
+        @Reference(name = "ResourceChangeListener", referenceInterface = 
ResourceChangeListener.class, cardinality = 
ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
+        @Reference(name = "ResourceResolverFactory", referenceInterface = 
ResourceResolverFactory.class, cardinality = 
ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) })
+public class ResourceChangeListenerWhiteboard {
+
+    public static final String TOPIC_RESOURCE_CHANGE_LISTENER_UPDATE = 
"org/apache/sling/api/resource/ResourceChangeListener/UPDATE";
+
+    private Map<ResourceChangeListener, ObserverConfiguration> listeners = new 
IdentityHashMap<ResourceChangeListener, ObserverConfiguration>();
+
+    private Map<ResourceChangeListener, Builder> pendingListeners = new 
IdentityHashMap<ResourceChangeListener, Builder>();
+
+    private String[] searchPaths;
+
+    @Reference
+    private EventAdmin eventAdmin;
+
+    public ObservationReporter getObservationReporter() {
+        return new BasicObservationReporter(listeners);
+    }
+
+    protected void bindResourceChangeListener(ResourceChangeListener listener, 
Map<String, Object> properties) {
+        Builder builder = new Builder();
+        builder.setFromProperties(properties);
+        builder.setIncludeExternal(listener instanceof 
ExternalResourceListener);
+
+        if (searchPaths == null) {
+            pendingListeners.put(listener, builder);
+        } else {
+            builder.setSearchPaths(searchPaths);
+            listeners.put(listener, builder.build());
+            postListenersChangedEvent();
+        }
+    }
+
+    protected void unbindResourceChangeListener(ResourceChangeListener 
listener, Map<String, Object> properties) {
+        if (listeners.remove(listener) != null) {
+            postListenersChangedEvent();
+        }
+        pendingListeners.remove(listener);
+    }
+
+    protected void bindResourceResolverFactory(ResourceResolverFactory 
factory) throws LoginException {
+        ResourceResolver resolver = factory.getResourceResolver(null);
+        try {
+            this.searchPaths = resolver.getSearchPath();
+            activatePendingListeners();
+        } finally {
+            resolver.close();
+        }
+    }
+
+    protected void unbindResourceResolverFactory(ResourceResolverFactory 
factory) {
+        this.searchPaths = null;
+    }
+
+    private void activatePendingListeners() {
+        boolean added = false;
+        for (Entry<ResourceChangeListener, Builder> e : 
pendingListeners.entrySet()) {
+            Builder builder = e.getValue();
+            builder.setSearchPaths(searchPaths);
+            listeners.put(e.getKey(), builder.build());
+            added = true;
+        }
+        pendingListeners.clear();
+        if (added) {
+            postListenersChangedEvent();
+        }
+    }
+
+    private void postListenersChangedEvent() {
+        eventAdmin.sendEvent(new Event(TOPIC_RESOURCE_CHANGE_LISTENER_UPDATE, 
new Hashtable<String, Object>()));
+    }
+}

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/observation/ResourceChangeListenerWhiteboard.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java?rev=1710993&view=auto
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java
 (added)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java
 Wed Oct 28 11:09:00 2015
@@ -0,0 +1,49 @@
+/*
+ * 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.providers;
+
+import java.util.Set;
+
+import org.apache.sling.spi.resource.provider.ObservationReporter;
+import org.apache.sling.spi.resource.provider.ProviderContext;
+
+/**
+ * Provider context implementation
+ */
+public class ProviderContextImpl implements ProviderContext {
+
+    private final ObservationReporter observationReporter;
+
+    private final Set<String> excludedPaths;
+
+    public ProviderContextImpl(final ObservationReporter observationReporter, 
final Set<String> excludedPaths) {
+        this.observationReporter = observationReporter;
+        this.excludedPaths = excludedPaths;
+    }
+
+    @Override
+    public ObservationReporter getObservationReporter() {
+        return observationReporter;
+    }
+
+    @Override
+    public Set<String> getExcludedPaths() {
+        return excludedPaths;
+    }
+}

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ProviderContextImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Modified: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java?rev=1710993&r1=1710992&r2=1710993&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
 Wed Oct 28 11:09:00 2015
@@ -22,10 +22,12 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.felix.scr.annotations.Activate;
@@ -34,11 +36,19 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.observation.ResourceChange;
+import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
+import org.apache.sling.api.resource.observation.ResourceChangeListener;
 import org.apache.sling.api.resource.runtime.dto.FailureReason;
 import org.apache.sling.api.resource.runtime.dto.ResourceProviderDTO;
 import org.apache.sling.api.resource.runtime.dto.ResourceProviderFailureDTO;
 import org.apache.sling.api.resource.runtime.dto.RuntimeDTO;
 import 
org.apache.sling.resourceresolver.impl.legacy.LegacyResourceProviderWhiteboard;
+import 
org.apache.sling.resourceresolver.impl.observation.BasicObservationReporter;
+import 
org.apache.sling.resourceresolver.impl.observation.ResourceChangeListenerWhiteboard;
+import org.apache.sling.spi.resource.provider.ObservationReporter;
+import org.apache.sling.spi.resource.provider.ObserverConfiguration;
+import org.apache.sling.spi.resource.provider.ProviderContext;
 import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -57,6 +67,8 @@ import org.slf4j.LoggerFactory;
 @Service(value = ResourceProviderTracker.class)
 public class ResourceProviderTracker {
 
+    private static final ObservationReporter EMPTY_REPORTER = new 
BasicObservationReporter(Collections.<ResourceChangeListener, 
ObserverConfiguration> emptyMap());
+
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
     private final Map<ServiceReference, ResourceProviderInfo> infos = new 
ConcurrentHashMap<ServiceReference, ResourceProviderInfo>();
@@ -72,6 +84,11 @@ public class ResourceProviderTracker {
     @Reference
     private EventAdmin eventAdmin;
 
+    private ObservationReporter reporter = EMPTY_REPORTER;
+
+    @Reference
+    private ResourceChangeListenerWhiteboard resourceChangeListeners;
+
     private volatile ResourceProviderStorage storage;
 
     @Activate
@@ -218,11 +235,12 @@ public class ResourceProviderTracker {
      */
     private void deactivate(final ResourceProviderHandler handler) {
         handler.deactivate();
-        postEvent(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED, 
handler.getInfo());
+        postOSGiEvent(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED, 
handler.getInfo());
+        postResourceProviderChange(ChangeType.PROVIDER_REMOVED, 
handler.getInfo());
         logger.debug("Deactivated resource provider {}", handler.getInfo());
     }
 
-    private void postEvent(final String topic, final ResourceProviderInfo 
info) {
+    private void postOSGiEvent(final String topic, final ResourceProviderInfo 
info) {
         final Dictionary<String, Object> eventProps = new Hashtable<String, 
Object>();
         eventProps.put(SlingConstants.PROPERTY_PATH, info.getPath());
         String pid = (String) 
info.getServiceReference().getProperty(Constants.SERVICE_PID);
@@ -235,6 +253,11 @@ public class ResourceProviderTracker {
         eventAdmin.postEvent(new Event(topic, eventProps));
     }
 
+    private void postResourceProviderChange(ChangeType type, final 
ResourceProviderInfo info) {
+        ResourceChange change = new ResourceChange(type, info.getPath(), 
false, null, null, null);
+        this.reporter.reportChanges(Collections.singletonList(change), false);
+    }
+
     /**
      * Activate a resource provider
      * @param handler The provider handler
@@ -246,7 +269,8 @@ public class ResourceProviderTracker {
 
             return false;
         }
-        postEvent(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED, 
handler.getInfo());
+        postOSGiEvent(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED, 
handler.getInfo());
+        postResourceProviderChange(ChangeType.PROVIDER_ADDED, 
handler.getInfo());
         logger.debug("Activated resource provider {}", handler.getInfo());
         return true;
     }
@@ -312,4 +336,16 @@ public class ResourceProviderTracker {
         d.serviceId = 
(Long)info.getServiceReference().getProperty(Constants.SERVICE_ID);
         d.useResourceAccessSecurity = info.getUseResourceAccessSecurity();
     }
+
+    private ProviderContext createProviderContext(final 
ResourceProviderHandler handler) {
+        final Set<String> excludedPaths = new HashSet<String>();
+        String path = handler.getInfo().getPath();
+        for (String providerPath : handlers.keySet()) {
+            if (providerPath.startsWith(path)) {
+                excludedPaths.add(providerPath);
+            }
+        }
+        excludedPaths.remove(path);
+        return new ProviderContextImpl(reporter, excludedPaths);
+    }
 }

Modified: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java?rev=1710993&r1=1710992&r2=1710993&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java
 Wed Oct 28 11:09:00 2015
@@ -95,7 +95,12 @@ public class AuthenticatedResourceProvid
 
     private Object authenticate() throws LoginException {
         if (!authenticated && (info.getAuthType() == AuthType.required || 
info.getAuthType() == AuthType.lazy)) {
-            contextData = rp.authenticate(authInfo);
+            try {
+                contextData = rp.authenticate(authInfo);
+            } catch ( final LoginException le ) {
+                logger.debug("Unable to login into resource provider " + rp, 
le);
+                throw le;
+            }
             authenticated = true;
         }
         return contextData;

Modified: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java?rev=1710993&r1=1710992&r2=1710993&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java
 Wed Oct 28 11:09:00 2015
@@ -35,11 +35,15 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
 import org.apache.commons.collections.IteratorUtils;
 import org.apache.commons.collections.ListUtils;
 import org.apache.commons.collections.Transformer;
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.sling.api.SlingException;
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.PersistenceException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
@@ -66,15 +70,15 @@ public class CombinedResourceProvider {
 
     private static final Logger logger = 
LoggerFactory.getLogger(CombinedResourceProvider.class);
 
-    private static final StatefulResourceProvider EMPTY_PROVIDER = new 
EmptyResourceProvider();
-
     private final ResourceProviderStorage storage;
 
     private final ResourceResolver resolver;
 
     private final ResourceProviderAuthenticator authenticator;
 
-    public CombinedResourceProvider(ResourceProviderStorage storage, 
ResourceResolver resolver, ResourceProviderAuthenticator authenticator) {
+    public CombinedResourceProvider(ResourceProviderStorage storage,
+            ResourceResolver resolver,
+            ResourceProviderAuthenticator authenticator) {
         this.storage = storage;
         this.resolver = resolver;
         this.authenticator = authenticator;
@@ -93,7 +97,8 @@ public class CombinedResourceProvider {
      * Refreshes all providers.
      */
     public void refresh() {
-        for (StatefulResourceProvider p : 
authenticator.getAll(storage.getRefreshableHandlers(), this)) {
+        for (StatefulResourceProvider p : authenticator.getAllUsed()) {
+            // TODO check for refreshable
             p.refresh();
         }
     }
@@ -120,14 +125,18 @@ public class CombinedResourceProvider {
      */
     public Resource getParent(Resource child) {
         final String path = child.getPath();
-        final StatefulResourceProvider provider = 
getBestMatchingProvider(path);
-        Resource parentCandidate = provider.getParent(child);
-        if (parentCandidate != null) {
-            return parentCandidate;
-        }
-        String parentPath = ResourceUtil.getParent(path);
-        if (parentPath != null && isIntermediatePath(parentPath)) {
-            return new SyntheticResource(resolver, parentPath, 
ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+        try {
+            final StatefulResourceProvider provider = 
getBestMatchingProvider(path);
+            Resource parentCandidate = provider.getParent(child);
+            if (parentCandidate != null) {
+                return parentCandidate;
+            }
+            String parentPath = ResourceUtil.getParent(path);
+            if (parentPath != null && isIntermediatePath(parentPath)) {
+                return new SyntheticResource(resolver, parentPath, 
ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+            }
+        } catch ( final LoginException le ) {
+            // ignore, we just return null
         }
         return null;
     }
@@ -193,26 +202,31 @@ public class CombinedResourceProvider {
      */
     @SuppressWarnings("unchecked")
     public Iterator<Resource> listChildren(final Resource parent) {
-        List<StatefulResourceProvider> matching = 
getMatchingProviders(parent.getPath());
-        Iterator<Resource> realChildren = head(matching).listChildren(parent);
-        Iterator<Resource> syntheticChildren = 
getSyntheticChildren(parent).iterator();
-        Iterator<Resource> allChildren;
-        if (realChildren == null) {
-            allChildren = syntheticChildren;
-        } else {
-            allChildren = new UniqueIterator(chainedIterator(realChildren, 
syntheticChildren));
-        }
-        return transformedIterator(allChildren, new Transformer() {
-            @Override
-            public Object transform(Object input) {
-                Resource resource = (Resource) input;
-                
resource.getResourceMetadata().setResolutionPath(resource.getPath());
-                return resource;
+        try {
+            List<StatefulResourceProvider> matching = 
getMatchingProviders(parent.getPath());
+            Iterator<Resource> realChildren = 
head(matching).listChildren(parent);
+            Iterator<Resource> syntheticChildren = 
getSyntheticChildren(parent).iterator();
+            Iterator<Resource> allChildren;
+            if (realChildren == null) {
+                allChildren = syntheticChildren;
+            } else {
+                allChildren = new UniqueIterator(chainedIterator(realChildren, 
syntheticChildren));
             }
-        });
+            return transformedIterator(allChildren, new Transformer() {
+                @Override
+                public Object transform(Object input) {
+                    Resource resource = (Resource) input;
+                    
resource.getResourceMetadata().setResolutionPath(resource.getPath());
+                    return resource;
+                }
+            });
+        } catch ( final LoginException le ) {
+            // ignore
+        }
+        return null;
     }
 
-    private List<Resource> getSyntheticChildren(Resource parent) {
+    private List<Resource> getSyntheticChildren(Resource parent) throws 
LoginException {
         Node<ResourceProviderHandler> node = 
storage.getTree().getNode(parent.getPath());
         if (node == null) {
             return Collections.emptyList();
@@ -240,12 +254,17 @@ public class CombinedResourceProvider {
      */
     public Collection<String> getAttributeNames() {
         final Set<String> names = new LinkedHashSet<String>();
+        try {
         for (StatefulResourceProvider p : 
authenticator.getAll(storage.getAttributableHandlers(), this)) {
             Collection<String> newNames = p.getAttributeNames();
             if (newNames != null) {
                 names.addAll(newNames);
             }
         }
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
         return names;
     }
 
@@ -255,12 +274,17 @@ public class CombinedResourceProvider {
      * the providers.
      */
     public Object getAttribute(String name) {
+        try {
         for (StatefulResourceProvider p : 
authenticator.getAll(storage.getAttributableHandlers(), this)) {
             Object attribute = p.getAttribute(name);
             if (attribute != null) {
                 return attribute;
             }
         }
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
         return null;
     }
 
@@ -276,6 +300,7 @@ public class CombinedResourceProvider {
      * @return The new resource
      */
     public Resource create(String path, Map<String, Object> properties) throws 
PersistenceException {
+        try {
         List<StatefulResourceProvider> matching = 
getMatchingModifiableProviders(path);
         Resource creationResultResource = head(matching).create(path, 
properties);
         if (creationResultResource != null) {
@@ -284,6 +309,10 @@ public class CombinedResourceProvider {
         // If none of the viable handlers could create the resource or if the
         // list of handlers was empty, throw an Exception
         throw new UnsupportedOperationException("create '" + getName(path) + 
"' at " + ResourceUtil.getParent(path));
+        } catch (LoginException le) {
+            // TODO - ignore throw PersistenceException
+            throw new SlingException("Unable to authenticate", le);
+        }
     }
 
     /**
@@ -298,6 +327,7 @@ public class CombinedResourceProvider {
      *             If deletion fails
      */
     public void delete(Resource resource) throws PersistenceException {
+        try {
         final String path = resource.getPath();
         final Map<String, String> parameters = 
resource.getResourceMetadata().getParameterMap();
         boolean anyProviderAttempted = false;
@@ -315,6 +345,10 @@ public class CombinedResourceProvider {
         if (!anyProviderAttempted) {
             throw new UnsupportedOperationException("delete at '" + path + 
"'");
         }
+    } catch (LoginException le) {
+        // TODO - ignore for a single handler
+        throw new SlingException("Unable to authenticate", le);
+    }
     }
 
     /**
@@ -358,11 +392,16 @@ public class CombinedResourceProvider {
      * Return the union of query languages supported by the providers.
      */
     public String[] getSupportedLanguages() {
+        try {
         Set<String> supportedLanguages = new LinkedHashSet<String>();
         for (StatefulResourceProvider p : 
authenticator.getAll(storage.getJcrQuerableHandlers(), this)) {
             
supportedLanguages.addAll(Arrays.asList(p.getSupportedLanguages()));
         }
         return supportedLanguages.toArray(new 
String[supportedLanguages.size()]);
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
     }
 
     /**
@@ -378,6 +417,7 @@ public class CombinedResourceProvider {
     }
 
     private List<StatefulResourceProvider> getQuerableProviders(String 
language) {
+        try {
         List<StatefulResourceProvider> querableProviders = new 
ArrayList<StatefulResourceProvider>();
         for (StatefulResourceProvider p : 
authenticator.getAll(storage.getJcrQuerableHandlers(), this)) {
             if (ArrayUtils.contains(p.getSupportedLanguages(), language)) {
@@ -385,6 +425,10 @@ public class CombinedResourceProvider {
             }
         }
         return querableProviders;
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
     }
 
     /**
@@ -405,6 +449,7 @@ public class CombinedResourceProvider {
      */
     @SuppressWarnings("unchecked")
     public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        try {
         for (StatefulResourceProvider p : 
authenticator.getAll(storage.getAdaptableHandlers(), this)) {
             final Object adaptee = p.adaptTo(type);
             if (adaptee != null) {
@@ -412,6 +457,10 @@ public class CombinedResourceProvider {
             }
         }
         return null;
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
     }
 
     /**
@@ -420,11 +469,16 @@ public class CombinedResourceProvider {
      * Returns false if there's no such provider.
      */
     public boolean copy(String srcAbsPath, String destAbsPath) throws 
PersistenceException {
+        try {
         List<StatefulResourceProvider> srcProviders = 
getMatchingProviders(srcAbsPath);
         List<StatefulResourceProvider> dstProviders = 
getMatchingModifiableProviders(destAbsPath);
         @SuppressWarnings("unchecked")
         List<StatefulResourceProvider> intersection = 
ListUtils.intersection(srcProviders, dstProviders);
         return head(intersection).copy(srcAbsPath, destAbsPath);
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
     }
 
     /**
@@ -433,18 +487,24 @@ public class CombinedResourceProvider {
      * Returns false if there's no such provider.
      */
     public boolean move(String srcAbsPath, String destAbsPath) throws 
PersistenceException {
+        try {
         List<StatefulResourceProvider> srcProviders = 
getMatchingModifiableProviders(srcAbsPath);
         List<StatefulResourceProvider> dstProviders = 
getMatchingModifiableProviders(destAbsPath);
         @SuppressWarnings("unchecked")
         List<StatefulResourceProvider> intersection = 
ListUtils.intersection(srcProviders, dstProviders);
         return head(intersection).move(srcAbsPath, destAbsPath);
+        } catch (LoginException le) {
+            // TODO - ignore for a single handler
+            throw new SlingException("Unable to authenticate", le);
+        }
     }
 
     public ResourceProviderStorage getResourceProviderStorage() {
         return this.storage;
     }
 
-    public StatefulResourceProvider getStatefulResourceProvider(final 
ResourceProviderHandler handler) {
+    public @CheckForNull StatefulResourceProvider 
getStatefulResourceProvider(@Nonnull final ResourceProviderHandler handler)
+    throws LoginException {
         if ( handler != null ) {
             return authenticator.getStateful(handler, this);
         }
@@ -456,12 +516,12 @@ public class CombinedResourceProvider {
      * @return
      * @throws SlingException
      */
-    private StatefulResourceProvider getBestMatchingProvider(final String 
path) {
+    private StatefulResourceProvider getBestMatchingProvider(final String 
path) throws LoginException {
         final ResourceProviderHandler handler = 
storage.getTree().getBestMatchingNode(path);
         return handler == null ? EmptyResourceProvider.SINGLETON : 
authenticator.getStateful(handler, this);
     }
 
-    private List<StatefulResourceProvider> getMatchingProviders(String path) {
+    private List<StatefulResourceProvider> getMatchingProviders(String path) 
throws LoginException {
         List<ResourceProviderHandler> handlers = 
storage.getTree().getMatchingNodes(path);
         StatefulResourceProvider[] matching = new 
StatefulResourceProvider[handlers.size()];
         int i = matching.length - 1;
@@ -471,7 +531,7 @@ public class CombinedResourceProvider {
         return Arrays.asList(matching);
     }
 
-    private List<StatefulResourceProvider> 
getMatchingModifiableProviders(String path) {
+    private List<StatefulResourceProvider> 
getMatchingModifiableProviders(String path) throws LoginException {
         List<ResourceProviderHandler> handlers = 
storage.getTree().getMatchingNodes(path);
         List<StatefulResourceProvider> matching = new 
ArrayList<StatefulResourceProvider>(handlers.size());
         for (ResourceProviderHandler h : handlers) {
@@ -485,20 +545,12 @@ public class CombinedResourceProvider {
 
     private static StatefulResourceProvider 
head(List<StatefulResourceProvider> list) {
         if (list.isEmpty()) {
-            return EMPTY_PROVIDER;
+            return EmptyResourceProvider.SINGLETON;
         } else {
             return list.get(0);
         }
     }
 
-    private static <T> List<T> tail(List<T> list) {
-        if (list.isEmpty()) {
-            return Collections.emptyList();
-        } else {
-            return list.subList(1, list.size());
-        }
-    }
-
     private class CombinedQueryResult extends QueryResult implements 
Iterable<Resource> {
 
         private final Query q;
@@ -517,6 +569,7 @@ public class CombinedResourceProvider {
 
         @Override
         public Iterator<Resource> iterator() {
+            try {
             @SuppressWarnings("unchecked")
             Iterator<Iterator<Resource>> iterators = 
IteratorUtils.transformedIterator(authenticator.getAll(storage.getNativeQuerableHandlers(),
 CombinedResourceProvider.this).iterator(),
                     new Transformer() {
@@ -527,6 +580,10 @@ public class CombinedResourceProvider {
                         }
                     });
             return new ChainedIterator<Resource>(iterators);
+            } catch (LoginException le) {
+                // TODO - ignore for a single handler
+                throw new SlingException("Unable to authenticate", le);
+            }
         }
     }
 

Modified: 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java?rev=1710993&r1=1710992&r2=1710993&view=diff
==============================================================================
--- 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java
 (original)
+++ 
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java
 Wed Oct 28 11:09:00 2015
@@ -24,7 +24,8 @@ import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.sling.api.SlingException;
+import javax.annotation.Nonnull;
+
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.runtime.dto.AuthType;
@@ -73,9 +74,6 @@ public class ResourceProviderAuthenticat
         StatefulResourceProvider rp = stateful.get(handler);
         if (rp == null) {
             rp = createStateful(handler, combinedProvider);
-            if (rp == null) {
-                return null;
-            }
             stateful.put(handler, rp);
             if (handler.getInfo().getAuthType() != AuthType.no) {
                 authenticated.add(rp);
@@ -87,12 +85,13 @@ public class ResourceProviderAuthenticat
         return rp;
     }
 
-    public StatefulResourceProvider getStateful(ResourceProviderHandler 
handler, CombinedResourceProvider combinedProvider) {
-        try {
-            return authenticate(handler, combinedProvider);
-        } catch (LoginException e) {
-            throw new SlingException("Can't authenticate provider", e);
-        }
+    public Collection<StatefulResourceProvider> getAllUsed() {
+        return stateful.values();
+    }
+
+    public StatefulResourceProvider getStateful(ResourceProviderHandler 
handler, CombinedResourceProvider combinedProvider)
+    throws LoginException {
+        return authenticate(handler, combinedProvider);
     }
 
     public Collection<StatefulResourceProvider> getAllUsedAuthenticated() {
@@ -104,7 +103,7 @@ public class ResourceProviderAuthenticat
     }
 
     public Collection<StatefulResourceProvider> 
getAll(List<ResourceProviderHandler> handlers,
-            CombinedResourceProvider combinedProvider) {
+            CombinedResourceProvider combinedProvider) throws LoginException {
         List<StatefulResourceProvider> result = new 
ArrayList<StatefulResourceProvider>(handlers.size());
         for (ResourceProviderHandler h : handlers) {
             result.add(getStateful(h, combinedProvider));
@@ -112,13 +111,9 @@ public class ResourceProviderAuthenticat
         return result;
     }
 
-    private StatefulResourceProvider createStateful(ResourceProviderHandler 
handler,
+    private @Nonnull StatefulResourceProvider 
createStateful(ResourceProviderHandler handler,
             CombinedResourceProvider combinedProvider) throws LoginException {
-        ResourceProvider<?> rp = handler.getResourceProvider();
-        if (rp == null) {
-            logger.warn("Empty resource provider for {}", handler);
-            return null;
-        }
+        final ResourceProvider<?> rp = handler.getResourceProvider();
         StatefulResourceProvider authenticated;
         authenticated = new AuthenticatedResourceProvider(rp, 
handler.getInfo(), resolver, authInfo, combinedProvider);
         if (handler.getInfo().getUseResourceAccessSecurity()) {


Reply via email to