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: package org.apache.catalina.ant;
019:
020: import java.io.BufferedOutputStream;
021: import java.io.InputStream;
022: import java.io.InputStreamReader;
023: import java.net.HttpURLConnection;
024: import java.net.URL;
025: import java.net.URLConnection;
026: import org.apache.catalina.util.Base64;
027: import org.apache.tools.ant.BuildException;
028: import org.apache.tools.ant.Project;
029:
030: /**
031: * Abstract base class for Ant tasks that interact with the
032: * <em>Manager</em> web application for dynamically deploying and
033: * undeploying applications. These tasks require Ant 1.4 or later.
034: *
035: * @author Craig R. McClanahan
036: * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
037: * @since 4.1
038: */
039:
040: public abstract class AbstractCatalinaTask extends
041: BaseRedirectorHelperTask {
042:
043: // ----------------------------------------------------- Instance Variables
044:
045: /**
046: * manager webapp's encoding.
047: */
048: private static String CHARSET = "utf-8";
049:
050: // ------------------------------------------------------------- Properties
051:
052: /**
053: * The charset used during URL encoding.
054: */
055: protected String charset = "ISO-8859-1";
056:
057: public String getCharset() {
058: return (this .charset);
059: }
060:
061: public void setCharset(String charset) {
062: this .charset = charset;
063: }
064:
065: /**
066: * The login password for the <code>Manager</code> application.
067: */
068: protected String password = null;
069:
070: public String getPassword() {
071: return (this .password);
072: }
073:
074: public void setPassword(String password) {
075: this .password = password;
076: }
077:
078: /**
079: * The URL of the <code>Manager</code> application to be used.
080: */
081: protected String url = "http://localhost:8080/manager";
082:
083: public String getUrl() {
084: return (this .url);
085: }
086:
087: public void setUrl(String url) {
088: this .url = url;
089: }
090:
091: /**
092: * The login username for the <code>Manager</code> application.
093: */
094: protected String username = null;
095:
096: public String getUsername() {
097: return (this .username);
098: }
099:
100: public void setUsername(String username) {
101: this .username = username;
102: }
103:
104: // --------------------------------------------------------- Public Methods
105:
106: /**
107: * Execute the specified command. This logic only performs the common
108: * attribute validation required by all subclasses; it does not perform
109: * any functional logic directly.
110: *
111: * @exception BuildException if a validation error occurs
112: */
113: public void execute() throws BuildException {
114:
115: if ((username == null) || (password == null) || (url == null)) {
116: throw new BuildException(
117: "Must specify all of 'username', 'password', and 'url'");
118: }
119:
120: }
121:
122: // ------------------------------------------------------ Protected Methods
123:
124: /**
125: * Execute the specified command, based on the configured properties.
126: *
127: * @param command Command to be executed
128: *
129: * @exception BuildException if an error occurs
130: */
131: public void execute(String command) throws BuildException {
132:
133: execute(command, null, null, -1);
134:
135: }
136:
137: /**
138: * Execute the specified command, based on the configured properties.
139: * The input stream will be closed upon completion of this task, whether
140: * it was executed successfully or not.
141: *
142: * @param command Command to be executed
143: * @param istream InputStream to include in an HTTP PUT, if any
144: * @param contentType Content type to specify for the input, if any
145: * @param contentLength Content length to specify for the input, if any
146: *
147: * @exception BuildException if an error occurs
148: */
149: public void execute(String command, InputStream istream,
150: String contentType, int contentLength)
151: throws BuildException {
152:
153: URLConnection conn = null;
154: InputStreamReader reader = null;
155: try {
156:
157: // Create a connection for this command
158: conn = (new URL(url + command)).openConnection();
159: HttpURLConnection hconn = (HttpURLConnection) conn;
160:
161: // Set up standard connection characteristics
162: hconn.setAllowUserInteraction(false);
163: hconn.setDoInput(true);
164: hconn.setUseCaches(false);
165: if (istream != null) {
166: hconn.setDoOutput(true);
167: hconn.setRequestMethod("PUT");
168: if (contentType != null) {
169: hconn.setRequestProperty("Content-Type",
170: contentType);
171: }
172: if (contentLength >= 0) {
173: hconn.setRequestProperty("Content-Length", ""
174: + contentLength);
175: }
176: } else {
177: hconn.setDoOutput(false);
178: hconn.setRequestMethod("GET");
179: }
180: hconn.setRequestProperty("User-Agent",
181: "Catalina-Ant-Task/1.0");
182:
183: // Set up an authorization header with our credentials
184: String input = username + ":" + password;
185: String output = new String(Base64.encode(input.getBytes()));
186: hconn
187: .setRequestProperty("Authorization", "Basic "
188: + output);
189:
190: // Establish the connection with the server
191: hconn.connect();
192:
193: // Send the request data (if any)
194: if (istream != null) {
195: BufferedOutputStream ostream = new BufferedOutputStream(
196: hconn.getOutputStream(), 1024);
197: byte buffer[] = new byte[1024];
198: while (true) {
199: int n = istream.read(buffer);
200: if (n < 0) {
201: break;
202: }
203: ostream.write(buffer, 0, n);
204: }
205: ostream.flush();
206: ostream.close();
207: istream.close();
208: }
209:
210: // Process the response message
211: reader = new InputStreamReader(hconn.getInputStream(),
212: CHARSET);
213: StringBuffer buff = new StringBuffer();
214: String error = null;
215: int msgPriority = Project.MSG_INFO;
216: boolean first = true;
217: while (true) {
218: int ch = reader.read();
219: if (ch < 0) {
220: break;
221: } else if ((ch == '\r') || (ch == '\n')) {
222: // in Win \r\n would cause handleOutput() to be called
223: // twice, the second time with an empty string,
224: // producing blank lines
225: if (buff.length() > 0) {
226: String line = buff.toString();
227: buff.setLength(0);
228: if (first) {
229: if (!line.startsWith("OK -")) {
230: error = line;
231: msgPriority = Project.MSG_ERR;
232: }
233: first = false;
234: }
235: handleOutput(line, msgPriority);
236: }
237: } else {
238: buff.append((char) ch);
239: }
240: }
241: if (buff.length() > 0) {
242: handleOutput(buff.toString(), msgPriority);
243: }
244: if (error != null && isFailOnError()) {
245: // exception should be thrown only if failOnError == true
246: // or error line will be logged twice
247: throw new BuildException(error);
248: }
249: } catch (Throwable t) {
250: if (isFailOnError()) {
251: throw new BuildException(t);
252: } else {
253: handleErrorOutput(t.getMessage());
254: }
255: } finally {
256: closeRedirector();
257: if (reader != null) {
258: try {
259: reader.close();
260: } catch (Throwable u) {
261: ;
262: }
263: reader = null;
264: }
265: if (istream != null) {
266: try {
267: istream.close();
268: } catch (Throwable u) {
269: ;
270: }
271: istream = null;
272: }
273: }
274:
275: }
276:
277: }
|