1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import org.apache.tools.ant.Task;
  19. import org.apache.tools.ant.BuildException;
  20. import org.apache.tools.ant.ExitStatusException;
  21. import org.apache.tools.ant.taskdefs.condition.Condition;
  22. import org.apache.tools.ant.taskdefs.condition.ConditionBase;
  23. /**
  24. * Exits the active build, giving an additional message
  25. * if available.
  26. *
  27. * The <code>if</code> and <code>unless</code> attributes make the
  28. * failure conditional -both probe for the named property being defined.
  29. * The <code>if</code> tests for the property being defined, the
  30. * <code>unless</code> for a property being undefined.
  31. *
  32. * If both attributes are set, then the test fails only if both tests
  33. * are true. i.e.
  34. * <pre>fail := defined(ifProperty) && !defined(unlessProperty)</pre>
  35. *
  36. * A single nested<CODE><condition></CODE> element can be specified
  37. * instead of using <CODE>if</CODE>/<CODE>unless</CODE> (a combined
  38. * effect can be achieved using <CODE>isset</CODE> conditions).
  39. *
  40. * @since Ant 1.2
  41. *
  42. * @ant.task name="fail" category="control"
  43. */
  44. public class Exit extends Task {
  45. private class NestedCondition extends ConditionBase implements Condition {
  46. public boolean eval() {
  47. if (countConditions() != 1) {
  48. throw new BuildException(
  49. "A single nested condition is required.");
  50. }
  51. return ((Condition)(getConditions().nextElement())).eval();
  52. }
  53. }
  54. private String message;
  55. private String ifCondition, unlessCondition;
  56. private NestedCondition nestedCondition;
  57. private Integer status;
  58. /**
  59. * A message giving further information on why the build exited.
  60. *
  61. * @param value message to output
  62. */
  63. public void setMessage(String value) {
  64. this.message = value;
  65. }
  66. /**
  67. * Only fail if a property of the given name exists in the current project.
  68. * @param c property name
  69. */
  70. public void setIf(String c) {
  71. ifCondition = c;
  72. }
  73. /**
  74. * Only fail if a property of the given name does not
  75. * exist in the current project.
  76. * @param c property name
  77. */
  78. public void setUnless(String c) {
  79. unlessCondition = c;
  80. }
  81. /**
  82. * Set the status code to associate with the thrown Exception.
  83. * @param i the <CODE>int</CODE> status
  84. */
  85. public void setStatus(int i) {
  86. status = new Integer(i);
  87. }
  88. /**
  89. * Throw a <CODE>BuildException</CODE> to exit (fail) the build.
  90. * If specified, evaluate conditions:
  91. * A single nested condition is accepted, but requires that the
  92. * <CODE>if</CODE>/<code>unless</code> attributes be omitted.
  93. * If the nested condition evaluates to true, or the
  94. * ifCondition is true or unlessCondition is false, the build will exit.
  95. * The error message is constructed from the text fields, from
  96. * the nested condition (if specified), or finally from
  97. * the if and unless parameters (if present).
  98. * @throws BuildException
  99. */
  100. public void execute() throws BuildException {
  101. boolean fail = (nestedConditionPresent()) ? testNestedCondition()
  102. : (testIfCondition() && testUnlessCondition());
  103. if (fail) {
  104. String text = null;
  105. if (message != null && message.trim().length() > 0) {
  106. text = message.trim();
  107. } else {
  108. if (ifCondition != null && ifCondition.length() > 0
  109. && getProject().getProperty(ifCondition) != null) {
  110. text = "if=" + ifCondition;
  111. }
  112. if (unlessCondition != null && unlessCondition.length() > 0
  113. && getProject().getProperty(unlessCondition) == null) {
  114. if (text == null) {
  115. text = "";
  116. } else {
  117. text += " and ";
  118. }
  119. text += "unless=" + unlessCondition;
  120. }
  121. if (nestedConditionPresent()) {
  122. text = "condition satisfied";
  123. } else {
  124. if (text == null) {
  125. text = "No message";
  126. }
  127. }
  128. }
  129. throw ((status == null) ? new BuildException(text)
  130. : new ExitStatusException(text, status.intValue()));
  131. }
  132. }
  133. /**
  134. * Set a multiline message.
  135. * @param msg the message to display
  136. */
  137. public void addText(String msg) {
  138. if (message == null) {
  139. message = "";
  140. }
  141. message += getProject().replaceProperties(msg);
  142. }
  143. /**
  144. * Add a condition element.
  145. * @return <CODE>ConditionBase</CODE>.
  146. * @since Ant 1.6.2
  147. */
  148. public ConditionBase createCondition() {
  149. if (nestedCondition != null) {
  150. throw new BuildException("Only one nested condition is allowed.");
  151. }
  152. nestedCondition = new NestedCondition();
  153. return nestedCondition;
  154. }
  155. /**
  156. * test the if condition
  157. * @return true if there is no if condition, or the named property exists
  158. */
  159. private boolean testIfCondition() {
  160. if (ifCondition == null || "".equals(ifCondition)) {
  161. return true;
  162. }
  163. return getProject().getProperty(ifCondition) != null;
  164. }
  165. /**
  166. * test the unless condition
  167. * @return true if there is no unless condition,
  168. * or there is a named property but it doesn't exist
  169. */
  170. private boolean testUnlessCondition() {
  171. if (unlessCondition == null || "".equals(unlessCondition)) {
  172. return true;
  173. }
  174. return getProject().getProperty(unlessCondition) == null;
  175. }
  176. /**
  177. * test the nested condition
  178. * @return true if there is none, or it evaluates to true
  179. */
  180. private boolean testNestedCondition() {
  181. boolean result = nestedConditionPresent();
  182. if (result && ifCondition != null || unlessCondition != null) {
  183. throw new BuildException("Nested conditions "
  184. + "not permitted in conjunction with if/unless attributes");
  185. }
  186. return result && nestedCondition.eval();
  187. }
  188. /**
  189. * test whether there is a nested condition.
  190. * @return <CODE>boolean</CODE>.
  191. */
  192. private boolean nestedConditionPresent() {
  193. return (nestedCondition != null);
  194. }
  195. }