1 package net.sourceforge.argval.version;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Set;
9 import java.util.SortedSet;
10 import java.util.TreeSet;
11 import java.util.regex.Matcher;
12 import java.util.regex.Pattern;
13
14 import net.sourceforge.argval.collection.CollectionUtil;
15 import net.sourceforge.argval.utils.StringUtil;
16
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20
21
22
23
24
25 public class VersionHierarchyImpl implements VersionHierarchy
26 {
27 protected Logger logger = LoggerFactory.getLogger(VersionHierarchyImpl.class);
28 private final String versionPartSeparator;
29 private final Map<String, VersionHierarchyImpl> versionMap = new HashMap<String, VersionHierarchyImpl>();
30
31 public VersionHierarchyImpl()
32 {
33 this(VersionHierarchy.VERSION_PART_SEPARATOR);
34 }
35 public VersionHierarchyImpl(String versionPartSeparator) {
36 super();
37 this.versionPartSeparator = versionPartSeparator;
38 }
39
40
41 public String getVersionPartSeparator() {
42 return versionPartSeparator;
43 }
44
45
46 public void addVersion(VersionNumber version)
47 {
48 addVersion(version.getPartitionedVersion());
49 }
50
51 public void addVersion(final String versionStr) {
52 addVersion(convertVersion(versionStr));
53 }
54
55 public void addVersion(final List<String> version)
56 {
57 if (version == null || version.size() == 0)
58 {
59 return;
60 }
61 final ArrayList<String> versionList = (version instanceof ArrayList<?>)
62 ? (ArrayList<String>)version
63 : new ArrayList<String>(version);
64
65 final String part = versionList.remove(0);
66 if (! this.versionMap.containsKey(part))
67 {
68 this.versionMap.put(part, new VersionHierarchyImpl());
69 }
70 this.versionMap.get(part).addVersion(versionList);
71 }
72
73 public List<String> convertVersion(final String versionStr) {
74 return StringUtil.convertToList(versionStr, getVersionPartSeparator());
75 }
76
77
78 public boolean isCompatible(VersionNumber version) {
79 return isCompatible(version.getPartitionedVersion());
80 }
81
82
83 public boolean isCompatible(String versionStr) {
84 return isCompatible(convertVersion(versionStr));
85 }
86
87
88 public boolean isCompatible(List<String> version) {
89 if (version == null || version.size() == 0) {
90 throw new IllegalArgumentException("Argument 'version' can not be null or an empty list.");
91 }
92 boolean isCompatibel = isCompatibel(version, 0);
93 logger.trace("isCompatible( " + CollectionUtil.toString(version) + " ) " + isCompatibel);
94 return isCompatibel;
95 }
96
97 private boolean isCompatibel(List<String> version, int index) {
98 final boolean isCompatibel;
99 if (index >= version.size()) {
100 isCompatibel = this.versionMap.size() == 0;
101 }
102 else {
103 if (this.versionMap.containsKey(version.get(index))) {
104 isCompatibel = this.versionMap.get(version.get(index)).isCompatibel(version, index + 1);
105 }
106 else {
107 if (this.versionMap.size() > 0) {
108 SortedSet<String> set = new TreeSet<String>(this.versionMap.keySet());
109
110
111
112 Pattern pattern = Pattern.compile("(\\d*)");
113 Matcher matcherA = pattern.matcher(version.get(index));
114 Matcher matcherB = pattern.matcher(set.last());
115 if (matcherA.matches() && matcherB.matches())
116 {
117 Integer valueA = Integer.valueOf(version.get(index));
118 Integer valueB = Integer.valueOf(set.last());
119 isCompatibel = valueA >= valueB;
120 }
121 else
122 {
123 isCompatibel = version.get(index).compareTo(set.last()) >= 0;
124 }
125 }
126 else {
127 isCompatibel = true;
128 }
129 }
130 }
131
132 return isCompatibel;
133 }
134
135 public String toString() {
136 List<String> allVersions = getRegisteredVersionAsStings();
137 return CollectionUtil.toString(allVersions);
138 }
139
140 public List<String> getRegisteredVersionAsStings()
141 {
142 final List<String> versionList = new ArrayList<String>();
143 visit("", versionList);
144 return versionList;
145 }
146
147 private void visit(final String versionStr, final List<String> versionList) {
148 if (this.versionMap.size() == 0) {
149 versionList.add(versionStr);
150 return;
151 }
152
153 for (final String part : new TreeSet<String>(versionMap.keySet())) {
154 versionMap.get(part).visit(versionStr + ((versionStr.length() > 0) ? VERSION_PART_SEPARATOR : "") + part, versionList);
155 }
156 }
157
158 private void visit(final List<String> singleVersion, final List<VersionNumber> versionList) {
159 if (this.versionMap.size() == 0) {
160 versionList.add(new VersionNumberImpl(singleVersion));
161 return;
162 }
163
164 Set<Integer> orderedNumbers = createOrderedNumberSet(versionMap.keySet());
165 if (orderedNumbers.size() > 0) {
166
167 for (final Integer part : orderedNumbers) {
168 ArrayList<String> newSingleList = new ArrayList<String>(singleVersion);
169 newSingleList.add(part.toString());
170 versionMap.get(part.toString()).visit(newSingleList, versionList);
171 }
172 }
173 else {
174 for (final String part : new TreeSet<String>(versionMap.keySet())) {
175 ArrayList<String> newSingleList = new ArrayList<String>(singleVersion);
176 newSingleList.add(part);
177 versionMap.get(part).visit(newSingleList, versionList);
178 }
179 }
180 }
181
182 private Set<Integer> createOrderedNumberSet(Set<String> versionStrSet) {
183 final TreeSet<Integer> numbers = new TreeSet<Integer>();
184 boolean isOnlyNumbers = true;
185 for (Iterator<String> iter = versionStrSet.iterator(); iter.hasNext(); ) {
186 String versionStr = iter.next();
187 if (Pattern.matches("\\d*", versionStr)) {
188 numbers.add(Integer.valueOf(versionStr));
189 }
190 else {
191 isOnlyNumbers = false;
192 }
193 }
194
195 if (! isOnlyNumbers) {
196 numbers.clear();
197 }
198 return numbers;
199 }
200
201
202 public List<VersionNumber> getRegisteredVersionNumbers() {
203 final List<VersionNumber> versionList = new ArrayList<VersionNumber>();
204 visit(new ArrayList<String>(), versionList);
205 return versionList;
206 }
207
208
209 public void accept(VersionNumberVisitor visitor) {
210 final List<VersionNumber> versionList = getRegisteredVersionNumbers();
211 for (VersionNumber versionNumber : versionList) {
212 visitor.visit(versionNumber);
213 }
214 }
215
216 }