/
Project.java
2470 lines (2300 loc) · 89.5 KB
/
Project.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.tools.ant;
import java.io.File;
import java.io.IOException;
import java.io.EOFException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Stack;
import java.util.Vector;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.tools.ant.input.DefaultInputHandler;
import org.apache.tools.ant.input.InputHandler;
import org.apache.tools.ant.helper.DefaultExecutor;
import org.apache.tools.ant.types.FilterSet;
import org.apache.tools.ant.types.FilterSetCollection;
import org.apache.tools.ant.types.Description;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceFactory;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.util.CollectionUtils;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.JavaEnvUtils;
import org.apache.tools.ant.util.StringUtils;
import org.apache.tools.ant.util.VectorSet;
/**
* Central representation of an Ant project. This class defines an
* Ant project with all of its targets, tasks and various other
* properties. It also provides the mechanism to kick off a build using
* a particular target name.
* <p>
* This class also encapsulates methods which allow files to be referred
* to using abstract path names which are translated to native system
* file paths at runtime.
*
*/
public class Project implements ResourceFactory {
/** Message priority of "error". */
public static final int MSG_ERR = 0;
/** Message priority of "warning". */
public static final int MSG_WARN = 1;
/** Message priority of "information". */
public static final int MSG_INFO = 2;
/** Message priority of "verbose". */
public static final int MSG_VERBOSE = 3;
/** Message priority of "debug". */
public static final int MSG_DEBUG = 4;
/**
* Constant for the "visiting" state, used when
* traversing a DFS of target dependencies.
*/
private static final String VISITING = "VISITING";
/**
* Constant for the "visited" state, used when
* traversing a DFS of target dependencies.
*/
private static final String VISITED = "VISITED";
/**
* Version constant for Java 1.0 .
*
* @deprecated since 1.5.x.
* Use {@link JavaEnvUtils#JAVA_1_0} instead.
*/
public static final String JAVA_1_0 = JavaEnvUtils.JAVA_1_0;
/**
* Version constant for Java 1.1 .
*
* @deprecated since 1.5.x.
* Use {@link JavaEnvUtils#JAVA_1_1} instead.
*/
public static final String JAVA_1_1 = JavaEnvUtils.JAVA_1_1;
/**
* Version constant for Java 1.2 .
*
* @deprecated since 1.5.x.
* Use {@link JavaEnvUtils#JAVA_1_2} instead.
*/
public static final String JAVA_1_2 = JavaEnvUtils.JAVA_1_2;
/**
* Version constant for Java 1.3 .
*
* @deprecated since 1.5.x.
* Use {@link JavaEnvUtils#JAVA_1_3} instead.
*/
public static final String JAVA_1_3 = JavaEnvUtils.JAVA_1_3;
/**
* Version constant for Java 1.4 .
*
* @deprecated since 1.5.x.
* Use {@link JavaEnvUtils#JAVA_1_4} instead.
*/
public static final String JAVA_1_4 = JavaEnvUtils.JAVA_1_4;
/** Default filter start token. */
public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
/** Default filter end token. */
public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
/** Instance of a utility class to use for file operations. */
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
/** Name of this project. */
private String name;
/** Description for this project (if any). */
private String description;
/** Map of references within the project (paths etc) (String to Object). */
private Hashtable<String, Object> references = new AntRefTable();
/** Map of id references - used for indicating broken build files */
private HashMap<String, Object> idReferences = new HashMap<String, Object>();
/** Name of the project's default target. */
private String defaultTarget;
/** Map from target names to targets (String to Target). */
private Hashtable<String, Target> targets = new Hashtable<String, Target>();
/** Set of global filters. */
private FilterSet globalFilterSet = new FilterSet();
{
// Initialize the globalFileSet's project
globalFilterSet.setProject(this);
}
/**
* Wrapper around globalFilterSet. This collection only ever
* contains one FilterSet, but the wrapper is needed in order to
* make it easier to use the FileUtils interface.
*/
private FilterSetCollection globalFilters
= new FilterSetCollection(globalFilterSet);
/** Project base directory. */
private File baseDir;
/** lock object used when adding/removing listeners */
private final Object listenersLock = new Object();
/** List of listeners to notify of build events. */
private volatile BuildListener[] listeners = new BuildListener[0];
/** for each thread, record whether it is currently executing
messageLogged */
private final ThreadLocal<Boolean> isLoggingMessage = new ThreadLocal<Boolean>() {
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
/**
* The Ant core classloader--may be <code>null</code> if using
* parent classloader.
*/
private ClassLoader coreLoader = null;
/** Records the latest task to be executed on a thread. */
private final Map<Thread,Task> threadTasks =
Collections.synchronizedMap(new WeakHashMap<Thread, Task>());
/** Records the latest task to be executed on a thread group. */
private final Map<ThreadGroup,Task> threadGroupTasks
= Collections.synchronizedMap(new WeakHashMap<ThreadGroup,Task>());
/**
* Called to handle any input requests.
*/
private InputHandler inputHandler = null;
/**
* The default input stream used to read any input.
*/
private InputStream defaultInputStream = null;
/**
* Keep going flag.
*/
private boolean keepGoingMode = false;
/**
* Set the input handler.
*
* @param handler the InputHandler instance to use for gathering input.
*/
public void setInputHandler(InputHandler handler) {
inputHandler = handler;
}
/**
* Set the default System input stream. Normally this stream is set to
* System.in. This inputStream is used when no task input redirection is
* being performed.
*
* @param defaultInputStream the default input stream to use when input
* is requested.
* @since Ant 1.6
*/
public void setDefaultInputStream(InputStream defaultInputStream) {
this.defaultInputStream = defaultInputStream;
}
/**
* Get this project's input stream.
*
* @return the InputStream instance in use by this Project instance to
* read input.
*/
public InputStream getDefaultInputStream() {
return defaultInputStream;
}
/**
* Retrieve the current input handler.
*
* @return the InputHandler instance currently in place for the project
* instance.
*/
public InputHandler getInputHandler() {
return inputHandler;
}
/**
* Create a new Ant project.
*/
public Project() {
inputHandler = new DefaultInputHandler();
}
/**
* Create and initialize a subproject. By default the subproject will be of
* the same type as its parent. If a no-arg constructor is unavailable, the
* <code>Project</code> class will be used.
* @return a Project instance configured as a subproject of this Project.
* @since Ant 1.7
*/
public Project createSubProject() {
Project subProject = null;
try {
subProject = (Project) (getClass().newInstance());
} catch (Exception e) {
subProject = new Project();
}
initSubProject(subProject);
return subProject;
}
/**
* Initialize a subproject.
* @param subProject the subproject to initialize.
*/
public void initSubProject(Project subProject) {
ComponentHelper.getComponentHelper(subProject)
.initSubProject(ComponentHelper.getComponentHelper(this));
subProject.setDefaultInputStream(getDefaultInputStream());
subProject.setKeepGoingMode(this.isKeepGoingMode());
subProject.setExecutor(getExecutor().getSubProjectExecutor());
}
/**
* Initialise the project.
*
* This involves setting the default task definitions and loading the
* system properties.
*
* @exception BuildException if the default task list cannot be loaded.
*/
public void init() throws BuildException {
initProperties();
ComponentHelper.getComponentHelper(this).initDefaultDefinitions();
}
/**
* Initializes the properties.
* @exception BuildException if an vital property could not be set.
* @since Ant 1.7
*/
public void initProperties() throws BuildException {
setJavaVersionProperty();
setSystemProperties();
setPropertyInternal(MagicNames.ANT_VERSION, Main.getAntVersion());
setAntLib();
}
/**
* Set a property to the location of ant.jar.
* Use the locator to find the location of the Project.class, and
* if this is not null, set the property {@link MagicNames#ANT_LIB}
* to the result
*/
private void setAntLib() {
File antlib = org.apache.tools.ant.launch.Locator.getClassSource(
Project.class);
if (antlib != null) {
setPropertyInternal(MagicNames.ANT_LIB, antlib.getAbsolutePath());
}
}
/**
* Factory method to create a class loader for loading classes from
* a given path.
*
* @param path the path from which classes are to be loaded.
*
* @return an appropriate classloader.
*/
public AntClassLoader createClassLoader(Path path) {
return AntClassLoader
.newAntClassLoader(getClass().getClassLoader(), this, path, true);
}
/**
* Factory method to create a class loader for loading classes from
* a given path.
*
* @param parent the parent classloader for the new loader.
* @param path the path from which classes are to be loaded.
*
* @return an appropriate classloader.
*/
public AntClassLoader createClassLoader(
ClassLoader parent, Path path) {
return AntClassLoader.newAntClassLoader(parent, this, path, true);
}
/**
* Set the core classloader for the project. If a <code>null</code>
* classloader is specified, the parent classloader should be used.
*
* @param coreLoader The classloader to use for the project.
* May be <code>null</code>.
*/
public void setCoreLoader(ClassLoader coreLoader) {
this.coreLoader = coreLoader;
}
/**
* Return the core classloader to use for this project.
* This may be <code>null</code>, indicating that
* the parent classloader should be used.
*
* @return the core classloader to use for this project.
*
*/
public ClassLoader getCoreLoader() {
return coreLoader;
}
/**
* Add a build listener to the list. This listener will
* be notified of build events for this project.
*
* @param listener The listener to add to the list.
* Must not be <code>null</code>.
*/
public void addBuildListener(BuildListener listener) {
synchronized (listenersLock) {
// If the listeners already has this listener, do nothing
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == listener) {
return;
}
}
// copy on write semantics
BuildListener[] newListeners =
new BuildListener[listeners.length + 1];
System.arraycopy(listeners, 0, newListeners, 0, listeners.length);
newListeners[listeners.length] = listener;
listeners = newListeners;
}
}
/**
* Remove a build listener from the list. This listener
* will no longer be notified of build events for this project.
*
* @param listener The listener to remove from the list.
* Should not be <code>null</code>.
*/
public void removeBuildListener(BuildListener listener) {
synchronized (listenersLock) {
// copy on write semantics
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == listener) {
BuildListener[] newListeners =
new BuildListener[listeners.length - 1];
System.arraycopy(listeners, 0, newListeners, 0, i);
System.arraycopy(listeners, i + 1, newListeners, i,
listeners.length - i - 1);
listeners = newListeners;
break;
}
}
}
}
/**
* Return a copy of the list of build listeners for the project.
*
* @return a list of build listeners for the project
*/
public Vector<BuildListener> getBuildListeners() {
synchronized (listenersLock) {
Vector<BuildListener> r = new Vector<BuildListener>(listeners.length);
for (int i = 0; i < listeners.length; i++) {
r.add(listeners[i]);
}
return r;
}
}
/**
* Write a message to the log with the default log level
* of MSG_INFO .
* @param message The text to log. Should not be <code>null</code>.
*/
public void log(String message) {
log(message, MSG_INFO);
}
/**
* Write a project level message to the log with the given log level.
* @param message The text to log. Should not be <code>null</code>.
* @param msgLevel The log priority level to use.
*/
public void log(String message, int msgLevel) {
log(message, null, msgLevel);
}
/**
* Write a project level message to the log with the given log level.
* @param message The text to log. Should not be <code>null</code>.
* @param throwable The exception causing this log, may be <code>null</code>.
* @param msgLevel The log priority level to use.
* @since 1.7
*/
public void log(String message, Throwable throwable, int msgLevel) {
fireMessageLogged(this, message, throwable, msgLevel);
}
/**
* Write a task level message to the log with the given log level.
* @param task The task to use in the log. Must not be <code>null</code>.
* @param message The text to log. Should not be <code>null</code>.
* @param msgLevel The log priority level to use.
*/
public void log(Task task, String message, int msgLevel) {
fireMessageLogged(task, message, null, msgLevel);
}
/**
* Write a task level message to the log with the given log level.
* @param task The task to use in the log. Must not be <code>null</code>.
* @param message The text to log. Should not be <code>null</code>.
* @param throwable The exception causing this log, may be <code>null</code>.
* @param msgLevel The log priority level to use.
* @since 1.7
*/
public void log(Task task, String message, Throwable throwable, int msgLevel) {
fireMessageLogged(task, message, throwable, msgLevel);
}
/**
* Write a target level message to the log with the given log level.
* @param target The target to use in the log.
* Must not be <code>null</code>.
* @param message The text to log. Should not be <code>null</code>.
* @param msgLevel The log priority level to use.
*/
public void log(Target target, String message, int msgLevel) {
log(target, message, null, msgLevel);
}
/**
* Write a target level message to the log with the given log level.
* @param target The target to use in the log.
* Must not be <code>null</code>.
* @param message The text to log. Should not be <code>null</code>.
* @param throwable The exception causing this log, may be <code>null</code>.
* @param msgLevel The log priority level to use.
* @since 1.7
*/
public void log(Target target, String message, Throwable throwable,
int msgLevel) {
fireMessageLogged(target, message, throwable, msgLevel);
}
/**
* Return the set of global filters.
*
* @return the set of global filters.
*/
public FilterSet getGlobalFilterSet() {
return globalFilterSet;
}
/**
* Set a property. Any existing property of the same name
* is overwritten, unless it is a user property.
* @param name The name of property to set.
* Must not be <code>null</code>.
* @param value The new value of the property.
* Must not be <code>null</code>.
*/
public void setProperty(String name, String value) {
PropertyHelper.getPropertyHelper(this).setProperty(name, value, true);
}
/**
* Set a property if no value currently exists. If the property
* exists already, a message is logged and the method returns with
* no other effect.
*
* @param name The name of property to set.
* Must not be <code>null</code>.
* @param value The new value of the property.
* Must not be <code>null</code>.
* @since 1.5
*/
public void setNewProperty(String name, String value) {
PropertyHelper.getPropertyHelper(this).setNewProperty(name, value);
}
/**
* Set a user property, which cannot be overwritten by
* set/unset property calls. Any previous value is overwritten.
* @param name The name of property to set.
* Must not be <code>null</code>.
* @param value The new value of the property.
* Must not be <code>null</code>.
* @see #setProperty(String,String)
*/
public void setUserProperty(String name, String value) {
PropertyHelper.getPropertyHelper(this).setUserProperty(name, value);
}
/**
* Set a user property, which cannot be overwritten by set/unset
* property calls. Any previous value is overwritten. Also marks
* these properties as properties that have not come from the
* command line.
*
* @param name The name of property to set.
* Must not be <code>null</code>.
* @param value The new value of the property.
* Must not be <code>null</code>.
* @see #setProperty(String,String)
*/
public void setInheritedProperty(String name, String value) {
PropertyHelper.getPropertyHelper(this).setInheritedProperty(name, value);
}
/**
* Set a property unless it is already defined as a user property
* (in which case the method returns silently).
*
* @param name The name of the property.
* Must not be <code>null</code>.
* @param value The property value. Must not be <code>null</code>.
*/
private void setPropertyInternal(String name, String value) {
PropertyHelper.getPropertyHelper(this).setProperty(name, value, false);
}
/**
* Return the value of a property, if it is set.
*
* @param propertyName The name of the property.
* May be <code>null</code>, in which case
* the return value is also <code>null</code>.
* @return the property value, or <code>null</code> for no match
* or if a <code>null</code> name is provided.
*/
public String getProperty(String propertyName) {
Object value = PropertyHelper.getPropertyHelper(this).getProperty(propertyName);
return value == null ? null : String.valueOf(value);
}
/**
* Replace ${} style constructions in the given value with the
* string value of the corresponding data types.
*
* @param value The string to be scanned for property references.
* May be <code>null</code>.
*
* @return the given string with embedded property names replaced
* by values, or <code>null</code> if the given string is
* <code>null</code>.
*
* @exception BuildException if the given value has an unclosed
* property name, e.g. <code>${xxx</code>.
*/
public String replaceProperties(String value) throws BuildException {
return PropertyHelper.getPropertyHelper(this).replaceProperties(null, value, null);
}
/**
* Return the value of a user property, if it is set.
*
* @param propertyName The name of the property.
* May be <code>null</code>, in which case
* the return value is also <code>null</code>.
* @return the property value, or <code>null</code> for no match
* or if a <code>null</code> name is provided.
*/
public String getUserProperty(String propertyName) {
return (String) PropertyHelper.getPropertyHelper(this).getUserProperty(propertyName);
}
/**
* Return a copy of the properties table.
* @return a hashtable containing all properties
* (including user properties).
*/
public Hashtable<String, Object> getProperties() {
return PropertyHelper.getPropertyHelper(this).getProperties();
}
/**
* Return a copy of the user property hashtable.
* @return a hashtable containing just the user properties.
*/
public Hashtable<String, Object> getUserProperties() {
return PropertyHelper.getPropertyHelper(this).getUserProperties();
}
/**
* Return a copy of the inherited property hashtable.
* @return a hashtable containing just the inherited properties.
* @since Ant 1.8.0
*/
public Hashtable<String, Object> getInheritedProperties() {
return PropertyHelper.getPropertyHelper(this).getInheritedProperties();
}
/**
* Copy all user properties that have been set on the command
* line or a GUI tool from this instance to the Project instance
* given as the argument.
*
* <p>To copy all "user" properties, you will also have to call
* {@link #copyInheritedProperties copyInheritedProperties}.</p>
*
* @param other the project to copy the properties to. Must not be null.
*
* @since Ant 1.5
*/
public void copyUserProperties(Project other) {
PropertyHelper.getPropertyHelper(this).copyUserProperties(other);
}
/**
* Copy all user properties that have not been set on the
* command line or a GUI tool from this instance to the Project
* instance given as the argument.
*
* <p>To copy all "user" properties, you will also have to call
* {@link #copyUserProperties copyUserProperties}.</p>
*
* @param other the project to copy the properties to. Must not be null.
*
* @since Ant 1.5
*/
public void copyInheritedProperties(Project other) {
PropertyHelper.getPropertyHelper(this).copyInheritedProperties(other);
}
/**
* Set the default target of the project.
*
* @param defaultTarget The name of the default target for this project.
* May be <code>null</code>, indicating that there is
* no default target.
*
* @deprecated since 1.5.x.
* Use setDefault.
* @see #setDefault(String)
*/
public void setDefaultTarget(String defaultTarget) {
setDefault(defaultTarget);
}
/**
* Return the name of the default target of the project.
* @return name of the default target or
* <code>null</code> if no default has been set.
*/
public String getDefaultTarget() {
return defaultTarget;
}
/**
* Set the default target of the project.
*
* @param defaultTarget The name of the default target for this project.
* May be <code>null</code>, indicating that there is
* no default target.
*/
public void setDefault(String defaultTarget) {
if (defaultTarget != null) {
setUserProperty(MagicNames.PROJECT_DEFAULT_TARGET, defaultTarget);
}
this.defaultTarget = defaultTarget;
}
/**
* Set the name of the project, also setting the user
* property <code>ant.project.name</code>.
*
* @param name The name of the project.
* Must not be <code>null</code>.
*/
public void setName(String name) {
setUserProperty(MagicNames.PROJECT_NAME, name);
this.name = name;
}
/**
* Return the project name, if one has been set.
*
* @return the project name, or <code>null</code> if it hasn't been set.
*/
public String getName() {
return name;
}
/**
* Set the project description.
*
* @param description The description of the project.
* May be <code>null</code>.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Return the project description, if one has been set.
*
* @return the project description, or <code>null</code> if it hasn't
* been set.
*/
public String getDescription() {
if (description == null) {
description = Description.getDescription(this);
}
return description;
}
/**
* Add a filter to the set of global filters.
*
* @param token The token to filter.
* Must not be <code>null</code>.
* @param value The replacement value.
* Must not be <code>null</code>.
* @deprecated since 1.4.x.
* Use getGlobalFilterSet().addFilter(token,value)
*
* @see #getGlobalFilterSet()
* @see FilterSet#addFilter(String,String)
*/
public void addFilter(String token, String value) {
if (token == null) {
return;
}
globalFilterSet.addFilter(new FilterSet.Filter(token, value));
}
/**
* Return a hashtable of global filters, mapping tokens to values.
*
* @return a hashtable of global filters, mapping tokens to values
* (String to String).
*
* @deprecated since 1.4.x
* Use getGlobalFilterSet().getFilterHash().
*
* @see #getGlobalFilterSet()
* @see FilterSet#getFilterHash()
*/
public Hashtable<String, String> getFilters() {
// we need to build the hashtable dynamically
return globalFilterSet.getFilterHash();
}
/**
* Set the base directory for the project, checking that
* the given filename exists and is a directory.
*
* @param baseD The project base directory.
* Must not be <code>null</code>.
*
* @exception BuildException if the directory if invalid.
*/
public void setBasedir(String baseD) throws BuildException {
setBaseDir(new File(baseD));
}
/**
* Set the base directory for the project, checking that
* the given file exists and is a directory.
*
* @param baseDir The project base directory.
* Must not be <code>null</code>.
* @exception BuildException if the specified file doesn't exist or
* isn't a directory.
*/
public void setBaseDir(File baseDir) throws BuildException {
baseDir = FILE_UTILS.normalize(baseDir.getAbsolutePath());
if (!baseDir.exists()) {
throw new BuildException("Basedir " + baseDir.getAbsolutePath()
+ " does not exist");
}
if (!baseDir.isDirectory()) {
throw new BuildException("Basedir " + baseDir.getAbsolutePath()
+ " is not a directory");
}
this.baseDir = baseDir;
setPropertyInternal(MagicNames.PROJECT_BASEDIR, this.baseDir.getPath());
String msg = "Project base dir set to: " + this.baseDir;
log(msg, MSG_VERBOSE);
}
/**
* Return the base directory of the project as a file object.
*
* @return the project base directory, or <code>null</code> if the
* base directory has not been successfully set to a valid value.
*/
public File getBaseDir() {
if (baseDir == null) {
try {
setBasedir(".");
} catch (BuildException ex) {
ex.printStackTrace();
}
}
return baseDir;
}
/**
* Set "keep-going" mode. In this mode Ant will try to execute
* as many targets as possible. All targets that do not depend
* on failed target(s) will be executed. If the keepGoing settor/getter
* methods are used in conjunction with the <code>ant.executor.class</code>
* property, they will have no effect.
* @param keepGoingMode "keep-going" mode
* @since Ant 1.6
*/
public void setKeepGoingMode(boolean keepGoingMode) {
this.keepGoingMode = keepGoingMode;
}
/**
* Return the keep-going mode. If the keepGoing settor/getter
* methods are used in conjunction with the <code>ant.executor.class</code>
* property, they will have no effect.
* @return "keep-going" mode
* @since Ant 1.6
*/
public boolean isKeepGoingMode() {
return this.keepGoingMode;
}
/**
* Return the version of Java this class is running under.
* @return the version of Java as a String, e.g. "1.1" .
* @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
* @deprecated since 1.5.x.
* Use org.apache.tools.ant.util.JavaEnvUtils instead.
*/
public static String getJavaVersion() {
return JavaEnvUtils.getJavaVersion();
}
/**
* Set the <code>ant.java.version</code> property and tests for
* unsupported JVM versions. If the version is supported,
* verbose log messages are generated to record the Java version
* and operating system name.
*
* @exception BuildException if this Java version is not supported.
*
* @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
*/
public void setJavaVersionProperty() throws BuildException {
String javaVersion = JavaEnvUtils.getJavaVersion();
setPropertyInternal(MagicNames.ANT_JAVA_VERSION, javaVersion);
// sanity check
if (!JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_4)) {
throw new BuildException("Ant cannot work on Java prior to 1.4");
}
log("Detected Java version: " + javaVersion + " in: "
+ System.getProperty("java.home"), MSG_VERBOSE);
log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
}
/**
* Add all system properties which aren't already defined as
* user properties to the project properties.
*/
public void setSystemProperties() {
Properties systemP = System.getProperties();
Enumeration<?> e = systemP.propertyNames();
while (e.hasMoreElements()) {
String propertyName = (String) e.nextElement();
String value = systemP.getProperty(propertyName);
if (value != null) {
this.setPropertyInternal(propertyName, value);
}
}
}
/**
* Add a new task definition to the project.
* Attempting to override an existing definition with an
* equivalent one (i.e. with the same classname) results in
* a verbose log message. Attempting to override an existing definition
* with a different one results in a warning log message and
* invalidates any tasks which have already been created with the
* old definition.
*
* @param taskName The name of the task to add.
* Must not be <code>null</code>.
* @param taskClass The full name of the class implementing the task.
* Must not be <code>null</code>.
*
* @exception BuildException if the class is unsuitable for being an Ant
* task. An error level message is logged before
* this exception is thrown.
*
* @see #checkTaskClass(Class)
*/
public void addTaskDefinition(String taskName, Class<?> taskClass)
throws BuildException {
ComponentHelper.getComponentHelper(this).addTaskDefinition(taskName,
taskClass);
}
/**
* Check whether or not a class is suitable for serving as Ant task.
* Ant task implementation classes must be public, concrete, and have
* a no-arg constructor.
*
* @param taskClass The class to be checked.
* Must not be <code>null</code>.
*
* @exception BuildException if the class is unsuitable for being an Ant
* task. An error level message is logged before
* this exception is thrown.
*/
public void checkTaskClass(final Class<?> taskClass) throws BuildException {
ComponentHelper.getComponentHelper(this).checkTaskClass(taskClass);
if (!Modifier.isPublic(taskClass.getModifiers())) {
final String message = taskClass + " is not public";
log(message, Project.MSG_ERR);
throw new BuildException(message);
}
if (Modifier.isAbstract(taskClass.getModifiers())) {
final String message = taskClass + " is abstract";
log(message, Project.MSG_ERR);
throw new BuildException(message);
}
try {
taskClass.getConstructor();
// don't have to check for public, since
// getConstructor finds public constructors only.