View Javadoc

1   /**
2    *
3    * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4    *
5    * ====================================================================
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   * ====================================================================
18   */
19  package org.jclouds.vcloud.config;
20  
21  import static com.google.common.base.Preconditions.checkNotNull;
22  import static com.google.common.base.Preconditions.checkState;
23  import static com.google.common.collect.Iterables.concat;
24  import static com.google.common.collect.Iterables.find;
25  import static com.google.common.collect.Iterables.get;
26  import static com.google.common.collect.Iterables.getLast;
27  import static com.google.common.collect.Iterables.transform;
28  import static com.google.common.collect.Maps.newLinkedHashMap;
29  import static com.google.common.collect.Maps.transformValues;
30  import static com.google.common.collect.Maps.uniqueIndex;
31  import static org.jclouds.Constants.PROPERTY_API_VERSION;
32  import static org.jclouds.Constants.PROPERTY_IDENTITY;
33  import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
34  import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_NETWORK;
35  import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED;
36  
37  import java.net.URI;
38  import java.util.Map;
39  import java.util.NoSuchElementException;
40  import java.util.SortedMap;
41  import java.util.Map.Entry;
42  import java.util.concurrent.ExecutionException;
43  import java.util.concurrent.TimeUnit;
44  import java.util.concurrent.TimeoutException;
45  import java.util.concurrent.atomic.AtomicReference;
46  
47  import javax.annotation.Resource;
48  import javax.inject.Inject;
49  import javax.inject.Named;
50  import javax.inject.Singleton;
51  
52  import org.jclouds.domain.Location;
53  import org.jclouds.http.HttpErrorHandler;
54  import org.jclouds.http.RequiresHttp;
55  import org.jclouds.http.annotation.ClientError;
56  import org.jclouds.http.annotation.Redirection;
57  import org.jclouds.http.annotation.ServerError;
58  import org.jclouds.logging.Logger;
59  import org.jclouds.predicates.RetryablePredicate;
60  import org.jclouds.rest.AsyncClientFactory;
61  import org.jclouds.rest.AuthorizationException;
62  import org.jclouds.rest.ConfiguresRestClient;
63  import org.jclouds.rest.config.RestClientModule;
64  import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
65  import org.jclouds.vcloud.CommonVCloudAsyncClient;
66  import org.jclouds.vcloud.CommonVCloudClient;
67  import org.jclouds.vcloud.VCloudToken;
68  import org.jclouds.vcloud.VCloudVersionsAsyncClient;
69  import org.jclouds.vcloud.compute.functions.FindLocationForResource;
70  import org.jclouds.vcloud.domain.Catalog;
71  import org.jclouds.vcloud.domain.CatalogItem;
72  import org.jclouds.vcloud.domain.Org;
73  import org.jclouds.vcloud.domain.ReferenceType;
74  import org.jclouds.vcloud.domain.VCloudSession;
75  import org.jclouds.vcloud.domain.VDC;
76  import org.jclouds.vcloud.endpoints.Network;
77  import org.jclouds.vcloud.endpoints.OrgList;
78  import org.jclouds.vcloud.endpoints.TasksList;
79  import org.jclouds.vcloud.functions.AllCatalogItemsInCatalog;
80  import org.jclouds.vcloud.functions.AllCatalogItemsInOrg;
81  import org.jclouds.vcloud.functions.AllCatalogsInOrg;
82  import org.jclouds.vcloud.functions.AllVDCsInOrg;
83  import org.jclouds.vcloud.functions.OrgsForLocations;
84  import org.jclouds.vcloud.functions.OrgsForNames;
85  import org.jclouds.vcloud.handlers.ParseVCloudErrorFromHttpResponse;
86  import org.jclouds.vcloud.predicates.TaskSuccess;
87  
88  import com.google.common.base.Function;
89  import com.google.common.base.Predicate;
90  import com.google.common.base.Predicates;
91  import com.google.common.base.Supplier;
92  import com.google.common.collect.Iterables;
93  import com.google.inject.ConfigurationException;
94  import com.google.inject.Injector;
95  import com.google.inject.Key;
96  import com.google.inject.Provides;
97  import com.google.inject.TypeLiteral;
98  import com.google.inject.name.Names;
99  
100 /**
101  * Configures the VCloud authentication service connection, including logging and http transport.
102  * 
103  * @author Adrian Cole
104  */
105 @RequiresHttp
106 @ConfiguresRestClient
107 public class CommonVCloudRestClientModule<S extends CommonVCloudClient, A extends CommonVCloudAsyncClient> extends
108          RestClientModule<S, A> {
109 
110    public CommonVCloudRestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
111       super(syncClientType, asyncClientType);
112    }
113 
114    public CommonVCloudRestClientModule(Class<S> syncClientType, Class<A> asyncClientType,
115             Map<Class<?>, Class<?>> delegateMap) {
116       super(syncClientType, asyncClientType, delegateMap);
117    }
118 
119    @Override
120    protected void configure() {
121       requestInjection(this);
122       super.configure();
123       bind(new TypeLiteral<Function<ReferenceType, Location>>() {
124       }).to(new TypeLiteral<FindLocationForResource>() {
125       });
126       bind(new TypeLiteral<Function<Org, Iterable<? extends Catalog>>>() {
127       }).to(new TypeLiteral<AllCatalogsInOrg>() {
128       });
129       bind(new TypeLiteral<Function<Org, Iterable<? extends VDC>>>() {
130       }).to(new TypeLiteral<AllVDCsInOrg>() {
131       });
132       bind(new TypeLiteral<Function<Iterable<String>, Iterable<? extends Org>>>() {
133       }).to(new TypeLiteral<OrgsForNames>() {
134       });
135       bind(new TypeLiteral<Function<Iterable<? extends Location>, Iterable<? extends Org>>>() {
136       }).to(new TypeLiteral<OrgsForLocations>() {
137       });
138       bind(new TypeLiteral<Function<Catalog, Iterable<? extends CatalogItem>>>() {
139       }).to(new TypeLiteral<AllCatalogItemsInCatalog>() {
140       });
141       bind(new TypeLiteral<Function<Org, Iterable<? extends CatalogItem>>>() {
142       }).to(new TypeLiteral<AllCatalogItemsInOrg>() {
143       });
144    }
145 
146    @Singleton
147    @Provides
148    CommonVCloudAsyncClient provideCommonVCloudAsyncClient(A in) {
149       return in;
150    }
151 
152    @Singleton
153    @Provides
154    CommonVCloudClient provideCommonVCloudClient(S in) {
155       return in;
156    }
157 
158    @Provides
159    @Singleton
160    @org.jclouds.vcloud.endpoints.VDC
161    protected Supplier<Map<String, String>> provideVDCtoORG(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
162             final Supplier<Map<String, ? extends Org>> orgToVDCSupplier) {
163       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, String>>(authException,
164                seconds, new Supplier<Map<String, String>>() {
165                   @Override
166                   public Map<String, String> get() {
167                      Map<String, String> returnVal = newLinkedHashMap();
168                      for (Entry<String, ? extends Org> orgr : orgToVDCSupplier.get().entrySet()) {
169                         for (String vdc : orgr.getValue().getVDCs().keySet()) {
170                            returnVal.put(vdc, orgr.getKey());
171                         }
172                      }
173                      return returnVal;
174                   }
175                });
176 
177    }
178 
179    @Provides
180    @org.jclouds.vcloud.endpoints.VDC
181    @Singleton
182    protected URI provideDefaultVDC(Org org, @org.jclouds.vcloud.endpoints.VDC String defaultVDC) {
183       checkState(org.getVDCs().size() > 0, "No vdcs present in org %s", org.getName());
184       return checkNotNull(org.getVDCs().get(defaultVDC), "vdc %s not present in org %s", defaultVDC, org.getName())
185                .getHref();
186    }
187 
188    @Provides
189    @org.jclouds.vcloud.endpoints.VDC
190    @Singleton
191    protected String provideDefaultVDCName(
192             @org.jclouds.vcloud.endpoints.VDC Supplier<Map<String, String>> vDCtoOrgSupplier) {
193       Map<String, String> vDCtoOrg = vDCtoOrgSupplier.get();
194       checkState(vDCtoOrg.keySet().size() > 0, "No vdcs present!");
195       return get(vDCtoOrg.keySet(), 0);
196    }
197 
198    @Provides
199    @org.jclouds.vcloud.endpoints.Catalog
200    @Singleton
201    protected URI provideCatalog(Org org, @Named(PROPERTY_IDENTITY) String user, WriteableCatalog writableCatalog) {
202       checkState(org.getCatalogs().size() > 0, "No catalogs present in org: " + org.getName());
203       try {
204          return find(org.getCatalogs().values(), writableCatalog).getHref();
205       } catch (NoSuchElementException e) {
206          throw new NoSuchElementException(String.format("no writable catalogs in org %s; catalogs %s", org, org
207                   .getCatalogs()));
208       }
209    }
210 
211    @Provides
212    @Singleton
213    protected Supplier<Map<String, ? extends Org>> provideOrgMapCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
214             final OrgMapSupplier supplier) {
215       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, ? extends Org>>(
216                authException, seconds, new Supplier<Map<String, ? extends Org>>() {
217                   @Override
218                   public Map<String, ? extends Org> get() {
219                      return supplier.get();
220                   }
221 
222                });
223    }
224 
225    @Provides
226    @Singleton
227    @OrgList
228    URI provideOrgListURI(Supplier<VCloudSession> sessionSupplier) {
229       VCloudSession session = sessionSupplier.get();
230       return URI.create(Iterables.getLast(session.getOrgs().values()).getHref().toASCIIString().replaceAll("org/.*",
231                "org"));
232    }
233 
234    @Singleton
235    public static class WriteableCatalog implements Predicate<ReferenceType> {
236       private final CommonVCloudClient client;
237 
238       @Inject
239       public WriteableCatalog(CommonVCloudClient client) {
240          this.client = client;
241       }
242 
243       @Override
244       public boolean apply(ReferenceType arg0) {
245          return !client.getCatalog(arg0.getHref()).isReadOnly();
246       }
247    }
248 
249    @Singleton
250    public static class OrgMapSupplier implements Supplier<Map<String, ? extends Org>> {
251       protected final Supplier<VCloudSession> sessionSupplier;
252       private final Function<Iterable<String>, Iterable<? extends Org>> organizationsForNames;
253 
254       @Inject
255       protected OrgMapSupplier(Supplier<VCloudSession> sessionSupplier,
256                Function<Iterable<String>, Iterable<? extends Org>> organizationsForNames) {
257          this.sessionSupplier = sessionSupplier;
258          this.organizationsForNames = organizationsForNames;
259       }
260 
261       @Override
262       public Map<String, ? extends Org> get() {
263          return uniqueIndex(organizationsForNames.apply(sessionSupplier.get().getOrgs().keySet()), name);
264       }
265    }
266 
267    @Singleton
268    public static class OrgCatalogSupplier implements
269             Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>> {
270       protected final Supplier<Map<String, ? extends Org>> orgSupplier;
271       private final Function<Org, Iterable<? extends org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg;
272 
273       @Inject
274       protected OrgCatalogSupplier(Supplier<Map<String, ? extends Org>> orgSupplier,
275                Function<Org, Iterable<? extends org.jclouds.vcloud.domain.Catalog>> allCatalogsInOrg) {
276          this.orgSupplier = orgSupplier;
277          this.allCatalogsInOrg = allCatalogsInOrg;
278       }
279 
280       @Override
281       public Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>> get() {
282          return transformValues(
283                   transformValues(orgSupplier.get(), allCatalogsInOrg),
284                   new Function<Iterable<? extends org.jclouds.vcloud.domain.Catalog>, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>() {
285 
286                      @Override
287                      public Map<String, ? extends org.jclouds.vcloud.domain.Catalog> apply(
288                               Iterable<? extends org.jclouds.vcloud.domain.Catalog> from) {
289                         return uniqueIndex(from, name);
290                      }
291 
292                   });
293       }
294    }
295 
296    @Resource
297    protected Logger logger = Logger.NULL;
298 
299    @VCloudToken
300    @Provides
301    String provideVCloudToken(Supplier<VCloudSession> cache) {
302       return checkNotNull(cache.get().getVCloudToken(), "No token present in session");
303    }
304 
305    @Provides
306    @org.jclouds.vcloud.endpoints.Org
307    @Singleton
308    protected URI provideOrg(@org.jclouds.vcloud.endpoints.Org Iterable<ReferenceType> orgs) {
309       return getLast(orgs).getHref();
310    }
311 
312    @Provides
313    @org.jclouds.vcloud.endpoints.Org
314    @Singleton
315    protected String provideOrgName(@org.jclouds.vcloud.endpoints.Org Iterable<ReferenceType> orgs) {
316       return getLast(orgs).getName();
317    }
318 
319    @Provides
320    @org.jclouds.vcloud.endpoints.Org
321    @Singleton
322    protected Supplier<Map<String, ReferenceType>> provideVDCtoORG(@Named(PROPERTY_SESSION_INTERVAL) long seconds,
323             final OrgNameToOrgSupplier supplier) {
324       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, ReferenceType>>(
325                authException, seconds, new Supplier<Map<String, ReferenceType>>() {
326                   @Override
327                   public Map<String, ReferenceType> get() {
328                      return supplier.get();
329                   }
330                });
331    }
332 
333    @Provides
334    @Singleton
335    protected Supplier<Map<URI, ? extends org.jclouds.vcloud.domain.VDC>> provideURIToVDC(
336             @Named(PROPERTY_SESSION_INTERVAL) long seconds, final URItoVDC supplier) {
337       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<URI, ? extends org.jclouds.vcloud.domain.VDC>>(
338                authException, seconds, new Supplier<Map<URI, ? extends org.jclouds.vcloud.domain.VDC>>() {
339                   @Override
340                   public Map<URI, ? extends org.jclouds.vcloud.domain.VDC> get() {
341                      return supplier.get();
342                   }
343                });
344    }
345 
346    @Singleton
347    public static class URItoVDC implements Supplier<Map<URI, ? extends org.jclouds.vcloud.domain.VDC>> {
348       private final Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> orgVDCMap;
349 
350       @Inject
351       URItoVDC(Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> orgVDCMap) {
352          this.orgVDCMap = orgVDCMap;
353       }
354 
355       @Override
356       public Map<URI, ? extends org.jclouds.vcloud.domain.VDC> get() {
357          return uniqueIndex(
358                   concat(transform(
359                            orgVDCMap.get().values(),
360                            new Function<Map<String, ? extends org.jclouds.vcloud.domain.VDC>, Iterable<? extends org.jclouds.vcloud.domain.VDC>>() {
361 
362                               @Override
363                               public Iterable<? extends org.jclouds.vcloud.domain.VDC> apply(
364                                        Map<String, ? extends org.jclouds.vcloud.domain.VDC> from) {
365                                  return from.values();
366                               }
367 
368                            })), new Function<org.jclouds.vcloud.domain.VDC, URI>() {
369 
370                      @Override
371                      public URI apply(org.jclouds.vcloud.domain.VDC from) {
372                         return from.getHref();
373                      }
374 
375                   });
376       }
377 
378    }
379 
380    @Provides
381    @org.jclouds.vcloud.endpoints.Org
382    @Singleton
383    protected Iterable<ReferenceType> provideOrgs(Supplier<VCloudSession> cache, @Named(PROPERTY_IDENTITY) String user) {
384       VCloudSession discovery = cache.get();
385       checkState(discovery.getOrgs().size() > 0, "No orgs present for user: " + user);
386       return discovery.getOrgs().values();
387    }
388 
389    protected AtomicReference<AuthorizationException> authException = new AtomicReference<AuthorizationException>();
390 
391    final static Function<ReferenceType, String> name = new Function<ReferenceType, String>() {
392 
393       @Override
394       public String apply(ReferenceType from) {
395          return from.getName();
396       }
397 
398    };
399 
400    @Provides
401    @Singleton
402    @org.jclouds.vcloud.endpoints.VCloudLogin
403    protected URI provideAuthenticationURI(VCloudVersionsAsyncClient versionService,
404             @Named(PROPERTY_API_VERSION) String version) throws InterruptedException, ExecutionException,
405             TimeoutException {
406       SortedMap<String, URI> versions = versionService.getSupportedVersions().get(180, TimeUnit.SECONDS);
407       checkState(versions.size() > 0, "No versions present");
408       checkState(versions.containsKey(version), "version " + version + " not present in: " + versions);
409       return versions.get(version);
410    }
411 
412    @Singleton
413    private static class OrgNameToOrgSupplier implements Supplier<Map<String, ReferenceType>> {
414       private final Supplier<VCloudSession> sessionSupplier;
415 
416       @SuppressWarnings("unused")
417       @Inject
418       OrgNameToOrgSupplier(Supplier<VCloudSession> sessionSupplier) {
419          this.sessionSupplier = sessionSupplier;
420       }
421 
422       @Override
423       public Map<String, ReferenceType> get() {
424          return sessionSupplier.get().getOrgs();
425       }
426 
427    }
428 
429    @Provides
430    @Singleton
431    protected VCloudVersionsAsyncClient provideVCloudVersions(AsyncClientFactory factory) {
432       return factory.create(VCloudVersionsAsyncClient.class);
433    }
434 
435    @Provides
436    @org.jclouds.vcloud.endpoints.Catalog
437    @Singleton
438    protected String provideCatalogName(
439             Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>> catalogs) {
440       return getLast(getLast(catalogs.get().values()).keySet());
441    }
442 
443    @Provides
444    @Network
445    @Singleton
446    protected URI provideDefaultNetwork(@org.jclouds.vcloud.endpoints.VDC URI defaultVDC, Injector injector) {
447       if (authException.get() != null)
448          throw authException.get();
449       try {
450          org.jclouds.vcloud.domain.VDC vDC = injector.getInstance(CommonVCloudClient.class).getVDC(defaultVDC);
451          Map<String, ReferenceType> networks = vDC.getAvailableNetworks();
452          checkState(networks.size() > 0, "No networks present in vDC: " + vDC.getName());
453          if (networks.size() == 1)
454             return Iterables.getLast(networks.values()).getHref();
455          String networkName = null;
456          try {
457             networkName = injector.getInstance(Key.get(String.class, Names.named(PROPERTY_VCLOUD_DEFAULT_NETWORK)));
458             ReferenceType network = networks.get(Iterables.find(networks.keySet(), Predicates
459                      .containsPattern(networkName)));
460             return network.getHref();
461          } catch (NoSuchElementException e) {
462             throw new IllegalStateException(String.format("network matching [%s] not in %s", networkName, networks.keySet()));
463          } catch (ConfigurationException e) {
464             return findDefaultNetworkForVDC(vDC, networks, injector);
465          }
466       } catch (AuthorizationException e) {
467          authException.set(e);
468          throw e;
469       }
470    }
471 
472    protected URI findDefaultNetworkForVDC(org.jclouds.vcloud.domain.VDC vDC, Map<String, ReferenceType> networks,
473             Injector injector) {
474       logger.warn("default network for vdc %s not set", vDC.getName());
475       return Iterables.getLast(networks.values()).getHref();
476    }
477 
478    @Provides
479    @Singleton
480    protected Org provideOrg(CommonVCloudClient discovery) {
481       if (authException.get() != null)
482          throw authException.get();
483       try {
484          return discovery.findOrgNamed(null);
485       } catch (AuthorizationException e) {
486          authException.set(e);
487          throw e;
488       }
489    }
490 
491    @Provides
492    @Singleton
493    protected Predicate<URI> successTester(Injector injector,
494             @Named(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED) long completed) {
495       return new RetryablePredicate<URI>(injector.getInstance(TaskSuccess.class), completed);
496    }
497 
498    @Provides
499    @Singleton
500    protected Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>> provideOrgCatalogItemMapSupplierCache(
501             @Named(PROPERTY_SESSION_INTERVAL) long seconds, final OrgCatalogSupplier supplier) {
502       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>>(
503                authException, seconds,
504                new Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>>() {
505                   @Override
506                   public Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>> get() {
507                      return supplier.get();
508                   }
509 
510                });
511    }
512 
513    @Provides
514    @Singleton
515    protected Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> provideOrgVDCSupplierCache(
516             @Named(PROPERTY_SESSION_INTERVAL) long seconds, final OrgVDCSupplier supplier) {
517       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>>(
518                authException, seconds,
519                new Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>>() {
520                   @Override
521                   public Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>> get() {
522                      return supplier.get();
523                   }
524 
525                });
526    }
527 
528    @Singleton
529    public static class OrgVDCSupplier implements
530             Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>> {
531       protected final Supplier<Map<String, ? extends Org>> orgSupplier;
532       private final Function<Org, Iterable<? extends org.jclouds.vcloud.domain.VDC>> allVDCsInOrg;
533 
534       @Inject
535       protected OrgVDCSupplier(Supplier<Map<String, ? extends Org>> orgSupplier,
536                Function<Org, Iterable<? extends org.jclouds.vcloud.domain.VDC>> allVDCsInOrg) {
537          this.orgSupplier = orgSupplier;
538          this.allVDCsInOrg = allVDCsInOrg;
539       }
540 
541       @Override
542       public Map<String, Map<String, ? extends org.jclouds.vcloud.domain.VDC>> get() {
543          return transformValues(
544                   transformValues(orgSupplier.get(), allVDCsInOrg),
545                   new Function<Iterable<? extends org.jclouds.vcloud.domain.VDC>, Map<String, ? extends org.jclouds.vcloud.domain.VDC>>() {
546 
547                      @Override
548                      public Map<String, ? extends org.jclouds.vcloud.domain.VDC> apply(
549                               Iterable<? extends org.jclouds.vcloud.domain.VDC> from) {
550                         return uniqueIndex(from, name);
551                      }
552 
553                   });
554       }
555    }
556 
557    @Singleton
558    public static class OrgCatalogItemSupplier implements
559             Supplier<Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>>> {
560       protected final Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>> catalogSupplier;
561       private final Function<org.jclouds.vcloud.domain.Catalog, Iterable<? extends CatalogItem>> allCatalogItemsInCatalog;
562 
563       @Inject
564       protected OrgCatalogItemSupplier(
565                Supplier<Map<String, Map<String, ? extends org.jclouds.vcloud.domain.Catalog>>> catalogSupplier,
566                Function<org.jclouds.vcloud.domain.Catalog, Iterable<? extends CatalogItem>> allCatalogItemsInCatalog) {
567          this.catalogSupplier = catalogSupplier;
568          this.allCatalogItemsInCatalog = allCatalogItemsInCatalog;
569       }
570 
571       @Override
572       public Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>> get() {
573          return transformValues(
574                   catalogSupplier.get(),
575                   new Function<Map<String, ? extends org.jclouds.vcloud.domain.Catalog>, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>>() {
576 
577                      @Override
578                      public Map<String, Map<String, ? extends CatalogItem>> apply(
579                               Map<String, ? extends org.jclouds.vcloud.domain.Catalog> from) {
580                         return transformValues(
581                                  from,
582                                  new Function<org.jclouds.vcloud.domain.Catalog, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>() {
583 
584                                     @Override
585                                     public Map<String, ? extends CatalogItem> apply(
586                                              org.jclouds.vcloud.domain.Catalog from) {
587                                        return uniqueIndex(allCatalogItemsInCatalog.apply(from), name);
588                                     }
589                                  });
590 
591                      }
592                   });
593       }
594    }
595 
596    @Provides
597    @Singleton
598    protected Supplier<Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>>> provideOrgCatalogItemSupplierCache(
599             @Named(PROPERTY_SESSION_INTERVAL) long seconds, final OrgCatalogItemSupplier supplier) {
600       return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier<Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>>>(
601                authException, seconds,
602                new Supplier<Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>>>() {
603                   @Override
604                   public Map<String, Map<String, Map<String, ? extends org.jclouds.vcloud.domain.CatalogItem>>> get() {
605                      return supplier.get();
606                   }
607                });
608    }
609 
610    @Provides
611    @TasksList
612    @Singleton
613    protected URI provideDefaultTasksList(Org org) {
614       return org.getTasksList().getHref();
615    }
616 
617    @Override
618    protected void bindErrorHandlers() {
619       bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseVCloudErrorFromHttpResponse.class);
620       bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseVCloudErrorFromHttpResponse.class);
621       bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseVCloudErrorFromHttpResponse.class);
622    }
623 }