summaryrefslogtreecommitdiffstats
path: root/java/com/google/gerrit/server/group/db/GroupConfigEntry.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/gerrit/server/group/db/GroupConfigEntry.java')
-rw-r--r--java/com/google/gerrit/server/group/db/GroupConfigEntry.java229
1 files changed, 229 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/group/db/GroupConfigEntry.java b/java/com/google/gerrit/server/group/db/GroupConfigEntry.java
new file mode 100644
index 0000000000..eff34588d8
--- /dev/null
+++ b/java/com/google/gerrit/server/group/db/GroupConfigEntry.java
@@ -0,0 +1,229 @@
+// Copyright (C) 2017 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.server.group.db;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.group.InternalGroup;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * A basic property of a group.
+ *
+ * <p>Each property knows how to read and write its value from/to a JGit {@link Config} file.
+ *
+ * <p><strong>Warning: </strong>This class is a low-level API for properties of groups in NoteDb. It
+ * may only be used by {@link GroupConfig}. Other classes should use {@link InternalGroupUpdate} to
+ * modify the properties of a group.
+ */
+enum GroupConfigEntry {
+ /**
+ * The numeric ID of a group. This property is equivalent to {@link InternalGroup#getId()}.
+ *
+ * <p>This is a mandatory property which may not be changed.
+ */
+ ID("id") {
+ @Override
+ void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config)
+ throws ConfigInvalidException {
+ int id = config.getInt(SECTION_NAME, super.keyName, -1);
+ if (id < 0) {
+ throw new ConfigInvalidException(
+ String.format(
+ "ID of the group %s must not be negative, found %d", groupUuid.get(), id));
+ }
+ group.setId(new AccountGroup.Id(id));
+ }
+
+ @Override
+ void initNewConfig(Config config, InternalGroupCreation group) {
+ AccountGroup.Id id = group.getId();
+
+ // Do not use config.setInt(...) to write the group ID because config.setInt(...) persists
+ // integers that can be expressed in KiB as a unit strings, e.g. "1024" is stored as "1k".
+ // Using config.setString(...) ensures that group IDs are human readable.
+ config.setString(SECTION_NAME, null, super.keyName, Integer.toString(id.get()));
+ }
+
+ @Override
+ void updateConfigValue(Config config, InternalGroupUpdate groupUpdate) {
+ // Updating the ID is not supported.
+ }
+ },
+ /**
+ * The name of a group. This property is equivalent to {@link InternalGroup#getNameKey()}.
+ *
+ * <p>This is a mandatory property.
+ */
+ NAME("name") {
+ @Override
+ void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config) {
+ String name = config.getString(SECTION_NAME, null, super.keyName);
+ // An empty name is invalid in NoteDb; GroupConfig will refuse to store it and it might be
+ // unusable in permissions. But, it was technically valid in the ReviewDb storage layer, and
+ // the NoteDb migration converted such groups faithfully, so we need to be able to read them
+ // back here.
+ name = Strings.nullToEmpty(name);
+ group.setNameKey(new AccountGroup.NameKey(name));
+ }
+
+ @Override
+ void initNewConfig(Config config, InternalGroupCreation group) {
+ AccountGroup.NameKey name = group.getNameKey();
+ config.setString(SECTION_NAME, null, super.keyName, name.get());
+ }
+
+ @Override
+ void updateConfigValue(Config config, InternalGroupUpdate groupUpdate) {
+ groupUpdate
+ .getName()
+ .ifPresent(name -> config.setString(SECTION_NAME, null, super.keyName, name.get()));
+ }
+ },
+ /**
+ * The description of a group. This property is equivalent to {@link
+ * InternalGroup#getDescription()}.
+ *
+ * <p>It defaults to {@code null} if not set.
+ */
+ DESCRIPTION("description") {
+ @Override
+ void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config) {
+ String description = config.getString(SECTION_NAME, null, super.keyName);
+ group.setDescription(Strings.emptyToNull(description));
+ }
+
+ @Override
+ void initNewConfig(Config config, InternalGroupCreation group) {
+ config.setString(SECTION_NAME, null, super.keyName, null);
+ }
+
+ @Override
+ void updateConfigValue(Config config, InternalGroupUpdate groupUpdate) {
+ groupUpdate
+ .getDescription()
+ .ifPresent(
+ description ->
+ config.setString(
+ SECTION_NAME, null, super.keyName, Strings.emptyToNull(description)));
+ }
+ },
+ /**
+ * The owner of a group. This property is equivalent to {@link InternalGroup#getOwnerGroupUUID()}.
+ *
+ * <p>It defaults to the group itself if not set.
+ */
+ OWNER_GROUP_UUID("ownerGroupUuid") {
+ @Override
+ void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config)
+ throws ConfigInvalidException {
+ String ownerGroupUuid = config.getString(SECTION_NAME, null, super.keyName);
+ if (Strings.isNullOrEmpty(ownerGroupUuid)) {
+ throw new ConfigInvalidException(
+ String.format("Owner UUID of the group %s must be defined", groupUuid.get()));
+ }
+ group.setOwnerGroupUUID(new AccountGroup.UUID(ownerGroupUuid));
+ }
+
+ @Override
+ void initNewConfig(Config config, InternalGroupCreation group) {
+ config.setString(SECTION_NAME, null, super.keyName, group.getGroupUUID().get());
+ }
+
+ @Override
+ void updateConfigValue(Config config, InternalGroupUpdate groupUpdate) {
+ groupUpdate
+ .getOwnerGroupUUID()
+ .ifPresent(
+ ownerGroupUuid ->
+ config.setString(SECTION_NAME, null, super.keyName, ownerGroupUuid.get()));
+ }
+ },
+ /**
+ * A flag indicating the visibility of a group. This property is equivalent to {@link
+ * InternalGroup#isVisibleToAll()}.
+ *
+ * <p>It defaults to {@code false} if not set.
+ */
+ VISIBLE_TO_ALL("visibleToAll") {
+ @Override
+ void readFromConfig(AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config) {
+ boolean visibleToAll = config.getBoolean(SECTION_NAME, super.keyName, false);
+ group.setVisibleToAll(visibleToAll);
+ }
+
+ @Override
+ void initNewConfig(Config config, InternalGroupCreation group) {
+ config.setBoolean(SECTION_NAME, null, super.keyName, false);
+ }
+
+ @Override
+ void updateConfigValue(Config config, InternalGroupUpdate groupUpdate) {
+ groupUpdate
+ .getVisibleToAll()
+ .ifPresent(
+ visibleToAll -> config.setBoolean(SECTION_NAME, null, super.keyName, visibleToAll));
+ }
+ };
+
+ private static final String SECTION_NAME = "group";
+
+ private final String keyName;
+
+ GroupConfigEntry(String keyName) {
+ this.keyName = keyName;
+ }
+
+ /**
+ * Reads the corresponding property of this {@code GroupConfigEntry} from the given {@code
+ * Config}. The read value is written to the corresponding property of {@code
+ * InternalGroup.Builder}.
+ *
+ * @param groupUuid the UUID of the group (necessary for helpful error messages)
+ * @param group the {@code InternalGroup.Builder} whose property value should be set
+ * @param config the {@code Config} from which the value of the property should be read
+ * @throws ConfigInvalidException if the property has an unexpected value
+ */
+ abstract void readFromConfig(
+ AccountGroup.UUID groupUuid, InternalGroup.Builder group, Config config)
+ throws ConfigInvalidException;
+
+ /**
+ * Initializes the corresponding property of this {@code GroupConfigEntry} in the given {@code
+ * Config}.
+ *
+ * <p>If the specified {@code InternalGroupCreation} has an entry for the property, that value is
+ * used. If not, the default value for the property is set. In any case, an existing entry for the
+ * property in the {@code Config} will be overwritten.
+ *
+ * @param config a new {@code Config}, typically without an entry for the property
+ * @param group an {@code InternalGroupCreation} detailing the initial value of mandatory group
+ * properties
+ */
+ abstract void initNewConfig(Config config, InternalGroupCreation group);
+
+ /**
+ * Updates the corresponding property of this {@code GroupConfigEntry} in the given {@code Config}
+ * if the {@code InternalGroupUpdate} mentions a modification.
+ *
+ * <p>This call is a no-op if the {@code InternalGroupUpdate} doesn't contain a modification for
+ * the property.
+ *
+ * @param config a {@code Config} for which the property should be updated
+ * @param groupUpdate an {@code InternalGroupUpdate} detailing the modifications on a group
+ */
+ abstract void updateConfigValue(Config config, InternalGroupUpdate groupUpdate);
+}