You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Property.java 23 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  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.taskdefs;
  19. import java.io.File;
  20. import java.io.FileInputStream;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.lang.reflect.Method;
  24. import java.net.URL;
  25. import java.util.Enumeration;
  26. import java.util.HashMap;
  27. import java.util.Iterator;
  28. import java.util.Map;
  29. import java.util.Properties;
  30. import java.util.Vector;
  31. import org.apache.tools.ant.AntClassLoader;
  32. import org.apache.tools.ant.BuildException;
  33. import org.apache.tools.ant.Project;
  34. import org.apache.tools.ant.PropertyHelper;
  35. import org.apache.tools.ant.Task;
  36. import org.apache.tools.ant.types.Path;
  37. import org.apache.tools.ant.types.Reference;
  38. import org.apache.tools.ant.util.FileUtils;
  39. import org.apache.tools.ant.property.ResolvePropertyMap;
  40. /**
  41. * Sets a property by name, or set of properties (from file or
  42. * resource) in the project. </p>
  43. * Properties are immutable: whoever sets a property first freezes it for the
  44. * rest of the build; they are most definitely not variable.
  45. * <p>There are seven ways to set properties:</p>
  46. * <ul>
  47. * <li>By supplying both the <i>name</i> and <i>value</i> attribute.</li>
  48. * <li>By supplying the <i>name</i> and nested text.</li>
  49. * <li>By supplying both the <i>name</i> and <i>refid</i> attribute.</li>
  50. * <li>By setting the <i>file</i> attribute with the filename of the property
  51. * file to load. This property file has the format as defined by the file used
  52. * in the class java.util.Properties.</li>
  53. * <li>By setting the <i>url</i> attribute with the url from which to load the
  54. * properties. This url must be directed to a file that has the format as defined
  55. * by the file used in the class java.util.Properties.</li>
  56. * <li>By setting the <i>resource</i> attribute with the resource name of the
  57. * property file to load. This property file has the format as defined by the
  58. * file used in the class java.util.Properties.</li>
  59. * <li>By setting the <i>environment</i> attribute with a prefix to use.
  60. * Properties will be defined for every environment variable by
  61. * prefixing the supplied name and a period to the name of the variable.</li>
  62. * </ul>
  63. * <p>Although combinations of these ways are possible, only one should be used
  64. * at a time. Problems might occur with the order in which properties are set, for
  65. * instance.</p>
  66. * <p>The value part of the properties being set, might contain references to other
  67. * properties. These references are resolved at the time these properties are set.
  68. * This also holds for properties loaded from a property file.</p>
  69. * Properties are case sensitive.
  70. *
  71. * @since Ant 1.1
  72. *
  73. * @ant.attribute.group name="name" description="One of these, when using the name attribute"
  74. * @ant.attribute.group name="noname" description="One of these, when not using the name attribute"
  75. * @ant.task category="property"
  76. */
  77. public class Property extends Task {
  78. // CheckStyle:VisibilityModifier OFF - bc
  79. protected String name;
  80. protected String value;
  81. protected File file;
  82. protected URL url;
  83. protected String resource;
  84. protected Path classpath;
  85. protected String env;
  86. protected Reference ref;
  87. protected String prefix;
  88. private Project fallback;
  89. private Object untypedValue;
  90. private boolean valueAttributeUsed = false;
  91. private boolean relative = false;
  92. private File basedir;
  93. protected boolean userProperty; // set read-only properties
  94. // CheckStyle:VisibilityModifier ON
  95. /**
  96. * Constructor for Property.
  97. */
  98. public Property() {
  99. this(false);
  100. }
  101. /**
  102. * Constructor for Property.
  103. * @param userProperty if true this is a user property
  104. * @since Ant 1.5
  105. */
  106. protected Property(boolean userProperty) {
  107. this(userProperty, null);
  108. }
  109. /**
  110. * Constructor for Property.
  111. * @param userProperty if true this is a user property
  112. * @param fallback a project to use to look for references if the reference is
  113. * not in the current project
  114. * @since Ant 1.5
  115. */
  116. protected Property(boolean userProperty, Project fallback) {
  117. this.userProperty = userProperty;
  118. this.fallback = fallback;
  119. }
  120. /**
  121. * Sets 'relative' attribute.
  122. * @param relative new value
  123. * @since Ant 1.8.0
  124. */
  125. public void setRelative(boolean relative) {
  126. this.relative = relative;
  127. }
  128. /**
  129. * Sets 'basedir' attribute.
  130. * @param basedir new value
  131. * @since Ant 1.8.0
  132. */
  133. public void setBasedir(File basedir) {
  134. this.basedir = basedir;
  135. }
  136. /**
  137. * The name of the property to set.
  138. * @param name property name
  139. */
  140. public void setName(String name) {
  141. this.name = name;
  142. }
  143. /**
  144. * Get the property name.
  145. * @return the property name
  146. */
  147. public String getName() {
  148. return name;
  149. }
  150. /**
  151. * Sets the property to the absolute filename of the
  152. * given file. If the value of this attribute is an absolute path, it
  153. * is left unchanged (with / and \ characters converted to the
  154. * current platforms conventions). Otherwise it is taken as a path
  155. * relative to the project's basedir and expanded.
  156. * @param location path to set
  157. *
  158. * @ant.attribute group="name"
  159. */
  160. public void setLocation(File location) {
  161. if (relative) {
  162. internalSetValue(location);
  163. } else {
  164. setValue(location.getAbsolutePath());
  165. }
  166. }
  167. /* the following method is first in source so IH will pick it up first:
  168. * Hopefully we'll never get any classes compiled by wise-guy compilers that behave otherwise...
  169. */
  170. /**
  171. * Set the value of the property.
  172. * @param value the value to use.
  173. */
  174. public void setValue(Object value) {
  175. valueAttributeUsed = true;
  176. internalSetValue(value);
  177. }
  178. private void internalSetValue(Object value) {
  179. this.untypedValue = value;
  180. //preserve protected string value for subclasses :(
  181. this.value = value == null ? null : value.toString();
  182. }
  183. /**
  184. * Set the value of the property as a String.
  185. * @param value value to assign
  186. *
  187. * @ant.attribute group="name"
  188. */
  189. public void setValue(String value) {
  190. setValue((Object) value);
  191. }
  192. /**
  193. * Set a (multiline) property as nested text.
  194. * @param msg the text to append to the output text
  195. * @since Ant 1.8.0
  196. */
  197. public void addText(String msg) {
  198. if (!valueAttributeUsed) {
  199. msg = getProject().replaceProperties(msg);
  200. String currentValue = getValue();
  201. if (currentValue != null) {
  202. msg = currentValue + msg;
  203. }
  204. internalSetValue(msg);
  205. } else if (msg.trim().length() > 0) {
  206. throw new BuildException("can't combine nested text with value"
  207. + " attribute");
  208. }
  209. }
  210. /**
  211. * Get the property value.
  212. * @return the property value
  213. */
  214. public String getValue() {
  215. return value;
  216. }
  217. /**
  218. * Filename of a property file to load.
  219. * @param file filename
  220. *
  221. * @ant.attribute group="noname"
  222. */
  223. public void setFile(File file) {
  224. this.file = file;
  225. }
  226. /**
  227. * Get the file attribute.
  228. * @return the file attribute
  229. */
  230. public File getFile() {
  231. return file;
  232. }
  233. /**
  234. * The url from which to load properties.
  235. * @param url url string
  236. *
  237. * @ant.attribute group="noname"
  238. */
  239. public void setUrl(URL url) {
  240. this.url = url;
  241. }
  242. /**
  243. * Get the url attribute.
  244. * @return the url attribute
  245. */
  246. public URL getUrl() {
  247. return url;
  248. }
  249. /**
  250. * Prefix to apply to properties loaded using <code>file</code>
  251. * or <code>resource</code>.
  252. * A "." is appended to the prefix if not specified.
  253. * @param prefix prefix string
  254. * @since Ant 1.5
  255. */
  256. public void setPrefix(String prefix) {
  257. this.prefix = prefix;
  258. if (!prefix.endsWith(".")) {
  259. this.prefix += ".";
  260. }
  261. }
  262. /**
  263. * Get the prefix attribute.
  264. * @return the prefix attribute
  265. * @since Ant 1.5
  266. */
  267. public String getPrefix() {
  268. return prefix;
  269. }
  270. /**
  271. * Sets a reference to an Ant datatype
  272. * declared elsewhere.
  273. * Only yields reasonable results for references
  274. * PATH like structures or properties.
  275. * @param ref reference
  276. *
  277. * @ant.attribute group="name"
  278. */
  279. public void setRefid(Reference ref) {
  280. this.ref = ref;
  281. }
  282. /**
  283. * Get the refid attribute.
  284. * @return the refid attribute
  285. */
  286. public Reference getRefid() {
  287. return ref;
  288. }
  289. /**
  290. * The resource name of a property file to load
  291. * @param resource resource on classpath
  292. *
  293. * @ant.attribute group="noname"
  294. */
  295. public void setResource(String resource) {
  296. this.resource = resource;
  297. }
  298. /**
  299. * Get the resource attribute.
  300. * @return the resource attribute
  301. */
  302. public String getResource() {
  303. return resource;
  304. }
  305. /**
  306. * Prefix to use when retrieving environment variables.
  307. * Thus if you specify environment=&quot;myenv&quot;
  308. * you will be able to access OS-specific
  309. * environment variables via property names &quot;myenv.PATH&quot; or
  310. * &quot;myenv.TERM&quot;.
  311. * <p>
  312. * Note that if you supply a property name with a final
  313. * &quot;.&quot; it will not be doubled. ie environment=&quot;myenv.&quot; will still
  314. * allow access of environment variables through &quot;myenv.PATH&quot; and
  315. * &quot;myenv.TERM&quot;. This functionality is currently only implemented
  316. * on select platforms. Feel free to send patches to increase the number of platforms
  317. * this functionality is supported on ;).<br>
  318. * Note also that properties are case sensitive, even if the
  319. * environment variables on your operating system are not, e.g. it
  320. * will be ${env.Path} not ${env.PATH} on Windows 2000.
  321. * @param env prefix
  322. *
  323. * @ant.attribute group="noname"
  324. */
  325. public void setEnvironment(String env) {
  326. this.env = env;
  327. }
  328. /**
  329. * Get the environment attribute.
  330. * @return the environment attribute
  331. * @since Ant 1.5
  332. */
  333. public String getEnvironment() {
  334. return env;
  335. }
  336. /**
  337. * The classpath to use when looking up a resource.
  338. * @param classpath to add to any existing classpath
  339. */
  340. public void setClasspath(Path classpath) {
  341. if (this.classpath == null) {
  342. this.classpath = classpath;
  343. } else {
  344. this.classpath.append(classpath);
  345. }
  346. }
  347. /**
  348. * The classpath to use when looking up a resource.
  349. * @return a path to be configured
  350. */
  351. public Path createClasspath() {
  352. if (this.classpath == null) {
  353. this.classpath = new Path(getProject());
  354. }
  355. return this.classpath.createPath();
  356. }
  357. /**
  358. * the classpath to use when looking up a resource,
  359. * given as reference to a &lt;path&gt; defined elsewhere
  360. * @param r a reference to a classpath
  361. */
  362. public void setClasspathRef(Reference r) {
  363. createClasspath().setRefid(r);
  364. }
  365. /**
  366. * Get the classpath used when looking up a resource.
  367. * @return the classpath
  368. * @since Ant 1.5
  369. */
  370. public Path getClasspath() {
  371. return classpath;
  372. }
  373. /**
  374. * @param userProperty ignored
  375. * @deprecated since 1.5.x.
  376. * This was never a supported feature and has been
  377. * deprecated without replacement.
  378. * @ant.attribute ignore="true"
  379. */
  380. public void setUserProperty(boolean userProperty) {
  381. log("DEPRECATED: Ignoring request to set user property in Property"
  382. + " task.", Project.MSG_WARN);
  383. }
  384. /**
  385. * get the value of this property
  386. * @return the current value or the empty string
  387. */
  388. public String toString() {
  389. return value == null ? "" : value;
  390. }
  391. /**
  392. * set the property in the project to the value.
  393. * if the task was give a file, resource or env attribute
  394. * here is where it is loaded
  395. * @throws BuildException on error
  396. */
  397. public void execute() throws BuildException {
  398. if (getProject() == null) {
  399. throw new IllegalStateException("project has not been set");
  400. }
  401. if (name != null) {
  402. if (untypedValue == null && ref == null) {
  403. throw new BuildException("You must specify value, location or "
  404. + "refid with the name attribute",
  405. getLocation());
  406. }
  407. } else {
  408. if (url == null && file == null && resource == null && env == null) {
  409. throw new BuildException("You must specify url, file, resource or "
  410. + "environment when not using the "
  411. + "name attribute", getLocation());
  412. }
  413. }
  414. if (url == null && file == null && resource == null && prefix != null) {
  415. throw new BuildException("Prefix is only valid when loading from "
  416. + "a url, file or resource", getLocation());
  417. }
  418. if (name != null && untypedValue != null) {
  419. if (relative) {
  420. try {
  421. File from = untypedValue instanceof File ? (File)untypedValue : new File(untypedValue.toString());
  422. File to = basedir != null ? basedir : getProject().getBaseDir();
  423. String relPath = FileUtils.getFileUtils().getRelativePath(to, from);
  424. relPath = relPath.replace('/', File.separatorChar);
  425. addProperty(name, relPath);
  426. } catch (Exception e) {
  427. throw new BuildException(e, getLocation());
  428. }
  429. } else {
  430. addProperty(name, untypedValue);
  431. }
  432. }
  433. if (file != null) {
  434. loadFile(file);
  435. }
  436. if (url != null) {
  437. loadUrl(url);
  438. }
  439. if (resource != null) {
  440. loadResource(resource);
  441. }
  442. if (env != null) {
  443. loadEnvironment(env);
  444. }
  445. if ((name != null) && (ref != null)) {
  446. try {
  447. addProperty(name,
  448. ref.getReferencedObject(getProject()).toString());
  449. } catch (BuildException be) {
  450. if (fallback != null) {
  451. addProperty(name,
  452. ref.getReferencedObject(fallback).toString());
  453. } else {
  454. throw be;
  455. }
  456. }
  457. }
  458. }
  459. /**
  460. * load properties from a url
  461. * @param url url to load from
  462. * @throws BuildException on error
  463. */
  464. protected void loadUrl(URL url) throws BuildException {
  465. Properties props = new Properties();
  466. log("Loading " + url, Project.MSG_VERBOSE);
  467. try {
  468. InputStream is = url.openStream();
  469. try {
  470. loadProperties(props, is, url.getFile().endsWith(".xml"));
  471. } finally {
  472. if (is != null) {
  473. is.close();
  474. }
  475. }
  476. addProperties(props);
  477. } catch (IOException ex) {
  478. throw new BuildException(ex, getLocation());
  479. }
  480. }
  481. /**
  482. * Loads the properties defined in the InputStream into the given
  483. * property. On Java5+ it supports reading from XML based property
  484. * definition.
  485. * @param props The property object to load into
  486. * @param is The input stream from where to load
  487. * @param isXml <tt>true</tt> if we should try to load from xml
  488. * @throws IOException if something goes wrong
  489. * @since 1.7.1
  490. * @see http://java.sun.com/dtd/properties.dtd
  491. * @see java.util.Properties#loadFromXML(InputStream)
  492. */
  493. private void loadProperties(
  494. Properties props, InputStream is, boolean isXml) throws IOException {
  495. if (isXml) {
  496. // load the xml based property definition
  497. // use reflection because of bwc to Java 1.3
  498. try {
  499. Method loadXmlMethod = props.getClass().getMethod("loadFromXML",
  500. new Class[] {InputStream.class});
  501. loadXmlMethod.invoke(props, new Object[] {is});
  502. } catch (NoSuchMethodException e) {
  503. e.printStackTrace();
  504. log("Can not load xml based property definition on Java < 5");
  505. } catch (Exception e) {
  506. // no-op
  507. e.printStackTrace();
  508. }
  509. } else {
  510. // load ".properties" format
  511. props.load(is);
  512. }
  513. }
  514. /**
  515. * load properties from a file
  516. * @param file file to load
  517. * @throws BuildException on error
  518. */
  519. protected void loadFile(File file) throws BuildException {
  520. Properties props = new Properties();
  521. log("Loading " + file.getAbsolutePath(), Project.MSG_VERBOSE);
  522. try {
  523. if (file.exists()) {
  524. FileInputStream fis = null;
  525. try {
  526. fis = new FileInputStream(file);
  527. loadProperties(props, fis, file.getName().endsWith(".xml"));
  528. } finally {
  529. FileUtils.close(fis);
  530. }
  531. addProperties(props);
  532. } else {
  533. log("Unable to find property file: " + file.getAbsolutePath(),
  534. Project.MSG_VERBOSE);
  535. }
  536. } catch (IOException ex) {
  537. throw new BuildException(ex, getLocation());
  538. }
  539. }
  540. /**
  541. * load properties from a resource in the current classpath
  542. * @param name name of resource to load
  543. */
  544. protected void loadResource(String name) {
  545. Properties props = new Properties();
  546. log("Resource Loading " + name, Project.MSG_VERBOSE);
  547. InputStream is = null;
  548. ClassLoader cL = null;
  549. boolean cleanup = false;
  550. try {
  551. if (classpath != null) {
  552. cleanup = true;
  553. cL = getProject().createClassLoader(classpath);
  554. } else {
  555. cL = this.getClass().getClassLoader();
  556. }
  557. if (cL == null) {
  558. is = ClassLoader.getSystemResourceAsStream(name);
  559. } else {
  560. is = cL.getResourceAsStream(name);
  561. }
  562. if (is != null) {
  563. loadProperties(props, is, name.endsWith(".xml"));
  564. addProperties(props);
  565. } else {
  566. log("Unable to find resource " + name, Project.MSG_WARN);
  567. }
  568. } catch (IOException ex) {
  569. throw new BuildException(ex, getLocation());
  570. } finally {
  571. if (is != null) {
  572. try {
  573. is.close();
  574. } catch (IOException e) {
  575. // ignore
  576. }
  577. }
  578. if (cleanup && cL != null) {
  579. ((AntClassLoader) cL).cleanup();
  580. }
  581. }
  582. }
  583. /**
  584. * load the environment values
  585. * @param prefix prefix to place before them
  586. */
  587. protected void loadEnvironment(String prefix) {
  588. Properties props = new Properties();
  589. if (!prefix.endsWith(".")) {
  590. prefix += ".";
  591. }
  592. log("Loading Environment " + prefix, Project.MSG_VERBOSE);
  593. Vector osEnv = Execute.getProcEnvironment();
  594. for (Enumeration e = osEnv.elements(); e.hasMoreElements();) {
  595. String entry = (String) e.nextElement();
  596. int pos = entry.indexOf('=');
  597. if (pos == -1) {
  598. log("Ignoring: " + entry, Project.MSG_WARN);
  599. } else {
  600. props.put(prefix + entry.substring(0, pos),
  601. entry.substring(pos + 1));
  602. }
  603. }
  604. addProperties(props);
  605. }
  606. /**
  607. * iterate through a set of properties,
  608. * resolve them then assign them
  609. * @param props the properties to iterate over
  610. */
  611. protected void addProperties(Properties props) {
  612. HashMap m = new HashMap(props);
  613. resolveAllProperties(m);
  614. for (Iterator it = m.keySet().iterator(); it.hasNext();) {
  615. Object k = it.next();
  616. if (k instanceof String) {
  617. String propertyName = (String) k;
  618. if (prefix != null) {
  619. propertyName = prefix + propertyName;
  620. }
  621. addProperty(propertyName, m.get(k));
  622. }
  623. }
  624. }
  625. /**
  626. * add a name value pair to the project property set
  627. * @param n name of property
  628. * @param v value to set
  629. */
  630. protected void addProperty(String n, String v) {
  631. addProperty(n, (Object) v);
  632. }
  633. /**
  634. * add a name value pair to the project property set
  635. * @param n name of property
  636. * @param v value to set
  637. * @since Ant 1.8
  638. */
  639. protected void addProperty(String n, Object v) {
  640. PropertyHelper ph = PropertyHelper.getPropertyHelper(getProject());
  641. if (userProperty) {
  642. if (ph.getUserProperty(n) == null) {
  643. ph.setInheritedProperty(n, v);
  644. } else {
  645. log("Override ignored for " + n, Project.MSG_VERBOSE);
  646. }
  647. } else {
  648. ph.setNewProperty(n, v);
  649. }
  650. }
  651. /**
  652. * resolve properties inside a properties hashtable
  653. * @param props properties object to resolve
  654. */
  655. private void resolveAllProperties(Map props) throws BuildException {
  656. PropertyHelper propertyHelper
  657. = (PropertyHelper) PropertyHelper.getPropertyHelper(getProject());
  658. new ResolvePropertyMap(
  659. getProject(),
  660. propertyHelper,
  661. propertyHelper.getExpanders()).resolveAllProperties(props);
  662. }
  663. }