001: /*
002: * ========================================================================
003: *
004: * Copyright 2004 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: * ========================================================================
019: */
020: package org.apache.cactus.integration.ant.container.resin;
021:
022: import java.io.File;
023: import java.net.URL;
024:
025: import org.apache.cactus.integration.ant.container.ContainerRunner;
026: import org.apache.cactus.integration.ant.deployment.EarParser;
027: import org.apache.cactus.integration.ant.deployment.WarParser;
028: import org.apache.cactus.integration.ant.util.DefaultAntTaskFactory;
029: import org.apache.tools.ant.BuildException;
030: import org.apache.tools.ant.Task;
031: import org.apache.tools.ant.types.Path;
032:
033: /**
034: * Task to start/stop a Resin instance.
035: *
036: * @since Cactus 1.7
037: * @version $Id: AbstractResinTask.java 239035 2004-08-15 15:02:27Z vmassol $
038: */
039: public abstract class AbstractResinTask extends Task {
040: /**
041: * The mandatory Resin installation directory.
042: */
043: private File dir;
044:
045: /**
046: * The action that will be executed by this task
047: * @see #setAction(String)
048: */
049: private String action;
050:
051: /**
052: * The archive that contains the enterprise application that will be
053: * deployed
054: */
055: private File earFile;
056:
057: /**
058: * The archive that contains the web-app that will be deployed.
059: */
060: private File warFile;
061:
062: /**
063: * URL used to verify if the container is started.
064: */
065: private URL testURL;
066:
067: /**
068: * A user-specific resin.conf configuration file. If this variable is not
069: * set, the default configuration file from the JAR resources will be used.
070: */
071: private File resinConf;
072:
073: /**
074: * The port to which the container should be bound.
075: */
076: private int port = 8080;
077:
078: /**
079: * The temporary directory from which the container will be started.
080: */
081: private File tmpDir;
082:
083: /**
084: * The file to which output of the container should be written.
085: */
086: private File output;
087:
088: /**
089: * Whether output of the container should be appended to an existing file,
090: * or the existing file should be truncated.
091: */
092: private boolean append;
093:
094: /**
095: * Additional classpath entries for the classpath that will be used to
096: * start the containers.
097: */
098: private Path containerClasspath;
099:
100: /**
101: * Sets the Resin installation directory.
102: *
103: * @param theDir The directory to set
104: */
105: public final void setDir(File theDir) {
106: this .dir = theDir;
107: }
108:
109: /**
110: * Sets the action to execute (either "start" or "stop").
111: *
112: * @param theAction the action that will be executed by this task
113: */
114: public void setAction(String theAction) {
115: this .action = theAction;
116: }
117:
118: /**
119: * Sets a web application archive to deploy in the container.
120: *
121: * @param theWarFile The WAR file to deploy
122: */
123: public final void setWarFile(File theWarFile) {
124: if (getEarFile() != null) {
125: throw new BuildException(
126: "You may only specify one of [earfile] and [warfile]");
127: }
128: this .warFile = theWarFile;
129: }
130:
131: /**
132: * Sets an enterprise application aarchive to deploy.
133: *
134: * @param theEarFile The EAR file to deploy
135: */
136: public final void setEarFile(File theEarFile) {
137: if (getWarFile() != null) {
138: throw new BuildException(
139: "You may only specify one of [earfile] and [warfile]");
140: }
141: this .earFile = theEarFile;
142: }
143:
144: /**
145: * Sets the URL to call for testing if the server is running.
146: *
147: * @param theTestURL the test URL to ping
148: */
149: public void setTestURL(URL theTestURL) {
150: this .testURL = theTestURL;
151: }
152:
153: /**
154: * Sets the temporary directory from which the container is run.
155: *
156: * @param theTmpDir The temporary directory to set
157: */
158: public final void setTmpDir(File theTmpDir) {
159: this .tmpDir = theTmpDir;
160: }
161:
162: /**
163: * Sets the configuration file to use for the test installation of Resin
164: *
165: * @param theResinConf The resin.conf file
166: */
167: public final void setResinConf(File theResinConf) {
168: this .resinConf = theResinConf;
169: }
170:
171: /**
172: * Sets the port to which the container should listen.
173: *
174: * @param thePort The port to set
175: */
176: public final void setPort(int thePort) {
177: this .port = thePort;
178: }
179:
180: /**
181: * Sets the file to which output of the container should be written.
182: *
183: * @param theOutput The output file to set
184: */
185: public final void setOutput(File theOutput) {
186: this .output = theOutput;
187: }
188:
189: /**
190: * Sets whether output of the container should be appended to an existing
191: * file, or the existing file should be truncated.
192: *
193: * @param isAppend Whether output should be appended
194: */
195: public final void setAppend(boolean isAppend) {
196: this .append = isAppend;
197: }
198:
199: /**
200: * Checks if the task is correctly initialized.
201: *
202: * @param theContainer the Resin container to verify
203: */
204: private void verify(AbstractResinContainer theContainer) {
205: theContainer.verify();
206:
207: if (getAction() == null) {
208: throw new BuildException(
209: "You must specify an [action] attribute");
210: }
211:
212: if (!getAction().equalsIgnoreCase("start")
213: && !getAction().equalsIgnoreCase("stop")) {
214: throw new BuildException(
215: "Valid actions are: [start] and [stop]");
216: }
217: }
218:
219: /**
220: * @return the instance of a Resin container to start/stop
221: */
222: protected abstract AbstractResinContainer getResinContainer();
223:
224: /**
225: * Start or stop the container depending on the action asked by the user.
226: * When starting the container, also prepare a valid container
227: * configuration and optionally deploy a war or ear in it.
228: *
229: * @see Task#execute()
230: */
231: public void execute() {
232: // Resin container that prepares, starts and stops a Resin
233: // instance.
234: AbstractResinContainer container = getResinContainer();
235:
236: // Sets the file to be deployed in the container.
237: if (getWarFile() != null) {
238: container.setDeployableFile(WarParser.parse(getWarFile()));
239: } else if (getEarFile() != null) {
240: container.setDeployableFile(EarParser.parse(getEarFile()));
241: }
242:
243: container.setDir(getDir());
244: container.setAntTaskFactory(new DefaultAntTaskFactory(
245: getProject(), getTaskName(), getLocation(),
246: getOwningTarget()));
247: container.setPort(getPort());
248:
249: // Add specific additional user-defined classpath
250: container.setContainerClasspath(this .containerClasspath);
251:
252: if (getResinConf() != null) {
253: container.setResinConf(getResinConf());
254: }
255:
256: if (getTmpDir() != null) {
257: container.setTmpDir(getTmpDir());
258: }
259:
260: if (getOutput() != null) {
261: container.setOutput(getOutput());
262: }
263:
264: if (getAppend()) {
265: container.setAppend(getAppend());
266: }
267:
268: // Verify that the task is correctly set up.
269: verify(container);
270:
271: // If the user has provided a test URL, we use a ContainerRunner
272: // that continuously polls this test URL to verify if the container
273: // is started. In that case, this task will only return when the
274: // container is up and running. If no test URL has been started
275: // we simply start the container and give back the control to the user
276: // without waiting for container to be up and running.
277:
278: ContainerRunner runner = null;
279: if (getTestURL() != null) {
280: runner = new ContainerRunner(container);
281: runner.setURL(getTestURL());
282: }
283:
284: // Decide whether to start or stop the container
285: if (getAction().equalsIgnoreCase("start")) {
286: if (getTestURL() != null) {
287: runner.startUpContainer();
288: } else {
289: container.startUp();
290: }
291: } else if (getAction().equalsIgnoreCase("stop")) {
292: if (getTestURL() != null) {
293: runner.shutDownContainer();
294: } else {
295: container.shutDown();
296: }
297: }
298: }
299:
300: /**
301: * @return the action to execute ("start" or "stop")
302: */
303: protected final String getAction() {
304: return this .action;
305: }
306:
307: /**
308: * @return the directory where Resin is installed
309: */
310: protected final File getDir() {
311: return this .dir;
312: }
313:
314: /**
315: * @return the test URL to ping to verify if the container is started
316: */
317: protected final URL getTestURL() {
318: return this .testURL;
319: }
320:
321: /**
322: * @return the port to use to start the container
323: */
324: protected final int getPort() {
325: return this .port;
326: }
327:
328: /**
329: * @return the configuration file to use for the test installation of Resin
330: */
331: protected final File getResinConf() {
332: return this .resinConf;
333: }
334:
335: /**
336: * @return the WAR file to deploy or null if none
337: */
338: protected final File getWarFile() {
339: return this .warFile;
340: }
341:
342: /**
343: * @return the EAR file to deploy or null if none
344: */
345: protected final File getEarFile() {
346: return this .earFile;
347: }
348:
349: /**
350: * @return the temporary directory from which the container is run
351: */
352: protected final File getTmpDir() {
353: return this .tmpDir;
354: }
355:
356: /**
357: * @return the file to which output of the container should be written
358: */
359: protected final File getOutput() {
360: return this .output;
361: }
362:
363: /**
364: * @return whether output of the container should be appended to an
365: * existing file, or the existing file should be truncated
366: */
367: protected final boolean getAppend() {
368: return this .append;
369: }
370:
371: /**
372: * Adds container classpath to the classpath that will be used for starting
373: * the container.
374: *
375: * @return reference to the classpath
376: */
377: public Path createContainerClasspath() {
378: if (this .containerClasspath == null) {
379: this .containerClasspath = new Path(this.project);
380: }
381:
382: return this.containerClasspath.createPath();
383: }
384: }
|