ch.cyberduck.core.ProtocolFactory.java Source code

Java tutorial

Introduction

Here is the source code for ch.cyberduck.core.ProtocolFactory.java

Source

package ch.cyberduck.core;

/*
 * Copyright (c) 2002-2017 iterate GmbH. All rights reserved.
 * https://cyberduck.io/
 *
 * 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 */

import ch.cyberduck.core.exception.AccessDeniedException;
import ch.cyberduck.core.preferences.PreferencesFactory;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public final class ProtocolFactory {
    private static final Logger log = Logger.getLogger(ProtocolFactory.class);

    private static final ProtocolFactory global = new ProtocolFactory();

    public static ProtocolFactory get() {
        return global;
    }

    private final Set<Protocol> registered;
    private final Local bundle;

    public ProtocolFactory() {
        this(new LinkedHashSet<Protocol>());
    }

    public ProtocolFactory(final Set<Protocol> protocols) {
        this(LocalFactory.get(PreferencesFactory.get().getProperty("application.profiles.path")), protocols);
    }

    public ProtocolFactory(final Local bundle, final Set<Protocol> protocols) {
        this.bundle = bundle;
        this.registered = protocols;
    }

    public void register(Protocol... protocols) {
        // Order determines list in connection dropdown
        for (Protocol protocol : protocols) {
            register(protocol);
        }
        if (bundle.exists()) {
            try {
                for (Local f : bundle.list().filter(new ProfileFilter())) {
                    final Profile profile = ProfileReaderFactory.get().read(f);
                    if (null == profile) {
                        continue;
                    }
                    if (log.isInfoEnabled()) {
                        log.info(String.format("Adding bundled protocol %s", profile));
                    }
                    // Replace previous possibly disable protocol in Preferences
                    registered.add(profile);
                }
            } catch (AccessDeniedException e) {
                log.warn(String.format("Failure reading collection %s %s", bundle, e.getMessage()));
            }
        }
        // Load thirdparty protocols
        final Local library = LocalFactory.get(PreferencesFactory.get().getProperty("application.support.path"),
                PreferencesFactory.get().getProperty("profiles.folder.name"));
        if (library.exists()) {
            try {
                for (Local profile : library.list().filter(new ProfileFilter())) {
                    final Profile protocol = ProfileReaderFactory.get().read(profile);
                    if (null == protocol) {
                        continue;
                    }
                    if (log.isInfoEnabled()) {
                        log.info(String.format("Adding thirdparty protocol %s", protocol));
                    }
                    // Replace previous possibly disable protocol in Preferences
                    registered.add(protocol);
                }
            } catch (AccessDeniedException e) {
                log.warn(String.format("Failure reading collection %s %s", library, e.getMessage()));
            }
        }
    }

    public void register(final Protocol protocol) {
        if (null == protocol) {
            log.error("Attempt to register unknown protocol");
            return;
        }
        registered.add(protocol);
    }

    /**
     * @return List of enabled protocols
     */
    public List<Protocol> find() {
        return this.find(Protocol::isEnabled);
    }

    /**
     * @param search Search filter for all registered protocols
     * @return List of registered protocols matching search criteria.
     */
    public List<Protocol> find(final Predicate<Protocol> search) {
        return registered.stream().filter(search).sorted().collect(Collectors.toList());
    }

    /**
     * @param identifier Provider name or hash code of protocol
     * @return Matching protocol or null if no match
     */
    public Protocol forName(final String identifier) {
        final List<Protocol> enabled = this.find();
        return enabled.stream().filter(protocol -> String.valueOf(protocol.hashCode()).equals(identifier))
                .findFirst().orElse(this.forName(enabled, identifier, null));
    }

    public Protocol forName(final String identifier, final String provider) {
        final List<Protocol> enabled = this.find();
        return this.forName(enabled, identifier, provider);
    }

    public Protocol forName(final List<Protocol> enabled, final String identifier, final String provider) {
        final Protocol match = enabled.stream().filter(protocol -> {
            if (StringUtils.equals(protocol.getIdentifier(), identifier)) {
                if (null == provider) {
                    // Matching protocol with no custom provider
                    return true;
                } else {
                    return StringUtils.equals(protocol.getProvider(), provider);
                }
            }
            // Fallback for bug in 6.1
            if (StringUtils.equals(String.format("%s-%s", protocol.getIdentifier(), protocol.getProvider()),
                    identifier)) {
                return true;
            }
            return false;
        }).findFirst().orElse(enabled.stream()
                .filter(protocol -> StringUtils.equals(protocol.getIdentifier(), identifier)).findFirst()
                .orElse(enabled.stream().filter(protocol -> StringUtils.equals(protocol.getProvider(), identifier))
                        .findFirst()
                        .orElse(enabled.stream()
                                .filter(protocol -> StringUtils.equals(protocol.getType().name(), identifier))
                                .findFirst().orElse(this.forScheme(enabled, identifier)))));
        if (null == match) {
            if (enabled.isEmpty()) {
                log.error(String.format("List of registered protocols in %s is empty", this));
            }
            log.error(String.format("Missing registered protocol for identifier %s", identifier));
        }
        return match;
    }

    public Protocol forType(final Protocol.Type type) {
        final List<Protocol> enabled = this.find();
        return this.forType(enabled, type);
    }

    private Protocol forType(final List<Protocol> enabled, final Protocol.Type type) {
        return enabled.stream().filter(protocol -> protocol.getType().equals(type)).findFirst().orElse(null);
    }

    /**
     * @param scheme Protocol scheme
     * @return Standard protocol for this scheme. This is ambiguous
     */
    public Protocol forScheme(final List<Protocol> enabled, final String scheme) {
        try {
            return this.forScheme(Scheme.valueOf(scheme));
        } catch (IllegalArgumentException e) {
            log.warn(String.format("Unknown scheme %s", scheme));
            return null;
        }
    }

    public Protocol forScheme(final Scheme scheme) {
        final List<Protocol> enabled = this.find();
        return this.forScheme(enabled, scheme);
    }

    private Protocol forScheme(final List<Protocol> enabled, final Scheme scheme) {
        final Scheme filter;
        switch (scheme) {
        case http:
            filter = Scheme.dav;
            break;
        case https:
            filter = Scheme.davs;
            break;
        default:
            filter = scheme;
            break;
        }
        return enabled.stream().filter(protocol -> Arrays.asList(protocol.getSchemes()).contains(filter))
                .findFirst()
                .orElse(enabled.stream().filter(protocol -> Arrays.asList(protocol.getSchemes()).contains(scheme))
                        .findFirst().orElse(null));
    }

    private static final class ProfileFilter implements Filter<Local> {
        @Override
        public boolean accept(final Local file) {
            return "cyberduckprofile".equals(FilenameUtils.getExtension(file.getName()));
        }

        @Override
        public Pattern toPattern() {
            return Pattern.compile(".*\\.cyberduckprofile");
        }
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("ProtocolFactory{");
        sb.append("registered=").append(registered);
        sb.append(", bundle=").append(bundle);
        sb.append('}');
        return sb.toString();
    }
}