001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.repository.data.holder.values; 017 018import java.util.List; 019import java.util.Map; 020import java.util.Set; 021import java.util.function.Function; 022import java.util.stream.Collectors; 023import java.util.stream.IntStream; 024 025/** 026 * Wrapper for a synchronizable repeater.<br> 027 * Contains the repeater values and a mapping between stored entry positions and new ones. 028 */ 029public final class SynchronizableRepeater 030{ 031 private List<Map<String, Object>> _entries; 032 private Map<Integer, Integer> _positionsMapping; 033 private List<Integer> _replacePositions; 034 private Set<Integer> _removedEntries; 035 private Mode _mode; 036 037 /** 038 * The entries write mode. 039 */ 040 public static enum Mode 041 { 042 /** The entries will replace all existing values */ 043 REPLACE_ALL, 044 /** The entries will replace specific entries */ 045 REPLACE, 046 /** The entries will be appended after existing entries */ 047 APPEND 048 } 049 050 private SynchronizableRepeater(List<Map<String, Object>> entries, Mode mode) 051 { 052 _entries = entries; 053 _mode = mode; 054 } 055 056 private SynchronizableRepeater(List<Map<String, Object>> entries, Map<Integer, Integer> positionsMapping, List<Integer> replacePositions, Set<Integer> removedEntries, Mode mode) 057 { 058 _entries = entries; 059 _positionsMapping = positionsMapping; 060 _replacePositions = replacePositions; 061 _removedEntries = removedEntries; 062 _mode = mode; 063 } 064 065 /** 066 * Replace all values in a repeater, optionally moving or removing entries. Entries not present in the mapping will be removed. 067 * @param entries the new repeater values. 068 * @param positionsMapping a mapping from stored positions to new ones. No mapping for an existing entry means removal. A null mapping means the identity mapping. 069 * @return a {@link SynchronizableRepeater} in replace mode. 070 */ 071 public static SynchronizableRepeater replaceAll(List<Map<String, Object>> entries, Map<Integer, Integer> positionsMapping) 072 { 073 SynchronizableRepeater repeater = new SynchronizableRepeater(entries, Mode.REPLACE_ALL); 074 repeater._positionsMapping = positionsMapping != null ? positionsMapping : IntStream.rangeClosed(1, entries.size()).boxed().collect(Collectors.toMap(Function.identity(), Function.identity())); 075 076 return repeater; 077 } 078 079 /** 080 * Replace values in a repeater. 081 * @param entries the new repeater values. 082 * @param positions the positions of the provided entries in the repeater. A null List means replacing the first entries. 083 * @return a {@link SynchronizableRepeater} in replace mode. 084 */ 085 public static SynchronizableRepeater replace(List<Map<String, Object>> entries, List<Integer> positions) 086 { 087 assert positions == null || positions.size() == entries.size(); 088 SynchronizableRepeater repeater = new SynchronizableRepeater(entries, Mode.REPLACE); 089 repeater._replacePositions = positions != null ? positions : IntStream.rangeClosed(1, entries.size()).boxed().collect(Collectors.toList()); 090 091 return repeater; 092 } 093 094 /** 095 * Append and/or remove entries in a repeater. 096 * @param newEntries the entries to be appended to the repeater. 097 * @param removedEntries the entries to be removed from the repeater. 098 * @return a {@link SynchronizableRepeater} in append mode. 099 */ 100 public static SynchronizableRepeater appendOrRemove(List<Map<String, Object>> newEntries, Set<Integer> removedEntries) 101 { 102 SynchronizableRepeater repeater = new SynchronizableRepeater(newEntries, Mode.APPEND); 103 repeater._removedEntries = removedEntries; 104 105 return repeater; 106 } 107 108 /** 109 * Copy the provided repeater, optionally replacing entries with given ones. 110 * @param repeater the SynchronizableRepeater to copy 111 * @param newEntries the new entries values 112 * @return a new SynchronizableRepeater 113 */ 114 public static SynchronizableRepeater copy(SynchronizableRepeater repeater, List<Map<String, Object>> newEntries) 115 { 116 return new SynchronizableRepeater(newEntries != null ? newEntries : repeater.getEntries(), repeater.getPositionsMapping(), repeater.getReplacePositions(), repeater.getRemovedEntries(), repeater.getMode()); 117 } 118 119 /** 120 * Returns the mapping from stored positions to new ones. 121 * @return the mapping from stored positions to new ones. 122 */ 123 public Map<Integer, Integer> getPositionsMapping() 124 { 125 return _positionsMapping; 126 } 127 128 /** 129 * Returns the positions of replacing entries. 130 * @return the positions of replacing entries. 131 */ 132 public List<Integer> getReplacePositions() 133 { 134 return _replacePositions; 135 } 136 137 /** 138 * Returns the new repeater values. 139 * @return the new repeater values. 140 */ 141 public List<Map<String, Object>> getEntries() 142 { 143 return _entries; 144 } 145 146 /** 147 * Returns the entries to be removed. <br> 148 * Only relevant for append mode.<br> 149 * For replace mode, removed entries are carried trough the positions mapping. 150 * @return the new repeater values. 151 */ 152 public Set<Integer> getRemovedEntries() 153 { 154 return _removedEntries; 155 } 156 157 /** 158 * Returns the write mode for provided entries. 159 * @return the write mode 160 */ 161 public Mode getMode() 162 { 163 return _mode; 164 } 165}