/** * Licensed to jclouds, Inc. (jclouds) under one or more * contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. jclouds licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jclouds; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Predicates.equalTo; import static com.google.common.base.Predicates.in; import static com.google.common.base.Throwables.propagate; import static com.google.common.primitives.Ints.asList; import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.jclouds.http.HttpUtils.contains404; import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull; import static org.jclouds.util.Throwables2.getFirstThrowableOfType; import org.jclouds.collect.IterableWithMarker; import org.jclouds.collect.IterableWithMarkers; import org.jclouds.collect.PagedIterable; import org.jclouds.collect.PagedIterables; import org.jclouds.rest.ResourceNotFoundException; import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; /** * * @author Adrian Cole */ public final class Fallbacks { private Fallbacks() { } public static final class NullOnNotFoundOr404 implements Fallback<Object> { public ListenableFuture<Object> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public Object createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(null, checkNotNull(t, "throwable")); } } public static final class VoidOnNotFoundOr404 implements Fallback<Void> { public ListenableFuture<Void> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public Void createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(null, checkNotNull(t, "throwable")); } } public static final class TrueOnNotFoundOr404 implements Fallback<Boolean> { public ListenableFuture<Boolean> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public Boolean createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(true, checkNotNull(t, "throwable")); } } public static final class FalseOnNotFoundOr404 implements Fallback<Boolean> { public ListenableFuture<Boolean> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public Boolean createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(false, checkNotNull(t, "throwable")); } } public static final class FalseOnNotFoundOr422 implements Fallback<Boolean> { public ListenableFuture<Boolean> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public Boolean createOrPropagate(Throwable t) throws Exception { if (containsResourceNotFoundException(checkNotNull(t, "throwable")) || returnValueOnCodeOrNull(t, true, equalTo(422)) != null) return false; throw propagate(t); } } /** * @author Leander Beernaert */ public static final class AbsentOn403Or404Or500 implements Fallback<Optional<Object>> { public ListenableFuture<Optional<Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public Optional<Object> createOrPropagate(Throwable t) throws Exception { Boolean returnVal = returnValueOnCodeOrNull(checkNotNull(t, "throwable"), true, in(asList(403, 404, 500))); if (returnVal != null) return Optional.absent(); throw propagate(t); } } public static final class EmptyFluentIterableOnNotFoundOr404 implements Fallback<FluentIterable<Object>> { public ListenableFuture<FluentIterable<Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public FluentIterable<Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(FluentIterable.from(ImmutableSet.of()), checkNotNull(t, "throwable")); } } public static final class EmptyIterableWithMarkerOnNotFoundOr404 implements Fallback<IterableWithMarker<Object>> { public ListenableFuture<IterableWithMarker<Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public IterableWithMarker<Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(IterableWithMarkers.from(ImmutableSet.of()), checkNotNull(t, "throwable")); } } public static final class EmptyPagedIterableOnNotFoundOr404 implements Fallback<PagedIterable<Object>> { public ListenableFuture<PagedIterable<Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public PagedIterable<Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(PagedIterables.of(IterableWithMarkers.from(ImmutableSet.of())), checkNotNull(t, "throwable")); } } public static final class EmptyListOnNotFoundOr404 implements Fallback<ImmutableList<Object>> { // NO_UCD // (unused // code) public ListenableFuture<ImmutableList<Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public ImmutableList<Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(ImmutableList.of(), checkNotNull(t, "throwable")); } } public static final class EmptySetOnNotFoundOr404 implements Fallback<ImmutableSet<Object>> { public ListenableFuture<ImmutableSet<Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public ImmutableSet<Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(ImmutableSet.of(), checkNotNull(t, "throwable")); } } public static final class EmptyMapOnNotFoundOr404 implements Fallback<ImmutableMap<Object, Object>> { public ListenableFuture<ImmutableMap<Object, Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public ImmutableMap<Object, Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(ImmutableMap.of(), checkNotNull(t, "throwable")); } } public static final class EmptyMultimapOnNotFoundOr404 implements Fallback<ImmutableMultimap<Object, Object>> { // NO_UCD // (unused // code) public ListenableFuture<ImmutableMultimap<Object, Object>> create(Throwable t) throws Exception { return immediateFuture(createOrPropagate(t)); } public ImmutableMultimap<Object, Object> createOrPropagate(Throwable t) throws Exception { return valOnNotFoundOr404(ImmutableMultimap.of(), checkNotNull(t, "throwable")); } } public static <T> T valOnNotFoundOr404(T val, Throwable t) { if (containsResourceNotFoundException(checkNotNull(t, "throwable")) || contains404(t)) return val; throw propagate(t); } private static boolean containsResourceNotFoundException(Throwable from) { return getFirstThrowableOfType(from, ResourceNotFoundException.class) != null; } }