001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs;
020:
021: import org.apache.tools.ant.Project;
022: import org.apache.tools.ant.Task;
023: import org.apache.tools.ant.BuildException;
024: import org.apache.tools.ant.ExitStatusException;
025: import org.apache.tools.ant.taskdefs.condition.Condition;
026: import org.apache.tools.ant.taskdefs.condition.ConditionBase;
027:
028: /**
029: * Exits the active build, giving an additional message
030: * if available.
031: *
032: * The <code>if</code> and <code>unless</code> attributes make the
033: * failure conditional -both probe for the named property being defined.
034: * The <code>if</code> tests for the property being defined, the
035: * <code>unless</code> for a property being undefined.
036: *
037: * If both attributes are set, then the test fails only if both tests
038: * are true. i.e.
039: * <pre>fail := defined(ifProperty) && !defined(unlessProperty)</pre>
040: *
041: * A single nested<code><condition></code> element can be specified
042: * instead of using <code>if</code>/<code>unless</code> (a combined
043: * effect can be achieved using <code>isset</code> conditions).
044: *
045: * @since Ant 1.2
046: *
047: * @ant.task name="fail" category="control"
048: */
049: public class Exit extends Task {
050:
051: private static class NestedCondition extends ConditionBase
052: implements Condition {
053: public boolean eval() {
054: if (countConditions() != 1) {
055: throw new BuildException(
056: "A single nested condition is required.");
057: }
058: return ((Condition) (getConditions().nextElement())).eval();
059: }
060: }
061:
062: private String message;
063: private String ifCondition, unlessCondition;
064: private NestedCondition nestedCondition;
065: private Integer status;
066:
067: /**
068: * A message giving further information on why the build exited.
069: *
070: * @param value message to output
071: */
072: public void setMessage(String value) {
073: this .message = value;
074: }
075:
076: /**
077: * Only fail if a property of the given name exists in the current project.
078: * @param c property name
079: */
080: public void setIf(String c) {
081: ifCondition = c;
082: }
083:
084: /**
085: * Only fail if a property of the given name does not
086: * exist in the current project.
087: * @param c property name
088: */
089: public void setUnless(String c) {
090: unlessCondition = c;
091: }
092:
093: /**
094: * Set the status code to associate with the thrown Exception.
095: * @param i the <code>int</code> status
096: */
097: public void setStatus(int i) {
098: status = new Integer(i);
099: }
100:
101: /**
102: * Throw a <code>BuildException</code> to exit (fail) the build.
103: * If specified, evaluate conditions:
104: * A single nested condition is accepted, but requires that the
105: * <code>if</code>/<code>unless</code> attributes be omitted.
106: * If the nested condition evaluates to true, or the
107: * ifCondition is true or unlessCondition is false, the build will exit.
108: * The error message is constructed from the text fields, from
109: * the nested condition (if specified), or finally from
110: * the if and unless parameters (if present).
111: * @throws BuildException on error
112: */
113: public void execute() throws BuildException {
114: boolean fail = (nestedConditionPresent()) ? testNestedCondition()
115: : (testIfCondition() && testUnlessCondition());
116: if (fail) {
117: String text = null;
118: if (message != null && message.trim().length() > 0) {
119: text = message.trim();
120: } else {
121: if (ifCondition != null
122: && ifCondition.length() > 0
123: && getProject().getProperty(ifCondition) != null) {
124: text = "if=" + ifCondition;
125: }
126: if (unlessCondition != null
127: && unlessCondition.length() > 0
128: && getProject().getProperty(unlessCondition) == null) {
129: if (text == null) {
130: text = "";
131: } else {
132: text += " and ";
133: }
134: text += "unless=" + unlessCondition;
135: }
136: if (nestedConditionPresent()) {
137: text = "condition satisfied";
138: } else {
139: if (text == null) {
140: text = "No message";
141: }
142: }
143: }
144: log("failing due to " + text, Project.MSG_DEBUG);
145: throw ((status == null) ? new BuildException(text)
146: : new ExitStatusException(text, status.intValue()));
147: }
148: }
149:
150: /**
151: * Set a multiline message.
152: * @param msg the message to display
153: */
154: public void addText(String msg) {
155: if (message == null) {
156: message = "";
157: }
158: message += getProject().replaceProperties(msg);
159: }
160:
161: /**
162: * Add a condition element.
163: * @return <code>ConditionBase</code>.
164: * @since Ant 1.6.2
165: */
166: public ConditionBase createCondition() {
167: if (nestedCondition != null) {
168: throw new BuildException(
169: "Only one nested condition is allowed.");
170: }
171: nestedCondition = new NestedCondition();
172: return nestedCondition;
173: }
174:
175: /**
176: * test the if condition
177: * @return true if there is no if condition, or the named property exists
178: */
179: private boolean testIfCondition() {
180: if (ifCondition == null || "".equals(ifCondition)) {
181: return true;
182: }
183: return getProject().getProperty(ifCondition) != null;
184: }
185:
186: /**
187: * test the unless condition
188: * @return true if there is no unless condition,
189: * or there is a named property but it doesn't exist
190: */
191: private boolean testUnlessCondition() {
192: if (unlessCondition == null || "".equals(unlessCondition)) {
193: return true;
194: }
195: return getProject().getProperty(unlessCondition) == null;
196: }
197:
198: /**
199: * test the nested condition
200: * @return true if there is none, or it evaluates to true
201: */
202: private boolean testNestedCondition() {
203: boolean result = nestedConditionPresent();
204:
205: if (result && ifCondition != null || unlessCondition != null) {
206: throw new BuildException(
207: "Nested conditions "
208: + "not permitted in conjunction with if/unless attributes");
209: }
210:
211: return result && nestedCondition.eval();
212: }
213:
214: /**
215: * test whether there is a nested condition.
216: * @return <code>boolean</code>.
217: */
218: private boolean nestedConditionPresent() {
219: return (nestedCondition != null);
220: }
221:
222: }
|