incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1376960 - in /sling/trunk/bundles/resourceresolver/src: main/java/org/apache/sling/resourceresolver/impl/ main/resources/OSGI-INF/metatype/ test/java/org/apache/sling/resourceresolver/impl/
Date Fri, 24 Aug 2012 15:23:37 GMT
Author: cziegeler
Date: Fri Aug 24 15:23:37 2012
New Revision: 1376960

URL: http://svn.apache.org/viewvc?rev=1376960&view=rev
Log:
SLING-2579 : ResourceResolverFactory should only be available if specific ResourceProvider/Factories
are registered

Added:
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/FactoryPreconditions.java
  (with props)
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
  (with props)
Modified:
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
    sling/trunk/bundles/resourceresolver/src/main/resources/OSGI-INF/metatype/metatype.properties
    sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/FactoryPreconditions.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/FactoryPreconditions.java?rev=1376960&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/FactoryPreconditions.java
(added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/FactoryPreconditions.java
Fri Aug 24 15:23:37 2012
@@ -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;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FactoryPreconditions {
+
+    private static final class RequiredProvider {
+        public String pid;
+        public Filter filter;
+        public final List<Map<String, Object>> matchingServices = new ArrayList<Map<String,Object>>();
+    };
+
+    private final List<Map<String, Object>> earlyPropertiesList = new ArrayList<Map<String,
Object>>();
+
+    private volatile List<RequiredProvider> requiredProviders;
+
+    private Boolean cachedResult = Boolean.FALSE;
+
+    public void activate(final BundleContext bc, final String[] configuration) {
+        final List<RequiredProvider> rps = new ArrayList<RequiredProvider>();
+        if ( configuration != null ) {
+            final Logger logger = LoggerFactory.getLogger(getClass());
+            for(final String r : configuration) {
+                if ( r != null && r.trim().length() > 0 ) {
+                    final String value = r.trim();
+                    RequiredProvider rp = new RequiredProvider();
+                    if ( value.startsWith("(") ) {
+                        try {
+                            rp.filter = bc.createFilter(value);
+                        } catch (final InvalidSyntaxException e) {
+                            logger.warn("Ignoring invalid filter syntax for required provider:
" + value, e);
+                            rp = null;
+                        }
+                    } else {
+                        rp.pid = value;
+                    }
+                    if ( rp != null ) {
+                        rps.add(rp);
+                    }
+                }
+            }
+        }
+        synchronized ( this ) {
+            this.requiredProviders = rps;
+            this.cachedResult = null;
+            for(final Map<String,Object> props : this.earlyPropertiesList) {
+                this.bindProvider(props);
+            }
+            this.earlyPropertiesList.clear();
+        }
+    }
+
+    public void deactivate() {
+        this.requiredProviders = null;
+    }
+
+    public boolean checkPreconditions() {
+        synchronized ( this ) {
+            if ( cachedResult != null ) {
+                return cachedResult;
+            }
+            boolean canRegister = false;
+            if ( this.requiredProviders != null) {
+                canRegister = true;
+                for(final RequiredProvider rp : this.requiredProviders) {
+                    if ( rp.matchingServices.size() == 0 ) {
+                        canRegister = false;
+                        break;
+                    }
+                }
+            }
+            this.cachedResult = canRegister;
+            return canRegister;
+        }
+    }
+
+    public void bindProvider(final Map<String, Object> props) {
+        synchronized ( this ) {
+            if ( this.requiredProviders == null ) {
+                this.earlyPropertiesList.add(props);
+                return;
+            }
+            Dictionary<String, Object> dict = null;
+            for(final RequiredProvider rp : this.requiredProviders) {
+                if ( rp.pid != null ) {
+                    if ( rp.pid.equals(props.get(Constants.SERVICE_PID)) ) {
+                        rp.matchingServices.add(props);
+                        this.cachedResult = null;
+                    }
+                } else {
+                    if ( dict == null ) {
+                        dict = new Hashtable<String, Object>(props);
+                    }
+                    if ( rp.filter.match(dict) ) {
+                        rp.matchingServices.add(props);
+                        this.cachedResult = null;
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean removeFromList(final List<Map<String, Object>> list, final
Map<String, Object> props) {
+        final Long id = (Long) props.get(Constants.SERVICE_ID);
+        int index = 0;
+        while ( index < list.size() ) {
+            final Long currentId = (Long ) list.get(index).get(Constants.SERVICE_ID);
+            if ( currentId == id ) {
+                list.remove(index);
+                return true;
+            }
+            index++;
+        }
+        return false;
+    }
+
+    public void unbindProvider(final Map<String, Object> props) {
+        synchronized ( this ) {
+            if ( this.requiredProviders == null ) {
+                this.removeFromList(this.earlyPropertiesList, props);
+                return;
+            }
+            for(final RequiredProvider rp : this.requiredProviders) {
+                if ( this.removeFromList(rp.matchingServices, props) ) {
+                    this.cachedResult = null;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

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

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

Propchange: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/FactoryPreconditions.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java?rev=1376960&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
(added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
Fri Aug 24 15:23:37 2012
@@ -0,0 +1,374 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.BidiMap;
+import org.apache.commons.collections.bidimap.TreeBidiMap;
+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.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+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.sling.api.resource.ResourceDecorator;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceProviderFactory;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.resourceresolver.impl.helper.ResourceDecoratorTracker;
+import org.apache.sling.resourceresolver.impl.mapping.MapEntries;
+import org.apache.sling.resourceresolver.impl.mapping.Mapping;
+import org.apache.sling.resourceresolver.impl.tree.RootResourceProviderEntry;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * The <code>ResourceResolverFactoryActivator/code> keeps track of required services
for the
+ * resource resolver factory.
+ * One all required providers and provider factories are available a resource resolver factory
+ * is registered.
+ *
+ * TODO : Should we implement modifiable? It would be easy but what about long running resolvers?
+ */
+@Component(
+     name = "org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl",
+     label = "%resource.resolver.name",
+     description = "%resource.resolver.description",
+     specVersion = "1.1",
+     metatype = true)
+@Properties({
+    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling Resource Resolver
Factory"),
+    @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation")
+})
+@References({
+    @Reference(name = "ResourceProvider", referenceInterface = ResourceProvider.class, cardinality
= ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
+    @Reference(name = "ResourceProviderFactory", referenceInterface = ResourceProviderFactory.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
+    @Reference(name = "ResourceDecorator", referenceInterface = ResourceDecorator.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC) })
+public class ResourceResolverFactoryActivator {
+
+    @Property(value = { "/apps", "/libs" })
+    public static final String PROP_PATH = "resource.resolver.searchpath";
+
+    /**
+     * Defines whether namespace prefixes of resource names inside the path
+     * (e.g. <code>jcr:</code> in <code>/home/path/jcr:content</code>)
are
+     * mangled or not.
+     * <p>
+     * Mangling means that any namespace prefix contained in the path is replaced as per
the generic
+     * substitution pattern <code>/([^:]+):/_$1_/</code> when calling the <code>map</code>
method of
+     * the resource resolver. Likewise the <code>resolve</code> methods will
unmangle such namespace
+     * prefixes according to the substituation pattern <code>/_([^_]+)_/$1:/</code>.
+     * <p>
+     * This feature is provided since there may be systems out there in the wild which cannot
cope
+     * with URLs containing colons, even though they are perfectly valid characters in the
path part
+     * of URI references with a scheme.
+     * <p>
+     * The default value of this property if no configuration is provided is <code>true</code>.
+     *
+     */
+    @Property(boolValue = true)
+    private static final String PROP_MANGLE_NAMESPACES = "resource.resolver.manglenamespaces";
+
+    @Property(boolValue = true)
+    private static final String PROP_ALLOW_DIRECT = "resource.resolver.allowDirect";
+
+    @Property(unbounded=PropertyUnbounded.ARRAY, value = "org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProviderFactory")
+    private static final String PROP_REQUIRED_PROVIDERS = "resource.resolver.required.providers";
+
+    /**
+     * The resolver.virtual property has no default configuration. But the sling
+     * maven plugin and the sling management console cannot handle empty
+     * multivalue properties at the moment. So we just add a dummy direct
+     * mapping.
+     */
+    @Property(value = "/:/", unbounded = PropertyUnbounded.ARRAY)
+    private static final String PROP_VIRTUAL = "resource.resolver.virtual";
+
+    @Property(value = { "/:/", "/content/:/", "/system/docroot/:/" })
+    private static final String PROP_MAPPING = "resource.resolver.mapping";
+
+    @Property(value = MapEntries.DEFAULT_MAP_ROOT)
+    private static final String PROP_MAP_LOCATION = "resource.resolver.map.location";
+
+    /** Tracker for the resource decorators. */
+    private final ResourceDecoratorTracker resourceDecoratorTracker = new ResourceDecoratorTracker();
+
+    /** all mappings */
+    private Mapping[] mappings;
+
+    /** The fake urls */
+    private BidiMap virtualURLMap;
+
+    /** <code>true</code>, if direct mappings from URI to handle are allowed
*/
+    private boolean allowDirect = false;
+
+    /** the search path for ResourceResolver.getResource(String) */
+    private String[] searchPath;
+
+    /** the root location of the /etc/map entries */
+    private String mapRoot;
+
+    /** whether to mangle paths with namespaces or not */
+    private boolean mangleNamespacePrefixes;
+
+    /** The root provider entry. */
+    private final RootResourceProviderEntry rootProviderEntry = new RootResourceProviderEntry();
+
+    /** Event admin. */
+    @Reference
+    private EventAdmin eventAdmin;
+
+    /** Registered resource resolver factory. */
+    private ResourceResolverFactoryImpl factory;
+
+    /** Registration .*/
+    private ServiceRegistration factoryRegistration;
+
+    /** ComponentContext */
+    private ComponentContext componentContext;
+
+    private final FactoryPreconditions preconds = new FactoryPreconditions();
+
+    /**
+     * Get the resource decorator tracker.
+     */
+    public ResourceDecoratorTracker getResourceDecoratorTracker() {
+        return this.resourceDecoratorTracker;
+    }
+
+    public EventAdmin getEventAdmin() {
+        return this.eventAdmin;
+    }
+
+    /**
+     * Getter for rootProviderEntry.
+     */
+    public RootResourceProviderEntry getRootProviderEntry() {
+        return rootProviderEntry;
+    }
+
+    /**
+     * This method is called from {@link MapEntries}
+     */
+    public BidiMap getVirtualURLMap() {
+        return virtualURLMap;
+    }
+
+    /**
+     * This method is called from {@link MapEntries}
+     */
+    public Mapping[] getMappings() {
+        return mappings;
+    }
+
+    public String[] getSearchPath() {
+        return searchPath;
+    }
+
+    public boolean isMangleNamespacePrefixes() {
+        return mangleNamespacePrefixes;
+
+    }
+
+    public String getMapRoot() {
+        return mapRoot;
+    }
+
+    // ---------- SCR Integration ---------------------------------------------
+
+    /** Activates this component, called by SCR before registering as a service */
+    @Activate
+    protected void activate(final ComponentContext componentContext) {
+        this.componentContext = componentContext;
+        this.rootProviderEntry.setEventAdmin(this.eventAdmin);
+        final Dictionary<?, ?> properties = componentContext.getProperties();
+
+        final BidiMap virtuals = new TreeBidiMap();
+        final String[] virtualList = PropertiesUtil.toStringArray(properties.get(PROP_VIRTUAL));
+        for (int i = 0; virtualList != null && i < virtualList.length; i++) {
+            final String[] parts = Mapping.split(virtualList[i]);
+            virtuals.put(parts[0], parts[2]);
+        }
+        virtualURLMap = virtuals;
+
+        final List<Mapping> maps = new ArrayList<Mapping>();
+        final String[] mappingList = (String[]) properties.get(PROP_MAPPING);
+        for (int i = 0; mappingList != null && i < mappingList.length; i++) {
+            maps.add(new Mapping(mappingList[i]));
+        }
+        final Mapping[] tmp = maps.toArray(new Mapping[maps.size()]);
+
+        // check whether direct mappings are allowed
+        final Boolean directProp = (Boolean) properties.get(PROP_ALLOW_DIRECT);
+        allowDirect = (directProp != null) ? directProp.booleanValue() : true;
+        if (allowDirect) {
+            final Mapping[] tmp2 = new Mapping[tmp.length + 1];
+            tmp2[0] = Mapping.DIRECT;
+            System.arraycopy(tmp, 0, tmp2, 1, tmp.length);
+            mappings = tmp2;
+        } else {
+            mappings = tmp;
+        }
+
+        // from configuration if available
+        searchPath = PropertiesUtil.toStringArray(properties.get(PROP_PATH));
+        if (searchPath != null && searchPath.length > 0) {
+            for (int i = 0; i < searchPath.length; i++) {
+                // ensure leading slash
+                if (!searchPath[i].startsWith("/")) {
+                    searchPath[i] = "/" + searchPath[i];
+                }
+                // ensure trailing slash
+                if (!searchPath[i].endsWith("/")) {
+                    searchPath[i] += "/";
+                }
+            }
+        }
+        if (searchPath == null) {
+            searchPath = new String[] { "/" };
+        }
+
+        // namespace mangling
+        mangleNamespacePrefixes = PropertiesUtil.toBoolean(properties.get(PROP_MANGLE_NAMESPACES),
false);
+
+        // the root of the resolver mappings
+        mapRoot = PropertiesUtil.toString(properties.get(PROP_MAP_LOCATION), MapEntries.DEFAULT_MAP_ROOT);
+
+        final BundleContext bc = componentContext.getBundleContext();
+
+        // check for required property
+        final String[] required = PropertiesUtil.toStringArray(properties.get(PROP_REQUIRED_PROVIDERS));
+        this.preconds.activate(bc, required);
+        this.checkFactoryPreconditions();
+    }
+
+    /**
+     * Deativates this component (called by SCR to take out of service)
+     */
+    @Deactivate
+    protected void deactivate() {
+        this.componentContext = null;
+        this.preconds.deactivate();
+        this.rootProviderEntry.setEventAdmin(null);
+        this.resourceDecoratorTracker.close();
+
+        this.unregisterFactory();
+    }
+
+    private void unregisterFactory() {
+        if ( this.factoryRegistration != null ) {
+            this.factoryRegistration.unregister();
+            this.factoryRegistration = null;
+        }
+        if ( this.factory != null ) {
+            this.factory.deactivate();
+            this.factory = null;
+        }
+    }
+
+    private void checkFactoryPreconditions() {
+        if ( this.componentContext != null ) {
+            final boolean result = this.preconds.checkPreconditions();
+            if ( result ) {
+                synchronized ( this ) {
+                    if ( factory == null ) {
+                        // register factory
+                        this.factory = new ResourceResolverFactoryImpl(this);
+                        this.factory.activate(this.componentContext.getBundleContext());
+                        final Dictionary<String, Object> serviceProps = new Hashtable<String,
Object>();
+                        serviceProps.put(Constants.SERVICE_VENDOR, this.componentContext.getProperties().get(Constants.SERVICE_VENDOR));
+                        serviceProps.put(Constants.SERVICE_DESCRIPTION, this.componentContext.getProperties().get(Constants.SERVICE_DESCRIPTION));
+
+                        this.factoryRegistration = this.componentContext.getBundleContext().registerService(ResourceResolverFactory.class.getName(),
+                                        factory, serviceProps);
+                    }
+                }
+            } else {
+                synchronized ( this ) {
+                    if ( factory != null ) {
+                        this.unregisterFactory();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Bind a resource provider.
+     */
+    protected void bindResourceProvider(final ResourceProvider provider, final Map<String,
Object> props) {
+        this.rootProviderEntry.bindResourceProvider(provider, props);
+        this.preconds.bindProvider(props);
+        this.checkFactoryPreconditions();
+    }
+
+    /**
+     * Unbind a resource provider.
+     */
+    protected void unbindResourceProvider(final ResourceProvider provider, final Map<String,
Object> props) {
+        this.rootProviderEntry.unbindResourceProvider(provider, props);
+        this.preconds.unbindProvider(props);
+        this.checkFactoryPreconditions();
+    }
+
+    /**
+     * Bind a resource provider factory.
+     */
+    protected void bindResourceProviderFactory(final ResourceProviderFactory provider, final
Map<String, Object> props) {
+        this.rootProviderEntry.bindResourceProviderFactory(provider, props);
+        this.preconds.bindProvider(props);
+        this.checkFactoryPreconditions();
+    }
+
+    /**
+     * Unbind a resource provider factory.
+     */
+    protected void unbindResourceProviderFactory(final ResourceProviderFactory provider,
final Map<String, Object> props) {
+        this.rootProviderEntry.unbindResourceProviderFactory(provider, props);
+        this.preconds.unbindProvider(props);
+        this.checkFactoryPreconditions();
+    }
+
+    /**
+     * Bind a resource decorator.
+     */
+    protected void bindResourceDecorator(final ResourceDecorator decorator, final Map<String,
Object> props) {
+        this.resourceDecoratorTracker.bindResourceDecorator(decorator, props);
+    }
+
+    /**
+     * Unbind a resource decorator.
+     */
+    protected void unbindResourceDecorator(final ResourceDecorator decorator, final Map<String,
Object> props) {
+        this.resourceDecoratorTracker.unbindResourceDecorator(decorator, props);
+    }
+}
\ No newline at end of file

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

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

Propchange: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java?rev=1376960&r1=1376959&r2=1376960&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
(original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
Fri Aug 24 15:23:37 2012
@@ -18,41 +18,19 @@
  */
 package org.apache.sling.resourceresolver.impl;
 
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.List;
 import java.util.Map;
-import java.util.regex.Pattern;
 
 import org.apache.commons.collections.BidiMap;
-import org.apache.commons.collections.bidimap.TreeBidiMap;
-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.Properties;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyUnbounded;
-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.LoginException;
-import org.apache.sling.api.resource.ResourceDecorator;
-import org.apache.sling.api.resource.ResourceProvider;
-import org.apache.sling.api.resource.ResourceProviderFactory;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.resourceresolver.impl.console.ResourceResolverWebConsolePlugin;
 import org.apache.sling.resourceresolver.impl.helper.ResourceDecoratorTracker;
 import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
 import org.apache.sling.resourceresolver.impl.mapping.MapEntries;
 import org.apache.sling.resourceresolver.impl.mapping.Mapping;
 import org.apache.sling.resourceresolver.impl.tree.RootResourceProviderEntry;
-import org.osgi.framework.Constants;
-import org.osgi.service.component.ComponentContext;
-import org.osgi.service.event.EventAdmin;
+import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,113 +43,22 @@ import org.slf4j.LoggerFactory;
  * <li>Fires OSGi EventAdmin events on behalf of internal helper objects
  * </ul>
  *
- * TODO : Should we implement modifiable? It would be easy but what about long running resolvers?
  */
-@Component(
-     name = "org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl",
-     label = "%resource.resolver.name",
-     description = "%resource.resolver.description",
-     specVersion = "1.1",
-     metatype = true)
-@Service(value = ResourceResolverFactory.class)
-@Properties({
-    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling ResourceResolverFactory
Implementation"),
-    @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation")
-})
-@References({
-    @Reference(name = "ResourceProvider", referenceInterface = ResourceProvider.class, cardinality
= ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
-    @Reference(name = "ResourceProviderFactory", referenceInterface = ResourceProviderFactory.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
-    @Reference(name = "ResourceDecorator", referenceInterface = ResourceDecorator.class,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC) })
 public class ResourceResolverFactoryImpl implements ResourceResolverFactory {
 
-    public final static class ResourcePattern {
-        public final Pattern pattern;
-
-        public final String replacement;
-
-        public ResourcePattern(final Pattern p, final String r) {
-            this.pattern = p;
-            this.replacement = r;
-        }
-    }
-
-    @Property(value = { "/apps", "/libs" })
-    public static final String PROP_PATH = "resource.resolver.searchpath";
-
-    /**
-     * Defines whether namespace prefixes of resource names inside the path
-     * (e.g. <code>jcr:</code> in <code>/home/path/jcr:content</code>)
are
-     * mangled or not.
-     * <p>
-     * Mangling means that any namespace prefix contained in the path is replaced as per
the generic
-     * substitution pattern <code>/([^:]+):/_$1_/</code> when calling the <code>map</code>
method of
-     * the resource resolver. Likewise the <code>resolve</code> methods will
unmangle such namespace
-     * prefixes according to the substituation pattern <code>/_([^_]+)_/$1:/</code>.
-     * <p>
-     * This feature is provided since there may be systems out there in the wild which cannot
cope
-     * with URLs containing colons, even though they are perfectly valid characters in the
path part
-     * of URI references with a scheme.
-     * <p>
-     * The default value of this property if no configuration is provided is <code>true</code>.
-     *
-     */
-    @Property(boolValue = true)
-    private static final String PROP_MANGLE_NAMESPACES = "resource.resolver.manglenamespaces";
-
-    @Property(boolValue = true)
-    private static final String PROP_ALLOW_DIRECT = "resource.resolver.allowDirect";
-
-    /**
-     * The resolver.virtual property has no default configuration. But the sling
-     * maven plugin and the sling management console cannot handle empty
-     * multivalue properties at the moment. So we just add a dummy direct
-     * mapping.
-     */
-    @Property(value = "/:/", unbounded = PropertyUnbounded.ARRAY)
-    private static final String PROP_VIRTUAL = "resource.resolver.virtual";
-
-    @Property(value = { "/:/", "/content/:/", "/system/docroot/:/" })
-    private static final String PROP_MAPPING = "resource.resolver.mapping";
-
-    @Property(value = MapEntries.DEFAULT_MAP_ROOT)
-    private static final String PROP_MAP_LOCATION = "resource.resolver.map.location";
-
-    /** Default logger */
-    private final Logger logger = LoggerFactory.getLogger(getClass());
-
-    /** Tracker for the resource decorators. */
-    private final ResourceDecoratorTracker resourceDecoratorTracker = new ResourceDecoratorTracker();
-
-    // helper for the new ResourceResolver
+    /** Helper for the resource resolver. */
     private MapEntries mapEntries = MapEntries.EMPTY;
 
-    /** all mappings */
-    private Mapping[] mappings;
-
-    /** The fake urls */
-    private BidiMap virtualURLMap;
-
-    /** <code>true</code>, if direct mappings from URI to handle are allowed
*/
-    private boolean allowDirect = false;
-
-    // the search path for ResourceResolver.getResource(String)
-    private String[] searchPath;
-
-    // the root location of the /etc/map entries
-    private String mapRoot;
-
-    private final RootResourceProviderEntry rootProviderEntry = new RootResourceProviderEntry();
-
-    // whether to mangle paths with namespaces or not
-    private boolean mangleNamespacePrefixes;
-
-    /** Event admin. */
-    @Reference
-    private EventAdmin eventAdmin;
-
     /** The web console plugin. */
     private ResourceResolverWebConsolePlugin plugin;
 
+    /** The activator */
+    private final ResourceResolverFactoryActivator activator;
+
+    public ResourceResolverFactoryImpl(final ResourceResolverFactoryActivator activator)
{
+        this.activator = activator;
+    }
+
     // ---------- Resource Resolver Factory ------------------------------------
 
     /**
@@ -204,141 +91,37 @@ public class ResourceResolverFactoryImpl
         final ResourceResolverContext ctx = new ResourceResolverContext(isAdmin, authenticationInfo);
 
         // login
-        this.rootProviderEntry.loginToRequiredFactories(ctx);
+        this.activator.getRootProviderEntry().loginToRequiredFactories(ctx);
 
         return new ResourceResolverImpl(this, ctx);
     }
 
-    /**
-     * Get the resource decorator tracker.
-     */
-    public ResourceDecoratorTracker getResourceDecoratorTracker() {
-        return this.resourceDecoratorTracker;
-    }
-
-    /**
-     * This method is called from {@link MapEntries}
-     */
-    public BidiMap getVirtualURLMap() {
-        return virtualURLMap;
-    }
-
-    /**
-     * This method is called from {@link MapEntries}
-     */
-    public Mapping[] getMappings() {
-        return mappings;
-    }
-
-    public String[] getSearchPath() {
-        return searchPath;
-    }
-
-    public boolean isMangleNamespacePrefixes() {
-        return mangleNamespacePrefixes;
-
-    }
-
-    public String getMapRoot() {
-        return mapRoot;
-    }
-
     public MapEntries getMapEntries() {
         return mapEntries;
     }
 
-    /**
-     * Getter for rootProviderEntry, making it easier to extend
-     * JcrResourceResolverFactoryImpl. See <a
-     * href="https://issues.apache.org/jira/browse/SLING-730">SLING-730</a>
-     *
-     * @return Our rootProviderEntry
-     */
-    protected RootResourceProviderEntry getRootProviderEntry() {
-        return rootProviderEntry;
-    }
-
-    // ---------- SCR Integration ---------------------------------------------
-
-    /** Activates this component, called by SCR before registering as a service */
-    @Activate
-    protected void activate(final ComponentContext componentContext) {
-        this.rootProviderEntry.setEventAdmin(this.eventAdmin);
-        final Dictionary<?, ?> properties = componentContext.getProperties();
-
-        final BidiMap virtuals = new TreeBidiMap();
-        final String[] virtualList = PropertiesUtil.toStringArray(properties.get(PROP_VIRTUAL));
-        for (int i = 0; virtualList != null && i < virtualList.length; i++) {
-            final String[] parts = Mapping.split(virtualList[i]);
-            virtuals.put(parts[0], parts[2]);
-        }
-        virtualURLMap = virtuals;
-
-        final List<Mapping> maps = new ArrayList<Mapping>();
-        final String[] mappingList = (String[]) properties.get(PROP_MAPPING);
-        for (int i = 0; mappingList != null && i < mappingList.length; i++) {
-            maps.add(new Mapping(mappingList[i]));
-        }
-        final Mapping[] tmp = maps.toArray(new Mapping[maps.size()]);
-
-        // check whether direct mappings are allowed
-        final Boolean directProp = (Boolean) properties.get(PROP_ALLOW_DIRECT);
-        allowDirect = (directProp != null) ? directProp.booleanValue() : true;
-        if (allowDirect) {
-            final Mapping[] tmp2 = new Mapping[tmp.length + 1];
-            tmp2[0] = Mapping.DIRECT;
-            System.arraycopy(tmp, 0, tmp2, 1, tmp.length);
-            mappings = tmp2;
-        } else {
-            mappings = tmp;
-        }
-
-        // from configuration if available
-        searchPath = PropertiesUtil.toStringArray(properties.get(PROP_PATH));
-        if (searchPath != null && searchPath.length > 0) {
-            for (int i = 0; i < searchPath.length; i++) {
-                // ensure leading slash
-                if (!searchPath[i].startsWith("/")) {
-                    searchPath[i] = "/" + searchPath[i];
-                }
-                // ensure trailing slash
-                if (!searchPath[i].endsWith("/")) {
-                    searchPath[i] += "/";
-                }
-            }
-        }
-        if (searchPath == null) {
-            searchPath = new String[] { "/" };
-        }
-
-        // namespace mangling
-        mangleNamespacePrefixes = PropertiesUtil.toBoolean(properties.get(PROP_MANGLE_NAMESPACES),
false);
-
-        // the root of the resolver mappings
-        mapRoot = PropertiesUtil.toString(properties.get(PROP_MAP_LOCATION), MapEntries.DEFAULT_MAP_ROOT);
-
-        // set up the map entries from configuration
-        try {
-            mapEntries = new MapEntries(this, componentContext.getBundleContext(), this.eventAdmin);
-        } catch (final Exception e) {
-            logger.error("activate: Cannot access repository, failed setting up Mapping Support",
e);
-        }
-
+    /** Activates this component */
+    protected void activate(final BundleContext bundleContext) {
+        final Logger logger = LoggerFactory.getLogger(getClass());
         try {
-            plugin = new ResourceResolverWebConsolePlugin(componentContext.getBundleContext(),
this);
+            plugin = new ResourceResolverWebConsolePlugin(bundleContext, this);
         } catch (final Throwable ignore) {
             // an exception here propably means the web console plugin is not
             // available
             logger.debug("activate: unable to setup web console plugin.", ignore);
         }
+        // set up the map entries from configuration
+        try {
+            mapEntries = new MapEntries(this, bundleContext, this.activator.getEventAdmin());
+        } catch (final Exception e) {
+            logger.error("activate: Cannot access repository, failed setting up Mapping Support",
e);
+        }
     }
 
     /**
-     * Deativates this component (called by SCR to take out of service)
+     * Deativates this component
      */
-    @Deactivate
     protected void deactivate() {
-        this.rootProviderEntry.setEventAdmin(null);
         if (plugin != null) {
             plugin.dispose();
             plugin = null;
@@ -348,48 +131,33 @@ public class ResourceResolverFactoryImpl
             mapEntries.dispose();
             mapEntries = MapEntries.EMPTY;
         }
-        this.resourceDecoratorTracker.close();
     }
 
-    /**
-     * Bind a resource provider.
-     */
-    protected void bindResourceProvider(final ResourceProvider provider, final Map<String,
Object> props) {
-        this.rootProviderEntry.bindResourceProvider(provider, props);
+    public ResourceDecoratorTracker getResourceDecoratorTracker() {
+        return this.activator.getResourceDecoratorTracker();
     }
 
-    /**
-     * Unbind a resource provider.
-     */
-    protected void unbindResourceProvider(final ResourceProvider provider, final Map<String,
Object> props) {
-        this.rootProviderEntry.unbindResourceProvider(provider, props);
+    public String[] getSearchPath() {
+        return this.activator.getSearchPath();
     }
 
-    /**
-     * Bind a resource provider factory.
-     */
-    protected void bindResourceProviderFactory(final ResourceProviderFactory provider, final
Map<String, Object> props) {
-        this.rootProviderEntry.bindResourceProviderFactory(provider, props);
+    public boolean isMangleNamespacePrefixes() {
+        return this.activator.isMangleNamespacePrefixes();
     }
 
-    /**
-     * Unbind a resource provider factory.
-     */
-    protected void unbindResourceProviderFactory(final ResourceProviderFactory provider,
final Map<String, Object> props) {
-        this.rootProviderEntry.unbindResourceProviderFactory(provider, props);
+    public String getMapRoot() {
+        return this.activator.getMapRoot();
     }
 
-    /**
-     * Bind a resource decorator.
-     */
-    protected void bindResourceDecorator(final ResourceDecorator decorator, final Map<String,
Object> props) {
-        this.resourceDecoratorTracker.bindResourceDecorator(decorator, props);
+    public Mapping[] getMappings() {
+        return this.activator.getMappings();
     }
 
-    /**
-     * Unbind a resource decorator.
-     */
-    protected void unbindResourceDecorator(final ResourceDecorator decorator, final Map<String,
Object> props) {
-        this.resourceDecoratorTracker.unbindResourceDecorator(decorator, props);
+    public BidiMap getVirtualURLMap() {
+        return this.activator.getVirtualURLMap();
+    }
+
+    public RootResourceProviderEntry getRootProviderEntry() {
+        return this.activator.getRootProviderEntry();
     }
 }
\ No newline at end of file

Modified: sling/trunk/bundles/resourceresolver/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1376960&r1=1376959&r2=1376960&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/resources/OSGI-INF/metatype/metatype.properties
(original)
+++ sling/trunk/bundles/resourceresolver/src/main/resources/OSGI-INF/metatype/metatype.properties
Fri Aug 24 15:23:37 2012
@@ -71,3 +71,9 @@ resource.resolver.manglenamespaces.descr
  containing colons, even though they are perfectly valid characters in the \
  path part of URI references with a scheme. The default value of this property \
  if no configuration is provided is "true".
+
+resource.resolver.required.providers.name = Required Providers
+resource.resolver.required.providers.description = A resource resolver factory is only \
+ available (registered) if all resource providers mentioned in this configuration \
+ are available. Each entry is either a service PID or a filter expression. \
+ Invalid filters are ignored.
\ No newline at end of file

Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java?rev=1376960&r1=1376959&r2=1376960&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
(original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
Fri Aug 24 15:23:37 2012
@@ -58,7 +58,7 @@ public class ResourceResolverImplTest {
     private ResourceResolverFactoryImpl resFac;
 
     @Before public void setup() {
-        resFac = new ResourceResolverFactoryImpl();
+        resFac = new ResourceResolverFactoryImpl(new ResourceResolverFactoryActivator());
         resResolver = new ResourceResolverImpl(resFac, new ResourceResolverContext(false,
null));
     }
 



Mime
View raw message