Merge pull request #64 in ITERATE/cyberduck from feature/windows/9074 to master
[cyberduck.git] / source / ch / cyberduck / core / openstack / SwiftSession.java
blob9956760bf726d51bc481c3bcca7966f9291c6b72
1 package ch.cyberduck.core.openstack;
3 /*
4 * Copyright (c) 2013 David Kocher. All rights reserved.
5 * http://cyberduck.ch/
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to:
18 * feedback@cyberduck.ch
21 import ch.cyberduck.core.AttributedList;
22 import ch.cyberduck.core.Cache;
23 import ch.cyberduck.core.DefaultIOExceptionMappingService;
24 import ch.cyberduck.core.Host;
25 import ch.cyberduck.core.HostKeyCallback;
26 import ch.cyberduck.core.HostPasswordStore;
27 import ch.cyberduck.core.ListProgressListener;
28 import ch.cyberduck.core.LoginCallback;
29 import ch.cyberduck.core.Path;
30 import ch.cyberduck.core.UrlProvider;
31 import ch.cyberduck.core.analytics.AnalyticsProvider;
32 import ch.cyberduck.core.analytics.QloudstatAnalyticsProvider;
33 import ch.cyberduck.core.cdn.DistributionConfiguration;
34 import ch.cyberduck.core.exception.AccessDeniedException;
35 import ch.cyberduck.core.exception.BackgroundException;
36 import ch.cyberduck.core.exception.InteroperabilityException;
37 import ch.cyberduck.core.exception.LoginFailureException;
38 import ch.cyberduck.core.features.Attributes;
39 import ch.cyberduck.core.features.Copy;
40 import ch.cyberduck.core.features.Delete;
41 import ch.cyberduck.core.features.Directory;
42 import ch.cyberduck.core.features.Headers;
43 import ch.cyberduck.core.features.Home;
44 import ch.cyberduck.core.features.Location;
45 import ch.cyberduck.core.features.Move;
46 import ch.cyberduck.core.features.Read;
47 import ch.cyberduck.core.features.Touch;
48 import ch.cyberduck.core.features.Upload;
49 import ch.cyberduck.core.features.Write;
50 import ch.cyberduck.core.http.HttpSession;
51 import ch.cyberduck.core.preferences.PreferencesFactory;
52 import ch.cyberduck.core.proxy.ProxyFinder;
53 import ch.cyberduck.core.ssl.DefaultX509KeyManager;
54 import ch.cyberduck.core.ssl.DisabledX509TrustManager;
55 import ch.cyberduck.core.ssl.X509KeyManager;
56 import ch.cyberduck.core.ssl.X509TrustManager;
57 import ch.cyberduck.core.threading.CancelCallback;
58 import ch.cyberduck.core.threading.ThreadPool;
60 import org.apache.http.impl.client.HttpClientBuilder;
61 import org.apache.log4j.Logger;
63 import javax.net.SocketFactory;
64 import java.io.IOException;
65 import java.util.HashMap;
66 import java.util.Iterator;
67 import java.util.Map;
68 import java.util.Set;
70 import ch.iterate.openstack.swift.Client;
71 import ch.iterate.openstack.swift.exception.GenericException;
72 import ch.iterate.openstack.swift.method.AuthenticationRequest;
73 import ch.iterate.openstack.swift.model.AccountInfo;
74 import ch.iterate.openstack.swift.model.Region;
76 /**
77 * @version $Id$
79 public class SwiftSession extends HttpSession<Client> {
80 private static final Logger log = Logger.getLogger(SwiftSession.class);
82 private final SwiftRegionService regionService
83 = new SwiftRegionService(this);
85 private SwiftDistributionConfiguration cdn
86 = new SwiftDistributionConfiguration(this, regionService);
88 protected Map<Region, AccountInfo> accounts
89 = new HashMap<Region, AccountInfo>();
91 public SwiftSession(final Host h) {
92 super(h, new DisabledX509TrustManager(), new DefaultX509KeyManager());
95 public SwiftSession(final Host host, final X509TrustManager trust, final X509KeyManager key) {
96 super(host, trust, key);
99 public SwiftSession(final Host host, final X509TrustManager trust, final X509KeyManager key, final ProxyFinder proxy) {
100 super(host, trust, key, proxy);
103 public SwiftSession(final Host host, final X509TrustManager trust, final X509KeyManager key, final SocketFactory socketFactory) {
104 super(host, trust, key, socketFactory);
107 @Override
108 public Client connect(final HostKeyCallback key) throws BackgroundException {
109 // Always inject new pool to builder on connect because the pool is shutdown on disconnect
110 final HttpClientBuilder pool = builder.build(this);
111 pool.disableContentCompression();
112 return new Client(pool.build());
115 @Override
116 protected void logout() throws BackgroundException {
117 try {
118 client.disconnect();
120 catch(IOException e) {
121 throw new DefaultIOExceptionMappingService().map(e);
125 @Override
126 public void login(final HostPasswordStore keychain, final LoginCallback prompt, final CancelCallback cancel,
127 final Cache<Path> cache) throws BackgroundException {
128 try {
129 final Set<? extends AuthenticationRequest> options = new SwiftAuthenticationService().getRequest(host, prompt);
130 for(Iterator<? extends AuthenticationRequest> iter = options.iterator(); iter.hasNext(); ) {
131 try {
132 final AuthenticationRequest auth = iter.next();
133 if(log.isInfoEnabled()) {
134 log.info(String.format("Attempt authentication with %s", auth));
136 client.authenticate(auth);
137 break;
139 catch(GenericException failure) {
140 final BackgroundException reason = new SwiftExceptionMappingService().map(failure);
141 if(reason instanceof LoginFailureException
142 || reason instanceof AccessDeniedException
143 || reason instanceof InteroperabilityException) {
144 if(!iter.hasNext()) {
145 throw failure;
148 else {
149 throw failure;
152 cancel.verify();
154 if(PreferencesFactory.get().getBoolean("openstack.account.preload")) {
155 final ThreadPool pool = new ThreadPool("accounts");
156 try {
157 pool.execute(new Runnable() {
158 @Override
159 public void run() {
160 for(Region region : client.getRegions()) {
161 try {
162 final AccountInfo info = client.getAccountInfo(region);
163 if(log.isInfoEnabled()) {
164 log.info(String.format("Signing key is %s", info.getTempUrlKey()));
166 accounts.put(region, info);
168 catch(IOException e) {
169 log.warn(String.format("Failure loading account info for region %s", region));
175 finally {
176 // Shutdown gracefully
177 pool.shutdown();
181 catch(GenericException e) {
182 throw new SwiftExceptionMappingService().map(e);
184 catch(IOException e) {
185 throw new DefaultIOExceptionMappingService().map(e);
189 @Override
190 public AttributedList<Path> list(final Path directory, final ListProgressListener listener) throws BackgroundException {
191 if(directory.isRoot()) {
192 return new AttributedList<Path>(new SwiftContainerListService(this,
193 new SwiftLocationFeature.SwiftRegion(host.getRegion())).list(listener));
195 else {
196 return new SwiftObjectListService(this, regionService).list(directory, listener);
200 @Override
201 public <T> T getFeature(final Class<T> type) {
202 if(type == Read.class) {
203 return (T) new SwiftReadFeature(this, regionService);
205 if(type == Write.class) {
206 return (T) new SwiftWriteFeature(this, regionService);
208 if(type == Upload.class) {
209 return (T) new SwiftThresholdUploadService(this, regionService);
211 if(type == Directory.class) {
212 return (T) new SwiftDirectoryFeature(this, regionService);
214 if(type == Delete.class) {
215 return (T) new SwiftMultipleDeleteFeature(this, new SwiftSegmentService(this, regionService), regionService);
217 if(type == Headers.class) {
218 return (T) new SwiftMetadataFeature(this, regionService);
220 if(type == Copy.class) {
221 return (T) new SwiftCopyFeature(this, regionService);
223 if(type == Move.class) {
224 return (T) new SwiftMoveFeature(this, regionService);
226 if(type == Touch.class) {
227 return (T) new SwiftTouchFeature(this, regionService);
229 if(type == Location.class) {
230 return (T) new SwiftLocationFeature(this);
232 if(type == AnalyticsProvider.class) {
233 return (T) new QloudstatAnalyticsProvider();
235 if(type == DistributionConfiguration.class) {
236 for(Region region : accounts.keySet()) {
237 if(null == region.getCDNManagementUrl()) {
238 log.warn(String.format("Missing CDN Management URL for region %s", region.getRegionId()));
239 return null;
242 return (T) cdn;
244 if(type == UrlProvider.class) {
245 if(host.getHostname().endsWith("identity.hpcloudsvc.com")) {
246 return (T) new SwiftHpUrlProvider(this);
248 return (T) new SwiftUrlProvider(this, accounts);
250 if(type == Attributes.class) {
251 return (T) new SwiftAttributesFeature(this, regionService);
253 if(type == Home.class) {
254 return (T) new SwiftHomeFinderService(this);
256 return super.getFeature(type);