Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfo.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfo.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfo.java (working copy) @@ -29,10 +29,11 @@ import org.apache.jackrabbit.oak.spi.mount.Mount; +import static com.google.common.base.Preconditions.checkNotNull; import static org.apache.jackrabbit.oak.commons.PathUtils.isAncestor; -final class MountInfo { - +final class MountInfo implements Mount { + private static final Function SANITIZE_PATH = new Function() { @Override public String apply(String input) { @@ -42,23 +43,25 @@ return input; } }; - - private final Mount mount; + + private final String name; + private final boolean readOnly; + private final boolean defaultMount; + private final String pathFragmentName; private final List includedPaths; - public MountInfo(Mount mount, List includedPaths){ - this.mount = mount; + public MountInfo(String name, boolean readOnly, boolean defaultMount, + List includedPaths) { + this.name = checkNotNull(name, "Mount name must not be null"); + this.readOnly = readOnly; + this.defaultMount = defaultMount; + this.pathFragmentName = "oak:" + name; this.includedPaths = cleanCopy(includedPaths); } - public Mount getMount() { - return mount; - } - + @Override public boolean isUnder(String path) { - path = SANITIZE_PATH.apply(path); - for (String includedPath : includedPaths) { if (isAncestor(path, includedPath)) { return true; @@ -68,9 +71,9 @@ return false; } - public boolean isMounted(String path){ - - if (path.contains(mount.getPathFragmentName())){ + @Override + public boolean isMounted(String path) { + if (path.contains(pathFragmentName)){ return true; } @@ -87,18 +90,65 @@ } @Override + public String getName() { + return name; + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + @Override + public boolean isDefault() { + return defaultMount; + } + + @Override + public String getPathFragmentName() { + return pathFragmentName; + } + + private static ImmutableList cleanCopy(List includedPaths) { + // ensure that paths don't have trailing slashes - this triggers an assertion in PahtUtils isAncestor + return ImmutableList.copyOf(Iterables.transform(includedPaths, SANITIZE_PATH)); + } + + @Override public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); - pw.print(mount); + String readAttr = readOnly ? "r" : "rw"; + String displayName = defaultMount ? "default" : name; + pw.print(displayName + "(" + readAttr + ")"); for (String path : includedPaths) { pw.printf("\t%s%n", path); } return sw.toString(); } - - private ImmutableList cleanCopy(List includedPaths) { - // ensure that paths don't have trailing slashes - this triggers an assertion in PahtUtils isAncestor - return ImmutableList.copyOf(Iterables.transform(includedPaths, SANITIZE_PATH)); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MountInfo other = (MountInfo) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoProviderService.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoProviderService.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoProviderService.java (working copy) @@ -32,6 +32,7 @@ import org.apache.jackrabbit.oak.commons.PropertiesUtil; import org.apache.jackrabbit.oak.spi.mount.Mount; import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider; +import org.apache.jackrabbit.oak.spi.mount.Mounts; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; @@ -72,14 +73,13 @@ String mountName = PropertiesUtil.toString(config.get(PROP_MOUNT_NAME), PROP_MOUNT_NAME_DEFAULT); boolean readOnly = PropertiesUtil.toBoolean(config.get(PROP_MOUNT_READONLY), PROP_MOUNT_READONLY_DEFAULT); - MountInfoProvider mip = MountInfoProvider.DEFAULT; - if (paths != null){ - Mount mount = new Mount(mountName.trim(), readOnly); + MountInfoProvider mip = Mounts.defaultMountInfoProvider(); + if (paths != null) { List trimmedPaths = new ArrayList(paths.length); - for (String path : paths){ + for (String path : paths) { trimmedPaths.add(path.trim()); } - MountInfo mi = new MountInfo(mount, trimmedPaths); + Mount mi = new MountInfo(mountName.trim(), readOnly, false, trimmedPaths); mip = new SimpleMountInfoProvider(Collections.singletonList(mi)); log.info("Enabling mount for {}", mi); } else { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/PrivateStoreValidatorProvider.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/PrivateStoreValidatorProvider.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/PrivateStoreValidatorProvider.java (working copy) @@ -24,6 +24,7 @@ import org.apache.jackrabbit.oak.spi.commit.*; import org.apache.jackrabbit.oak.spi.mount.Mount; import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider; +import org.apache.jackrabbit.oak.spi.mount.Mounts; import org.apache.jackrabbit.oak.spi.state.NodeState; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; @@ -50,7 +51,7 @@ private boolean failOnDetection; @Reference - private MountInfoProvider mountInfoProvider = MountInfoProvider.DEFAULT; + private MountInfoProvider mountInfoProvider = Mounts.defaultMountInfoProvider(); private ServiceRegistration serviceRegistration; Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/SimpleMountInfoProvider.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/SimpleMountInfoProvider.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/multiplex/SimpleMountInfoProvider.java (working copy) @@ -23,38 +23,39 @@ import java.util.List; import java.util.Map; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.jackrabbit.oak.spi.mount.Mount; import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider; +import org.apache.jackrabbit.oak.spi.mount.Mounts; import static java.util.Arrays.asList; /** - * A simple and inefficient implementation to manage mountpoints + * A simple and inefficient implementation to manage mount points */ public class SimpleMountInfoProvider implements MountInfoProvider { - private final List mountInfos; + private final Map mounts; + private final Mount defMount; private final boolean hasMounts; - public SimpleMountInfoProvider(List mountInfos){ - this.mountInfos = ImmutableList.copyOf(mountInfos); + public SimpleMountInfoProvider(List mountInfos) { this.mounts = getMounts(mountInfos); - this.hasMounts = !mountInfos.isEmpty(); + this.hasMounts = !this.mounts.isEmpty(); + this.defMount = defaultMount(this.mounts); //TODO add validation of mountpoints } @Override public Mount getMountByPath(String path) { - for (MountInfo md : mountInfos){ - if (md.isMounted(path)){ - return md.getMount(); + for (Mount m : mounts.values()){ + if (m.isMounted(path)){ + return m; } } - return Mount.DEFAULT; + return defMount; } @Override @@ -72,18 +73,22 @@ return hasMounts; } - @Override public Collection getMountsPlacedUnder(String path) { Collection mounts = Lists.newArrayList(); - for ( MountInfo mount : mountInfos ) { + for ( Mount mount : this.mounts.values()) { if ( mount.isUnder(path) ) { - mounts.add(mount.getMount()); + mounts.add(mount); } } return mounts; } + @Override + public Mount getDefaultMount() { + return defMount; + } + //~----------------------------------------< builder > public static Builder newBuilder(){ @@ -91,15 +96,15 @@ } public static final class Builder { - private final List mounts = Lists.newArrayListWithCapacity(1); + private final List mounts = Lists.newArrayListWithCapacity(1); public Builder mount(String name, String... paths) { - mounts.add(new MountInfo(new Mount(name), asList(paths))); + mounts.add(new MountInfo(name, false, false, asList(paths))); return this; } public Builder readOnlyMount(String name, String... paths) { - mounts.add(new MountInfo(new Mount(name, true), asList(paths))); + mounts.add(new MountInfo(name, true, false, asList(paths))); return this; } @@ -110,12 +115,16 @@ //~----------------------------------------< private > - private static Map getMounts(List mountInfos) { + private static Map getMounts(List mountInfos) { Map mounts = Maps.newHashMap(); - for (MountInfo mi : mountInfos){ - mounts.put(mi.getMount().getName(), mi.getMount()); + for (Mount mi : mountInfos) { + mounts.put(mi.getName(), mi); } return ImmutableMap.copyOf(mounts); } + private static Mount defaultMount(Map mounts) { + return Mounts.defaultMount(mounts.values()); + } + } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/Mount.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/Mount.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/Mount.java (working copy) @@ -19,74 +19,17 @@ package org.apache.jackrabbit.oak.spi.mount; -import static com.google.common.base.Preconditions.checkNotNull; - -public final class Mount { - /** - * Default Mount info which indicates that no explicit mount - * is created for given path - */ - public static final Mount DEFAULT = new Mount("", false, true); - - private final String name; - private final boolean readOnly; - private final boolean defaultMount; - private final String pathFragmentName; - - public Mount(String name){ - this(name, false); - } - - public Mount(String name, boolean readOnly) { - this(name, readOnly, false); - } - - private Mount(String name, boolean readOnly, boolean defaultMount){ - this.name = checkNotNull(name, "Mount name must not be null"); - this.readOnly = readOnly; - this.defaultMount = defaultMount; - this.pathFragmentName = "oak:" + name; - } - - public String getName() { - return name; - } - - public boolean isReadOnly() { - return readOnly; - } +public interface Mount { - public boolean isDefault(){ - return defaultMount; - } + String getName(); - /** - * Decorated mount name which is meant to be used for constructing path - * which should become part of given mount - */ - public String getPathFragmentName() { - return pathFragmentName; - } + boolean isReadOnly(); - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + public boolean isDefault(); - Mount mount = (Mount) o; + String getPathFragmentName(); - return name.equals(mount.name); - } + boolean isMounted(String path); - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public String toString() { - String readAttr = readOnly ? "r" : "rw"; - String displayName = defaultMount ? "default" : name; - return displayName + "(" + readAttr + ")"; - } + boolean isUnder(String path); } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/MountInfoProvider.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/MountInfoProvider.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/MountInfoProvider.java (working copy) @@ -20,36 +20,11 @@ package org.apache.jackrabbit.oak.spi.mount; import java.util.Collection; -import java.util.Collections; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; public interface MountInfoProvider { - MountInfoProvider DEFAULT = new MountInfoProvider() { - @Override - public Mount getMountByPath(String path) { - return Mount.DEFAULT; - } - - @Override - public Collection getNonDefaultMounts() { - return Collections.emptySet(); - } - - @Override - public Mount getMountByName(String name) { - return null; - } - - @Override - public boolean hasNonDefaultMounts() { - return false; - } - - public Collection getMountsPlacedUnder(String path) { - return Collections.emptySet(); - }; - }; /** * Maps a given path to logical store name. @@ -58,11 +33,13 @@ * @return mountInfo for the given path. If no explicit mount configured then * default mount would be returned */ + @Nonnull Mount getMountByPath(String path); /** * Set of non default mount points configured for the setup */ + @Nonnull Collection getNonDefaultMounts(); /** @@ -79,12 +56,19 @@ * Return true if there are explicit mounts configured */ boolean hasNonDefaultMounts(); - + /** * Returns all mounts placed under the specified path * * @param path the path under which mounts are to be found * @return a collection of mounts, possibly empty */ - Collection getMountsPlacedUnder(String path); + @Nonnull + Collection getMountsPlacedUnder(String path); + + /** + * Returns the default mount + */ + @Nonnull + Mount getDefaultMount(); } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/Mounts.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/Mounts.java (revision 0) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/Mounts.java (revision 0) @@ -0,0 +1,132 @@ +/* + * 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.jackrabbit.oak.spi.mount; + +import java.util.Collection; +import java.util.Collections; + +public final class Mounts { + + private Mounts() { + } + + static final MountInfoProvider DEFAULT_PROVIDER = new MountInfoProvider() { + @Override + public Mount getMountByPath(String path) { + return DEFAULT_MOUNT; + } + + @Override + public Collection getNonDefaultMounts() { + return Collections.emptySet(); + } + + @Override + public Mount getMountByName(String name) { + return DEFAULT_MOUNT.getName().equals(name) ? DEFAULT_MOUNT : null; + } + + @Override + public boolean hasNonDefaultMounts() { + return false; + } + + @Override + public Collection getMountsPlacedUnder(String path) { + return Collections.emptySet(); + } + + @Override + public Mount getDefaultMount() { + return DEFAULT_MOUNT; + } + }; + + /** + * Default Mount info which indicates that no explicit mount is created for + * given path + */ + private static Mount DEFAULT_MOUNT = new DefaultMount(); + + static final class DefaultMount implements Mount { + + private final Collection mounts; + + DefaultMount() { + this(Collections. emptySet()); + } + + DefaultMount(Collection mounts) { + this.mounts = mounts; + } + + @Override + public String getName() { + return ""; + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public boolean isDefault() { + return true; + } + + @Override + public String getPathFragmentName() { + return "oak:"; + } + + @Override + public boolean isMounted(String path) { + for (Mount m : mounts) { + if (m.isMounted(path)) { + return false; + } + } + return true; + } + + @Override + public boolean isUnder(String path) { + for (Mount m : mounts) { + if (m.isMounted(path)) { + return false; + } + } + return true; + } + }; + + public static MountInfoProvider defaultMountInfoProvider() { + return DEFAULT_PROVIDER; + } + + public static Mount defaultMount() { + return DEFAULT_MOUNT; + } + + public static Mount defaultMount(Collection mounts) { + return new DefaultMount(mounts); + } +} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/package-info.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/package-info.java (revision 1752297) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/mount/package-info.java (working copy) @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -@Version("1.0.0") +@Version("2.0.0") @Export(optional = "provide:=true") package org.apache.jackrabbit.oak.spi.mount; Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoProviderServiceTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoProviderServiceTest.java (revision 1752297) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoProviderServiceTest.java (working copy) @@ -22,6 +22,7 @@ import java.util.Collections; import com.google.common.collect.ImmutableMap; + import org.apache.jackrabbit.oak.spi.mount.Mount; import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider; import org.apache.sling.testing.mock.osgi.MockOsgi; @@ -29,6 +30,7 @@ import org.junit.Rule; import org.junit.Test; +import static org.apache.jackrabbit.oak.spi.mount.Mounts.defaultMountInfoProvider; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -47,7 +49,7 @@ MountInfoProvider provider = context.getService(MountInfoProvider.class); assertNotNull(provider); - assertEquals(MountInfoProvider.DEFAULT, provider); + assertEquals(defaultMountInfoProvider(), provider); MockOsgi.deactivate(service); assertNull(context.getService(MountInfoProvider.class)); @@ -63,9 +65,11 @@ Mount m = provider.getMountByName(MountInfoProviderService.PROP_MOUNT_NAME_DEFAULT); assertNotNull(m); + Mount defMount = provider.getDefaultMount(); + assertNotNull(defMount); assertFalse(m.isReadOnly()); assertEquals(m, provider.getMountByPath("/a")); - assertEquals(Mount.DEFAULT, provider.getMountByPath("/x")); + assertEquals(defMount, provider.getMountByPath("/x")); } @Test @@ -82,10 +86,12 @@ Mount m = provider.getMountByName(MountInfoProviderService.PROP_MOUNT_NAME_DEFAULT); assertNull(m); + Mount defMount = provider.getDefaultMount(); + assertNotNull(defMount); m = provider.getMountByName("foo"); assertEquals(m, provider.getMountByPath("/a")); - assertEquals(Mount.DEFAULT, provider.getMountByPath("/x")); + assertEquals(defMount, provider.getMountByPath("/x")); assertTrue(m.isReadOnly()); } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoTest.java (revision 1752297) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/MountInfoTest.java (working copy) @@ -19,17 +19,17 @@ package org.apache.jackrabbit.oak.plugins.multiplex; -import org.apache.jackrabbit.oak.spi.mount.Mount; -import org.junit.Test; - import static com.google.common.collect.ImmutableList.of; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; public class MountInfoTest { @Test public void mountNameInPath() throws Exception{ - MountInfo md = new MountInfo(new Mount("foo"), of("/a", "/b")); + MountInfo md = new MountInfo("foo", false, false, of("/a", "/b")); assertTrue(md.isMounted("/a")); assertTrue(md.isMounted("/b")); assertTrue(md.isMounted("/b/c/d")); Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/PrivateStoreValidatorProviderTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/PrivateStoreValidatorProviderTest.java (revision 1752297) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/PrivateStoreValidatorProviderTest.java (working copy) @@ -29,6 +29,7 @@ import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent; import org.apache.jackrabbit.oak.spi.commit.EditorProvider; import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider; +import org.apache.jackrabbit.oak.spi.mount.Mounts; import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider; import org.apache.sling.testing.mock.osgi.MockOsgi; import org.apache.sling.testing.mock.osgi.junit.OsgiContext; @@ -186,7 +187,7 @@ } private MountInfoProvider createMountInfoProvider(String... readOnlyPaths) { - MountInfoProvider mountInfoProvider = MountInfoProvider.DEFAULT; + MountInfoProvider mountInfoProvider = Mounts.defaultMountInfoProvider(); if (readOnlyPaths.length > 0) { mountInfoProvider = SimpleMountInfoProvider.newBuilder().readOnlyMount("readOnly", readOnlyPaths).build(); } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/SimpleMountInfoProviderTest.java =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/SimpleMountInfoProviderTest.java (revision 1752297) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/multiplex/SimpleMountInfoProviderTest.java (working copy) @@ -35,7 +35,7 @@ public class SimpleMountInfoProviderTest { @Test public void defaultMount() throws Exception { - MountInfoProvider mip = new SimpleMountInfoProvider(Collections.emptyList()); + MountInfoProvider mip = new SimpleMountInfoProvider(Collections.emptyList()); assertNotNull(mip.getMountByPath("/a")); assertTrue(mip.getMountByPath("/a").isDefault()); @@ -65,7 +65,7 @@ Collection mounts = mip.getNonDefaultMounts(); assertEquals(2, mounts.size()); - assertFalse(mounts.contains(Mount.DEFAULT)); + assertFalse(mounts.contains(mip.getDefaultMount())); assertNotNull(mip.getMountByName("foo")); assertNotNull(mip.getMountByName("bar"));