org.jclouds.samples.googleappengine.GetAllResourcesController.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.samples.googleappengine.GetAllResourcesController.java

Source

/**
 * 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.samples.googleappengine;

import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Iterables.transform;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jclouds.View;
import org.jclouds.domain.ResourceMetadata;
import org.jclouds.logging.Logger;
import org.jclouds.samples.googleappengine.domain.ResourceResult;
import org.jclouds.samples.googleappengine.functions.ResourceMetadataToResourceResult;
import org.jclouds.samples.googleappengine.functions.ViewToAsyncResources;
import org.jclouds.samples.googleappengine.functions.ViewToId;

import com.google.common.base.Stopwatch;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;

/**
 * Shows an example of how to list all resources from all views!
 * 
 * @author Adrian Cole
 */
@Singleton
public class GetAllResourcesController extends HttpServlet {

    private final ListeningExecutorService currentRequestExecutorService;
    private final Iterable<View> views;
    private final ViewToAsyncResources viewToAsyncResources;
    private final ResourceMetadataToResourceResult resourceMetadataToStatusResult;
    private final Provider<Long> remainingMillis;

    @Resource
    protected Logger logger = Logger.NULL;

    @Inject
    GetAllResourcesController(ListeningExecutorService currentRequestExecutorService, Iterable<View> views,
            ViewToAsyncResources viewToAsyncResources,
            ResourceMetadataToResourceResult resourceMetadataToStatusResult, Provider<Long> remainingMillis) {
        this.currentRequestExecutorService = currentRequestExecutorService;
        this.views = views;
        this.viewToAsyncResources = viewToAsyncResources;
        this.resourceMetadataToStatusResult = resourceMetadataToStatusResult;
        this.remainingMillis = remainingMillis;
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            addResourcesToRequest(request);
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/WEB-INF/jsp/resources.jsp");
            dispatcher.forward(request, response);
        } catch (Exception e) {
            logger.error(e, "Error listing resources");
            throw new ServletException(e);
        }
    }

    private void addResourcesToRequest(HttpServletRequest request) {
        Stopwatch watch = new Stopwatch().start();
        logger.info("ready to list views: %s", transform(views, ViewToId.INSTANCE));
        Iterable<ListenableFuture<? extends Iterable<? extends ResourceMetadata<?>>>> asyncResources = transform(
                views, viewToAsyncResources);
        logger.info("launched %s tasks with %sms remaining", size(asyncResources), remainingMillis.get());

        Set<Iterable<? extends ResourceMetadata<?>>> done = allResourcesWithinDeadline(asyncResources);
        logger.info("%s tasks completed in %sms with %sms remaining", size(done), watch.stop().elapsedMillis(),
                remainingMillis.get());

        Iterable<ResourceMetadata<?>> flattened = concat(done);

        Set<ResourceResult> results = FluentIterable.from(flattened).transform(resourceMetadataToStatusResult)
                .toImmutableSet();

        request.setAttribute("resources", results);
    }

    private <T> Set<T> allResourcesWithinDeadline(Iterable<ListenableFuture<? extends T>> asyncResources) {
        Builder<T> resourcesWeCanList = addToBuilderOnComplete(asyncResources);

        // only serve resources that made it by the timeout
        blockUntilAllDoneOrCancelOnTimeout(asyncResources);

        return resourcesWeCanList.build();
    }

    private <T> Builder<T> addToBuilderOnComplete(Iterable<ListenableFuture<? extends T>> asyncResources) {

        final Builder<T> resourcesWeCanList = ImmutableSet.<T>builder();

        for (final ListenableFuture<? extends T> asyncResource : asyncResources) {
            Futures.addCallback(asyncResource, new FutureCallback<T>() {
                public void onSuccess(T result) {
                    if (result != null)
                        resourcesWeCanList.add(result);
                }

                public void onFailure(Throwable t) {
                    if (!(t instanceof CancellationException))
                        logger.error(t, "exception getting resource %s: %s", asyncResource, t.getMessage());
                }
            }, currentRequestExecutorService);

        }
        return resourcesWeCanList;
    }

    // ensure we don't violate our request timeouts.
    private void blockUntilAllDoneOrCancelOnTimeout(Iterable<? extends ListenableFuture<?>> asyncResources) {
        try {
            for (ListenableFuture<?> asyncResource : asyncResources) {
                if (remainingMillis.get() > 0) {
                    try {
                        asyncResource.get(remainingMillis.get(), TimeUnit.MILLISECONDS);
                    } catch (Exception e) {
                        logger.info("exception getting resource %s: %s", asyncResource, e.getMessage());
                    }
                }
            }
        } finally {
            if (remainingMillis.get() < 0) {
                for (ListenableFuture<?> asyncResource : asyncResources) {
                    if (!asyncResource.isDone())
                        asyncResource.cancel(true);
                }
            }
        }

    }

}