test_class.declarator: writer
test_class.modifier: private
test_class.original_string: private MembershipWriter writer;
test_class.type: MembershipWriter
test_class.var_name: writer
test_class.file: oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipWriterTest.java
test_class.identifier: MembershipWriterTest
test_class.superclass: extends MembershipBaseTest
test_case.body: @Test
      public void testAddFewMembers() throws Exception {
          Group g = createGroup();
          g.addMembers(createGroup().getID(), createUser().getID());
  
          assertFalse(getTree(g).hasChild(REP_MEMBERS_LIST));
      }
test_case.class_method_signature: MembershipWriterTest.testAddFewMembers()
test_case.full_signature: @Test public void testAddFewMembers()
test_case.identifier: testAddFewMembers
test_case.invocations: createGroup addMembers getID createGroup getID createUser assertFalse hasChild getTree
test_case.modifiers: @Test public
test_case.parameters: ()
test_case.return: void
test_case.signature: void testAddFewMembers()
focal_class.declarator: DEFAULT_MEMBERSHIP_THRESHOLD = 100
focal_class.modifier: public static final
focal_class.original_string: public static final int DEFAULT_MEMBERSHIP_THRESHOLD = 100;
focal_class.type: int
focal_class.var_name: DEFAULT_MEMBERSHIP_THRESHOLD
focal_class.declarator: membershipSizeThreshold = DEFAULT_MEMBERSHIP_THRESHOLD
focal_class.modifier: private
focal_class.original_string: private int membershipSizeThreshold = DEFAULT_MEMBERSHIP_THRESHOLD;
focal_class.type: int
focal_class.var_name: membershipSizeThreshold
focal_class.file: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/MembershipWriter.java
focal_class.identifier: MembershipWriter
focal_class.class_method_signature: MembershipWriter.setMembershipSizeThreshold(int membershipSizeThreshold)
focal_class.full_signature:  void setMembershipSizeThreshold(int membershipSizeThreshold)
focal_class.identifier: setMembershipSizeThreshold
focal_class.parameters: (int membershipSizeThreshold)
focal_class.return: void
focal_class.signature: void setMembershipSizeThreshold(int membershipSizeThreshold)
focal_class.class_method_signature: MembershipWriter.addMember(@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.full_signature:  boolean addMember(@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.identifier: addMember
focal_class.parameters: (@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.return: boolean
focal_class.signature: boolean addMember(@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.class_method_signature: MembershipWriter.addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.full_signature: @NotNull Set<String> addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.identifier: addMembers
focal_class.modifiers: @NotNull
focal_class.parameters: (@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.return: Set<String>
focal_class.signature: Set<String> addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.class_method_signature: MembershipWriter.createMemberRefTree(@NotNull Tree groupTree, @NotNull Tree membersList)
focal_class.full_signature: @NotNull private static Tree createMemberRefTree(@NotNull Tree groupTree, @NotNull Tree membersList)
focal_class.identifier: createMemberRefTree
focal_class.modifiers: @NotNull private static
focal_class.parameters: (@NotNull Tree groupTree, @NotNull Tree membersList)
focal_class.return: Tree
focal_class.signature: Tree createMemberRefTree(@NotNull Tree groupTree, @NotNull Tree membersList)
focal_class.class_method_signature: MembershipWriter.nextRefNodeName(@NotNull Tree membersList)
focal_class.full_signature: @NotNull private static String nextRefNodeName(@NotNull Tree membersList)
focal_class.identifier: nextRefNodeName
focal_class.modifiers: @NotNull private static
focal_class.parameters: (@NotNull Tree membersList)
focal_class.return: String
focal_class.signature: String nextRefNodeName(@NotNull Tree membersList)
focal_class.class_method_signature: MembershipWriter.removeMember(@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.full_signature:  boolean removeMember(@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.identifier: removeMember
focal_class.parameters: (@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.return: boolean
focal_class.signature: boolean removeMember(@NotNull Tree groupTree, @NotNull String memberContentId)
focal_class.class_method_signature: MembershipWriter.removeMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.full_signature: @NotNull Set<String> removeMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.identifier: removeMembers
focal_class.modifiers: @NotNull
focal_class.parameters: (@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_class.return: Set<String>
focal_class.signature: Set<String> removeMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_method.body: @NotNull
      Set<String> addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds) {
          // check all possible rep:members properties for the new member and also find the one with the least values
          Tree membersList = groupTree.getChild(UserConstants.REP_MEMBERS_LIST);
          Iterator<Tree> trees = Iterators.concat(
                  Iterators.singletonIterator(groupTree),
                  membersList.getChildren().iterator()
          );
  
          Set<String> failed = new HashSet<>(memberIds.size());
          int bestCount = membershipSizeThreshold;
          PropertyState bestProperty = null;
          Tree bestTree = null;
  
          // remove existing memberIds from the map and find best-matching tree
          // for the insertion of the new members.
          while (trees.hasNext() && !memberIds.isEmpty()) {
              Tree t = trees.next();
              PropertyState refs = t.getProperty(UserConstants.REP_MEMBERS);
              if (refs != null) {
                  int numRefs = 0;
                  for (String ref : refs.getValue(Type.WEAKREFERENCES)) {
                      String id = memberIds.remove(ref);
                      if (id != null) {
                          failed.add(id);
                          if (memberIds.isEmpty()) {
                              break;
                          }
                      }
                      numRefs++;
                  }
                  if (numRefs < bestCount) {
                      bestCount = numRefs;
                      bestProperty = refs;
                      bestTree = t;
                  }
              }
          }
  
          // update member content structure by starting inserting new member IDs
          // with the best-matching property and create new member-ref-nodes as needed.
          if (!memberIds.isEmpty()) {
              PropertyBuilder<String> propertyBuilder;
              int propCnt;
              if (bestProperty == null) {
                  // we don't have a good candidate to store the new members.
                  // so there are no members at all or all are full
                  if (!groupTree.hasProperty(UserConstants.REP_MEMBERS)) {
                      bestTree = groupTree;
                  } else {
                      bestTree = createMemberRefTree(groupTree, membersList);
                  }
                  propertyBuilder = PropertyBuilder.array(Type.WEAKREFERENCE, UserConstants.REP_MEMBERS);
                  propCnt = 0;
              } else {
                  propertyBuilder = PropertyBuilder.copy(Type.WEAKREFERENCE, bestProperty);
                  propCnt = bestCount;
              }
              // if adding all new members to best-property would exceed the threshold
              // the new ids need to be distributed to different member-ref-nodes
              // for simplicity this is achieved by introducing new tree(s)
              if ((propCnt + memberIds.size()) > membershipSizeThreshold) {
                  while (!memberIds.isEmpty()) {
                      Set<String> s = new HashSet<>();
                      Iterator<String> it = memberIds.keySet().iterator();
                      while (propCnt < membershipSizeThreshold && it.hasNext()) {
                          s.add(it.next());
                          it.remove();
                          propCnt++;
                      }
                      propertyBuilder.addValues(s);
                      bestTree.setProperty(propertyBuilder.getPropertyState());
  
                      if (it.hasNext()) {
                          // continue filling the next (new) node + propertyBuilder pair
                          propCnt = 0;
                          bestTree = createMemberRefTree(groupTree, membersList);
                          propertyBuilder = PropertyBuilder.array(Type.WEAKREFERENCE, UserConstants.REP_MEMBERS);
                      }
                  }
              } else {
                  propertyBuilder.addValues(memberIds.keySet());
                  bestTree.setProperty(propertyBuilder.getPropertyState());
              }
          }
          return failed;
      }
focal_method.class_method_signature: MembershipWriter.addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_method.full_signature: @NotNull Set<String> addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_method.identifier: addMembers
focal_method.invocations: getChild concat singletonIterator iterator getChildren size hasNext isEmpty next getProperty getValue remove add isEmpty isEmpty hasProperty createMemberRefTree array copy size isEmpty iterator keySet hasNext add next remove addValues setProperty getPropertyState hasNext createMemberRefTree array addValues keySet setProperty getPropertyState
focal_method.modifiers: @NotNull
focal_method.parameters: (@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)
focal_method.return: Set<String>
focal_method.signature: Set<String> addMembers(@NotNull Tree groupTree, @NotNull Map<String, String> memberIds)