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