summaryrefslogtreecommitdiffstats
path: root/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
blob: 9e0e8f67892636996cc0d8b23c5b9ba199231200 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright (C) 2008 The Android Open Source Project
//
// 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.gerrit.httpd.rpc;

import com.google.gerrit.common.errors.InvalidQueryException;
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException;
import com.google.inject.Provider;
import java.io.IOException;

/** Support for services which require a {@link ReviewDb} instance. */
public class BaseServiceImplementation {
  private final Provider<ReviewDb> schema;
  private final Provider<? extends CurrentUser> currentUser;

  protected BaseServiceImplementation(
      final Provider<ReviewDb> schema, Provider<? extends CurrentUser> currentUser) {
    this.schema = schema;
    this.currentUser = currentUser;
  }

  protected Account.Id getAccountId() {
    CurrentUser u = currentUser.get();
    return u.isIdentifiedUser() ? u.getAccountId() : null;
  }

  protected CurrentUser getUser() {
    return currentUser.get();
  }

  protected ReviewDb getDb() {
    return schema.get();
  }

  /**
   * Executes {@code action.run} with an active ReviewDb connection.
   *
   * <p>A database handle is automatically opened and closed around the action's {@link
   * Action#run(ReviewDb)} method. OrmExceptions are caught and passed into the onFailure method of
   * the callback.
   *
   * @param <T> type of result the callback expects.
   * @param callback the callback that will receive the result.
   * @param action the action logic to perform.
   */
  protected <T> void run(AsyncCallback<T> callback, Action<T> action) {
    try {
      final T r = action.run(schema.get());
      if (r != null) {
        callback.onSuccess(r);
      }
    } catch (InvalidQueryException e) {
      callback.onFailure(e);
    } catch (NoSuchProjectException e) {
      if (e.getMessage() != null) {
        callback.onFailure(new NoSuchEntityException(e.getMessage()));
      } else {
        callback.onFailure(new NoSuchEntityException());
      }
    } catch (NoSuchGroupException e) {
      callback.onFailure(new NoSuchEntityException());
    } catch (OrmRuntimeException e) {
      Exception ex = e;
      if (e.getCause() instanceof OrmException) {
        ex = (OrmException) e.getCause();
      }
      handleOrmException(callback, ex);
    } catch (OrmException e) {
      handleOrmException(callback, e);
    } catch (IOException e) {
      callback.onFailure(e);
    } catch (Failure e) {
      if (e.getCause() instanceof NoSuchProjectException
          || e.getCause() instanceof NoSuchChangeException) {
        callback.onFailure(new NoSuchEntityException());

      } else {
        callback.onFailure(e.getCause());
      }
    }
  }

  private static <T> void handleOrmException(AsyncCallback<T> callback, Exception e) {
    if (e.getCause() instanceof Failure) {
      callback.onFailure(e.getCause().getCause());
    } else if (e.getCause() instanceof NoSuchEntityException) {
      callback.onFailure(e.getCause());
    } else {
      callback.onFailure(e);
    }
  }

  /** Exception whose cause is passed into onFailure. */
  public static class Failure extends Exception {
    private static final long serialVersionUID = 1L;

    public Failure(Throwable why) {
      super(why);
    }
  }

  /** Arbitrary action to run with a database connection. */
  public interface Action<T> {
    /**
     * Perform this action, returning the onSuccess value.
     *
     * @param db an open database handle to be used by this connection.
     * @return he value to pass to {@link AsyncCallback#onSuccess(Object)}.
     * @throws OrmException any schema based action failed.
     * @throws Failure cause is given to {@link AsyncCallback#onFailure(Throwable)}.
     * @throws NoSuchProjectException
     * @throws NoSuchGroupException
     * @throws InvalidQueryException
     */
    T run(ReviewDb db)
        throws OrmException, Failure, NoSuchProjectException, NoSuchGroupException,
            InvalidQueryException, IOException;
  }
}