Package com.google.walkaround.wave.server.googleimport

Source Code of com.google.walkaround.wave.server.googleimport.ImportTaskHandler

/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed 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 com.google.walkaround.wave.server.googleimport;

import com.google.appengine.api.taskqueue.Queue;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.walkaround.proto.ImportTaskPayload;
import com.google.walkaround.util.server.RetryHelper;
import com.google.walkaround.util.server.RetryHelper.PermanentFailure;
import com.google.walkaround.util.server.RetryHelper.RetryableFailure;
import com.google.walkaround.util.server.appengine.CheckedDatastore;
import com.google.walkaround.util.server.appengine.CheckedDatastore.CheckedTransaction;
import com.google.walkaround.util.server.servlet.AbstractHandler;
import com.google.walkaround.util.server.servlet.BadRequestException;
import com.google.walkaround.util.server.servlet.TryAgainLaterException;
import com.google.walkaround.wave.server.auth.AccountStore;
import com.google.walkaround.wave.server.auth.ServletAuthHelper;
import com.google.walkaround.wave.server.auth.StableUserId;
import com.google.walkaround.wave.server.auth.UserContext;

import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;

import javax.annotation.Nullable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Handles task queue callbacks for import tasks.
*
* @author ohler@google.com (Christian Ohler)
*/
public class ImportTaskHandler extends AbstractHandler {

  @SuppressWarnings("unused")
  private static final Logger log = Logger.getLogger(ImportTaskHandler.class.getName());

  public static final String USER_ID_HEADER = "X-Walkaround-Import-User-Id";
  public static final String TASK_ID_HEADER = "X-Walkaround-Import-Task-Id";

  @Inject AccountStore accountStore;
  @Inject UserContext userContext;
  @Inject ServletAuthHelper authHelper;
  @Inject PerUserTable perUserTable;
  @Inject CheckedDatastore datastore;
  @Inject @ImportTaskQueue Queue taskQueue;
  // Provider because we need to set up the UserContext before this can be instantiated.
  @Inject Provider<TaskDispatcher> taskDispatcher;

  private ImportTask readTask(StableUserId userId, long taskId) throws IOException {
    try {
      CheckedTransaction tx = datastore.beginTransaction();
      try {
        return perUserTable.getTask(tx, userId, taskId);
      } finally {
        tx.rollback();
      }
    } catch (RetryableFailure e) {
      // If we can't even read the task, let the task queue retry rather than
      // doing it here.  Seems better because it means we don't use waste a
      // thread for waiting.
      throw new IOException("PermanentFailure reading task: " + userId + ", " + taskId, e);
    } catch (PermanentFailure e) {
      throw new IOException("PermanentFailure reading task: " + userId + ", " + taskId, e);
    }
  }

  private void handleTask(final StableUserId userId, final long taskId) throws IOException {
    ImportTask taskToProcess = readTask(userId, taskId);
    if (taskToProcess == null) {
      log.info("Task is gone from datastore; either already completed or cancelled");
      return;
    }
    log.info("Task to process: " + taskToProcess);
    final List<ImportTaskPayload> followupTasks = taskDispatcher.get().processTask(taskToProcess);
    // If the processing returns normally, the task has been completed.  (Other
    // tasks may have been scheduled.)
    try {
      new RetryHelper().run(
          new RetryHelper.VoidBody() {
            @Override public void run() throws RetryableFailure, PermanentFailure {
              CheckedTransaction tx = datastore.beginTransaction();
              try {
                if (perUserTable.getTask(tx, userId, taskId) == null) {
                  // If the task is already gone, make sure we don't schedule follow-up tasks.
                  log.info(
                      "Task is gone from datastore; either completed concurrently or cancelled");
                  return;
                }
                perUserTable.deleteTask(tx, userId, taskId);
                for (ImportTaskPayload payload : followupTasks) {
                  perUserTable.addTask(tx, userId, payload);
                }
                tx.commit();
              } finally {
                tx.close();
              }
            }
          });
    } catch (PermanentFailure e) {
      // Ugh, all the real work is done but then we failed to delete the task
      // entity.  We'll have to do the task all over again...
      throw new IOException("PermanentFailure deleting completed task: " + userId + " " + taskId,
          e);
    }
  }

  @Override
  public void doPost(final HttpServletRequest req, final HttpServletResponse resp)
      throws IOException, ServletException {
    log.info("Received task: queue " + req.getHeader("X-AppEngine-QueueName")
        + ", task name " + req.getHeader("X-AppEngine-TaskName")
        + ", retry count " + req.getHeader("X-AppEngine-TaskRetryCount"));
    final StableUserId userId = new StableUserId(requireParameter(req, USER_ID_HEADER));
    final long taskId;
    try {
      taskId = Long.parseLong(requireParameter(req, TASK_ID_HEADER));
    } catch (NumberFormatException e) {
      throw new BadRequestException("Bad task id");
    }
    log.info("userId=" + userId + ", taskId=" + taskId);

    authHelper.serve(
        new ServletAuthHelper.ServletBody() {
          @Override public void run() throws IOException {
            handleTask(userId, taskId);
          }
        },
        new ServletAuthHelper.AccountLookup() {
          @Override @Nullable public AccountStore.Record getAccount()
              throws PermanentFailure, IOException {
            return accountStore.get(userId);
          }
        },
        new ServletAuthHelper.NeedNewOAuthTokenHandler() {
          @Override public void sendNeedTokenResponse() throws IOException {
            // TODO(ohler): When loading /import (and probably /inbox as well),
            // check not just whether we have an OAuth token, but also whether
            // it's still valid.
            throw new TryAgainLaterException(
                "Need OAuth token.  Let's hope the user re-enables interactively: "
                + userId);
          }
      });
  }

}
TOP

Related Classes of com.google.walkaround.wave.server.googleimport.ImportTaskHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.