1 package org.codehaus.mojo.tomcat;
2
3 /*
4 * Copyright 2005 Mark Hobson.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 import org.apache.commons.codec.binary.Base64;
20
21 import java.io.BufferedOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.io.OutputStream;
26 import java.net.HttpURLConnection;
27 import java.net.URL;
28 import java.net.URLEncoder;
29
30 /**
31 * A Tomcat manager webapp invocation wrapper.
32 *
33 * @author Mark Hobson <markhobson@gmail.com>
34 * @version $Id: TomcatManager.java 6588 2008-03-28 12:22:57Z bentmann $
35 */
36 public class TomcatManager
37 {
38 // ----------------------------------------------------------------------
39 // Constants
40 // ----------------------------------------------------------------------
41
42 /**
43 * The charset to use when decoding Tomcat manager responses.
44 */
45 private static final String MANAGER_CHARSET = "UTF-8";
46
47 // ----------------------------------------------------------------------
48 // Fields
49 // ----------------------------------------------------------------------
50
51 /**
52 * The full URL of the Tomcat manager instance to use.
53 */
54 private URL url;
55
56 /**
57 * The username to use when authenticating with Tomcat manager.
58 */
59 private String username;
60
61 /**
62 * The password to use when authenticating with Tomcat manager.
63 */
64 private String password;
65
66 /**
67 * The URL encoding charset to use when communicating with Tomcat manager.
68 */
69 private String charset;
70
71 /**
72 * The user agent name to use when communicating with Tomcat manager.
73 */
74 private String userAgent;
75
76 // ----------------------------------------------------------------------
77 // Constructors
78 // ----------------------------------------------------------------------
79
80 /**
81 * Creates a Tomcat manager wrapper for the specified URL that uses a
82 * username of <code>admin</code>, an empty password and ISO-8859-1 URL
83 * encoding.
84 *
85 * @param url the full URL of the Tomcat manager instance to use
86 */
87 public TomcatManager( URL url )
88 {
89 this( url, "admin" );
90 }
91
92 /**
93 * Creates a Tomcat manager wrapper for the specified URL and username that
94 * uses an empty password and ISO-8859-1 URL encoding.
95 *
96 * @param url the full URL of the Tomcat manager instance to use
97 * @param username the username to use when authenticating with Tomcat manager
98 */
99 public TomcatManager( URL url, String username )
100 {
101 this( url, username, "" );
102 }
103
104 /**
105 * Creates a Tomcat manager wrapper for the specified URL, username and
106 * password that uses ISO-8859-1 URL encoding.
107 *
108 * @param url the full URL of the Tomcat manager instance to use
109 * @param username the username to use when authenticating with Tomcat manager
110 * @param password the password to use when authenticating with Tomcat manager
111 */
112 public TomcatManager( URL url, String username, String password )
113 {
114 this( url, username, password, "ISO-8859-1" );
115 }
116
117 /**
118 * Creates a Tomcat manager wrapper for the specified URL, username,
119 * password and URL encoding.
120 *
121 * @param url the full URL of the Tomcat manager instance to use
122 * @param username the username to use when authenticating with Tomcat manager
123 * @param password the password to use when authenticating with Tomcat manager
124 * @param charset the URL encoding charset to use when communicating with
125 * Tomcat manager
126 */
127 public TomcatManager( URL url, String username, String password, String charset )
128 {
129 this.url = url;
130 this.username = username;
131 this.password = password;
132 this.charset = charset;
133 }
134
135 // ----------------------------------------------------------------------
136 // Public Methods
137 // ----------------------------------------------------------------------
138
139 /**
140 * Gets the full URL of the Tomcat manager instance.
141 *
142 * @return the full URL of the Tomcat manager instance
143 */
144 public URL getURL()
145 {
146 return url;
147 }
148
149 /**
150 * Gets the username to use when authenticating with Tomcat manager.
151 *
152 * @return the username to use when authenticating with Tomcat manager
153 */
154 public String getUserName()
155 {
156 return username;
157 }
158
159 /**
160 * Gets the password to use when authenticating with Tomcat manager.
161 *
162 * @return the password to use when authenticating with Tomcat manager
163 */
164 public String getPassword()
165 {
166 return password;
167 }
168
169 /**
170 * Gets the URL encoding charset to use when communicating with Tomcat
171 * manager.
172 *
173 * @return the URL encoding charset to use when communicating with Tomcat
174 * manager
175 */
176 public String getCharset()
177 {
178 return charset;
179 }
180
181 /**
182 * Gets the user agent name to use when communicating with Tomcat manager.
183 *
184 * @return the user agent name to use when communicating with Tomcat
185 * manager
186 */
187 public String getUserAgent()
188 {
189 return userAgent;
190 }
191
192 /**
193 * Sets the user agent name to use when communicating with Tomcat manager.
194 *
195 * @param userAgent the user agent name to use when communicating with Tomcat
196 * manager
197 */
198 public void setUserAgent( String userAgent )
199 {
200 this.userAgent = userAgent;
201 }
202
203 /**
204 * Deploys the specified WAR as a URL to the specified context path.
205 *
206 * @param path the webapp context path to deploy to
207 * @param war the URL of the WAR to deploy
208 * @return the Tomcat manager response
209 * @throws TomcatManagerException if the Tomcat manager request fails
210 * @throws IOException if an i/o error occurs
211 */
212 public String deploy( String path, URL war )
213 throws TomcatManagerException, IOException
214 {
215 return deploy( path, war, false );
216 }
217
218 /**
219 * Deploys the specified WAR as a URL to the specified context path,
220 * optionally undeploying the webapp if it already exists.
221 *
222 * @param path the webapp context path to deploy to
223 * @param war the URL of the WAR to deploy
224 * @param update whether to first undeploy the webapp if it already exists
225 * @return the Tomcat manager response
226 * @throws TomcatManagerException if the Tomcat manager request fails
227 * @throws IOException if an i/o error occurs
228 */
229 public String deploy( String path, URL war, boolean update )
230 throws TomcatManagerException, IOException
231 {
232 return deploy( path, war, update, null );
233 }
234
235 /**
236 * Deploys the specified WAR as a URL to the specified context path,
237 * optionally undeploying the webapp if it already exists and using the
238 * specified tag name.
239 *
240 * @param path the webapp context path to deploy to
241 * @param war the URL of the WAR to deploy
242 * @param update whether to first undeploy the webapp if it already exists
243 * @param tag the tag name to use
244 * @return the Tomcat manager response
245 * @throws TomcatManagerException if the Tomcat manager request fails
246 * @throws IOException if an i/o error occurs
247 */
248 public String deploy( String path, URL war, boolean update, String tag )
249 throws TomcatManagerException, IOException
250 {
251 return deployImpl( path, null, war, null, update, tag );
252 }
253
254 /**
255 * Deploys the specified WAR as a HTTP PUT to the specified context path.
256 *
257 * @param path the webapp context path to deploy to
258 * @param war an input stream to the WAR to deploy
259 * @return the Tomcat manager response
260 * @throws TomcatManagerException if the Tomcat manager request fails
261 * @throws IOException if an i/o error occurs
262 */
263 public String deploy( String path, InputStream war )
264 throws TomcatManagerException, IOException
265 {
266 return deploy( path, war, false );
267 }
268
269 /**
270 * Deploys the specified WAR as a HTTP PUT to the specified context path,
271 * optionally undeploying the webapp if it already exists.
272 *
273 * @param path the webapp context path to deploy to
274 * @param war an input stream to the WAR to deploy
275 * @param update whether to first undeploy the webapp if it already exists
276 * @return the Tomcat manager response
277 * @throws TomcatManagerException if the Tomcat manager request fails
278 * @throws IOException if an i/o error occurs
279 */
280 public String deploy( String path, InputStream war, boolean update )
281 throws TomcatManagerException, IOException
282 {
283 return deploy( path, war, update, null );
284 }
285
286 /**
287 * Deploys the specified WAR as a HTTP PUT to the specified context path,
288 * optionally undeploying the webapp if it already exists and using the
289 * specified tag name.
290 *
291 * @param path the webapp context path to deploy to
292 * @param war an input stream to the WAR to deploy
293 * @param update whether to first undeploy the webapp if it already exists
294 * @param tag the tag name to use
295 * @return the Tomcat manager response
296 * @throws TomcatManagerException if the Tomcat manager request fails
297 * @throws IOException if an i/o error occurs
298 */
299 public String deploy( String path, InputStream war, boolean update, String tag )
300 throws TomcatManagerException, IOException
301 {
302 return deployImpl( path, null, null, war, update, tag );
303 }
304
305 /**
306 * Deploys the specified context XML configuration to the specified context
307 * path.
308 *
309 * @param path the webapp context path to deploy to
310 * @param config the URL of the context XML configuration to deploy
311 * @return the Tomcat manager response
312 * @throws TomcatManagerException if the Tomcat manager request fails
313 * @throws IOException if an i/o error occurs
314 */
315 public String deployContext( String path, URL config )
316 throws TomcatManagerException, IOException
317 {
318 return deployContext( path, config, false );
319 }
320
321 /**
322 * Deploys the specified context XML configuration to the specified context
323 * path, optionally undeploying the webapp if it already exists.
324 *
325 * @param path the webapp context path to deploy to
326 * @param config the URL of the context XML configuration to deploy
327 * @param update whether to first undeploy the webapp if it already exists
328 * @return the Tomcat manager response
329 * @throws TomcatManagerException if the Tomcat manager request fails
330 * @throws IOException if an i/o error occurs
331 */
332 public String deployContext( String path, URL config, boolean update )
333 throws TomcatManagerException, IOException
334 {
335 return deployContext( path, config, update, null );
336 }
337
338 /**
339 * Deploys the specified context XML configuration to the specified context
340 * path, optionally undeploying the webapp if it already exists and using
341 * the specified tag name.
342 *
343 * @param path the webapp context path to deploy to
344 * @param config the URL of the context XML configuration to deploy
345 * @param update whether to first undeploy the webapp if it already exists
346 * @param tag the tag name to use
347 * @return the Tomcat manager response
348 * @throws TomcatManagerException if the Tomcat manager request fails
349 * @throws IOException if an i/o error occurs
350 */
351 public String deployContext( String path, URL config, boolean update, String tag )
352 throws TomcatManagerException, IOException
353 {
354 return deployContext( path, config, null, update, tag );
355 }
356
357 /**
358 * Deploys the specified context XML configuration and WAR as a URL to the
359 * specified context path.
360 *
361 * @param path the webapp context path to deploy to
362 * @param config the URL of the context XML configuration to deploy
363 * @param war the URL of the WAR to deploy
364 * @return the Tomcat manager response
365 * @throws TomcatManagerException if the Tomcat manager request fails
366 * @throws IOException if an i/o error occurs
367 */
368 public String deployContext( String path, URL config, URL war )
369 throws TomcatManagerException, IOException
370 {
371 return deployContext( path, config, war, false );
372 }
373
374 /**
375 * Deploys the specified context XML configuration and WAR as a URL to the
376 * specified context path, optionally undeploying the webapp if it already
377 * exists.
378 *
379 * @param path the webapp context path to deploy to
380 * @param config the URL of the context XML configuration to deploy
381 * @param war the URL of the WAR to deploy
382 * @param update whether to first undeploy the webapp if it already exists
383 * @return the Tomcat manager response
384 * @throws TomcatManagerException if the Tomcat manager request fails
385 * @throws IOException if an i/o error occurs
386 */
387 public String deployContext( String path, URL config, URL war, boolean update )
388 throws TomcatManagerException, IOException
389 {
390 return deployContext( path, config, war, update, null );
391 }
392
393 /**
394 * Deploys the specified context XML configuration and WAR as a URL to the
395 * specified context path, optionally undeploying the webapp if it already
396 * exists and using the specified tag name.
397 *
398 * @param path the webapp context path to deploy to
399 * @param config the URL of the context XML configuration to deploy
400 * @param war the URL of the WAR to deploy
401 * @param update whether to first undeploy the webapp if it already exists
402 * @param tag the tag name to use
403 * @return the Tomcat manager response
404 * @throws TomcatManagerException if the Tomcat manager request fails
405 * @throws IOException if an i/o error occurs
406 */
407 public String deployContext( String path, URL config, URL war, boolean update, String tag )
408 throws TomcatManagerException, IOException
409 {
410 return deployImpl( path, config, war, null, update, tag );
411 }
412
413 /**
414 * Undeploys the webapp at the specified context path.
415 *
416 * @param path the webapp context path to undeploy
417 * @return the Tomcat manager response
418 * @throws TomcatManagerException if the Tomcat manager request fails
419 * @throws IOException if an i/o error occurs
420 */
421 public String undeploy( String path )
422 throws TomcatManagerException, IOException
423 {
424 return invoke( "/undeploy?path=" + URLEncoder.encode( path, charset ) );
425 }
426
427 /**
428 * Reloads the webapp at the specified context path.
429 *
430 * @param path the webapp context path to reload
431 * @return the Tomcat manager response
432 * @throws TomcatManagerException if the Tomcat manager request fails
433 * @throws IOException if an i/o error occurs
434 */
435 public String reload( String path )
436 throws TomcatManagerException, IOException
437 {
438 return invoke( "/reload?path=" + URLEncoder.encode( path, charset ) );
439 }
440
441 /**
442 * Starts the webapp at the specified context path.
443 *
444 * @param path the webapp context path to start
445 * @return the Tomcat manager response
446 * @throws TomcatManagerException if the Tomcat manager request fails
447 * @throws IOException if an i/o error occurs
448 */
449 public String start( String path )
450 throws TomcatManagerException, IOException
451 {
452 return invoke( "/start?path=" + URLEncoder.encode( path, charset ) );
453 }
454
455 /**
456 * Stops the webapp at the specified context path.
457 *
458 * @param path the webapp context path to stop
459 * @return the Tomcat manager response
460 * @throws TomcatManagerException if the Tomcat manager request fails
461 * @throws IOException if an i/o error occurs
462 */
463 public String stop( String path )
464 throws TomcatManagerException, IOException
465 {
466 return invoke( "/stop?path=" + URLEncoder.encode( path, charset ) );
467 }
468
469 /**
470 * Lists all the currently deployed web applications.
471 *
472 * @return the list of currently deployed applications
473 * @throws TomcatManagerException if the Tomcat manager request fails
474 * @throws IOException if an i/o error occurs
475 */
476 public String list()
477 throws TomcatManagerException, IOException
478 {
479 return invoke( "/list" );
480 }
481
482 /**
483 * Lists information about the Tomcat version, OS, and JVM properties.
484 *
485 * @return the server information
486 * @throws TomcatManagerException if the Tomcat manager request fails
487 * @throws IOException if an i/o error occurs
488 */
489 public String getServerInfo()
490 throws TomcatManagerException, IOException
491 {
492 return invoke( "/serverinfo" );
493 }
494
495 /**
496 * Lists all of the global JNDI resources.
497 *
498 * @return the list of all global JNDI resources
499 * @throws TomcatManagerException if the Tomcat manager request fails
500 * @throws IOException if an i/o error occurs
501 */
502 public String getResources()
503 throws TomcatManagerException, IOException
504 {
505 return getResources( null );
506 }
507
508 /**
509 * Lists the global JNDI resources of the given type.
510 *
511 * @param type the class name of the resources to list, or <code>null</code>
512 * for all
513 * @return the list of global JNDI resources of the given type
514 * @throws TomcatManagerException if the Tomcat manager request fails
515 * @throws IOException if an i/o error occurs
516 */
517 public String getResources( String type )
518 throws TomcatManagerException, IOException
519 {
520 StringBuffer buffer = new StringBuffer();
521 buffer.append( "/resources" );
522
523 if ( type != null )
524 buffer.append( "?type=" + URLEncoder.encode( type, charset ) );
525
526 return invoke( buffer.toString() );
527 }
528
529 /**
530 * Lists the security role names and corresponding descriptions that are
531 * available.
532 *
533 * @return the list of security role names and corresponding descriptions
534 * @throws TomcatManagerException if the Tomcat manager request fails
535 * @throws IOException if an i/o error occurs
536 */
537 public String getRoles()
538 throws TomcatManagerException, IOException
539 {
540 return invoke( "/roles" );
541 }
542
543 /**
544 * Lists the default session timeout and the number of currently active
545 * sessions for the given context path.
546 *
547 * @param path the context path to list session information for
548 * @return the default session timeout and the number of currently active
549 * sessions
550 * @throws TomcatManagerException if the Tomcat manager request fails
551 * @throws IOException if an i/o error occurs
552 */
553 public String getSessions( String path )
554 throws TomcatManagerException, IOException
555 {
556 return invoke( "/sessions?path=" + URLEncoder.encode( path, charset ) );
557 }
558
559 // ----------------------------------------------------------------------
560 // Protected Methods
561 // ----------------------------------------------------------------------
562
563 /**
564 * Invokes Tomcat manager with the specified command.
565 *
566 * @param path the Tomcat manager command to invoke
567 * @return the Tomcat manager response
568 * @throws TomcatManagerException if the Tomcat manager request fails
569 * @throws IOException if an i/o error occurs
570 */
571 protected String invoke( String path )
572 throws TomcatManagerException, IOException
573 {
574 return invoke( path, null );
575 }
576
577 /**
578 * Invokes Tomcat manager with the specified command and content data.
579 *
580 * @param path the Tomcat manager command to invoke
581 * @param data an input stream to the content data
582 * @return the Tomcat manager response
583 * @throws TomcatManagerException if the Tomcat manager request fails
584 * @throws IOException if an i/o error occurs
585 */
586 protected String invoke( String path, InputStream data )
587 throws TomcatManagerException, IOException
588 {
589 HttpURLConnection connection = (HttpURLConnection) new URL( url + path ).openConnection();
590 connection.setAllowUserInteraction( false );
591 connection.setDoInput( true );
592 connection.setUseCaches( false );
593
594 if ( data == null )
595 {
596 connection.setDoOutput( false );
597 connection.setRequestMethod( "GET" );
598 }
599 else
600 {
601 connection.setDoOutput( true );
602 connection.setRequestMethod( "PUT" );
603 connection.setRequestProperty( "Content-Type", "application/octet-stream" );
604 }
605
606 if ( userAgent != null )
607 {
608 connection.setRequestProperty( "User-Agent", userAgent );
609 }
610 connection.setRequestProperty( "Authorization", toAuthorization( username, password ) );
611
612 connection.connect();
613
614 if ( data != null )
615 {
616 pipe( data, connection.getOutputStream() );
617 }
618
619 String response = toString( connection.getInputStream(), MANAGER_CHARSET );
620
621 if ( !response.startsWith( "OK -" ) )
622 {
623 throw new TomcatManagerException( response );
624 }
625
626 return response;
627 }
628
629 // ----------------------------------------------------------------------
630 // Private Methods
631 // ----------------------------------------------------------------------
632
633 /**
634 * Deploys the specified WAR.
635 *
636 * @param path the webapp context path to deploy to
637 * @param config the URL of the context XML configuration to deploy, or null
638 * for none
639 * @param war the URL of the WAR to deploy, or null to use
640 * <code>data</code>
641 * @param data an input stream to the WAR to deploy, or null to use
642 * <code>war</code>
643 * @param update whether to first undeploy the webapp if it already exists
644 * @param tag the tag name to use
645 * @return the Tomcat manager response
646 * @throws TomcatManagerException if the Tomcat manager request fails
647 * @throws IOException if an i/o error occurs
648 */
649 private String deployImpl( String path, URL config, URL war, InputStream data, boolean update, String tag )
650 throws TomcatManagerException, IOException
651 {
652 StringBuffer buffer = new StringBuffer( "/deploy" );
653 buffer.append( "?path=" ).append( URLEncoder.encode( path, charset ) );
654
655 if ( config != null )
656 {
657 buffer.append( "&config=" ).append( URLEncoder.encode( config.toString(), charset ) );
658 }
659
660 if ( war != null )
661 {
662 buffer.append( "&war=" ).append( URLEncoder.encode( war.toString(), charset ) );
663 }
664 else
665 {
666 // for Tomcat 5.0.27
667 buffer.append( "&war=" );
668 }
669
670 if ( update )
671 {
672 buffer.append( "&update=true" );
673 }
674
675 if ( tag != null )
676 {
677 buffer.append( "&tag=" ).append( URLEncoder.encode( tag, charset ) );
678 }
679
680 return invoke( buffer.toString(), data );
681 }
682
683 /**
684 * Gets the HTTP Basic Authorization header value for the supplied username
685 * and password.
686 *
687 * @param username the username to use for authentication
688 * @param password the password to use for authentication
689 * @return the HTTP Basic Authorization header value
690 */
691 private String toAuthorization( String username, String password )
692 {
693 StringBuffer buffer = new StringBuffer();
694 buffer.append( username ).append( ':' );
695 if ( password != null )
696 {
697 buffer.append( password );
698 }
699 return "Basic " + new String( Base64.encodeBase64( buffer.toString().getBytes() ) );
700 }
701
702 /**
703 * Reads all the data from the specified input stream and writes it to the
704 * specified output stream. Both streams are also closed.
705 *
706 * @param in the input stream to read from
707 * @param out the output stream to write to
708 * @throws IOException if an i/o error occurs
709 */
710 private void pipe( InputStream in, OutputStream out )
711 throws IOException
712 {
713 out = new BufferedOutputStream( out );
714 int n;
715 byte[] bytes = new byte[1024 * 4];
716 while ( ( n = in.read( bytes ) ) != -1 )
717 {
718 out.write( bytes, 0, n );
719 }
720 out.flush();
721 out.close();
722 in.close();
723 }
724
725 /**
726 * Gets the data from the specified input stream as a string using the
727 * specified charset.
728 *
729 * @param in the input stream to read from
730 * @param charset the charset to use when constructing the string
731 * @return a string representation of the data read from the input stream
732 * @throws IOException if an i/o error occurs
733 */
734 private String toString( InputStream in, String charset )
735 throws IOException
736 {
737 InputStreamReader reader = new InputStreamReader( in, charset );
738
739 StringBuffer buffer = new StringBuffer();
740 char[] chars = new char[1024];
741 int n;
742 while ( ( n = reader.read( chars, 0, chars.length ) ) != -1 )
743 {
744 buffer.append( chars, 0, n );
745 }
746
747 return buffer.toString();
748 }
749 }