You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by to...@apache.org on 2015/10/21 10:23:11 UTC
svn commit: r1709747 [2/4] - in /sling/trunk/bundles/resourceresolver: ./
src/main/java/org/apache/sling/resourceresolver/impl/
src/main/java/org/apache/sling/resourceresolver/impl/helper/
src/main/java/org/apache/sling/resourceresolver/impl/legacy/ sr...
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParametersParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParametersParser.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParametersParser.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParametersParser.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,159 @@
+/*
+ * 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.params;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+class ParametersParser {
+
+ private enum ParamsState {
+ INIT, NAME, EQUALS, VALUE, QUOTED_VALUE, QUOTE_END
+ }
+
+ private StringBuilder name;
+
+ private StringBuilder value;
+
+ private Map<String, String> parameters = new LinkedHashMap<String, String>();
+
+ private boolean invalid;
+
+ /**
+ * Parses parameters string, eg.: {@code ;x=123;a='1.0'}. The result of the method is available in
+ * {@link #parameters} and {@link #invalid}.
+ *
+ * @param chars Array containing path with parameters.
+ * @param from Index of the first character of the parameters substring (it must be a semicolon).
+ * @param dotAllowed If true, the dot in parameter value won't stop parsing.
+ * @return Index of the first character not related to parameters.
+ */
+ public int parseParameters(final char[] chars, final int from, final boolean dotAllowed) {
+ resetCurrentParameter();
+ parameters.clear();
+ invalid = false;
+
+ ParamsState state = ParamsState.INIT;
+ for (int i = from; i <= chars.length; i++) {
+ final char c;
+ if (i == chars.length) {
+ c = 0;
+ } else {
+ c = chars[i];
+ }
+ switch (state) {
+ case INIT:
+ if (c == ';') {
+ state = ParamsState.NAME;
+ } else if (c == '.' || c == '/' || c == 0) {
+ invalid = true;
+ return i;
+ }
+ break;
+
+ case NAME:
+ if (c == '=') {
+ state = ParamsState.EQUALS;
+ } else if (c == '.' || c == '/' || c == 0) {
+ invalid = true;
+ return i;
+ } else if (c == ';') {
+ resetCurrentParameter();
+ } else {
+ name.append(c);
+ }
+ break;
+
+ case EQUALS:
+ if (c == '\'') {
+ state = ParamsState.QUOTED_VALUE;
+ } else if (c == '.' || c == '/' || c == 0) {
+ addParameter(); // empty one
+ return i;
+ } else if (c == ';') {
+ state = ParamsState.NAME; // empty one
+ addParameter();
+ } else {
+ state = ParamsState.VALUE;
+ value.append(c);
+ }
+ break;
+
+ case QUOTED_VALUE:
+ if (c == '\'') {
+ state = ParamsState.QUOTE_END;
+ addParameter();
+ } else if (c == 0) {
+ invalid = true;
+ return i;
+ } else {
+ value.append(c);
+ }
+ break;
+
+ case VALUE:
+ if (c == ';') {
+ state = ParamsState.NAME;
+ addParameter();
+ } else if ((c == '.' && !dotAllowed) || c == '/' || c == 0) {
+ addParameter();
+ return i;
+ } else {
+ value.append(c);
+ }
+ break;
+
+ case QUOTE_END:
+ if (c == ';') {
+ state = ParamsState.NAME;
+ } else {
+ return i;
+ }
+ }
+ }
+
+ return chars.length;
+ }
+
+ /**
+ * @return Parsed parameters.
+ */
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * @return True if the {@link #parseParameters(char[], int, boolean)} method failed.
+ */
+ public boolean isInvalid() {
+ return invalid;
+ }
+
+ private void resetCurrentParameter() {
+ name = new StringBuilder();
+ value = new StringBuilder();
+ }
+
+ private void addParameter() {
+ parameters.put(name.toString(), value.toString());
+ name = new StringBuilder();
+ value = new StringBuilder();
+ }
+}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParsedParameters.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParsedParameters.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParsedParameters.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/ParsedParameters.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,75 @@
+/*
+ * 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 SF 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.params;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Parses path looking for semicolon-separated parameters. Parameters are extracted and exposed as an
+ * immutable map. The path without parameters is available as raw path.
+ *
+ * Parameters should be added immedietaly before or after selectors and extension:
+ * {@code /content/test;v='1.0'.html} or {@code /content/test.html;v=1.0}. Quotes can be used to escape the
+ * parameter value (it is necessary if the value contains dot and parameter is added before extension).
+ */
+public class ParsedParameters {
+
+ private final Map<String, String> parameters;
+
+ private final String parametersString;
+
+ private final String path;
+
+ /**
+ * Parse path and create parameters object.
+ *
+ * @param fullPath Path to parse.
+ */
+ public ParsedParameters(final String fullPath) {
+ final PathParser parser = new PathParser();
+ parser.parse(fullPath);
+
+ parametersString = parser.getParametersString();
+ parameters = Collections.unmodifiableMap(parser.getParameters());
+ path = parser.getPath();
+ }
+
+ /**
+ * @return Path with no parameters.
+ */
+ public String getRawPath() {
+ return path;
+ }
+
+ /**
+ * @return Path's substring containing parameters
+ */
+ public String getParametersString() {
+ return parametersString;
+ }
+
+ /**
+ * @return Map of the parameters.
+ */
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/PathParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/PathParser.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/PathParser.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/params/PathParser.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,171 @@
+/*
+ * 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.params;
+
+import java.util.Collections;
+import java.util.Map;
+
+class PathParser {
+
+ /**
+ * List of states. V1 and V2 prefixes means variant 1 and 2. In V1, the parameters are added after
+ * selectors and extension: {@code /content/test.sel.html;v=1.0}. In V2 parameters are added before
+ * selectors and extension: {@code /content/test;v='1.0'.sel.html}
+ */
+ private enum ParserState {
+ INIT, V1_EXTENSION, V1_PARAMS, V2_PARAMS, V2_EXTENSION, SUFFIX, INVALID
+ }
+
+ private String rawPath;
+
+ private String parametersString;
+
+ private Map<String, String> parameters;
+
+ /**
+ * @return Path with no parameters.
+ */
+ public String getPath() {
+ return rawPath;
+ }
+
+ /**
+ * @return Path's substring containing parameters
+ */
+ public String getParametersString() {
+ return parametersString;
+ }
+
+ /**
+ * @return Parsed parameters.
+ */
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Parses path containing parameters. Results will be available in {@link #rawPath} and {@link parameters}.
+ *
+ * @param path
+ */
+ public void parse(String path) {
+ this.rawPath = path;
+ this.parameters = Collections.emptyMap();
+
+ if (path == null) {
+ return;
+ }
+
+ // indexOf shortcut for the most common case
+ final int di = path.indexOf('.');
+ final int si = path.indexOf(';');
+ if (di == -1 && si == -1) {
+ return;
+ }
+
+ final char[] chars = path.toCharArray();
+ final ParametersParser parametersParser = new ParametersParser();
+
+ ParserState state = ParserState.INIT;
+ int paramsStart = -1, paramsEnd = -1;
+
+ int i = (di != -1) ? ((si != -1) ? Math.min(di, si) : di) : si;
+ for (; i <= chars.length; i++) {
+ final char c;
+ if (i == chars.length) {
+ c = 0;
+ } else {
+ c = chars[i];
+ }
+
+ switch (state) {
+ case INIT:
+ if (c == '.') {
+ state = ParserState.V1_EXTENSION;
+ } else if (c == ';') {
+ paramsStart = i;
+ i = parametersParser.parseParameters(chars, i, false);
+ paramsEnd = i--;
+ state = parametersParser.isInvalid() ? ParserState.INVALID : ParserState.V2_PARAMS;
+ }
+ break;
+
+ case V1_EXTENSION:
+ if (c == '/') {
+ state = ParserState.SUFFIX;
+ } else if (c == ';') {
+ paramsStart = i;
+ i = parametersParser.parseParameters(chars, i, true);
+ paramsEnd = i--;
+ state = parametersParser.isInvalid() ? ParserState.INVALID : ParserState.V1_PARAMS;
+ }
+ break;
+
+ case V1_PARAMS:
+ if (c == '/') {
+ state = ParserState.SUFFIX;
+ } else if (c == '.') {
+ state = ParserState.INVALID; // no dots after params
+ }
+ break;
+
+ case V2_PARAMS:
+ if (c == '/') {
+ state = ParserState.INVALID; // there was no extension, so no suffix is allowed
+ } else if (c == '.') {
+ state = ParserState.V2_EXTENSION;
+ }
+ break;
+
+ case V2_EXTENSION:
+ if (c == '/') {
+ state = ParserState.SUFFIX;
+ }
+ break;
+
+ case SUFFIX:
+ case INVALID:
+ break;
+ }
+ }
+
+ if (state == ParserState.INVALID) {
+ paramsStart = paramsEnd = -1;
+ } else {
+ cutPath(path, paramsStart, paramsEnd);
+ parameters = parametersParser.getParameters();
+ }
+ }
+
+ private void cutPath(String path, int from, int to) {
+ if (from == -1) {
+ rawPath = path;
+ parametersString = null;
+ } else if (to == -1) {
+ rawPath = path.substring(0, from);
+ parametersString = path.substring(from);
+ } else {
+ rawPath = path.substring(0, from) + path.substring(to);
+ parametersString = path.substring(from, to);
+ }
+ }
+
+
+}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderHandler.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderHandler.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderHandler.java Wed Oct 21 08:23:09 2015
@@ -18,20 +18,32 @@
*/
package org.apache.sling.resourceresolver.impl.providers;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.resourceresolver.impl.legacy.LegacyResourceProviderWhiteboard;
+import org.apache.sling.resourceresolver.impl.providers.tree.Pathable;
import org.apache.sling.spi.resource.provider.ResourceProvider;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
-public class ResourceProviderHandler implements Comparable<ResourceProviderHandler> {
+public class ResourceProviderHandler implements Comparable<ResourceProviderHandler>, Pathable {
private final ResourceProviderInfo info;
private final BundleContext bundleContext;
+ private final EventAdmin eventAdmin;
+
private volatile ResourceProvider<?> provider;
- public ResourceProviderHandler(final BundleContext bc, final ResourceProviderInfo info) {
+ public ResourceProviderHandler(final BundleContext bc, final ResourceProviderInfo info, final EventAdmin eventAdmin) {
this.info = info;
this.bundleContext = bc;
+ this.eventAdmin = eventAdmin;
}
public ResourceProviderInfo getInfo() {
@@ -46,20 +58,40 @@ public class ResourceProviderHandler imp
this.provider = (ResourceProvider<?>) this.bundleContext.getService(this.info.getServiceReference());
}
rp = this.provider;
+ postEvent(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED);
}
}
return rp;
}
+ private void postEvent(String topic) {
+ 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);
+ if (pid == null) {
+ pid = (String) info.getServiceReference().getProperty(LegacyResourceProviderWhiteboard.ORIGINAL_SERVICE_PID);
+ }
+ if (pid != null) {
+ eventProps.put(Constants.SERVICE_PID, pid);
+ }
+ eventAdmin.postEvent(new Event(topic, eventProps));
+ }
+
public void deactivate() {
if ( this.provider != null ) {
this.provider = null;
this.bundleContext.ungetService(this.info.getServiceReference());
+ postEvent(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED);
}
}
@Override
public int compareTo(final ResourceProviderHandler o) {
- return this.info.compareTo(o.info);
+ return this.getInfo().compareTo(o.getInfo());
+ }
+
+ @Override
+ public String getPath() {
+ return this.getInfo().getPath();
}
}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderInfo.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderInfo.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderInfo.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderInfo.java Wed Oct 21 08:23:09 2015
@@ -22,12 +22,16 @@ import org.apache.sling.api.resource.run
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.spi.resource.provider.ResourceProvider;
import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Information about a registered resource provider
*/
public class ResourceProviderInfo implements Comparable<ResourceProviderInfo> {
+ private static final Logger logger = LoggerFactory.getLogger(ResourceProviderInfo.class);
+
private final ServiceReference ref;
private final String path;
@@ -40,6 +44,12 @@ public class ResourceProviderInfo implem
private final boolean modifiable;
+ private final boolean adaptable;
+
+ private final boolean refreshable;
+
+ private final boolean attributable;
+
public ResourceProviderInfo(final ServiceReference ref) {
this.ref = ref;
this.path = PropertiesUtil.toString(ref.getProperty(ResourceProvider.PROPERTY_ROOT), "");
@@ -50,10 +60,13 @@ public class ResourceProviderInfo implem
try {
aType = AuthType.valueOf(authType);
} catch ( final IllegalArgumentException iae) {
- // ignore
+ logger.error("Illegal auth type {} for resource provider {}", authType, name);
}
this.authType = aType;
this.modifiable = PropertiesUtil.toBoolean(ref.getProperty(ResourceProvider.PROPERTY_MODIFIABLE), false);
+ this.adaptable = PropertiesUtil.toBoolean(ref.getProperty(ResourceProvider.PROPERTY_ADAPTABLE), false);
+ this.refreshable = PropertiesUtil.toBoolean(ref.getProperty(ResourceProvider.PROPERTY_REFRESHABLE), false);
+ this.attributable = PropertiesUtil.toBoolean(ref.getProperty(ResourceProvider.PROPERTY_ATTRIBUTABLE), false);
}
public boolean isValid() {
@@ -98,6 +111,18 @@ public class ResourceProviderInfo implem
return this.modifiable;
}
+ public boolean isAdaptable() {
+ return adaptable;
+ }
+
+ public boolean isRefreshable() {
+ return refreshable;
+ }
+
+ public boolean isAttributable() {
+ return attributable;
+ }
+
public String getName() {
return this.name;
}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderStorage.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderStorage.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderStorage.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderStorage.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,108 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+import org.apache.sling.api.resource.runtime.dto.AuthType;
+import org.apache.sling.resourceresolver.impl.providers.tree.PathTree;
+
+public class ResourceProviderStorage {
+
+ private final List<ResourceProviderHandler> allHandlers;
+
+ private final List<ResourceProviderHandler> authRequiredHandlers;
+
+ private final List<ResourceProviderHandler> adaptableHandlers;
+
+ private final List<ResourceProviderHandler> attributableHandlers;
+
+ private final List<ResourceProviderHandler> refreshableHandlers;
+
+ private final List<ResourceProviderHandler> jcrQuerableHandlers;
+
+ private final List<ResourceProviderHandler> nativeQuerableHandlers;
+
+ private final PathTree<ResourceProviderHandler> handlersTree;
+
+ public ResourceProviderStorage(List<ResourceProviderHandler> handlers) {
+ this.allHandlers = handlers;
+ this.authRequiredHandlers = new ArrayList<ResourceProviderHandler>();
+ this.adaptableHandlers = new ArrayList<ResourceProviderHandler>();
+ this.attributableHandlers = new ArrayList<ResourceProviderHandler>();
+ this.refreshableHandlers = new ArrayList<ResourceProviderHandler>();
+ this.jcrQuerableHandlers = new ArrayList<ResourceProviderHandler>();
+ this.nativeQuerableHandlers = new ArrayList<ResourceProviderHandler>();
+ for (ResourceProviderHandler h : allHandlers) {
+ ResourceProviderInfo info = h.getInfo();
+ if (info.getAuthType() == AuthType.required) {
+ this.authRequiredHandlers.add(h);
+ }
+ if (info.isAdaptable()) {
+ this.adaptableHandlers.add(h);
+ }
+ if (info.isAttributable()) {
+ this.attributableHandlers.add(h);
+ }
+ if (info.isRefreshable()) {
+ this.refreshableHandlers.add(h);
+ }
+ if (h.getResourceProvider().getJCRQueryProvider() != null) {
+ this.jcrQuerableHandlers.add(h);
+ }
+ if (h.getResourceProvider().getQueryProvider() != null) {
+ this.nativeQuerableHandlers.add(h);
+ }
+ }
+ this.handlersTree = new PathTree<ResourceProviderHandler>(handlers);
+ }
+
+ public List<ResourceProviderHandler> getAllHandlers() {
+ return allHandlers;
+ }
+
+ public List<ResourceProviderHandler> getAuthRequiredHandlers() {
+ return authRequiredHandlers;
+ }
+
+ public List<ResourceProviderHandler> getAdaptableHandlers() {
+ return adaptableHandlers;
+ }
+
+ public List<ResourceProviderHandler> getAttributableHandlers() {
+ return attributableHandlers;
+ }
+
+ public List<ResourceProviderHandler> getRefreshableHandlers() {
+ return refreshableHandlers;
+ }
+
+ public List<ResourceProviderHandler> getJcrQuerableHandlers() {
+ return jcrQuerableHandlers;
+ }
+
+ public List<ResourceProviderHandler> getNativeQuerableHandlers() {
+ return nativeQuerableHandlers;
+ }
+
+ public PathTree<ResourceProviderHandler> getTree() {
+ return handlersTree;
+ }
+}
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=1709747&r1=1709746&r2=1709747&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 21 08:23:09 2015
@@ -21,6 +21,7 @@ package org.apache.sling.resourceresolve
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -28,6 +29,7 @@ import java.util.concurrent.ConcurrentHa
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.runtime.dto.FailureReason;
import org.apache.sling.api.resource.runtime.dto.ResourceProviderDTO;
@@ -37,6 +39,7 @@ import org.apache.sling.spi.resource.pro
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.EventAdmin;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
@@ -58,6 +61,11 @@ public class ResourceProviderTracker {
private final Map<ResourceProviderInfo, FailureReason> invalidProviders = new HashMap<ResourceProviderInfo, FailureReason>();
+ @Reference
+ private EventAdmin eventAdmin;
+
+ private volatile ResourceProviderStorage storage;
+
@Activate
protected void activate(final BundleContext bundleContext) {
this.bundleContext = bundleContext;
@@ -88,6 +96,7 @@ public class ResourceProviderTracker {
return reference;
}
});
+ this.tracker.open();
}
@Deactivate
@@ -97,33 +106,38 @@ public class ResourceProviderTracker {
this.tracker = null;
}
this.infos.clear();
+ this.handlers.clear();
+ this.invalidProviders.clear();
}
private void register(final ResourceProviderInfo info) {
if ( info.isValid() ) {
logger.debug("Registering new resource provider {}", info);
synchronized ( this.handlers ) {
- List<ResourceProviderHandler> infos = this.handlers.get(info.getPath());
- if ( infos == null ) {
- infos = new ArrayList<ResourceProviderHandler>();
- this.handlers.put(info.getPath(), infos);
+ List<ResourceProviderHandler> matchingHandlers = this.handlers.get(info.getPath());
+ if ( matchingHandlers == null ) {
+ matchingHandlers = new ArrayList<ResourceProviderHandler>();
+ this.handlers.put(info.getPath(), matchingHandlers);
}
- final ResourceProviderHandler handler = new ResourceProviderHandler(bundleContext, info);
- infos.add(handler);
- Collections.sort(infos);
- if ( infos.get(0) == handler ) {
+ final ResourceProviderHandler handler = new ResourceProviderHandler(bundleContext, info, eventAdmin);
+ matchingHandlers.add(handler);
+ Collections.sort(matchingHandlers);
+ if ( matchingHandlers.get(0) == handler ) {
if ( !this.activate(handler) ) {
- infos.remove(handler);
- if ( infos.isEmpty() ) {
+ matchingHandlers.remove(handler);
+ if ( matchingHandlers.isEmpty() ) {
this.handlers.remove(info.getPath());
}
} else {
- if ( infos.size() > 1 ) {
- this.deactivate(infos.get(1));
+ if ( matchingHandlers.size() > 1 ) {
+ this.deactivate(matchingHandlers.get(1));
}
}
}
}
+ synchronized(this) {
+ storage = null;
+ }
} else {
logger.debug("Ignoring invalid resource provider {}", info);
synchronized ( this.invalidProviders ) {
@@ -135,30 +149,31 @@ public class ResourceProviderTracker {
private void unregister(final ResourceProviderInfo info) {
if ( info.isValid() ) {
logger.debug("Unregistering resource provider {}", info);
- final List<ResourceProviderHandler> infos = this.handlers.get(info.getPath());
- if ( infos != null ) {
- boolean activate = false;
- if ( infos.get(0).getInfo() == info ) {
- activate = true;
- this.deactivate(infos.get(0));
- }
- if ( infos.remove(info) ) {
- if ( infos.isEmpty() ) {
- this.handlers.remove(info.getPath());
- } else {
- while ( activate ) {
- if ( !this.activate(infos.get(0)) ) {
- infos.remove(0);
- activate = !this.handlers.isEmpty();
- if ( !activate ) {
- this.handlers.remove(info.getPath());
- }
+ synchronized (this.handlers) {
+ final List<ResourceProviderHandler> matchingHandlers = this.handlers.get(info.getPath());
+ if ( matchingHandlers != null ) {
+ boolean doActivateNext = false;
+ if ( matchingHandlers.get(0).getInfo() == info ) {
+ doActivateNext = true;
+ this.deactivate(matchingHandlers.get(0));
+ }
+ if (removeHandlerByInfo(info, matchingHandlers)) {
+ while (doActivateNext && !matchingHandlers.isEmpty()) {
+ if (this.activate(matchingHandlers.get(0))) {
+ doActivateNext = false;
+ } else {
+ matchingHandlers.remove(0);
}
}
}
+ if (matchingHandlers.isEmpty()) {
+ this.handlers.remove(info.getPath());
+ }
}
}
-
+ synchronized(this) {
+ storage = null;
+ }
} else {
logger.debug("Unregistering invalid resource provider {}", info);
synchronized ( this.invalidProviders ) {
@@ -167,6 +182,19 @@ public class ResourceProviderTracker {
}
}
+ private boolean removeHandlerByInfo(final ResourceProviderInfo info, final List<ResourceProviderHandler> infos) {
+ Iterator<ResourceProviderHandler> it = infos.iterator();
+ boolean removed = false;
+ while (it.hasNext()) {
+ if (it.next().getInfo() == info) {
+ it.remove();
+ removed = true;
+ break;
+ }
+ }
+ return removed;
+ }
+
private void deactivate(final ResourceProviderHandler handler) {
handler.deactivate();
logger.debug("Deactivated resource provider {}", handler.getInfo());
@@ -217,6 +245,32 @@ public class ResourceProviderTracker {
dto.failedProviders = failures.toArray(new ResourceProviderFailureDTO[failures.size()]);
}
+ private List<ResourceProviderHandler> getHandlers() {
+ List<ResourceProviderHandler> result = new ArrayList<ResourceProviderHandler>();
+ synchronized (this.handlers) {
+ for (List<ResourceProviderHandler> list : handlers.values()) {
+ ResourceProviderHandler h = list.get(0);
+ if (h != null) {
+ result.add(h);
+ }
+ }
+ }
+ return result;
+ }
+
+ public ResourceProviderStorage getResourceProviderStorage() {
+ ResourceProviderStorage result = storage;
+ if (result == null) {
+ synchronized(this) {
+ if (storage == null) {
+ storage = new ResourceProviderStorage(getHandlers());
+ }
+ result = storage;
+ }
+ }
+ return result;
+ }
+
private void fill(final ResourceProviderDTO d, final ResourceProviderInfo info) {
d.authType = info.getAuthType();
d.modifiable = info.getModifiable();
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AbstractIterator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AbstractIterator.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AbstractIterator.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AbstractIterator.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,53 @@
+/*
+ * 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.stateful;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public abstract class AbstractIterator<T> implements Iterator<T> {
+
+ private T nextElement;
+
+ protected abstract T seek();
+
+ @Override
+ public boolean hasNext() {
+ if (nextElement == null) {
+ nextElement = seek();
+ }
+ return nextElement != null;
+ }
+
+ @Override
+ public T next() {
+ if (nextElement == null && !hasNext()) {
+ throw new NoSuchElementException();
+ }
+ final T result = nextElement;
+ nextElement = null;
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+}
Added: 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=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,384 @@
+/*
+ * 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.stateful;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.ArrayUtils;
+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;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.resource.query.Query;
+import org.apache.sling.api.resource.query.QueryInstructions;
+import org.apache.sling.api.resource.runtime.dto.AuthType;
+import org.apache.sling.resourceresolver.impl.BasicResolveContext;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderInfo;
+import org.apache.sling.spi.resource.provider.JCRQueryProvider;
+import org.apache.sling.spi.resource.provider.QueryProvider;
+import org.apache.sling.spi.resource.provider.QueryResult;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This {@link StatefulResourceProvider} implementation authenticates the
+ * underlying {@link ResourceProvider}. The authentication can be done during
+ * creation of the object (for {@link AuthType#required}) or before invoking the
+ * first method (for {@link AuthType#lazy}).
+ */
+public class AuthenticatedResourceProvider implements StatefulResourceProvider {
+
+ private static final Logger logger = LoggerFactory.getLogger(AuthenticatedResourceProvider.class);
+
+ private static final String FORBIDDEN_ATTRIBUTE = ResourceResolverFactory.PASSWORD;
+
+ private final ResourceProvider<Object> rp;
+
+ private final ResourceProviderInfo info;
+
+ private final Map<String, Object> authInfo;
+
+ private final ResourceResolver resolver;
+
+ private boolean authenticated;
+
+ private Object contextData;
+
+ private ResolveContext<Object> cachedContext;
+
+ private QueryProvider<Object> cachedQueryProvider;
+
+ private JCRQueryProvider<Object> cachedJcrQueryProvider;
+
+ @SuppressWarnings("unchecked")
+ public AuthenticatedResourceProvider(ResourceProvider<?> rp, ResourceProviderInfo info, ResourceResolver resolver,
+ Map<String, Object> authInfo) throws LoginException {
+ this.rp = (ResourceProvider<Object>) rp;
+ this.info = info;
+ this.authInfo = authInfo;
+ this.resolver = resolver;
+ if (info.getAuthType() == AuthType.required) {
+ authenticate();
+ }
+ }
+
+ private Object authenticate() throws LoginException {
+ if (!authenticated && (info.getAuthType() == AuthType.required || info.getAuthType() == AuthType.lazy)) {
+ contextData = rp.authenticate(authInfo);
+ authenticated = true;
+ }
+ return contextData;
+ }
+
+ private ResolveContext<Object> getBasicContext() throws LoginException {
+ if (cachedContext != null) {
+ return cachedContext;
+ }
+ return cachedContext = getContext(null, null);
+ }
+
+ @Override
+ public ResolveContext<Object> getContext(Map<String, String> parameters) throws LoginException {
+ if (parameters == null || parameters.isEmpty()) {
+ return getBasicContext();
+ } else {
+ return getContext(parameters, null);
+ }
+ }
+
+ private ResolveContext<Object> getContext(Map<String, String> parameters, List<StatefulResourceProvider> parentProviders) throws LoginException {
+ ResourceProvider<Object> parentProvider = null;
+ ResolveContext<Object> parentContext = null;
+ try {
+ if (parentProviders != null && !parentProviders.isEmpty()) {
+ StatefulResourceProvider statefulParentProvider = parentProviders.get(0);
+ parentProvider = statefulParentProvider.getResourceProvider();
+ parentContext = statefulParentProvider.getContext(parameters);
+ }
+ } catch (LoginException e) {
+ logger.warn("Can't authenticate the parent resource provider", e);
+ }
+ return new BasicResolveContext<Object>(resolver, parameters, authenticate(), parentProvider, parentContext);
+ }
+
+ @Override
+ public void logout() {
+ if (authenticated) {
+ try {
+ rp.logout(getBasicContext().getProviderState());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ authenticated = false;
+ cachedContext = null;
+ }
+ }
+
+ @Override
+ public void refresh() {
+ try {
+ rp.refresh(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ }
+
+ @Override
+ public boolean isLive() {
+ try {
+ return rp.isLive(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return false;
+ }
+ }
+
+ @Override
+ public Resource getParent(Resource child, List<StatefulResourceProvider> parentProviders) {
+ try {
+ return rp.getParent(getContext(child.getResourceMetadata().getParameterMap(), parentProviders), child);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @Override
+ public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve, List<StatefulResourceProvider> parentProviders) {
+ try {
+ return rp.getResource(getContext(parameters, parentProviders), path, parent);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+
+ }
+
+ @Override
+ public Iterator<Resource> listChildren(Resource parent, List<StatefulResourceProvider> parentProviders) {
+ try {
+ return rp.listChildren(getContext(parent.getResourceMetadata().getParameterMap(), parentProviders), parent);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @Override
+ public Collection<String> getAttributeNames() {
+ Set<String> attributeNames = new LinkedHashSet<String>();
+ Collection<String> rpAttributeNames = null;
+ try {
+ rpAttributeNames = rp.getAttributeNames(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ if (rpAttributeNames != null) {
+ attributeNames.addAll(rpAttributeNames);
+ }
+ if (authInfo != null) {
+ attributeNames.addAll(authInfo.keySet());
+ }
+ attributeNames.remove(FORBIDDEN_ATTRIBUTE);
+ return attributeNames;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ if (FORBIDDEN_ATTRIBUTE.equals(name)) {
+ return null;
+ }
+ Object attribute = null;
+ try {
+ attribute = rp.getAttribute(getBasicContext(), name);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ if (attribute == null) {
+ attribute = authInfo.get(name);
+ }
+ return attribute;
+ }
+
+ @Override
+ public Resource create(String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+ try {
+ return rp.create(getContext(null, parentProviders), path, properties);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @Override
+ public void delete(Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+ try {
+ rp.delete(getContext(resource.getResourceMetadata().getParameterMap(), parentProviders), resource);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ }
+
+ @Override
+ public void revert() {
+ try {
+ rp.revert(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ }
+
+ @Override
+ public void commit() throws PersistenceException {
+ try {
+ rp.commit(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ }
+ }
+
+ @Override
+ public boolean hasChanges() {
+ try {
+ return rp.hasChanges(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return false;
+ }
+ }
+
+ private QueryProvider<Object> getQueryProvider() {
+ if (cachedQueryProvider == null) {
+ cachedQueryProvider = rp.getQueryProvider();
+ }
+ return cachedQueryProvider;
+ }
+
+ private JCRQueryProvider<Object> getJcrQueryProvider() {
+ if (cachedJcrQueryProvider == null) {
+ cachedJcrQueryProvider = rp.getJCRQueryProvider();
+ }
+ return cachedJcrQueryProvider;
+ }
+
+ @Override
+ public QueryResult find(Query q, QueryInstructions qi) {
+ final QueryProvider<Object> provider = getQueryProvider();
+ if (provider == null) {
+ return null;
+ }
+ try {
+ return provider.find(getBasicContext(), q, qi);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ final JCRQueryProvider<Object> jcrQueryProvider = getJcrQueryProvider();
+ if (jcrQueryProvider == null) {
+ return null;
+ }
+ try {
+ return jcrQueryProvider.getSupportedLanguages(getBasicContext());
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ }
+
+ @Override
+ public Iterator<Resource> findResources(String query, String language) {
+ final JCRQueryProvider<Object> jcrQueryProvider = getJcrQueryProvider();
+ if (jcrQueryProvider == null) {
+ return null;
+ }
+ try {
+ return jcrQueryProvider.findResources(getBasicContext(), query, language);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public Iterator<Map<String, Object>> queryResources(String query, String language) {
+ final JCRQueryProvider<Object> jcrQueryProvider = getJcrQueryProvider();
+ if (jcrQueryProvider == null) {
+ return null;
+ }
+ try {
+ return (Iterator) jcrQueryProvider.queryResources(getBasicContext(), query, language);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @Override
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ try {
+ return rp.adaptTo(getBasicContext(), type);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return null;
+ }
+ }
+
+ @Override
+ public boolean copy(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+ try {
+ return rp.copy(getContext(null, parentProviders), srcAbsPath, destAbsPath);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean move(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+ try {
+ return rp.move(getContext(null, parentProviders), srcAbsPath, destAbsPath);
+ } catch (LoginException e) {
+ logger.error("Can't create context", e);
+ return false;
+ }
+ }
+
+ @Override
+ public ResourceResolver getResourceResolver() {
+ return resolver;
+ }
+
+ @Override
+ public ResourceProvider<Object> getResourceProvider() {
+ return rp;
+ }
+}
Added: 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=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,587 @@
+/*
+ * 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.stateful;
+
+import static org.apache.commons.collections.IteratorUtils.chainedIterator;
+import static org.apache.commons.collections.IteratorUtils.transformedIterator;
+import static org.apache.sling.api.resource.ResourceUtil.getName;
+import static org.apache.sling.spi.resource.provider.ResourceProvider.RESOURCE_TYPE_SYNTHETIC;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+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.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.api.resource.query.Query;
+import org.apache.sling.api.resource.query.QueryInstructions;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderInfo;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderStorage;
+import org.apache.sling.resourceresolver.impl.providers.tree.Node;
+import org.apache.sling.spi.resource.provider.QueryResult;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class takes a number of {@link StatefulResourceProvider} objects and
+ * exposes it as one such object. Provider appropriate for the given operation
+ * is chosen basing on its {@link ResourceProviderInfo#getPath()} (more specific
+ * first) and service ranking.
+ */
+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) {
+ this.storage = storage;
+ this.resolver = resolver;
+ this.authenticator = authenticator;
+ }
+
+ /**
+ * Logouts from all providers.
+ */
+ public void logout() {
+ for (StatefulResourceProvider p : authenticator.getAllUsedAuthenticated()) {
+ p.logout();
+ }
+ }
+
+ /**
+ * Refreshes all providers.
+ */
+ public void refresh() {
+ for (StatefulResourceProvider p : authenticator.getAll(storage.getRefreshableHandlers())) {
+ p.refresh();
+ }
+ }
+
+ /**
+ * Returns {@code true} if all providers are live.
+ */
+ public boolean isLive() {
+ for (StatefulResourceProvider p : authenticator.getAllUsedAuthenticated()) {
+ if (!p.isLive()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns parent from the most appropriate resource provider accepting the
+ * given children.
+ *
+ * In some cases the {@link SyntheticResource} can be returned if no
+ * resource provider returns parent for this child. See
+ * {@link #getResource(String, Resource, Map, boolean)} for more details
+ */
+ public Resource getParent(Resource child) {
+ String path = child.getPath();
+ List<StatefulResourceProvider> matching = getMatchingProviders(path);
+ Resource parentCandidate = head(matching).getParent(child, tail(matching));
+ if (parentCandidate != null) {
+ return parentCandidate;
+ }
+ String parentPath = ResourceUtil.getParent(path);
+ if (parentPath != null && isIntermediatePath(parentPath)) {
+ return new SyntheticResource(resolver, parentPath, ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+ }
+ return null;
+ }
+
+ /**
+ * Returns resource from the most appropriate resource provider.
+ * <br/><br/>
+ * If there's no such provider and the path is a part of some resource
+ * provider path, then the {@link SyntheticResource} will be returned. For
+ * instance, if we have resource provider under
+ * {@code /libs/sling/servlet/default/GET.servlet} and no resource provider
+ * returns a resource for {@code /libs/sling/servlet/default}, then the
+ * {@link SyntheticResource} will be returned to provide a consistent
+ * resource tree.
+ * <br/><br/>
+ * The same behaviour occurs in {@link #getParent(Resource)} and
+ * {@link #listChildren(Resource)}.
+ */
+ public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve) {
+ if (path == null || path.length() == 0 || path.charAt(0) != '/') {
+ logger.debug("Not absolute {}", path);
+ return null; // path must be absolute
+ }
+
+ try {
+ List<StatefulResourceProvider> matching = getMatchingProviders(path);
+ Resource resourceCandidate = head(matching).getResource(path, parent, parameters, isResolve, tail(matching));
+ if (resourceCandidate != null) {
+ return resourceCandidate;
+ }
+
+ // query: /libs/sling/servlet/default
+ // resource Provider: libs/sling/servlet/default/GET.servlet
+ // list will match libs, sling, servlet, default
+ // and there will be no resource provider at the end
+ // SLING-3482 : this is only done for getResource but not resolve
+ // as it is important e.g. for servlet resolution
+ // to get the parent resource for resource traversal.
+ if (!isResolve && isIntermediatePath(path)) {
+ logger.debug("Resolved Synthetic {}", path);
+ return new SyntheticResource(resolver, path, ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+ }
+ } catch (SlingException e) {
+ throw e;
+ } catch (Exception e) {
+ logger.warn("Unexpected exception while trying to get resource for " + path, e);
+ }
+ logger.debug("Resource null {} ", path);
+ return null;
+ }
+
+ private boolean isIntermediatePath(final String fullPath) {
+ return storage.getTree().getNode(fullPath) != null;
+ }
+
+ /**
+ * This method asks all matching resource providers for the children iterators,
+ * merges them, adds {@link SyntheticResource}s (see
+ * {@link #getResource(String, Resource, Map, boolean)} for more details),
+ * filters out the duplicates and returns the resulting iterator. All
+ * transformations are done lazily, during the {@link Iterator#hasNext()}
+ * invocation on the result.
+ */
+ @SuppressWarnings("unchecked")
+ public Iterator<Resource> listChildren(final Resource parent) {
+ List<StatefulResourceProvider> matching = getMatchingProviders(parent.getPath());
+ Iterator<Resource> realChildren = head(matching).listChildren(parent, tail(matching));
+ 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;
+ }
+ });
+ }
+
+ private List<Resource> getSyntheticChildren(Resource parent) {
+ Node<ResourceProviderHandler> node = storage.getTree().getNode(parent.getPath());
+ if (node == null) {
+ return Collections.emptyList();
+ }
+ List<Resource> children = new ArrayList<Resource>();
+ for (Entry<String, Node<ResourceProviderHandler>> entry : node.getChildren().entrySet()) {
+ final String name = entry.getKey();
+ final ResourceProviderHandler handler = entry.getValue().getValue();
+ final String childPath = new StringBuilder(parent.getPath()).append('/').append(name).toString();
+ final Resource child;
+ if (handler == null) {
+ child = new SyntheticResource(resolver, childPath, RESOURCE_TYPE_SYNTHETIC);
+ } else {
+ child = authenticator.getStateful(handler).getResource(childPath, parent, null, false, null);
+ }
+ if (child != null) {
+ children.add(child);
+ }
+ }
+ return children;
+ }
+
+ /**
+ * Returns the union of all attribute names.
+ */
+ public Collection<String> getAttributeNames() {
+ final Set<String> names = new LinkedHashSet<String>();
+ for (StatefulResourceProvider p : authenticator.getAll(storage.getAttributableHandlers())) {
+ Collection<String> newNames = p.getAttributeNames();
+ if (newNames != null) {
+ names.addAll(newNames);
+ }
+ }
+ return names;
+ }
+
+ /**
+ * Returns the first non-null result of the
+ * {@link StatefulResourceProvider#getAttribute(String)} invocation on
+ * the providers.
+ */
+ public Object getAttribute(String name) {
+ for (StatefulResourceProvider p : authenticator.getAll(storage.getAttributableHandlers())) {
+ Object attribute = p.getAttribute(name);
+ if (attribute != null) {
+ return attribute;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Create a resource. Iterate over all modifiable ResourceProviders
+ * stopping at the first one which creates the resource and return the
+ * created resource.
+ *
+ * @throws UnsupportedOperationException
+ * If creation is not allowed/possible
+ * @throws PersistenceException
+ * If creation fails
+ * @return The new resource
+ */
+ public Resource create(String path, Map<String, Object> properties) throws PersistenceException {
+ List<StatefulResourceProvider> matching = getMatchingModifiableProviders(path);
+ Resource creationResultResource = head(matching).create(path, properties, tail(matching));
+ if (creationResultResource != null) {
+ return creationResultResource;
+ }
+ // 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));
+ }
+
+ /**
+ * Delete the resource. Iterate over all modifiable ResourceProviders
+ * giving each an opportunity to delete the resource if they are able.
+ *
+ * @throws NullPointerException
+ * if resource is null
+ * @throws UnsupportedOperationException
+ * If deletion is not allowed/possible
+ * @throws PersistenceException
+ * If deletion fails
+ */
+ public void delete(Resource resource) throws PersistenceException {
+ final String path = resource.getPath();
+ final Map<String, String> parameters = resource.getResourceMetadata().getParameterMap();
+ boolean anyProviderAttempted = false;
+
+ // Give all viable handlers a chance to delete the resource
+ for (StatefulResourceProvider p : getMatchingModifiableProviders(path)) {
+ Resource providerResource = p.getResource(path, null, parameters, false, null);
+ if (providerResource != null) {
+ anyProviderAttempted = true;
+ p.delete(providerResource, null);
+ }
+ }
+ // If none of the viable handlers could delete the resource or if the
+ // list of handlers was empty, throw an Exception
+ if (!anyProviderAttempted) {
+ throw new UnsupportedOperationException("delete at '" + path + "'");
+ }
+ }
+
+ /**
+ * Revert changes on all modifiable ResourceProviders.
+ */
+ public void revert() {
+ for (StatefulResourceProvider p : authenticator.getAllUsedModifiable()) {
+ p.revert();
+ }
+ }
+
+ /**
+ * Commit changes on all modifiable ResourceProviders.
+ */
+ public void commit() throws PersistenceException {
+ for (StatefulResourceProvider p : authenticator.getAllUsedModifiable()) {
+ p.commit();
+ }
+ }
+
+ /**
+ * Check if any modifiable ResourceProvider has uncommited changes.
+ */
+ public boolean hasChanges() {
+ for (StatefulResourceProvider p : authenticator.getAllUsedModifiable()) {
+ if (p.hasChanges()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Queries all resource providers and combines the results.
+ */
+ public QueryResult find(final Query q, final QueryInstructions qi) {
+ return new CombinedQueryResult(q, qi);
+ }
+
+ /**
+ * Return the union of query languages supported by the providers.
+ */
+ public String[] getSupportedLanguages() {
+ Set<String> supportedLanguages = new LinkedHashSet<String>();
+ for (StatefulResourceProvider p : authenticator.getAll(storage.getJcrQuerableHandlers())) {
+ supportedLanguages.addAll(Arrays.asList(p.getSupportedLanguages()));
+ }
+ return supportedLanguages.toArray(new String[supportedLanguages.size()]);
+ }
+
+ /**
+ * Queries all resource providers and combines the results.
+ */
+ public Iterator<Resource> findResources(final String query, final String language) {
+ List<StatefulResourceProvider> querableRP = getQuerableProviders(language);
+ List<Iterator<Resource>> iterators = new ArrayList<Iterator<Resource>>(querableRP.size());
+ for (StatefulResourceProvider p : querableRP) {
+ iterators.add(p.findResources(query, language));
+ }
+ return new ChainedIterator<Resource>(iterators.iterator());
+ }
+
+ private List<StatefulResourceProvider> getQuerableProviders(String language) {
+ List<StatefulResourceProvider> querableProviders = new ArrayList<StatefulResourceProvider>();
+ for (StatefulResourceProvider p : authenticator.getAll(storage.getJcrQuerableHandlers())) {
+ if (ArrayUtils.contains(p.getSupportedLanguages(), language)) {
+ querableProviders.add(p);
+ }
+ }
+ return querableProviders;
+ }
+
+ /**
+ * Queries all resource providers and combines the results.
+ */
+ public Iterator<Map<String, Object>> queryResources(final String query, final String language) {
+ List<StatefulResourceProvider> querableRP = getQuerableProviders(language);
+ List<Iterator<Map<String, Object>>> iterators = new ArrayList<Iterator<Map<String, Object>>>(querableRP.size());
+ for (StatefulResourceProvider p : querableRP) {
+ iterators.add(p.queryResources(query, language));
+ }
+ return new ChainedIterator<Map<String, Object>>(iterators.iterator());
+ }
+
+ /**
+ * Returns the first non-null result of the adaptTo() method invoked on the
+ * providers.
+ */
+ @SuppressWarnings("unchecked")
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ for (StatefulResourceProvider p : authenticator.getAll(storage.getAdaptableHandlers())) {
+ final Object adaptee = p.adaptTo(type);
+ if (adaptee != null) {
+ return (AdapterType) adaptee;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Tries to find a resource provider accepting both paths and invokes
+ * {@link StatefulResourceProvider#copy(String, String)} method on it.
+ * Returns false if there's no such provider.
+ */
+ public boolean copy(String srcAbsPath, String destAbsPath) throws PersistenceException {
+ 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, tail(intersection));
+ }
+
+ /**
+ * Tries to find a resource provider accepting both paths and invokes
+ * {@link StatefulResourceProvider#move(String, String)} method on it.
+ * Returns false if there's no such provider.
+ */
+ public boolean move(String srcAbsPath, String destAbsPath) throws PersistenceException {
+ 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, tail(intersection));
+ }
+
+ private List<StatefulResourceProvider> getMatchingProviders(String path) {
+ List<ResourceProviderHandler> handlers = storage.getTree().getMatchingNodes(path);
+ StatefulResourceProvider[] matching = new StatefulResourceProvider[handlers.size()];
+ int i = matching.length - 1;
+ for (ResourceProviderHandler h : handlers) {
+ matching[i--] = authenticator.getStateful(h); // reverse order
+ }
+ return Arrays.asList(matching);
+ }
+
+ private List<StatefulResourceProvider> getMatchingModifiableProviders(String path) {
+ List<ResourceProviderHandler> handlers = storage.getTree().getMatchingNodes(path);
+ List<StatefulResourceProvider> matching = new ArrayList<StatefulResourceProvider>(handlers.size());
+ for (ResourceProviderHandler h : handlers) {
+ if (h.getInfo().getModifiable()) {
+ matching.add(authenticator.getStateful(h));
+ }
+ }
+ Collections.reverse(matching);
+ return matching;
+ }
+
+ private static StatefulResourceProvider head(List<StatefulResourceProvider> list) {
+ if (list.isEmpty()) {
+ return EMPTY_PROVIDER;
+ } 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;
+
+ private final QueryInstructions qi;
+
+ public CombinedQueryResult(Query q, QueryInstructions qi) {
+ this.q = q;
+ this.qi = qi;
+ }
+
+ @Override
+ public Iterable<Resource> getResources() {
+ return this;
+ }
+
+ @Override
+ public Iterator<Resource> iterator() {
+ @SuppressWarnings("unchecked")
+ Iterator<Iterator<Resource>> iterators = IteratorUtils.transformedIterator(authenticator.getAll(storage.getNativeQuerableHandlers()).iterator(),
+ new Transformer() {
+ @Override
+ public Object transform(Object input) {
+ StatefulResourceProvider rp = (StatefulResourceProvider) input;
+ return rp.find(q, qi).getResources().iterator();
+ }
+ });
+ return new ChainedIterator<Resource>(iterators);
+ }
+ }
+
+ private static class ChainedIterator<T> extends AbstractIterator<T> {
+
+ private final Iterator<Iterator<T>> iterators;
+
+ private Iterator<T> currentIterator;
+
+ public ChainedIterator(Iterator<Iterator<T>> iterators) {
+ this.iterators = iterators;
+ }
+
+ @Override
+ protected T seek() {
+ while (true) {
+ if (currentIterator == null) {
+ if (!iterators.hasNext()) {
+ return null;
+ }
+ currentIterator = iterators.next();
+ continue;
+ }
+ if (currentIterator.hasNext()) {
+ return currentIterator.next();
+ } else {
+ currentIterator = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * This iterator removes duplicated Resource entries. Regular resources
+ * overrides the synthetic ones.
+ */
+ private static class UniqueIterator extends AbstractIterator<Resource> {
+
+ private final Iterator<Resource> input;
+
+ private final List<String> visited;
+
+ private final Map<String, Resource> delayed;
+
+ private Iterator<Resource> delayedIterator;
+
+ public UniqueIterator(Iterator<Resource> input) {
+ this.input = input;
+ this.visited = new ArrayList<String>();
+ this.delayed = new LinkedHashMap<String, Resource>();
+ }
+
+ @Override
+ protected Resource seek() {
+ while (input.hasNext()) {
+ Resource next = input.next();
+ String path = next.getPath();
+
+ if (visited.contains(path)) {
+ continue;
+ } else if (next instanceof SyntheticResource) {
+ delayed.put(path, next);
+ } else {
+ visited.add(path);
+ delayed.remove(path);
+ return next;
+ }
+ }
+
+ if (delayedIterator == null) {
+ delayedIterator = delayed.values().iterator();
+ }
+ if (delayedIterator.hasNext()) {
+ return delayedIterator.next();
+ }
+ return null;
+ }
+ }
+}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,151 @@
+/*
+ * 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.stateful;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+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.api.resource.query.Query;
+import org.apache.sling.api.resource.query.QueryInstructions;
+import org.apache.sling.spi.resource.provider.QueryResult;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+
+public class EmptyResourceProvider implements StatefulResourceProvider {
+
+ @Override
+ public ResourceResolver getResourceResolver() {
+ return null;
+ }
+
+ @Override
+ public void logout() {
+ }
+
+ @Override
+ public void refresh() {
+ }
+
+ @Override
+ public boolean isLive() {
+ return false;
+ }
+
+ @Override
+ public Resource getParent(Resource child, List<StatefulResourceProvider> parentProviders) {
+ return null;
+ }
+
+ @Override
+ public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve,
+ List<StatefulResourceProvider> parentProviders) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Resource> listChildren(Resource parent, List<StatefulResourceProvider> parentProviders) {
+ return null;
+ }
+
+ @Override
+ public Collection<String> getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public Resource create(String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders)
+ throws PersistenceException {
+ return null;
+ }
+
+ @Override
+ public void delete(Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+ }
+
+ @Override
+ public void revert() {
+ }
+
+ @Override
+ public void commit() throws PersistenceException {
+ }
+
+ @Override
+ public boolean hasChanges() {
+ return false;
+ }
+
+ @Override
+ public QueryResult find(Query q, QueryInstructions qi) {
+ return null;
+ }
+
+ @Override
+ public String[] getSupportedLanguages() {
+ return null;
+ }
+
+ @Override
+ public Iterator<Resource> findResources(String query, String language) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Map<String, Object>> queryResources(String query, String language) {
+ return null;
+ }
+
+ @Override
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ return null;
+ }
+
+ @Override
+ public boolean copy(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders)
+ throws PersistenceException {
+ return false;
+ }
+
+ @Override
+ public boolean move(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders)
+ throws PersistenceException {
+ return false;
+ }
+
+ @Override
+ public ResourceProvider<Object> getResourceProvider() {
+ return null;
+ }
+
+ @Override
+ public ResolveContext<Object> getContext(Map<String, String> parameters) {
+ return null;
+ }
+
+}
Added: 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=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,127 @@
+/*
+ * 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.stateful;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+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.runtime.dto.AuthType;
+import org.apache.sling.resourceresolver.impl.ResourceAccessSecurityTracker;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ResourceProviderAuthenticator {
+
+ private static final Logger logger = LoggerFactory.getLogger(ResourceProviderAuthenticator.class);
+
+ private final Map<ResourceProviderHandler, StatefulResourceProvider> stateful;
+
+ private final List<StatefulResourceProvider> authenticated;
+
+ private final List<StatefulResourceProvider> authenticatedModifiable;
+
+ private final ResourceResolver resolver;
+
+ private final Map<String, Object> authInfo;
+
+ private final ResourceAccessSecurityTracker securityTracker;
+
+ boolean allProvidersAuthenticated;
+
+ public ResourceProviderAuthenticator(ResourceResolver resolver, Map<String, Object> authInfo,
+ ResourceAccessSecurityTracker securityTracker) throws LoginException {
+ this.stateful = new IdentityHashMap<ResourceProviderHandler, StatefulResourceProvider>();
+ this.authenticated = new ArrayList<StatefulResourceProvider>();
+ this.authenticatedModifiable = new ArrayList<StatefulResourceProvider>();
+ this.resolver = resolver;
+ this.authInfo = authInfo;
+ this.securityTracker = securityTracker;
+ }
+
+ public void authenticateAll(List<ResourceProviderHandler> handlers) throws LoginException {
+ for (ResourceProviderHandler h : handlers) {
+ authenticate(h);
+ }
+ }
+
+ private StatefulResourceProvider authenticate(ResourceProviderHandler handler) throws LoginException {
+ StatefulResourceProvider rp = stateful.get(handler);
+ if (rp == null) {
+ rp = createStateful(handler);
+ if (rp == null) {
+ return null;
+ }
+ stateful.put(handler, rp);
+ if (handler.getInfo().getAuthType() != AuthType.no) {
+ authenticated.add(rp);
+ }
+ if (handler.getInfo().getModifiable()) {
+ authenticatedModifiable.add(rp);
+ }
+ }
+ return rp;
+ }
+
+ public StatefulResourceProvider getStateful(ResourceProviderHandler handler) {
+ try {
+ return authenticate(handler);
+ } catch (LoginException e) {
+ throw new SlingException("Can't authenticate provider", e);
+ }
+ }
+
+ public Collection<StatefulResourceProvider> getAllUsedAuthenticated() {
+ return authenticated;
+ }
+
+ public Collection<StatefulResourceProvider> getAllUsedModifiable() {
+ return authenticatedModifiable;
+ }
+
+ public Collection<StatefulResourceProvider> getAll(List<ResourceProviderHandler> handlers) {
+ List<StatefulResourceProvider> result = new ArrayList<StatefulResourceProvider>(handlers.size());
+ for (ResourceProviderHandler h : handlers) {
+ result.add(getStateful(h));
+ }
+ return result;
+ }
+
+ private StatefulResourceProvider createStateful(ResourceProviderHandler handler) throws LoginException {
+ ResourceProvider<?> rp = handler.getResourceProvider();
+ if (rp == null) {
+ logger.warn("Empty resource provider for {}", handler);
+ return null;
+ }
+ StatefulResourceProvider authenticated;
+ authenticated = new AuthenticatedResourceProvider(rp, handler.getInfo(), resolver, authInfo);
+ if (handler.getInfo().getUseResourceAccessSecurity()) {
+ authenticated = new SecureResourceProvider(authenticated, securityTracker);
+ }
+ return authenticated;
+ }
+
+}
\ No newline at end of file