1 package org.apache.tomcat.maven.common.deployer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.codec.binary.Base64;
23 import org.apache.commons.io.IOUtils;
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.http.Header;
26 import org.apache.http.HttpHost;
27 import org.apache.http.HttpResponse;
28 import org.apache.http.HttpStatus;
29 import org.apache.http.auth.AuthScope;
30 import org.apache.http.auth.Credentials;
31 import org.apache.http.auth.UsernamePasswordCredentials;
32 import org.apache.http.client.AuthCache;
33 import org.apache.http.client.methods.HttpGet;
34 import org.apache.http.client.methods.HttpPut;
35 import org.apache.http.client.methods.HttpRequestBase;
36 import org.apache.http.client.protocol.ClientContext;
37 import org.apache.http.entity.AbstractHttpEntity;
38 import org.apache.http.impl.auth.BasicScheme;
39 import org.apache.http.impl.client.BasicAuthCache;
40 import org.apache.http.impl.client.DefaultHttpClient;
41 import org.apache.http.impl.conn.PoolingClientConnectionManager;
42 import org.apache.http.protocol.BasicHttpContext;
43
44 import java.io.File;
45 import java.io.FileInputStream;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.OutputStream;
49 import java.io.PrintStream;
50 import java.net.URL;
51 import java.net.URLEncoder;
52 import java.text.DecimalFormat;
53 import java.text.DecimalFormatSymbols;
54 import java.util.Locale;
55
56
57
58
59
60
61
62 public class TomcatManager
63 {
64
65
66
67
68
69
70
71 private static final String MANAGER_CHARSET = "UTF-8";
72
73
74
75
76
77
78
79
80 private URL url;
81
82
83
84
85 private String username;
86
87
88
89
90 private String password;
91
92
93
94
95 private String charset;
96
97
98
99
100 private String userAgent;
101
102
103
104
105 private DefaultHttpClient httpClient;
106
107
108
109
110 private BasicHttpContext localContext;
111
112
113
114
115
116
117
118
119
120
121
122 public TomcatManager( URL url )
123 {
124 this( url, "admin" );
125 }
126
127
128
129
130
131
132
133
134 public TomcatManager( URL url, String username )
135 {
136 this( url, username, "" );
137 }
138
139
140
141
142
143
144
145
146 public TomcatManager( URL url, String username, String password )
147 {
148 this( url, username, password, "ISO-8859-1" );
149 }
150
151
152
153
154
155
156
157
158
159
160 public TomcatManager( URL url, String username, String password, String charset )
161 {
162 this.url = url;
163 this.username = username;
164 this.password = password;
165 this.charset = charset;
166
167 PoolingClientConnectionManager poolingClientConnectionManager = new PoolingClientConnectionManager();
168 poolingClientConnectionManager.setMaxTotal( 5 );
169 this.httpClient = new DefaultHttpClient( poolingClientConnectionManager );
170 if ( StringUtils.isNotEmpty( username ) )
171 {
172 Credentials creds = new UsernamePasswordCredentials( username, password );
173
174 String host = url.getHost();
175 int port = url.getPort() > -1 ? url.getPort() : AuthScope.ANY_PORT;
176
177 httpClient.getCredentialsProvider().setCredentials( new AuthScope( host, port ), creds );
178
179 AuthCache authCache = new BasicAuthCache();
180 BasicScheme basicAuth = new BasicScheme();
181 HttpHost targetHost = new HttpHost( url.getHost(), url.getPort(), url.getProtocol() );
182 authCache.put( targetHost, basicAuth );
183
184 localContext = new BasicHttpContext();
185 localContext.setAttribute( ClientContext.AUTH_CACHE, authCache );
186 }
187 }
188
189
190
191
192
193
194
195
196
197
198 public URL getURL()
199 {
200 return url;
201 }
202
203
204
205
206
207
208 public String getUserName()
209 {
210 return username;
211 }
212
213
214
215
216
217
218 public String getPassword()
219 {
220 return password;
221 }
222
223
224
225
226
227
228 public String getCharset()
229 {
230 return charset;
231 }
232
233
234
235
236
237
238 public String getUserAgent()
239 {
240 return userAgent;
241 }
242
243
244
245
246
247
248 public void setUserAgent( String userAgent )
249 {
250 this.userAgent = userAgent;
251 }
252
253
254
255
256
257
258
259
260
261
262 public TomcatManagerResponse deploy( String path, URL war )
263 throws TomcatManagerException, IOException
264 {
265 return deploy( path, war, false );
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279 public TomcatManagerResponse deploy( String path, URL war, boolean update )
280 throws TomcatManagerException, IOException
281 {
282 return deploy( path, war, update, null );
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297 public TomcatManagerResponse deploy( String path, URL war, boolean update, String tag )
298 throws TomcatManagerException, IOException
299 {
300 return deployImpl( path, null, war, null, update, tag );
301 }
302
303
304
305
306
307
308
309
310
311
312 public TomcatManagerResponse deploy( String path, File war )
313 throws TomcatManagerException, IOException
314 {
315 return deploy( path, war, false );
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329 public TomcatManagerResponse deploy( String path, File war, boolean update )
330 throws TomcatManagerException, IOException
331 {
332 return deploy( path, war, update, null );
333 }
334
335
336
337
338
339
340
341
342
343
344
345
346
347 public TomcatManagerResponse deploy( String path, File war, boolean update, String tag )
348 throws TomcatManagerException, IOException
349 {
350 return deployImpl( path, null, null, war, update, tag );
351 }
352
353
354
355
356
357
358
359
360
361
362
363
364 public TomcatManagerResponse deploy( String path, File war, boolean update, String tag, long length )
365 throws TomcatManagerException, IOException
366 {
367 return deployImpl( path, null, null, war, update, tag, length );
368 }
369
370
371
372
373
374
375
376
377
378
379 public TomcatManagerResponse deployContext( String path, URL config )
380 throws TomcatManagerException, IOException
381 {
382 return deployContext( path, config, false );
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396 public TomcatManagerResponse deployContext( String path, URL config, boolean update )
397 throws TomcatManagerException, IOException
398 {
399 return deployContext( path, config, update, null );
400 }
401
402
403
404
405
406
407
408
409
410
411
412
413
414 public TomcatManagerResponse deployContext( String path, URL config, boolean update, String tag )
415 throws TomcatManagerException, IOException
416 {
417 return deployContext( path, config, null, update, tag );
418 }
419
420
421
422
423
424
425
426
427
428
429
430 public TomcatManagerResponse deployContext( String path, URL config, URL war )
431 throws TomcatManagerException, IOException
432 {
433 return deployContext( path, config, war, false );
434 }
435
436
437
438
439
440
441
442
443
444
445
446
447
448 public TomcatManagerResponse deployContext( String path, URL config, URL war, boolean update )
449 throws TomcatManagerException, IOException
450 {
451 return deployContext( path, config, war, update, null );
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467 public TomcatManagerResponse deployContext( String path, URL config, URL war, boolean update, String tag )
468 throws TomcatManagerException, IOException
469 {
470 return deployImpl( path, config, war, null, update, tag );
471 }
472
473
474
475
476
477
478
479
480
481 public TomcatManagerResponse undeploy( String path )
482 throws TomcatManagerException, IOException
483 {
484 return invoke( "/undeploy?path=" + URLEncoder.encode( path, charset ) );
485 }
486
487
488
489
490
491
492
493
494
495 public TomcatManagerResponse reload( String path )
496 throws TomcatManagerException, IOException
497 {
498 return invoke( "/reload?path=" + URLEncoder.encode( path, charset ) );
499 }
500
501
502
503
504
505
506
507
508
509 public TomcatManagerResponse start( String path )
510 throws TomcatManagerException, IOException
511 {
512 return invoke( "/start?path=" + URLEncoder.encode( path, charset ) );
513 }
514
515
516
517
518
519
520
521
522
523 public TomcatManagerResponse stop( String path )
524 throws TomcatManagerException, IOException
525 {
526 return invoke( "/stop?path=" + URLEncoder.encode( path, charset ) );
527 }
528
529
530
531
532
533
534
535
536 public TomcatManagerResponse list()
537 throws TomcatManagerException, IOException
538 {
539 return invoke( "/list" );
540 }
541
542
543
544
545
546
547
548
549 public TomcatManagerResponse getServerInfo()
550 throws TomcatManagerException, IOException
551 {
552 return invoke( "/serverinfo" );
553 }
554
555
556
557
558
559
560
561
562 public TomcatManagerResponse getResources()
563 throws TomcatManagerException, IOException
564 {
565 return getResources( null );
566 }
567
568
569
570
571
572
573
574
575
576 public TomcatManagerResponse getResources( String type )
577 throws TomcatManagerException, IOException
578 {
579 StringBuffer buffer = new StringBuffer();
580 buffer.append( "/resources" );
581
582 if ( type != null )
583 {
584 buffer.append( "?type=" + URLEncoder.encode( type, charset ) );
585 }
586 return invoke( buffer.toString() );
587 }
588
589
590
591
592
593
594
595
596 public TomcatManagerResponse getRoles()
597 throws TomcatManagerException, IOException
598 {
599 return invoke( "/roles" );
600 }
601
602
603
604
605
606
607
608
609
610 public TomcatManagerResponse getSessions( String path )
611 throws TomcatManagerException, IOException
612 {
613 return invoke( "/sessions?path=" + URLEncoder.encode( path, charset ) );
614 }
615
616
617
618
619
620
621
622
623
624
625
626
627
628 protected TomcatManagerResponse invoke( String path )
629 throws TomcatManagerException, IOException
630 {
631 return invoke( path, null, -1 );
632 }
633
634
635
636
637
638 private TomcatManagerResponse deployImpl( String path, URL config, URL war, File data, boolean update, String tag )
639 throws TomcatManagerException, IOException
640 {
641 return deployImpl( path, config, war, data, update, tag, -1 );
642 }
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657 private TomcatManagerResponse deployImpl( String path, URL config, URL war, File data, boolean update, String tag,
658 long length )
659 throws TomcatManagerException, IOException
660 {
661 StringBuilder buffer = new StringBuilder( "/deploy" );
662 buffer.append( "?path=" ).append( URLEncoder.encode( path, charset ) );
663
664 if ( config != null )
665 {
666 buffer.append( "&config=" ).append( URLEncoder.encode( config.toString(), charset ) );
667 }
668
669 if ( war != null )
670 {
671 buffer.append( "&war=" ).append( URLEncoder.encode( war.toString(), charset ) );
672 }
673
674 if ( update )
675 {
676 buffer.append( "&update=true" );
677 }
678
679 if ( tag != null )
680 {
681 buffer.append( "&tag=" ).append( URLEncoder.encode( tag, charset ) );
682 }
683
684 return invoke( buffer.toString(), data, length );
685 }
686
687
688
689
690
691
692
693
694
695
696
697 protected TomcatManagerResponse invoke( String path, File data, long length )
698 throws TomcatManagerException, IOException
699 {
700
701 HttpRequestBase httpRequestBase = null;
702 if ( data == null )
703 {
704 httpRequestBase = new HttpGet( url + path );
705 }
706 else
707 {
708 HttpPut httpPut = new HttpPut( url + path );
709
710 httpPut.setEntity( new RequestEntityImplementation( data, length, url + path ) );
711
712 httpRequestBase = httpPut;
713
714 }
715
716 if ( userAgent != null )
717 {
718 httpRequestBase.setHeader( "User-Agent", userAgent );
719 }
720
721 HttpResponse response = httpClient.execute( httpRequestBase, localContext );
722
723 int statusCode = response.getStatusLine().getStatusCode();
724
725 switch ( statusCode )
726 {
727
728 case HttpStatus.SC_OK:
729 case HttpStatus.SC_CREATED:
730 case HttpStatus.SC_ACCEPTED:
731 break;
732
733 case HttpStatus.SC_MOVED_PERMANENTLY:
734 case HttpStatus.SC_MOVED_TEMPORARILY:
735 case HttpStatus.SC_SEE_OTHER:
736 String relocateUrl = calculateRelocatedUrl( response );
737 this.url = new URL( relocateUrl );
738 return invoke( path, data, length );
739 }
740
741 return new TomcatManagerResponse().setStatusCode( response.getStatusLine().getStatusCode() ).setReasonPhrase(
742 response.getStatusLine().getReasonPhrase() ).setHttpResponseBody(
743 IOUtils.toString( response.getEntity().getContent() ) );
744
745 }
746
747 protected String calculateRelocatedUrl( HttpResponse response )
748 {
749 Header locationHeader = response.getFirstHeader( "Location" );
750 String locationField = locationHeader.getValue();
751
752 return locationField.startsWith( "http" ) ? locationField : url.toString() + '/' + locationField;
753 }
754
755
756
757
758
759
760
761
762
763 private String toAuthorization( String username, String password )
764 {
765 StringBuffer buffer = new StringBuffer();
766 buffer.append( username ).append( ':' );
767 if ( password != null )
768 {
769 buffer.append( password );
770 }
771 return "Basic " + new String( Base64.encodeBase64( buffer.toString().getBytes() ) );
772 }
773
774 private final class RequestEntityImplementation
775 extends AbstractHttpEntity
776 {
777
778 private final static int BUFFER_SIZE = 2048;
779
780 private File file;
781
782 PrintStream out = System.out;
783
784 private long length = -1;
785
786 private int lastLength;
787
788 private String url;
789
790 private long startTime;
791
792 private RequestEntityImplementation( final File file, long length, String url )
793 {
794 this.file = file;
795 this.length = length;
796 this.url = url;
797 }
798
799 public long getContentLength()
800 {
801 return length >= 0 ? length : ( file.length() >= 0 ? file.length() : -1 );
802 }
803
804
805 public InputStream getContent()
806 throws IOException, IllegalStateException
807 {
808 return new FileInputStream( this.file );
809 }
810
811 public boolean isRepeatable()
812 {
813 return true;
814 }
815
816
817 public void writeTo( final OutputStream outstream )
818 throws IOException
819 {
820 long completed = 0;
821 if ( outstream == null )
822 {
823 throw new IllegalArgumentException( "Output stream may not be null" );
824 }
825 FileInputStream stream = new FileInputStream( this.file );
826 transferInitiated( this.url );
827 this.startTime = System.currentTimeMillis();
828 try
829 {
830 byte[] buffer = new byte[BUFFER_SIZE];
831
832 int l;
833 if ( this.length < 0 )
834 {
835
836 while ( ( l = stream.read( buffer ) ) != -1 )
837 {
838 transferProgressed( completed += buffer.length, -1 );
839 outstream.write( buffer, 0, l );
840 }
841 }
842 else
843 {
844
845 long remaining = this.length;
846 while ( remaining > 0 )
847 {
848 int transferSize = (int) Math.min( BUFFER_SIZE, remaining );
849 completed += transferSize;
850 l = stream.read( buffer, 0, transferSize );
851 if ( l == -1 )
852 {
853 break;
854 }
855
856 outstream.write( buffer, 0, l );
857 remaining -= l;
858 transferProgressed( completed, this.length );
859 }
860 }
861 transferSucceeded( completed );
862 }
863 finally
864 {
865 stream.close();
866 out.println();
867 }
868
869 }
870
871 public boolean isStreaming()
872 {
873 return true;
874 }
875
876
877 public void transferInitiated( String url )
878 {
879 String message = "Uploading";
880
881 out.println( message + ": " + url );
882 }
883
884 public void transferProgressed( long completedSize, long totalSize )
885 {
886
887 StringBuilder buffer = new StringBuilder( 64 );
888
889 buffer.append( getStatus( completedSize, totalSize ) ).append( " " );
890 lastLength = buffer.length();
891 buffer.append( '\r' );
892
893 out.print( buffer );
894 }
895
896 public void transferSucceeded( long contentLength )
897 {
898
899 if ( contentLength >= 0 )
900 {
901 String type = "Uploaded";
902 String len = contentLength >= 1024 ? toKB( contentLength ) + " KB" : contentLength + " B";
903
904 String throughput = "";
905 long duration = System.currentTimeMillis() - startTime;
906 if ( duration > 0 )
907 {
908 DecimalFormat format = new DecimalFormat( "0.0", new DecimalFormatSymbols( Locale.ENGLISH ) );
909 double kbPerSec = ( contentLength / 1024.0 ) / ( duration / 1000.0 );
910 throughput = " at " + format.format( kbPerSec ) + " KB/sec";
911 }
912
913 out.println( type + ": " + url + " (" + len + throughput + ")" );
914 }
915 }
916
917 private String getStatus( long complete, long total )
918 {
919 if ( total >= 1024 )
920 {
921 return toKB( complete ) + "/" + toKB( total ) + " KB ";
922 }
923 else if ( total >= 0 )
924 {
925 return complete + "/" + total + " B ";
926 }
927 else if ( complete >= 1024 )
928 {
929 return toKB( complete ) + " KB ";
930 }
931 else
932 {
933 return complete + " B ";
934 }
935 }
936
937 private long toKB( long bytes )
938 {
939 return ( bytes + 1023 ) / 1024;
940 }
941
942 }
943 }