Line data Source code
1 : // Copyright (C) 2013 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.acceptance; 16 : 17 : import com.google.gerrit.server.CurrentUser; 18 : import com.google.gerrit.server.RequestCleanup; 19 : import com.google.gerrit.server.util.RequestContext; 20 : import com.google.gerrit.server.util.ThreadLocalRequestContext; 21 : import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator; 22 : import com.google.gerrit.server.util.time.TimeUtil; 23 : import com.google.inject.Inject; 24 : import com.google.inject.Key; 25 : import com.google.inject.OutOfScopeException; 26 : import com.google.inject.Provider; 27 : import com.google.inject.Scope; 28 : import java.util.HashMap; 29 : import java.util.Map; 30 : 31 : /** Guice scopes for state during an Acceptance Test connection. */ 32 : public class AcceptanceTestRequestScope { 33 138 : private static final Key<RequestCleanup> RC_KEY = Key.get(RequestCleanup.class); 34 : 35 : public static class Context implements RequestContext { 36 132 : private final RequestCleanup cleanup = new RequestCleanup(); 37 132 : private final Map<Key<?>, Object> map = new HashMap<>(); 38 : private final SshSession session; 39 : private final CurrentUser user; 40 : 41 : final long created; 42 : volatile long started; 43 : volatile long finished; 44 : 45 132 : private Context(SshSession s, CurrentUser u, long at) { 46 132 : session = s; 47 132 : user = u; 48 132 : created = started = finished = at; 49 132 : map.put(RC_KEY, cleanup); 50 132 : } 51 : 52 : private Context(Context p, SshSession s, CurrentUser c) { 53 0 : this(s, c, p.created); 54 0 : started = p.started; 55 0 : finished = p.finished; 56 0 : } 57 : 58 : public SshSession getSession() { 59 13 : return session; 60 : } 61 : 62 : @Override 63 : public CurrentUser getUser() { 64 132 : if (user == null) { 65 0 : throw new IllegalStateException("user == null, forgot to set it?"); 66 : } 67 132 : return user; 68 : } 69 : 70 : synchronized <T> T get(Key<T> key, Provider<T> creator) { 71 : @SuppressWarnings("unchecked") 72 0 : T t = (T) map.get(key); 73 0 : if (t == null) { 74 0 : t = creator.get(); 75 0 : map.put(key, t); 76 : } 77 0 : return t; 78 : } 79 : } 80 : 81 0 : static class ContextProvider implements Provider<Context> { 82 : @Override 83 : public Context get() { 84 0 : return requireContext(); 85 : } 86 : } 87 : 88 0 : static class SshSessionProvider implements Provider<SshSession> { 89 : @Override 90 : public SshSession get() { 91 0 : return requireContext().getSession(); 92 : } 93 : } 94 : 95 : static class Propagator extends ThreadLocalRequestScopePropagator<Context> { 96 : private final AcceptanceTestRequestScope atrScope; 97 : 98 : @Inject 99 : Propagator(AcceptanceTestRequestScope atrScope, ThreadLocalRequestContext local) { 100 0 : super(REQUEST, current, local); 101 0 : this.atrScope = atrScope; 102 0 : } 103 : 104 : @Override 105 : protected Context continuingContext(Context ctx) { 106 : // The cleanup is not chained, since the RequestScopePropagator executors 107 : // the Context's cleanup when finished executing. 108 0 : return atrScope.newContinuingContext(ctx); 109 : } 110 : } 111 : 112 138 : private static final ThreadLocal<Context> current = new ThreadLocal<>(); 113 : 114 : private static Context requireContext() { 115 0 : final Context ctx = current.get(); 116 0 : if (ctx == null) { 117 0 : throw new OutOfScopeException("Not in command/request"); 118 : } 119 0 : return ctx; 120 : } 121 : 122 : private final ThreadLocalRequestContext local; 123 : 124 : @Inject 125 138 : AcceptanceTestRequestScope(ThreadLocalRequestContext local) { 126 138 : this.local = local; 127 138 : } 128 : 129 : public Context newContext(SshSession s, CurrentUser user) { 130 132 : return new Context(s, user, TimeUtil.nowMs()); 131 : } 132 : 133 : private Context newContinuingContext(Context ctx) { 134 0 : return new Context(ctx, ctx.getSession(), ctx.getUser()); 135 : } 136 : 137 : public Context set(Context ctx) { 138 132 : Context old = current.get(); 139 132 : current.set(ctx); 140 132 : local.setContext(ctx); 141 132 : return old; 142 : } 143 : 144 : public Context get() { 145 132 : return current.get(); 146 : } 147 : 148 : /** 149 : * Disables read and write access to NoteDb and returns the context prior to that modification. 150 : */ 151 : public Context disableNoteDb() { 152 6 : Context old = current.get(); 153 6 : Context ctx = new Context(old.session, old.user, old.created); 154 : 155 6 : current.set(ctx); 156 6 : local.setContext(ctx); 157 6 : return old; 158 : } 159 : 160 : /** Returns exactly one instance per command executed. */ 161 138 : static final Scope REQUEST = 162 138 : new Scope() { 163 : @Override 164 : public <T> Provider<T> scope(Key<T> key, Provider<T> creator) { 165 0 : return new Provider<>() { 166 : @Override 167 : public T get() { 168 0 : return requireContext().get(key, creator); 169 : } 170 : 171 : @Override 172 : public String toString() { 173 0 : return String.format("%s[%s]", creator, REQUEST); 174 : } 175 : }; 176 : } 177 : 178 : @Override 179 : public String toString() { 180 0 : return "Acceptance Test Scope.REQUEST"; 181 : } 182 : }; 183 : }