com.xebialabs.overthere.cifs.PathMapper.java Source code

Java tutorial

Introduction

Here is the source code for com.xebialabs.overthere.cifs.PathMapper.java

Source

/*
 * Copyright (c) 2008-2014, XebiaLabs B.V., All rights reserved.
 *
 *
 * Overthere is licensed under the terms of the GPLv2
 * <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most XebiaLabs Libraries.
 * There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
 * this software, see the FLOSS License Exception
 * <http://github.com/xebialabs/overthere/blob/master/LICENSE>.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation; version 2
 * of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
 * Floor, Boston, MA 02110-1301  USA
 */
package com.xebialabs.overthere.cifs;

import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.regex.Pattern;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables;

import static java.lang.String.format;
import static java.util.regex.Pattern.quote;

class PathMapper {
    private static final String DRIVE_DESIGNATOR = ":";
    private static final String ADMIN_SHARE_DESIGNATOR = "$";
    private static final Pattern ADMIN_SHARE_PATTERN = Pattern.compile("[a-zA-Z]" + quote(ADMIN_SHARE_DESIGNATOR));

    private final SortedMap<String, String> sharesForPaths;
    private final Map<String, String> pathsForShares;

    @VisibleForTesting
    PathMapper(final Map<String, String> mappings) {
        // longest first, so reverse lexicographical order
        ImmutableSortedMap.Builder<String, String> sharesForPath = ImmutableSortedMap.reverseOrder();
        ImmutableMap.Builder<String, String> pathsForShare = ImmutableMap.builder();
        for (Entry<String, String> mapping : mappings.entrySet()) {
            String pathPrefixToMatch = mapping.getKey();
            String shareForPathPrefix = mapping.getValue();
            sharesForPath.put(pathPrefixToMatch.toLowerCase(), shareForPathPrefix);
            pathsForShare.put(shareForPathPrefix.toLowerCase(), pathPrefixToMatch);
        }
        this.sharesForPaths = sharesForPath.build();
        this.pathsForShares = pathsForShare.build();
    }

    /**
     * Attempts to use provided path-to-share mappings to convert the given local path to a remotely accessible path,
     * using the longest matching prefix if available.
     * <p/>
     * Falls back to using administrative shares if none of the explicit mappings applies to the path to convert.
     *
     * @param path the local path to convert
     * @return the remotely accessible path (using shares) at which the local path can be accessed using SMB
     */
    @VisibleForTesting
    String toSharedPath(String path) {
        final String lowerCasePath = path.toLowerCase();
        // assumes correct format drive: or drive:\path
        String mappedPathPrefix = Iterables.find(sharesForPaths.keySet(), new Predicate<String>() {
            @Override
            public boolean apply(String input) {
                return lowerCasePath.startsWith(input);
            }
        }, null);
        // the share + the remainder of the path if found, otherwise the path with ':' replaced by '$'
        return ((mappedPathPrefix != null)
                ? sharesForPaths.get(mappedPathPrefix) + path.substring(mappedPathPrefix.length())
                : path.substring(0, 1) + ADMIN_SHARE_DESIGNATOR + path.substring(2));
    }

    /**
     * @param path the remotely accessible path to convert (minus the host name, i.e. beginning with the share)
     * @return the local path (using drive letters) corresponding to the path that is remotely accessible using SMB
     */
    @VisibleForTesting
    String toLocalPath(String path) {
        final String lowerCasePath = path.toLowerCase();
        // assumes correct format share or share\path
        String mappedShare = Iterables.find(pathsForShares.keySet(), new Predicate<String>() {
            @Override
            public boolean apply(String input) {
                return lowerCasePath.startsWith(input);
            }
        }, null);
        if (mappedShare != null) {
            return pathsForShares.get(mappedShare) + path.substring(mappedShare.length());
        } else if ((path.length() >= 2) && ADMIN_SHARE_PATTERN.matcher(path.substring(0, 2)).matches()) {
            return path.substring(0, 1) + DRIVE_DESIGNATOR + path.substring(2);
        } else {
            throw new IllegalArgumentException(
                    format("Remote path name '%s' uses unrecognized (i.e. neither mapped nor administrative) share",
                            path));
        }
    }
}