Rewrite our build as modular maven components
This refactoring splits the code up into different components, with their own per-component CLASSPATH. By moving all of our classes into isolated components we can better isolate the classpaths and try to avoid unexpected dependency problems. It also allows us to more clearly define which components are used by the GWT UI and thus must be compiled under GWT, and which components are run on the server and can therefore use more of the J2SE API. Change-Id: I833cc22bacc5655d1c9099ed7c2b0e0a5b08855a Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
// Copyright (C) 2009 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;
|
||||
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.readFixInt64;
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.writeBytes;
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.writeFixInt64;
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
|
||||
import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
|
||||
import static java.util.concurrent.TimeUnit.HOURS;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import com.google.gerrit.reviewdb.Account;
|
||||
import com.google.gerrit.server.cache.Cache;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
@Singleton
|
||||
class WebSessionManager {
|
||||
static final String CACHE_NAME = "web_sessions";
|
||||
|
||||
static long now() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private final SecureRandom prng;
|
||||
private final Cache<Key, Val> self;
|
||||
|
||||
@Inject
|
||||
WebSessionManager(@Named(CACHE_NAME) final Cache<Key, Val> cache) {
|
||||
prng = new SecureRandom();
|
||||
self = cache;
|
||||
}
|
||||
|
||||
Key createKey(final Account.Id who) {
|
||||
try {
|
||||
final int nonceLen = 20;
|
||||
final ByteArrayOutputStream buf;
|
||||
final byte[] rnd = new byte[nonceLen];
|
||||
prng.nextBytes(rnd);
|
||||
|
||||
buf = new ByteArrayOutputStream(3 + nonceLen);
|
||||
writeVarInt32(buf, (int) Key.serialVersionUID);
|
||||
writeVarInt32(buf, who.get());
|
||||
writeBytes(buf, rnd);
|
||||
|
||||
return new Key(CookieBase64.encode(buf.toByteArray()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Cannot produce new account cookie", e);
|
||||
}
|
||||
}
|
||||
|
||||
Val createVal(final Key key, final Val val) {
|
||||
return createVal(key, val.getAccountId(), val.isPersistentCookie());
|
||||
}
|
||||
|
||||
Val createVal(final Key key, final Account.Id who, final boolean remember) {
|
||||
// Refresh the cookie every hour or when it is half-expired.
|
||||
// This reduces the odds that the user session will be kicked
|
||||
// early but also avoids us needing to refresh the cookie on
|
||||
// every single request.
|
||||
//
|
||||
final long halfAgeRefresh = self.getTimeToLive(MILLISECONDS) >>> 1;
|
||||
final long minRefresh = MILLISECONDS.convert(1, HOURS);
|
||||
final long refresh = Math.min(halfAgeRefresh, minRefresh);
|
||||
final long refreshCookieAt = now() + refresh;
|
||||
|
||||
final Val val = new Val(who, refreshCookieAt, remember);
|
||||
self.put(key, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
int getCookieAge(final Val val) {
|
||||
if (val.isPersistentCookie()) {
|
||||
// Client may store the cookie until we would remove it from our
|
||||
// own cache, after which it will certainly be invalid.
|
||||
//
|
||||
return (int) self.getTimeToLive(SECONDS);
|
||||
} else {
|
||||
// Client should not store the cookie, as the user asked for us
|
||||
// to not remember them long-term. Sending -1 as the age will
|
||||
// cause the cookie to be only for this "browser session", which
|
||||
// is usually until the user exits their browser.
|
||||
//
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Val get(final Key key) {
|
||||
return self.get(key);
|
||||
}
|
||||
|
||||
void destroy(final Key key) {
|
||||
self.remove(key);
|
||||
}
|
||||
|
||||
static final class Key implements Serializable {
|
||||
static final long serialVersionUID = 2L;
|
||||
|
||||
private transient String token;
|
||||
|
||||
Key(final String t) {
|
||||
token = t;
|
||||
}
|
||||
|
||||
String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return token.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof Key && token.equals(((Key) obj).token);
|
||||
}
|
||||
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
||||
writeString(out, token);
|
||||
}
|
||||
|
||||
private void readObject(final ObjectInputStream in) throws IOException {
|
||||
token = readString(in);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Val implements Serializable {
|
||||
static final long serialVersionUID = Key.serialVersionUID;
|
||||
|
||||
private transient Account.Id accountId;
|
||||
private transient long refreshCookieAt;
|
||||
private transient boolean persistentCookie;
|
||||
|
||||
Val(final Account.Id accountId, final long refreshCookieAt,
|
||||
final boolean persistentCookie) {
|
||||
this.accountId = accountId;
|
||||
this.refreshCookieAt = refreshCookieAt;
|
||||
this.persistentCookie = persistentCookie;
|
||||
}
|
||||
|
||||
Account.Id getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
boolean needsCookieRefresh() {
|
||||
return refreshCookieAt <= now();
|
||||
}
|
||||
|
||||
boolean isPersistentCookie() {
|
||||
return persistentCookie;
|
||||
}
|
||||
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
||||
writeVarInt32(out, 1);
|
||||
writeVarInt32(out, accountId.get());
|
||||
|
||||
writeVarInt32(out, 2);
|
||||
writeFixInt64(out, refreshCookieAt);
|
||||
|
||||
writeVarInt32(out, 3);
|
||||
writeVarInt32(out, persistentCookie ? 1 : 0);
|
||||
|
||||
writeVarInt32(out, 0);
|
||||
}
|
||||
|
||||
private void readObject(final ObjectInputStream in) throws IOException {
|
||||
PARSE: for (;;) {
|
||||
final int tag = readVarInt32(in);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
break PARSE;
|
||||
case 1:
|
||||
accountId = new Account.Id(readVarInt32(in));
|
||||
continue;
|
||||
case 2:
|
||||
refreshCookieAt = readFixInt64(in);
|
||||
continue;
|
||||
case 3:
|
||||
persistentCookie = readVarInt32(in) != 0;
|
||||
continue;
|
||||
default:
|
||||
throw new IOException("Unknown tag found in object: " + tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user