Format all Java files with google-java-format
Having a standard tool for formatting saves reviewers' valuable time. google-java-format is Google's standard formatter and is somewhat inspired by gofmt[1]. This commit formats everything using google-java-format version 1.2. The downside of this one-off formatting is breaking blame. This can be somewhat hacked around with a tool like git-hyper-blame[2], but it's definitely not optimal until/unless this kind of feature makes its way to git core. Not in this change: * Tool support, e.g. Eclipse. The command must be run manually [3]. * Documentation of best practice, e.g. new 100-column default. [1] https://talks.golang.org/2015/gofmt-en.slide#3 [2] https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/git-hyper-blame.html [3] git ls-files | grep java$ | xargs google-java-format -i Change-Id: Id5f3c6de95ce0b68b41f0a478b5c99a93675aaa3 Signed-off-by: David Pursehouse <dpursehouse@collab.net>
This commit is contained in:

committed by
David Pursehouse

parent
6723b6d0fa
commit
292fa154c1
@@ -23,8 +23,8 @@ import com.google.inject.ProvisionException;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* The default RequestContext to use when not in a request scope e.g.
|
||||
* ThreadLocalRequestContext is not set.
|
||||
* The default RequestContext to use when not in a request scope e.g. ThreadLocalRequestContext is
|
||||
* not set.
|
||||
*/
|
||||
@Singleton
|
||||
public class FallbackRequestContext implements RequestContext {
|
||||
@@ -46,8 +46,7 @@ public class FallbackRequestContext implements RequestContext {
|
||||
return new Provider<ReviewDb>() {
|
||||
@Override
|
||||
public ReviewDb get() {
|
||||
throw new ProvisionException(
|
||||
"Automatic ReviewDb only available in request scope");
|
||||
throw new ProvisionException("Automatic ReviewDb only available in request scope");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -24,7 +24,6 @@ import com.google.inject.Provider;
|
||||
import com.google.inject.servlet.ServletScopes;
|
||||
import com.google.inject.util.Providers;
|
||||
import com.google.inject.util.Types;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.SocketAddress;
|
||||
@@ -49,9 +48,7 @@ public class GuiceRequestScopePropagator extends RequestScopePropagator {
|
||||
this.peer = remotePeerProvider.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RequestScopePropagator#wrap(Callable)
|
||||
*/
|
||||
/** @see RequestScopePropagator#wrap(Callable) */
|
||||
// ServletScopes#continueRequest is deprecated, but it's not obvious their
|
||||
// recommended replacement is an appropriate drop-in solution; see
|
||||
// https://gerrit-review.googlesource.com/83971
|
||||
@@ -63,12 +60,10 @@ public class GuiceRequestScopePropagator extends RequestScopePropagator {
|
||||
// Request scopes appear to use specific keys in their map, instead of only
|
||||
// providers. Add bindings for both the key to the instance directly and the
|
||||
// provider to the instance to be safe.
|
||||
seedMap.put(Key.get(typeOfProvider(String.class), CanonicalWebUrl.class),
|
||||
Providers.of(url));
|
||||
seedMap.put(Key.get(typeOfProvider(String.class), CanonicalWebUrl.class), Providers.of(url));
|
||||
seedMap.put(Key.get(String.class, CanonicalWebUrl.class), url);
|
||||
|
||||
seedMap.put(Key.get(typeOfProvider(SocketAddress.class), RemotePeer.class),
|
||||
Providers.of(peer));
|
||||
seedMap.put(Key.get(typeOfProvider(SocketAddress.class), RemotePeer.class), Providers.of(peer));
|
||||
seedMap.put(Key.get(SocketAddress.class, RemotePeer.class), peer);
|
||||
|
||||
return ServletScopes.continueRequest(callable, seedMap);
|
||||
|
@@ -32,16 +32,15 @@ public final class HostPlatform {
|
||||
|
||||
private static boolean compute(String platform) {
|
||||
final String osDotName =
|
||||
AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
});
|
||||
return osDotName != null
|
||||
&& osDotName.toLowerCase().contains(platform);
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
});
|
||||
return osDotName != null && osDotName.toLowerCase().contains(platform);
|
||||
}
|
||||
|
||||
private HostPlatform() {
|
||||
}
|
||||
private HostPlatform() {}
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@ package com.google.gerrit.server.util;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@@ -71,23 +70,30 @@ public class IdGenerator {
|
||||
}
|
||||
|
||||
private static short hi16(final int in) {
|
||||
return (short) ( //
|
||||
((in >>> 24 & 0xff)) | //
|
||||
((in >>> 16 & 0xff) << 8) //
|
||||
);
|
||||
return (short)
|
||||
( //
|
||||
((in >>> 24 & 0xff))
|
||||
| //
|
||||
((in >>> 16 & 0xff) << 8) //
|
||||
);
|
||||
}
|
||||
|
||||
private static short lo16(final int in) {
|
||||
return (short) ( //
|
||||
((in >>> 8 & 0xff)) | //
|
||||
((in & 0xff) << 8) //
|
||||
);
|
||||
return (short)
|
||||
( //
|
||||
((in >>> 8 & 0xff))
|
||||
| //
|
||||
((in & 0xff) << 8) //
|
||||
);
|
||||
}
|
||||
|
||||
private static int result(final short v0, final short v1) {
|
||||
return ((v0 & 0xff) << 24) | //
|
||||
(((v0 >>> 8) & 0xff) << 16) | //
|
||||
((v1 & 0xff) << 8) | //
|
||||
return ((v0 & 0xff) << 24)
|
||||
| //
|
||||
(((v0 >>> 8) & 0xff) << 16)
|
||||
| //
|
||||
((v1 & 0xff) << 8)
|
||||
| //
|
||||
((v1 >>> 8) & 0xff);
|
||||
}
|
||||
}
|
||||
|
@@ -46,20 +46,17 @@ public abstract class LabelVote {
|
||||
if (sign == 0) {
|
||||
return create(text, (short) 1);
|
||||
}
|
||||
return create(text.substring(0, i),
|
||||
(short)(sign * Short.parseShort(text.substring(i + 1))));
|
||||
return create(text.substring(0, i), (short) (sign * Short.parseShort(text.substring(i + 1))));
|
||||
}
|
||||
|
||||
public static LabelVote parseWithEquals(String text) {
|
||||
checkArgument(!Strings.isNullOrEmpty(text), "Empty label vote");
|
||||
int e = text.lastIndexOf('=');
|
||||
checkArgument(e >= 0, "Label vote missing '=': %s", text);
|
||||
return create(text.substring(0, e),
|
||||
Short.parseShort(text.substring(e + 1), text.length()));
|
||||
return create(text.substring(0, e), Short.parseShort(text.substring(e + 1), text.length()));
|
||||
}
|
||||
|
||||
public static StringBuilder appendTo(StringBuilder sb, String label,
|
||||
short value) {
|
||||
public static StringBuilder appendTo(StringBuilder sb, String label, short value) {
|
||||
if (value == (short) 0) {
|
||||
return sb.append('-').append(label);
|
||||
} else if (value < 0) {
|
||||
@@ -77,12 +74,12 @@ public abstract class LabelVote {
|
||||
}
|
||||
|
||||
public abstract String label();
|
||||
|
||||
public abstract short value();
|
||||
|
||||
public String format() {
|
||||
// Max short string length is "-32768".length() == 6.
|
||||
return appendTo(new StringBuilder(label().length() + 6), label(), value())
|
||||
.toString();
|
||||
return appendTo(new StringBuilder(label().length() + 6), label(), value()).toString();
|
||||
}
|
||||
|
||||
public String formatWithEquals() {
|
||||
|
@@ -16,18 +16,15 @@ package com.google.gerrit.server.util;
|
||||
|
||||
import com.google.gerrit.common.data.Capable;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public final class MagicBranch {
|
||||
private static final Logger log =
|
||||
LoggerFactory.getLogger(MagicBranch.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(MagicBranch.class);
|
||||
|
||||
public static final String NEW_CHANGE = "refs/for/";
|
||||
public static final String NEW_DRAFT_CHANGE = "refs/drafts/";
|
||||
@@ -66,15 +63,14 @@ public final class MagicBranch {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a (magic branch)/branch_name reference exists in the
|
||||
* destination repository and only returns Capable.OK if it does not match any.
|
||||
* Checks if a (magic branch)/branch_name reference exists in the destination repository and only
|
||||
* returns Capable.OK if it does not match any.
|
||||
*
|
||||
* These block the client from being able to even send us a pack file, as it
|
||||
* is very unlikely the user passed the --force flag and the new commit is
|
||||
* probably not going to fast-forward the branch.
|
||||
* <p>These block the client from being able to even send us a pack file, as it is very unlikely
|
||||
* the user passed the --force flag and the new commit is probably not going to fast-forward the
|
||||
* branch.
|
||||
*/
|
||||
public static Capable checkMagicBranchRefs(Repository repo,
|
||||
Project project) {
|
||||
public static Capable checkMagicBranchRefs(Repository repo, Project project) {
|
||||
Capable result = checkMagicBranchRef(NEW_CHANGE, repo, project);
|
||||
if (result != Capable.OK) {
|
||||
return result;
|
||||
@@ -91,8 +87,7 @@ public final class MagicBranch {
|
||||
return Capable.OK;
|
||||
}
|
||||
|
||||
private static Capable checkMagicBranchRef(String branchName, Repository repo,
|
||||
Project project) {
|
||||
private static Capable checkMagicBranchRef(String branchName, Repository repo, Project project) {
|
||||
Map<String, Ref> blockingFors;
|
||||
try {
|
||||
blockingFors = repo.getRefDatabase().getRefs(branchName);
|
||||
@@ -103,15 +98,16 @@ public final class MagicBranch {
|
||||
}
|
||||
if (!blockingFors.isEmpty()) {
|
||||
String projName = project.getName();
|
||||
log.error("Repository '" + projName
|
||||
+ "' needs the following refs removed to receive changes: "
|
||||
+ blockingFors.keySet());
|
||||
log.error(
|
||||
"Repository '"
|
||||
+ projName
|
||||
+ "' needs the following refs removed to receive changes: "
|
||||
+ blockingFors.keySet());
|
||||
return new Capable("One or more " + branchName + " names blocks change upload");
|
||||
}
|
||||
|
||||
return Capable.OK;
|
||||
}
|
||||
|
||||
private MagicBranch() {
|
||||
}
|
||||
private MagicBranch() {}
|
||||
}
|
||||
|
@@ -21,24 +21,26 @@ import com.google.gwtorm.server.SchemaFactory;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.util.Providers;
|
||||
|
||||
/**
|
||||
* Closeable version of a {@link RequestContext} with manually-specified
|
||||
* providers.
|
||||
*/
|
||||
/** Closeable version of a {@link RequestContext} with manually-specified providers. */
|
||||
public class ManualRequestContext implements RequestContext, AutoCloseable {
|
||||
private final Provider<CurrentUser> userProvider;
|
||||
private final Provider<ReviewDb> db;
|
||||
private final ThreadLocalRequestContext requestContext;
|
||||
private final RequestContext old;
|
||||
|
||||
public ManualRequestContext(CurrentUser user, SchemaFactory<ReviewDb> schemaFactory,
|
||||
ThreadLocalRequestContext requestContext) throws OrmException {
|
||||
public ManualRequestContext(
|
||||
CurrentUser user,
|
||||
SchemaFactory<ReviewDb> schemaFactory,
|
||||
ThreadLocalRequestContext requestContext)
|
||||
throws OrmException {
|
||||
this(Providers.of(user), schemaFactory, requestContext);
|
||||
}
|
||||
|
||||
public ManualRequestContext(Provider<CurrentUser> userProvider,
|
||||
public ManualRequestContext(
|
||||
Provider<CurrentUser> userProvider,
|
||||
SchemaFactory<ReviewDb> schemaFactory,
|
||||
ThreadLocalRequestContext requestContext) throws OrmException {
|
||||
ThreadLocalRequestContext requestContext)
|
||||
throws OrmException {
|
||||
this.userProvider = userProvider;
|
||||
this.db = Providers.of(schemaFactory.open());
|
||||
this.requestContext = requestContext;
|
||||
|
@@ -16,36 +16,31 @@ package com.google.gerrit.server.util;
|
||||
|
||||
import com.google.gerrit.common.data.RefConfigSection;
|
||||
import com.google.gerrit.server.project.RefPattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* Order the Ref Pattern by the most specific. This sort is done by:
|
||||
*
|
||||
* <ul>
|
||||
* <li>1 - The minor value of Levenshtein string distance between the branch
|
||||
* name and the regex string shortest example. A shorter distance is a more
|
||||
* specific match.
|
||||
* <li>2 - Finites first, infinities after.
|
||||
* <li>3 - Number of transitions. More transitions is more specific.
|
||||
* <li>4 - Length of the expression text.
|
||||
* <li>1 - The minor value of Levenshtein string distance between the branch name and the regex
|
||||
* string shortest example. A shorter distance is a more specific match.
|
||||
* <li>2 - Finites first, infinities after.
|
||||
* <li>3 - Number of transitions. More transitions is more specific.
|
||||
* <li>4 - Length of the expression text.
|
||||
* </ul>
|
||||
*
|
||||
* Levenshtein distance is a measure of the similarity between two strings.
|
||||
* The distance is the number of deletions, insertions, or substitutions
|
||||
* required to transform one string into another.
|
||||
* Levenshtein distance is a measure of the similarity between two strings. The distance is the
|
||||
* number of deletions, insertions, or substitutions required to transform one string into another.
|
||||
*
|
||||
* For example, if given refs/heads/m* and refs/heads/*, the distances are 5
|
||||
* and 6. It means that refs/heads/m* is more specific because it's closer to
|
||||
* refs/heads/master than refs/heads/*.
|
||||
* <p>For example, if given refs/heads/m* and refs/heads/*, the distances are 5 and 6. It means that
|
||||
* refs/heads/m* is more specific because it's closer to refs/heads/master than refs/heads/*.
|
||||
*
|
||||
* Another example could be refs/heads/* and refs/heads/[a-zA-Z]*, the
|
||||
* distances are both 6. Both are infinite, but refs/heads/[a-zA-Z]* has more
|
||||
* transitions, which after all turns it more specific.
|
||||
* <p>Another example could be refs/heads/* and refs/heads/[a-zA-Z]*, the distances are both 6. Both
|
||||
* are infinite, but refs/heads/[a-zA-Z]* has more transitions, which after all turns it more
|
||||
* specific.
|
||||
*/
|
||||
public final class MostSpecificComparator implements
|
||||
Comparator<RefConfigSection> {
|
||||
public final class MostSpecificComparator implements Comparator<RefConfigSection> {
|
||||
private final String refName;
|
||||
|
||||
public MostSpecificComparator(String refName) {
|
||||
@@ -111,8 +106,7 @@ public final class MostSpecificComparator implements
|
||||
|
||||
private int transitions(String pattern) {
|
||||
if (RefPattern.isRE(pattern)) {
|
||||
return RefPattern.toRegExp(pattern).toAutomaton()
|
||||
.getNumberOfTransitions();
|
||||
return RefPattern.toRegExp(pattern).toAutomaton().getNumberOfTransitions();
|
||||
|
||||
} else if (pattern.endsWith("/*")) {
|
||||
return pattern.length();
|
||||
|
@@ -25,12 +25,12 @@ import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* Helper to create one-off request contexts.
|
||||
* <p>
|
||||
* Each call to {@link #open()} opens a new {@link ReviewDb}, so this class
|
||||
* should only be used in a bounded try/finally block.
|
||||
* <p>
|
||||
* The user in the request context is {@link InternalUser} or the
|
||||
* {@link IdentifiedUser} associated to the userId passed as parameter.
|
||||
*
|
||||
* <p>Each call to {@link #open()} opens a new {@link ReviewDb}, so this class should only be used
|
||||
* in a bounded try/finally block.
|
||||
*
|
||||
* <p>The user in the request context is {@link InternalUser} or the {@link IdentifiedUser}
|
||||
* associated to the userId passed as parameter.
|
||||
*/
|
||||
@Singleton
|
||||
public class OneOffRequestContext {
|
||||
@@ -40,7 +40,8 @@ public class OneOffRequestContext {
|
||||
private final IdentifiedUser.GenericFactory identifiedUserFactory;
|
||||
|
||||
@Inject
|
||||
OneOffRequestContext(InternalUser.Factory userFactory,
|
||||
OneOffRequestContext(
|
||||
InternalUser.Factory userFactory,
|
||||
SchemaFactory<ReviewDb> schemaFactory,
|
||||
ThreadLocalRequestContext requestContext,
|
||||
IdentifiedUser.GenericFactory identifiedUserFactory) {
|
||||
@@ -51,12 +52,11 @@ public class OneOffRequestContext {
|
||||
}
|
||||
|
||||
public ManualRequestContext open() throws OrmException {
|
||||
return new ManualRequestContext(userFactory.create(),
|
||||
schemaFactory, requestContext);
|
||||
return new ManualRequestContext(userFactory.create(), schemaFactory, requestContext);
|
||||
}
|
||||
|
||||
public ManualRequestContext openAs(Account.Id userId) throws OrmException {
|
||||
return new ManualRequestContext(identifiedUserFactory.create(userId),
|
||||
schemaFactory, requestContext);
|
||||
return new ManualRequestContext(
|
||||
identifiedUserFactory.create(userId), schemaFactory, requestContext);
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@ package com.google.gerrit.server.util;
|
||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||
import com.google.gerrit.extensions.systemstatus.ServerInformation;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.apache.log4j.AsyncAppender;
|
||||
import org.apache.log4j.Layout;
|
||||
import org.apache.log4j.LogManager;
|
||||
@@ -31,10 +30,8 @@ public abstract class PluginLogFile implements LifecycleListener {
|
||||
private final Layout layout;
|
||||
|
||||
@Inject
|
||||
public PluginLogFile(SystemLog systemLog,
|
||||
ServerInformation serverInfo,
|
||||
String logName,
|
||||
Layout layout) {
|
||||
public PluginLogFile(
|
||||
SystemLog systemLog, ServerInformation serverInfo, String logName, Layout layout) {
|
||||
this.systemLog = systemLog;
|
||||
this.serverInfo = serverInfo;
|
||||
this.logName = logName;
|
||||
@@ -43,8 +40,7 @@ public abstract class PluginLogFile implements LifecycleListener {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
AsyncAppender asyncAppender =
|
||||
systemLog.createAsyncAppender(logName, layout);
|
||||
AsyncAppender asyncAppender = systemLog.createAsyncAppender(logName, layout);
|
||||
Logger logger = LogManager.getLogger(logName);
|
||||
logger.removeAppender(logName);
|
||||
logger.addAppender(asyncAppender);
|
||||
|
@@ -38,8 +38,7 @@ public class PluginRequestContext implements RequestContext {
|
||||
return new Provider<ReviewDb>() {
|
||||
@Override
|
||||
public ReviewDb get() {
|
||||
throw new ProvisionException(
|
||||
"Automatic ReviewDb only available in request scope");
|
||||
throw new ProvisionException("Automatic ReviewDb only available in request scope");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -16,13 +16,11 @@ package com.google.gerrit.server.util;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class RangeUtil {
|
||||
private static final Pattern RANGE_PATTERN =
|
||||
Pattern.compile("(>|>=|=|<|<=|)([+-]?\\d+)$");
|
||||
private static final Pattern RANGE_PATTERN = Pattern.compile("(>|>=|=|<|<=|)([+-]?\\d+)$");
|
||||
|
||||
private RangeUtil() {}
|
||||
|
||||
|
@@ -21,11 +21,9 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.primitives.Chars;
|
||||
|
||||
import dk.brics.automaton.Automaton;
|
||||
import dk.brics.automaton.RegExp;
|
||||
import dk.brics.automaton.RunAutomaton;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -88,12 +86,10 @@ public abstract class RegexListSearcher<T> implements Function<T, String> {
|
||||
}
|
||||
|
||||
if (prefixOnly) {
|
||||
return begin < end ? list.subList(begin, end) : ImmutableList.<T> of();
|
||||
return begin < end ? list.subList(begin, end) : ImmutableList.<T>of();
|
||||
}
|
||||
|
||||
return Iterables.filter(
|
||||
list.subList(begin, end),
|
||||
x -> pattern.run(apply(x)));
|
||||
return Iterables.filter(list.subList(begin, end), x -> pattern.run(apply(x)));
|
||||
}
|
||||
|
||||
public boolean hasMatch(List<T> list) {
|
||||
|
@@ -19,10 +19,11 @@ import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* The RequestContext is an interface exposing the fields that are needed
|
||||
* by the GerritGlobalModule scope.
|
||||
* The RequestContext is an interface exposing the fields that are needed by the GerritGlobalModule
|
||||
* scope.
|
||||
*/
|
||||
public interface RequestContext {
|
||||
CurrentUser getUser();
|
||||
|
||||
Provider<ReviewDb> getReviewDbProvider();
|
||||
}
|
||||
|
@@ -19,13 +19,13 @@ import com.google.common.hash.Hashing;
|
||||
import com.google.gerrit.common.TimeUtil;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/** Unique identifier for an end-user request, used in logs and similar. */
|
||||
public class RequestId {
|
||||
private static final String MACHINE_ID;
|
||||
|
||||
static {
|
||||
String id;
|
||||
try {
|
||||
@@ -48,10 +48,15 @@ public class RequestId {
|
||||
|
||||
private RequestId(String resourceId) {
|
||||
Hasher h = Hashing.sha1().newHasher();
|
||||
h.putLong(Thread.currentThread().getId())
|
||||
.putUnencodedChars(MACHINE_ID);
|
||||
str = "[" + resourceId + "-" + TimeUtil.nowTs().getTime() +
|
||||
"-" + h.hash().toString().substring(0, 8) + "]";
|
||||
h.putLong(Thread.currentThread().getId()).putUnencodedChars(MACHINE_ID);
|
||||
str =
|
||||
"["
|
||||
+ resourceId
|
||||
+ "-"
|
||||
+ TimeUtil.nowTs().getTime()
|
||||
+ "-"
|
||||
+ h.hash().toString().substring(0, 8)
|
||||
+ "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -27,21 +27,18 @@ import com.google.inject.Key;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Scope;
|
||||
import com.google.inject.servlet.ServletScopes;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Base class for propagating request-scoped data between threads.
|
||||
* <p>
|
||||
* Request scopes are typically linked to a {@link ThreadLocal}, which is only
|
||||
* available to the current thread. In order to allow background work involving
|
||||
* RequestScoped data, the ThreadLocal data must be copied from the request thread to
|
||||
* the new background thread.
|
||||
* <p>
|
||||
* Every type of RequestScope must provide an implementation of
|
||||
* RequestScopePropagator. See {@link #wrap(Callable)} for details on the
|
||||
* implementation, usage, and restrictions.
|
||||
*
|
||||
* <p>Request scopes are typically linked to a {@link ThreadLocal}, which is only available to the
|
||||
* current thread. In order to allow background work involving RequestScoped data, the ThreadLocal
|
||||
* data must be copied from the request thread to the new background thread.
|
||||
*
|
||||
* <p>Every type of RequestScope must provide an implementation of RequestScopePropagator. See
|
||||
* {@link #wrap(Callable)} for details on the implementation, usage, and restrictions.
|
||||
*
|
||||
* @see ThreadLocalRequestScopePropagator
|
||||
*/
|
||||
@@ -51,7 +48,8 @@ public abstract class RequestScopePropagator {
|
||||
private final ThreadLocalRequestContext local;
|
||||
private final Provider<RequestScopedReviewDbProvider> dbProviderProvider;
|
||||
|
||||
protected RequestScopePropagator(Scope scope,
|
||||
protected RequestScopePropagator(
|
||||
Scope scope,
|
||||
ThreadLocalRequestContext local,
|
||||
Provider<RequestScopedReviewDbProvider> dbProviderProvider) {
|
||||
this.scope = scope;
|
||||
@@ -60,26 +58,24 @@ public abstract class RequestScopePropagator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the current request state is available when the passed in
|
||||
* Callable is invoked.
|
||||
* Ensures that the current request state is available when the passed in Callable is invoked.
|
||||
*
|
||||
* <p>If needed wraps the passed in Callable in a new {@link Callable} that propagates the current
|
||||
* request state when the returned Callable is invoked. The method must be called in a request
|
||||
* scope and the returned Callable may only be invoked in a thread that is not already in a
|
||||
* request scope or is in the same request scope. The returned Callable will inherit toString()
|
||||
* from the passed in Callable. A {@link com.google.gerrit.server.git.WorkQueue.Executor} does not
|
||||
* accept a Callable, so there is no ProjectCallable implementation. Implementations of this
|
||||
* method must be consistent with Guice's {@link ServletScopes#continueRequest(Callable,
|
||||
* java.util.Map)}.
|
||||
*
|
||||
* <p>There are some limitations:
|
||||
*
|
||||
* If needed wraps the passed in Callable in a new {@link Callable} that
|
||||
* propagates the current request state when the returned Callable is invoked.
|
||||
* The method must be called in a request scope and the returned Callable may
|
||||
* only be invoked in a thread that is not already in a request scope or is in
|
||||
* the same request scope. The returned Callable will inherit toString() from
|
||||
* the passed in Callable. A
|
||||
* {@link com.google.gerrit.server.git.WorkQueue.Executor} does not accept a
|
||||
* Callable, so there is no ProjectCallable implementation. Implementations of
|
||||
* this method must be consistent with Guice's
|
||||
* {@link ServletScopes#continueRequest(Callable, java.util.Map)}.
|
||||
* <p>
|
||||
* There are some limitations:
|
||||
* <ul>
|
||||
* <li>Derived objects (i.e. anything marked created in a request scope) will
|
||||
* not be transported.</li>
|
||||
* <li>State changes to the request scoped context after this method is called
|
||||
* will not be seen in the continued thread.</li>
|
||||
* <li>Derived objects (i.e. anything marked created in a request scope) will not be
|
||||
* transported.
|
||||
* <li>State changes to the request scoped context after this method is called will not be seen
|
||||
* in the continued thread.
|
||||
* </ul>
|
||||
*
|
||||
* @param callable the Callable to wrap.
|
||||
@@ -88,8 +84,7 @@ public abstract class RequestScopePropagator {
|
||||
@SuppressWarnings("javadoc") // See GuiceRequestScopePropagator#wrapImpl
|
||||
public final <T> Callable<T> wrap(final Callable<T> callable) {
|
||||
final RequestContext callerContext = checkNotNull(local.getContext());
|
||||
final Callable<T> wrapped =
|
||||
wrapImpl(context(callerContext, cleanup(callable)));
|
||||
final Callable<T> wrapped = wrapImpl(context(callerContext, cleanup(callable)));
|
||||
return new Callable<T>() {
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
@@ -107,15 +102,14 @@ public abstract class RequestScopePropagator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps runnable in a new {@link Runnable} that propagates the current
|
||||
* request state when the runnable is invoked. The method must be called in a
|
||||
* request scope and the returned Runnable may only be invoked in a thread
|
||||
* that is not already in a request scope. The returned Runnable will inherit
|
||||
* toString() from the passed in Runnable. Furthermore, if the passed runnable
|
||||
* is of type {@link ProjectRunnable}, the returned runnable will be of the
|
||||
* same type with the methods delegated.
|
||||
* Wraps runnable in a new {@link Runnable} that propagates the current request state when the
|
||||
* runnable is invoked. The method must be called in a request scope and the returned Runnable may
|
||||
* only be invoked in a thread that is not already in a request scope. The returned Runnable will
|
||||
* inherit toString() from the passed in Runnable. Furthermore, if the passed runnable is of type
|
||||
* {@link ProjectRunnable}, the returned runnable will be of the same type with the methods
|
||||
* delegated.
|
||||
*
|
||||
* See {@link #wrap(Callable)} for details on implementation and usage.
|
||||
* <p>See {@link #wrap(Callable)} for details on implementation and usage.
|
||||
*
|
||||
* @param runnable the Runnable to wrap.
|
||||
* @return a new Runnable which will execute in the current request scope.
|
||||
@@ -175,27 +169,26 @@ public abstract class RequestScopePropagator {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #wrap(Callable)
|
||||
*/
|
||||
/** @see #wrap(Callable) */
|
||||
protected abstract <T> Callable<T> wrapImpl(Callable<T> callable);
|
||||
|
||||
protected <T> Callable<T> context(final RequestContext context,
|
||||
final Callable<T> callable) {
|
||||
protected <T> Callable<T> context(final RequestContext context, final Callable<T> callable) {
|
||||
return new Callable<T>() {
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
RequestContext old = local.setContext(new RequestContext() {
|
||||
@Override
|
||||
public CurrentUser getUser() {
|
||||
return context.getUser();
|
||||
}
|
||||
RequestContext old =
|
||||
local.setContext(
|
||||
new RequestContext() {
|
||||
@Override
|
||||
public CurrentUser getUser() {
|
||||
return context.getUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Provider<ReviewDb> getReviewDbProvider() {
|
||||
return dbProviderProvider.get();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public Provider<ReviewDb> getReviewDbProvider() {
|
||||
return dbProviderProvider.get();
|
||||
}
|
||||
});
|
||||
try {
|
||||
return callable.call();
|
||||
} finally {
|
||||
@@ -209,14 +202,17 @@ public abstract class RequestScopePropagator {
|
||||
return new Callable<T>() {
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
RequestCleanup cleanup = scope.scope(
|
||||
Key.get(RequestCleanup.class),
|
||||
new Provider<RequestCleanup>() {
|
||||
@Override
|
||||
public RequestCleanup get() {
|
||||
return new RequestCleanup();
|
||||
}
|
||||
}).get();
|
||||
RequestCleanup cleanup =
|
||||
scope
|
||||
.scope(
|
||||
Key.get(RequestCleanup.class),
|
||||
new Provider<RequestCleanup>() {
|
||||
@Override
|
||||
public RequestCleanup get() {
|
||||
return new RequestCleanup();
|
||||
}
|
||||
})
|
||||
.get();
|
||||
try {
|
||||
return callable.call();
|
||||
} finally {
|
||||
|
@@ -40,8 +40,7 @@ public class ServerRequestContext implements RequestContext {
|
||||
return new Provider<ReviewDb>() {
|
||||
@Override
|
||||
public ReviewDb get() {
|
||||
throw new ProvisionException(
|
||||
"Automatic ReviewDb only available in request scope");
|
||||
throw new ProvisionException("Automatic ReviewDb only available in request scope");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -23,8 +23,7 @@ import java.net.UnknownHostException;
|
||||
public final class SocketUtil {
|
||||
/** True if this InetAddress is a raw IPv6 in dotted quad notation. */
|
||||
public static boolean isIPv6(final InetAddress ip) {
|
||||
return ip instanceof Inet6Address
|
||||
&& ip.getHostName().equals(ip.getHostAddress());
|
||||
return ip instanceof Inet6Address && ip.getHostName().equals(ip.getHostAddress());
|
||||
}
|
||||
|
||||
/** Get the name or IP address, or {@code *} if this address is a wildcard IP. */
|
||||
@@ -110,12 +109,10 @@ public final class SocketUtil {
|
||||
}
|
||||
|
||||
/** Parse and resolve an address string, looking up the IP address. */
|
||||
public static InetSocketAddress resolve(final String desc,
|
||||
final int defaultPort) {
|
||||
public static InetSocketAddress resolve(final String desc, final int defaultPort) {
|
||||
final InetSocketAddress addr = parse(desc, defaultPort);
|
||||
if (addr.getAddress() != null && addr.getAddress().isAnyLocalAddress()) {
|
||||
return addr;
|
||||
|
||||
}
|
||||
try {
|
||||
final InetAddress host = InetAddress.getByName(addr.getHostName());
|
||||
@@ -125,6 +122,5 @@ public final class SocketUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private SocketUtil() {
|
||||
}
|
||||
private SocketUtil() {}
|
||||
}
|
||||
|
@@ -17,19 +17,17 @@ package com.google.gerrit.server.util;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
|
||||
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
|
||||
/**
|
||||
* It parses from a configuration file submodule sections.
|
||||
* <p>
|
||||
* Example of submodule sections:
|
||||
*
|
||||
* <p>Example of submodule sections:
|
||||
*
|
||||
* <pre>
|
||||
* [submodule "project-a"]
|
||||
@@ -49,9 +47,8 @@ public class SubmoduleSectionParser {
|
||||
private final String canonicalWebUrl;
|
||||
private final Branch.NameKey superProjectBranch;
|
||||
|
||||
public SubmoduleSectionParser(Config bbc,
|
||||
String canonicalWebUrl,
|
||||
Branch.NameKey superProjectBranch) {
|
||||
public SubmoduleSectionParser(
|
||||
Config bbc, String canonicalWebUrl, Branch.NameKey superProjectBranch) {
|
||||
this.bbc = bbc;
|
||||
this.canonicalWebUrl = canonicalWebUrl;
|
||||
this.superProjectBranch = superProjectBranch;
|
||||
@@ -74,8 +71,12 @@ public class SubmoduleSectionParser {
|
||||
String branch = bbc.getString("submodule", id, "branch");
|
||||
|
||||
try {
|
||||
if (url != null && url.length() > 0 && path != null && path.length() > 0
|
||||
&& branch != null && branch.length() > 0) {
|
||||
if (url != null
|
||||
&& url.length() > 0
|
||||
&& path != null
|
||||
&& path.length() > 0
|
||||
&& branch != null
|
||||
&& branch.length() > 0) {
|
||||
// All required fields filled.
|
||||
String project;
|
||||
|
||||
@@ -107,8 +108,7 @@ public class SubmoduleSectionParser {
|
||||
URI thisServerURI = new URI(canonicalWebUrl);
|
||||
String thisHost = thisServerURI.getHost();
|
||||
String targetHost = targetServerURI.getHost();
|
||||
if (thisHost == null || targetHost == null ||
|
||||
!targetHost.equalsIgnoreCase(thisHost)) {
|
||||
if (thisHost == null || targetHost == null || !targetHost.equalsIgnoreCase(thisHost)) {
|
||||
return null;
|
||||
}
|
||||
String p1 = targetServerURI.getPath();
|
||||
@@ -128,14 +128,14 @@ public class SubmoduleSectionParser {
|
||||
}
|
||||
|
||||
if (project.endsWith(Constants.DOT_GIT_EXT)) {
|
||||
project = project.substring(0, //
|
||||
project.length() - Constants.DOT_GIT_EXT.length());
|
||||
project =
|
||||
project.substring(
|
||||
0, //
|
||||
project.length() - Constants.DOT_GIT_EXT.length());
|
||||
}
|
||||
Project.NameKey projectKey = new Project.NameKey(project);
|
||||
return new SubmoduleSubscription(
|
||||
superProjectBranch,
|
||||
new Branch.NameKey(projectKey, branch),
|
||||
path);
|
||||
superProjectBranch, new Branch.NameKey(projectKey, branch), path);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
// Error in url syntax (in fact it is uri syntax)
|
||||
|
@@ -22,7 +22,8 @@ import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.AsyncAppender;
|
||||
import org.apache.log4j.DailyRollingFileAppender;
|
||||
@@ -35,13 +36,9 @@ import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Singleton
|
||||
public class SystemLog {
|
||||
private static final org.slf4j.Logger log =
|
||||
LoggerFactory.getLogger(SystemLog.class);
|
||||
private static final org.slf4j.Logger log = LoggerFactory.getLogger(SystemLog.class);
|
||||
|
||||
public static final String LOG4J_CONFIGURATION = "log4j.configuration";
|
||||
|
||||
@@ -86,8 +83,8 @@ public class SystemLog {
|
||||
if (appender != null) {
|
||||
async.addAppender(appender);
|
||||
} else {
|
||||
log.warn("No appender with the name: " + name + " was found. " + name
|
||||
+ " logging is disabled");
|
||||
log.warn(
|
||||
"No appender with the name: " + name + " was found. " + name + " logging is disabled");
|
||||
}
|
||||
}
|
||||
async.activateOptions();
|
||||
@@ -104,8 +101,7 @@ public class SystemLog {
|
||||
|
||||
private static final class DieErrorHandler implements ErrorHandler {
|
||||
@Override
|
||||
public void error(String message, Exception e, int errorCode,
|
||||
LoggingEvent event) {
|
||||
public void error(String message, Exception e, int errorCode, LoggingEvent event) {
|
||||
error(e != null ? e.getMessage() : message);
|
||||
}
|
||||
|
||||
@@ -120,19 +116,15 @@ public class SystemLog {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateOptions() {
|
||||
}
|
||||
public void activateOptions() {}
|
||||
|
||||
@Override
|
||||
public void setAppender(Appender appender) {
|
||||
}
|
||||
public void setAppender(Appender appender) {}
|
||||
|
||||
@Override
|
||||
public void setBackupAppender(Appender appender) {
|
||||
}
|
||||
public void setBackupAppender(Appender appender) {}
|
||||
|
||||
@Override
|
||||
public void setLogger(Logger logger) {
|
||||
}
|
||||
public void setLogger(Logger logger) {}
|
||||
}
|
||||
}
|
||||
|
@@ -29,9 +29,9 @@ import com.google.inject.name.Named;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
* ThreadLocalRequestContext manages the current RequestContext using a
|
||||
* ThreadLocal. When the context is set, the fields exposed by the context
|
||||
* are considered in scope. Otherwise, the FallbackRequestContext is used.
|
||||
* ThreadLocalRequestContext manages the current RequestContext using a ThreadLocal. When the
|
||||
* context is set, the fields exposed by the context are considered in scope. Otherwise, the
|
||||
* FallbackRequestContext is used.
|
||||
*/
|
||||
public class ThreadLocalRequestContext {
|
||||
private static final String FALLBACK = "FALLBACK";
|
||||
@@ -41,13 +41,13 @@ public class ThreadLocalRequestContext {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ThreadLocalRequestContext.class);
|
||||
bind(RequestContext.class).annotatedWith(Names.named(FALLBACK))
|
||||
bind(RequestContext.class)
|
||||
.annotatedWith(Names.named(FALLBACK))
|
||||
.to(FallbackRequestContext.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
RequestContext provideRequestContext(
|
||||
@Named(FALLBACK) RequestContext fallback) {
|
||||
RequestContext provideRequestContext(@Named(FALLBACK) RequestContext fallback) {
|
||||
return MoreObjects.firstNonNull(local.get(), fallback);
|
||||
}
|
||||
|
||||
@@ -61,8 +61,7 @@ public class ThreadLocalRequestContext {
|
||||
if (user.isIdentifiedUser()) {
|
||||
return user.asIdentifiedUser();
|
||||
}
|
||||
throw new ProvisionException(NotSignedInException.MESSAGE,
|
||||
new NotSignedInException());
|
||||
throw new ProvisionException(NotSignedInException.MESSAGE, new NotSignedInException());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -75,8 +74,7 @@ public class ThreadLocalRequestContext {
|
||||
private static final ThreadLocal<RequestContext> local = new ThreadLocal<>();
|
||||
|
||||
@Inject
|
||||
ThreadLocalRequestContext() {
|
||||
}
|
||||
ThreadLocalRequestContext() {}
|
||||
|
||||
public RequestContext setContext(@Nullable RequestContext ctx) {
|
||||
RequestContext old = getContext();
|
||||
|
@@ -18,21 +18,20 @@ import com.google.gerrit.server.config.RequestScopedReviewDbProvider;
|
||||
import com.google.inject.OutOfScopeException;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Scope;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* {@link RequestScopePropagator} implementation for request scopes based on
|
||||
* a {@link ThreadLocal} context.
|
||||
* {@link RequestScopePropagator} implementation for request scopes based on a {@link ThreadLocal}
|
||||
* context.
|
||||
*
|
||||
* @param <C> "context" type stored in the {@link ThreadLocal}.
|
||||
*/
|
||||
public abstract class ThreadLocalRequestScopePropagator<C>
|
||||
extends RequestScopePropagator {
|
||||
public abstract class ThreadLocalRequestScopePropagator<C> extends RequestScopePropagator {
|
||||
|
||||
private final ThreadLocal<C> threadLocal;
|
||||
|
||||
protected ThreadLocalRequestScopePropagator(Scope scope,
|
||||
protected ThreadLocalRequestScopePropagator(
|
||||
Scope scope,
|
||||
ThreadLocal<C> threadLocal,
|
||||
ThreadLocalRequestContext local,
|
||||
Provider<RequestScopedReviewDbProvider> dbProviderProvider) {
|
||||
@@ -40,9 +39,7 @@ public abstract class ThreadLocalRequestScopePropagator<C>
|
||||
this.threadLocal = threadLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RequestScopePropagator#wrap(Callable)
|
||||
*/
|
||||
/** @see RequestScopePropagator#wrap(Callable) */
|
||||
@Override
|
||||
protected final <T> Callable<T> wrapImpl(final Callable<T> callable) {
|
||||
final C ctx = continuingContext(requireContext());
|
||||
@@ -73,15 +70,13 @@ public abstract class ThreadLocalRequestScopePropagator<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new context object based on the passed in context that has no
|
||||
* request scoped objects initialized.
|
||||
* <p>
|
||||
* Note that some code paths expect request-scoped objects like
|
||||
* {@code CurrentUser} to be constructible starting from just the context
|
||||
* object returned by this method. For example, in the SSH scope, the context
|
||||
* includes the {@code SshSession}, which is used by
|
||||
* {@code SshCurrentUserProvider} to construct a new {@code CurrentUser} in
|
||||
* the new thread.
|
||||
* Returns a new context object based on the passed in context that has no request scoped objects
|
||||
* initialized.
|
||||
*
|
||||
* <p>Note that some code paths expect request-scoped objects like {@code CurrentUser} to be
|
||||
* constructible starting from just the context object returned by this method. For example, in
|
||||
* the SSH scope, the context includes the {@code SshSession}, which is used by {@code
|
||||
* SshCurrentUserProvider} to construct a new {@code CurrentUser} in the new thread.
|
||||
*
|
||||
* @param ctx the context to continue.
|
||||
* @return a new context.
|
||||
|
@@ -21,7 +21,9 @@ public class TreeFormatter {
|
||||
|
||||
public interface TreeNode {
|
||||
String getDisplayName();
|
||||
|
||||
boolean isVisible();
|
||||
|
||||
SortedSet<? extends TreeNode> getChildren();
|
||||
}
|
||||
|
||||
@@ -62,8 +64,7 @@ public class TreeFormatter {
|
||||
printTree(rootNode, 0, true);
|
||||
}
|
||||
|
||||
private void printTree(final TreeNode node, final int level,
|
||||
final boolean isLast) {
|
||||
private void printTree(final TreeNode node, final int level, final boolean isLast) {
|
||||
printNode(node, level, isLast);
|
||||
final SortedSet<? extends TreeNode> childNodes = node.getChildren();
|
||||
int i = 0;
|
||||
@@ -80,8 +81,7 @@ public class TreeFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
private void printNode(final TreeNode node, final int level,
|
||||
final boolean isLast) {
|
||||
private void printNode(final TreeNode node, final int level, final boolean isLast) {
|
||||
printIndention(level);
|
||||
stdout.print(isLast ? LAST_NODE_PREFIX : NODE_PREFIX);
|
||||
if (node.isVisible()) {
|
||||
|
Reference in New Issue
Block a user