ch.cyberduck.core.cf.CFSession.java Source code

Java tutorial

Introduction

Here is the source code for ch.cyberduck.core.cf.CFSession.java

Source

package ch.cyberduck.core.cf;

/*
 * Copyright (c) 2002-2010 David Kocher. All rights reserved.
 *
 * http://cyberduck.ch/
 *
 * 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.
 *
 * Bug fixes, suggestions and comments should be sent to:
 * dkocher@cyberduck.ch
 */

import ch.cyberduck.core.ConnectionCanceledException;
import ch.cyberduck.core.Credentials;
import ch.cyberduck.core.Host;
import ch.cyberduck.core.LoginController;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.Preferences;
import ch.cyberduck.core.Protocol;
import ch.cyberduck.core.cdn.Distribution;
import ch.cyberduck.core.cdn.DistributionConfiguration;
import ch.cyberduck.core.cloud.CloudSession;
import ch.cyberduck.core.i18n.Locale;
import ch.cyberduck.core.identity.DefaultCredentialsIdentityConfiguration;
import ch.cyberduck.core.identity.IdentityConfiguration;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpException;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.rackspacecloud.client.cloudfiles.FilesCDNContainer;
import com.rackspacecloud.client.cloudfiles.FilesClient;
import com.rackspacecloud.client.cloudfiles.FilesContainerMetaData;
import com.rackspacecloud.client.cloudfiles.FilesException;

/**
 * Rackspace Cloud Files Implementation
 *
 * @version $Id: CFSession.java 10823 2013-04-08 17:31:39Z dkocher $
 */
public class CFSession extends CloudSession implements DistributionConfiguration {
    private static final Logger log = Logger.getLogger(CFSession.class);

    private FilesClient client;

    public CFSession(Host h) {
        super(h);
    }

    @Override
    protected FilesClient getClient() throws ConnectionCanceledException {
        if (null == client) {
            throw new ConnectionCanceledException();
        }
        return client;
    }

    @Override
    protected void connect() throws IOException {
        if (this.isConnected()) {
            return;
        }
        this.client = new FilesClient(this.http(), null, null, null, null, this.timeout());
        this.fireConnectionWillOpenEvent();

        // Configure for authentication URL
        this.configure();

        // Prompt the login credentials first
        this.login();

        this.fireConnectionDidOpenEvent();
    }

    /**
     * Set connection properties
     *
     * @throws java.io.IOException If the connection is already canceled
     */
    protected void configure() throws IOException {
        final FilesClient c = this.getClient();
        c.setConnectionTimeOut(this.timeout());
        c.setUserAgent(this.getUserAgent());
        // Do not calculate ETag in advance
        c.setUseETag(false);
        c.setAuthenticationURL(this.getAuthenticationUrl());
    }

    private String getAuthenticationUrl() {
        final StringBuilder authentication = new StringBuilder();
        authentication.append(host.getProtocol().getScheme().toString()).append("://");
        if (host.getHostname().equals("storage.clouddrive.com")) {
            // Legacy bookmarks. Use default authentication server for Rackspace.
            authentication.append("auth.api.rackspacecloud.com");
        } else {
            // Use custom authentication server. Swift (OpenStack Object Storage) installation.
            authentication.append(host.getHostname());
        }
        authentication.append(":").append(host.getPort());
        if (StringUtils.isBlank(host.getProtocol().getContext())) {
            authentication.append(Path.normalize(Preferences.instance().getProperty("cf.authentication.context")));
        } else {
            authentication.append(Path.normalize(host.getProtocol().getContext()));
        }
        if (log.isInfoEnabled()) {
            log.info(String.format("Using authentication URL %s", authentication.toString()));
        }
        return authentication.toString();
    }

    @Override
    protected void login(final LoginController controller, final Credentials credentials) throws IOException {
        final FilesClient client = this.getClient();
        client.setUserName(credentials.getUsername());
        client.setPassword(credentials.getPassword());
        try {
            if (!client.login()) {
                this.message(Locale.localizedString("Login failed", "Credentials"));
                controller.fail(host.getProtocol(), credentials);
                this.login();
            }
        } catch (HttpException e) {
            IOException failure = new IOException(e.getMessage());
            failure.initCause(e);
            throw failure;
        }
    }

    @Override
    public void close() {
        try {
            if (this.isConnected()) {
                this.fireConnectionWillCloseEvent();
            }
        } finally {
            // No logout required
            client = null;
            this.fireConnectionDidCloseEvent();
        }
    }

    /**
     * @return No Content-Range support
     */
    @Override
    public boolean isUploadResumable() {
        return false;
    }

    @Override
    public boolean isRenameSupported(final Path file) {
        return !file.attributes().isVolume();
    }

    /**
     * Creating files is only possible inside a bucket.
     *
     * @param workdir The workdir to create query
     * @return False if directory is root.
     */
    @Override
    public boolean isCreateFileSupported(final Path workdir) {
        return !workdir.isRoot();
    }

    @Override
    public boolean isChecksumSupported() {
        return true;
    }

    @Override
    public boolean isCDNSupported() {
        try {
            return StringUtils.isNotBlank(this.getClient().getCdnManagementURL());
        } catch (ConnectionCanceledException e) {
            return false;
        }
    }

    @Override
    public DistributionConfiguration cdn() {
        return this;
    }

    /**
     * Cache distribution status result.
     */
    private Map<String, Distribution> distributionStatus = new HashMap<String, Distribution>();

    @Override
    public boolean isCached(Distribution.Method method) {
        return !distributionStatus.isEmpty();
    }

    @Override
    public String getOrigin(Distribution.Method method, String container) {
        return container;
    }

    @Override
    public void write(final boolean enabled, final String origin, final Distribution.Method method,
            final String[] cnames, final boolean logging, final String loggingBucket,
            final String defaultRootObject) {
        try {
            this.check();
            if (enabled) {
                this.message(
                        MessageFormat.format(Locale.localizedString("Enable {0} Distribution", "Status"), "CDN"));
            } else {
                this.message(
                        MessageFormat.format(Locale.localizedString("Disable {0} Distribution", "Status"), "CDN"));
            }
            if (StringUtils.isNotBlank(defaultRootObject)) {
                this.getClient().updateContainerMetadata(origin,
                        Collections.singletonMap("Web-Index", defaultRootObject));
            }
            try {
                this.getClient().getCDNContainerInfo(origin);
            } catch (FilesException e) {
                if (404 == e.getHttpStatusCode()) {
                    // Not found.
                    this.getClient().cdnEnableContainer(origin);
                }
            }
            // Toggle content distribution for the container without changing the TTL expiration
            this.getClient().cdnUpdateContainer(origin, -1, enabled, logging);
        } catch (IOException e) {
            this.error("Cannot write CDN configuration", e);
        } catch (HttpException e) {
            this.error("Cannot write CDN configuration", e);
        } finally {
            distributionStatus.clear();
        }
    }

    @Override
    public Distribution read(final String origin, final Distribution.Method method) {
        if (!distributionStatus.containsKey(origin)) {
            try {
                this.check();
                this.message(MessageFormat
                        .format(Locale.localizedString("Reading CDN configuration of {0}", "Status"), origin));

                final FilesCDNContainer info = this.getClient().getCDNContainerInfo(origin);
                final Distribution distribution = new Distribution(info.getName(),
                        new URI(this.getClient().getStorageURL()).getHost(), method, info.isEnabled(),
                        info.getCdnURL(), info.getSSLURL(), info.getStreamingURL(),
                        info.isEnabled() ? Locale.localizedString("CDN Enabled", "Mosso")
                                : Locale.localizedString("CDN Disabled", "Mosso"),
                        info.getRetainLogs()) {
                    @Override
                    public String getLoggingTarget() {
                        return ".CDN_ACCESS_LOGS";
                    }
                };
                final FilesContainerMetaData metadata = this.getClient().getContainerMetaData(origin);
                if (metadata.getMetaData().containsKey("Web-Index")) {
                    distribution.setDefaultRootObject(metadata.getMetaData().get("Web-Index"));
                }
                distribution.setContainers(Collections.singletonList(".CDN_ACCESS_LOGS"));
                distributionStatus.put(origin, distribution);
            } catch (HttpException e) {
                log.warn(e.getMessage());
                // Not found.
                distributionStatus.put(origin, new Distribution(null, origin, method, false, null,
                        Locale.localizedString("CDN Disabled", "Mosso")));
            } catch (IOException e) {
                this.error("Cannot read CDN configuration", e);
            } catch (URISyntaxException e) {
                this.error("Cannot read CDN configuration", e);
            }
        }
        if (distributionStatus.containsKey(origin)) {
            return distributionStatus.get(origin);
        }
        return new Distribution(origin, method);
    }

    @Override
    public void invalidate(final String origin, final Distribution.Method method, final List<Path> files,
            final boolean recursive) {
        try {
            this.check();
            this.message(MessageFormat.format(Locale.localizedString("Writing CDN configuration of {0}", "Status"),
                    origin));
            for (Path file : files) {
                if (file.isContainer()) {
                    this.getClient().purgeCDNContainer(origin, null);
                } else {
                    this.getClient().purgeCDNObject(origin, file.getKey(), null);
                }
            }
        } catch (IOException e) {
            this.error("Cannot write CDN configuration", e);
        } catch (HttpException e) {
            this.error("Cannot write CDN configuration", e);
        } finally {
            distributionStatus.clear();
        }
    }

    @Override
    public boolean isInvalidationSupported(final Distribution.Method method) {
        return true;
    }

    @Override
    public boolean isDefaultRootSupported(final Distribution.Method method) {
        return true;
    }

    @Override
    public boolean isLoggingSupported(final Distribution.Method method) {
        return method.equals(Distribution.DOWNLOAD);
    }

    @Override
    public boolean isAnalyticsSupported(final Distribution.Method method) {
        return this.isLoggingSupported(method);
    }

    @Override
    public boolean isCnameSupported(final Distribution.Method method) {
        return false;
    }

    @Override
    public Protocol getProtocol() {
        return getHost().getProtocol();
    }

    @Override
    public List<Distribution.Method> getMethods(final String container) {
        if (!this.isCDNSupported()) {
            return Collections.emptyList();
        }
        return Arrays.asList(Distribution.DOWNLOAD);
    }

    public String getName() {
        return Locale.localizedString("Akamai", "Mosso");
    }

    @Override
    public String getName(final Distribution.Method method) {
        return this.getName();
    }

    @Override
    public void clear() {
        distributionStatus.clear();
    }

    @Override
    public IdentityConfiguration iam() {
        return new DefaultCredentialsIdentityConfiguration(host);
    }
}