Line 0
Link Here
|
|
|
1 |
/* |
2 |
* Licensed to the Apache Software Foundation (ASF) under one or more |
3 |
* contributor license agreements. See the NOTICE file distributed with |
4 |
* this work for additional information regarding copyright ownership. |
5 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
6 |
* (the "License"); you may not use this file except in compliance with |
7 |
* the License. You may obtain a copy of the License at |
8 |
* |
9 |
* http://www.apache.org/licenses/LICENSE-2.0 |
10 |
* |
11 |
* Unless required by applicable law or agreed to in writing, software |
12 |
* distributed under the License is distributed on an "AS IS" BASIS, |
13 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 |
* See the License for the specific language governing permissions and |
15 |
* limitations under the License. |
16 |
* |
17 |
*/ |
18 |
package org.apache.tools.ant; |
19 |
|
20 |
/* |
21 |
* A class representing a project address |
22 |
* The main (root) project has a null address |
23 |
* Subprojects are created with <ant> and <antcall> |
24 |
* The subprojects of the main project have the addresses 1, 2, 3 etc. |
25 |
* Subprojects of project 1 have the addresses 1.1, 1.2, 1.3 etc. |
26 |
* Subprojects of project 2 have the addresses 2.1, 2.2, 2.3 etc. |
27 |
* And so on |
28 |
* Address "root" can be used to point to the root project |
29 |
* Address "infinity" points to a non-existent first level subproject with an |
30 |
* infinitly high address. If there are n subprojects in the main project, |
31 |
* the address "infinity" acts the same as address n+1) |
32 |
* Can be converted to a string representation and back |
33 |
* Objects of this class are immutable |
34 |
* |
35 |
*/ |
36 |
public class ProjectAddress { |
37 |
|
38 |
private boolean isRoot = false; |
39 |
private boolean isInfinity = false; |
40 |
private int[] chambers = null; |
41 |
private int noChambers = -1; |
42 |
|
43 |
public static void main( String[] args ) { |
44 |
if ( args.length < 2 ) { |
45 |
System.err.println("Please specify two target addresses"); |
46 |
return; |
47 |
} |
48 |
|
49 |
ProjectAddress a, b; |
50 |
try { |
51 |
a = new ProjectAddress(args[0]); |
52 |
b = new ProjectAddress(args[1]); |
53 |
} catch ( BuildException be ) { |
54 |
System.err.println("Failed to construct address"); |
55 |
System.err.println(be.getMessage()); |
56 |
return; |
57 |
} |
58 |
System.out.println( "a: " + a ); |
59 |
System.out.println( "b: " + b ); |
60 |
System.out.println( "a.isAfter(b): " + a.isAfter(b) ); |
61 |
System.out.println( "b.isAfter(a): " + b.isAfter(a) ); |
62 |
System.out.println( "a.isDescendantOf(b): " + a.isDescendantOf(b) ); |
63 |
System.out.println( "b.isDescendantOf(a): " + b.isDescendantOf(a) ); |
64 |
|
65 |
} |
66 |
|
67 |
/** |
68 |
* Construct a ProjectAddress from its string representation |
69 |
* @param addressAsString a string representation of an address |
70 |
*/ |
71 |
public ProjectAddress( String addressAsString ) throws BuildException { |
72 |
|
73 |
//catch null |
74 |
if ( addressAsString == null ) { |
75 |
throw new BuildException( "null address string" ); |
76 |
} |
77 |
|
78 |
//catch root keyword |
79 |
if ( addressAsString.equals("root") ) { |
80 |
isRoot = true; |
81 |
return; |
82 |
} |
83 |
|
84 |
//catch infinity keyword |
85 |
if ( addressAsString.equals("infinity") ) { |
86 |
isInfinity = true; |
87 |
return; |
88 |
} |
89 |
|
90 |
//spilt string address into chambers |
91 |
String[] chambersAsStrings = addressAsString.split("\\."); |
92 |
|
93 |
//create empty chambers for this address |
94 |
noChambers = chambersAsStrings.length; |
95 |
chambers = new int[noChambers]; |
96 |
|
97 |
//load the chambers, checking each is a positive integer |
98 |
for ( int i=0; i<chambersAsStrings.length; i++ ) { |
99 |
|
100 |
//check it's an int |
101 |
try { |
102 |
chambers[i] = Integer.parseInt( chambersAsStrings[i] ); |
103 |
} catch( NumberFormatException e ) { |
104 |
throw new BuildException( "invalid address string (contains non int chambers): '" + addressAsString + "'" ); |
105 |
} |
106 |
|
107 |
//check it's not negative |
108 |
if ( chambers[i] < 0 ) { |
109 |
throw new BuildException( "invalid address string (contains negative int chambers): '" + addressAsString + "'" ); |
110 |
} |
111 |
|
112 |
} |
113 |
|
114 |
} |
115 |
|
116 |
/** |
117 |
* Create a ProjectAddress as the child of the given parent ProjectAddress |
118 |
* using the given subaddress |
119 |
* E.g., passing in parent 3.5 and subaddress 2 will construct address 3.5.2 |
120 |
*/ |
121 |
public ProjectAddress( ProjectAddress parent, int subAddress ) throws BuildException { |
122 |
|
123 |
if ( subAddress < 0 ) { |
124 |
throw new BuildException( "subaddress must be positive" ); |
125 |
} |
126 |
|
127 |
if ( parent == null || parent.isRoot() ) { |
128 |
|
129 |
//create one chamber |
130 |
noChambers = 1; |
131 |
chambers = new int[noChambers]; |
132 |
chambers[0] = subAddress; |
133 |
|
134 |
} else { |
135 |
|
136 |
//create empty chambers with one more chamber than parent |
137 |
noChambers = parent.noChambers()+1; |
138 |
chambers = new int[noChambers]; |
139 |
|
140 |
//copy parent chambers to this address |
141 |
for ( int i=0; i<parent.noChambers(); i++ ) { |
142 |
chambers[i] = parent.getChamber(i); |
143 |
} |
144 |
|
145 |
//the last chamber is the sub address |
146 |
chambers[noChambers-1] = subAddress; |
147 |
|
148 |
} |
149 |
|
150 |
} |
151 |
|
152 |
/** |
153 |
* @return true if this address is the root, false otherwise |
154 |
*/ |
155 |
public boolean isRoot() { |
156 |
return isRoot; |
157 |
} |
158 |
|
159 |
/** |
160 |
* @return true if this address is the infinity address, false otherwise |
161 |
*/ |
162 |
public boolean isInfinity() { |
163 |
return isInfinity; |
164 |
} |
165 |
|
166 |
/** |
167 |
* Gets the value in the given chamber of this address |
168 |
* E.g., getChamber(2) on address 3.4.7.5 will return 7 |
169 |
* @return the value in the given chamber |
170 |
*/ |
171 |
public int getChamber( int chamber ) { |
172 |
if ( chamber >=0 && chamber < noChambers ) { |
173 |
return chambers[chamber]; |
174 |
} else { |
175 |
return -1; |
176 |
} |
177 |
} |
178 |
|
179 |
/** |
180 |
* @return the number of chambers this address has |
181 |
*/ |
182 |
public int noChambers() { |
183 |
return noChambers; |
184 |
} |
185 |
|
186 |
/** |
187 |
* Converts this address to its string representation |
188 |
* That is, either "root", "infinity", or a string like: |
189 |
* "1.11.2.6" |
190 |
* @return the string representation of this address |
191 |
*/ |
192 |
public String toString() { |
193 |
if ( isRoot ) { |
194 |
return "root"; |
195 |
} |
196 |
|
197 |
if ( isInfinity ) { |
198 |
return "infinity"; |
199 |
} |
200 |
|
201 |
StringBuffer addressString = new StringBuffer(); |
202 |
for ( int i=0; i<noChambers; i++ ) { |
203 |
addressString.append( "" + chambers[i] ); |
204 |
if ( i < noChambers -1 ) { |
205 |
addressString.append( "." ); |
206 |
} |
207 |
} |
208 |
return addressString.toString(); |
209 |
|
210 |
} |
211 |
|
212 |
/* |
213 |
* Returns true if this address is after the given address |
214 |
* E.g., new ProjectAddress("1.6").isAfter(new ProjectAddress("1.5")) would return true |
215 |
* E.g., new ProjectAddress("1.4").isAfter(new ProjectAddress("1.8.5)) would return false |
216 |
* By convention, consider an address to be after itself |
217 |
* Have used 'this' keyword in code for readablilty |
218 |
*/ |
219 |
public boolean isAfter( ProjectAddress otherAddress ) throws BuildException { |
220 |
|
221 |
//catch null |
222 |
if ( otherAddress == null ) { |
223 |
throw new BuildException( |
224 |
"Null ProjectAddress given in ProjectAddress.isAfter()"); |
225 |
} |
226 |
|
227 |
//everything is after root |
228 |
if ( otherAddress.isRoot() ) { |
229 |
return true; |
230 |
} |
231 |
|
232 |
//root is after nothing |
233 |
//(except itself, but that's already caught) |
234 |
if ( this.isRoot ) { |
235 |
return false; |
236 |
} |
237 |
|
238 |
//infinity is after everything |
239 |
if ( this.isInfinity ) { |
240 |
return true; |
241 |
} |
242 |
|
243 |
//nothing is after infinity |
244 |
// (except itself, but that's already caught) |
245 |
if ( otherAddress.isInfinity() ) { |
246 |
return false; |
247 |
} |
248 |
|
249 |
//step through, checking that chambers of this are higher than |
250 |
//or equal to chambers of otherAddress |
251 |
for ( int i=0; i<otherAddress.noChambers(); i++ ) { |
252 |
|
253 |
int thisChamber = i < this.noChambers ? this.chambers[i] : 0; |
254 |
|
255 |
if( thisChamber < otherAddress.getChamber(i) ) { |
256 |
return false; |
257 |
} |
258 |
|
259 |
if( thisChamber > otherAddress.getChamber(i) ) { |
260 |
return true; |
261 |
} |
262 |
} |
263 |
|
264 |
//first [otherAddress.noChambers()] chambers are equal |
265 |
return true; |
266 |
} |
267 |
|
268 |
|
269 |
public boolean isDescendantOf( ProjectAddress otherAddress ) { |
270 |
|
271 |
//catch null |
272 |
if ( otherAddress == null ) { |
273 |
throw new BuildException( |
274 |
"Null ProjectAddress given in ProjectAddress.isDescendantOf()"); |
275 |
} |
276 |
|
277 |
//everything decends from root |
278 |
if ( otherAddress.isRoot() ) { |
279 |
return true; |
280 |
} |
281 |
|
282 |
//root descends from nothing |
283 |
//(except itself but that's already caught) |
284 |
if ( this.isRoot ) { |
285 |
return false; |
286 |
} |
287 |
|
288 |
//infinity descends from itself |
289 |
if ( this.isInfinity && otherAddress.isInfinity() ) { |
290 |
return true; |
291 |
} |
292 |
|
293 |
//nothing descends from infinity |
294 |
//(except itself but that's already caught) |
295 |
if ( otherAddress.isInfinity() ) { |
296 |
return false; |
297 |
} |
298 |
|
299 |
//infinity descends only from nothing |
300 |
//(except root and itself, but that's already caught) |
301 |
if ( this.isInfinity ) { |
302 |
return false; |
303 |
} |
304 |
|
305 |
//make sure x is at least as deep as y |
306 |
if ( this.noChambers < otherAddress.noChambers() ) { |
307 |
return false; |
308 |
} |
309 |
|
310 |
//step through, making sure x values are equal to y values |
311 |
for ( int i=0; i<otherAddress.noChambers(); i++ ) { |
312 |
if( this.chambers[i] != otherAddress.getChamber(i) ) { |
313 |
return false; |
314 |
} |
315 |
} |
316 |
|
317 |
//first [otherAddress.noChambers()] chambers are equal |
318 |
return true; |
319 |
|
320 |
} |
321 |
|
322 |
|
323 |
} |