20
20
import com .google .cloud .AuthCredentials .ServiceAccountAuthCredentials ;
21
21
import com .google .cloud .ReadChannel ;
22
22
import com .google .cloud .WriteChannel ;
23
+ import com .google .cloud .storage .Acl ;
23
24
import com .google .cloud .storage .Blob ;
24
25
import com .google .cloud .storage .BlobId ;
25
26
import com .google .cloud .storage .BlobInfo ;
30
31
import com .google .cloud .storage .Storage .CopyRequest ;
31
32
import com .google .cloud .storage .Storage .SignUrlOption ;
32
33
import com .google .cloud .storage .StorageOptions ;
34
+ import com .google .cloud .storage .spi .StorageRpc ;
33
35
import com .google .cloud .storage .spi .StorageRpc .Tuple ;
36
+ import com .google .common .collect .ImmutableMap ;
34
37
35
38
import java .io .FileOutputStream ;
36
39
import java .io .IOException ;
51
54
import java .util .Arrays ;
52
55
import java .util .HashMap ;
53
56
import java .util .Iterator ;
57
+ import java .util .LinkedList ;
54
58
import java .util .List ;
55
59
import java .util .Map ;
56
60
import java .util .concurrent .TimeUnit ;
75
79
* cp <from_bucket> <from_path> <to_bucket> <to_path> |
76
80
* compose <bucket> <from_path>+ <to_path> |
77
81
* update_metadata <bucket> <file> [key=value]* |
78
- * sign_url <service_account_private_key_file> <service_account_email> <bucket> <path>"}</pre>
82
+ * sign_url <service_account_private_key_file> <service_account_email> <bucket> <path> |
83
+ * add-acl domain <bucket> <path>? <domain> OWNER|READER|WRITER |
84
+ * add-acl project <bucket> <path>? <projectId>:(OWNERS|EDITORS|VIEWERS) OWNER|READER|WRITER |
85
+ * add-acl user <bucket> <path>? <userEmail>|allUsers|allAuthenticatedUsers OWNER|READER|WRITER |
86
+ * add-acl group <bucket> <path>? <group> OWNER|READER|WRITER"}</pre>
79
87
* </li>
80
88
* </ol>
81
89
*
87
95
public class StorageExample {
88
96
89
97
private static final Map <String , StorageAction > ACTIONS = new HashMap <>();
98
+ private static final Map <String , StorageAction > ACL_ACTIONS = new HashMap <>();
90
99
91
100
private abstract static class StorageAction <T > {
92
101
@@ -119,6 +128,48 @@ public String params() {
119
128
}
120
129
}
121
130
131
+ private static class ParentAction extends StorageAction <StorageRpc .Tuple <StorageAction , Object >> {
132
+
133
+ private final Map <String , StorageAction > subActions ;
134
+
135
+ ParentAction (Map <String , StorageAction > subActions ) {
136
+ this .subActions = ImmutableMap .copyOf (subActions );
137
+ }
138
+
139
+ @ Override
140
+ @ SuppressWarnings ("unchecked" )
141
+ void run (Storage storage , StorageRpc .Tuple <StorageAction , Object > subaction ) throws Exception {
142
+ subaction .x ().run (storage , subaction .y ());
143
+ }
144
+
145
+ @ Override
146
+ StorageRpc .Tuple <StorageAction , Object > parse (String ... args ) throws Exception {
147
+ if (args .length >= 1 ) {
148
+ StorageAction action = subActions .get (args [0 ]);
149
+ if (action != null ) {
150
+ Object actionArguments = action .parse (Arrays .copyOfRange (args , 1 , args .length ));
151
+ return StorageRpc .Tuple .of (action , actionArguments );
152
+ } else {
153
+ throw new IllegalArgumentException ("Unrecognized entity '" + args [0 ] + "'." );
154
+ }
155
+ }
156
+ throw new IllegalArgumentException ("Missing required entity." );
157
+ }
158
+
159
+ @ Override
160
+ public String params () {
161
+ StringBuilder builder = new StringBuilder ();
162
+ for (Map .Entry <String , StorageAction > entry : subActions .entrySet ()) {
163
+ builder .append ('\n' ).append (entry .getKey ());
164
+ String param = entry .getValue ().params ();
165
+ if (param != null && !param .isEmpty ()) {
166
+ builder .append (' ' ).append (param );
167
+ }
168
+ }
169
+ return builder .toString ();
170
+ }
171
+ }
172
+
122
173
/**
123
174
* This class demonstrates how to retrieve Bucket or Blob metadata.
124
175
* If more than one blob is supplied a Batch operation would be used to get all blobs metadata
@@ -512,6 +563,188 @@ public String params() {
512
563
}
513
564
}
514
565
566
+ private abstract static class AclAction extends StorageAction <Tuple <BlobId , Acl >> {
567
+
568
+ @ Override
569
+ public void run (Storage storage , Tuple <BlobId , Acl > params ) {
570
+ BlobId blobId = params .x ();
571
+ Acl acl = params .y ();
572
+ if (blobId .name ().isEmpty ()) {
573
+ Bucket bucket = storage .get (blobId .bucket ());
574
+ if (bucket == null ) {
575
+ System .out .printf ("Bucket %s does not exist%n" , blobId .bucket ());
576
+ return ;
577
+ }
578
+ bucket .toBuilder ().acl (addAcl (bucket .acl (), acl )).build ().update ();
579
+ System .out .printf ("Added ACL %s to bucket %s%n" , acl , blobId .bucket ());
580
+ } else {
581
+ Blob blob = storage .get (blobId );
582
+ if (blob == null ) {
583
+ System .out .printf ("Blob %s does not exist%n" , blobId );
584
+ return ;
585
+ }
586
+ blob .toBuilder ().acl (addAcl (blob .acl (), acl )).build ().update ();
587
+ System .out .printf ("Added ACL %s to blob %s%n" , acl , blobId );
588
+ }
589
+ }
590
+
591
+ private static List <Acl > addAcl (List <Acl > acls , Acl newAcl ) {
592
+ List <Acl > newAcls = new LinkedList <>(acls );
593
+ newAcls .add (newAcl );
594
+ return newAcls ;
595
+ }
596
+ }
597
+
598
+ /**
599
+ * This class demonstrates how to add an ACL to a blob or a bucket for a group of users
600
+ * (identified by the group's email).
601
+ *
602
+ * @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
603
+ * Control Lists (ACLs)</a>
604
+ */
605
+ private static class AddGroupAclAction extends AclAction {
606
+
607
+ @ Override
608
+ Tuple <BlobId , Acl > parse (String ... args ) {
609
+ if (args .length >= 3 ) {
610
+ BlobId blob ;
611
+ int nextArg ;
612
+ if (args .length == 3 ) {
613
+ blob = BlobId .of (args [0 ], "" );
614
+ nextArg = 1 ;
615
+ } else if (args .length == 4 ) {
616
+ blob = BlobId .of (args [0 ], args [1 ]);
617
+ nextArg = 2 ;
618
+ } else {
619
+ throw new IllegalArgumentException ("Too many arguments." );
620
+ }
621
+ String group = args [nextArg ++];
622
+ Acl .Role role = Acl .Role .valueOf (args [nextArg ]);
623
+ return Tuple .of (blob , Acl .of (new Acl .Group (group ), role ));
624
+ }
625
+ throw new IllegalArgumentException ("Missing required bucket, groupEmail or role arguments." );
626
+ }
627
+
628
+ @ Override
629
+ public String params () {
630
+ return "<bucket> <path>? <group> OWNER|READER|WRITER" ;
631
+ }
632
+ }
633
+
634
+ /**
635
+ * This class demonstrates how to add an ACL to a blob or a bucket for a domain.
636
+ *
637
+ * @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
638
+ * Control Lists (ACLs)</a>
639
+ */
640
+ private static class AddDomainAclAction extends AclAction {
641
+
642
+ @ Override
643
+ Tuple <BlobId , Acl > parse (String ... args ) {
644
+ if (args .length >= 3 ) {
645
+ BlobId blob ;
646
+ int nextArg ;
647
+ if (args .length == 3 ) {
648
+ blob = BlobId .of (args [0 ], "" );
649
+ nextArg = 1 ;
650
+ } else if (args .length == 4 ) {
651
+ blob = BlobId .of (args [0 ], args [1 ]);
652
+ nextArg = 2 ;
653
+ } else {
654
+ throw new IllegalArgumentException ("Too many arguments." );
655
+ }
656
+ String domain = args [nextArg ++];
657
+ Acl .Role role = Acl .Role .valueOf (args [nextArg ]);
658
+ return Tuple .of (blob , Acl .of (new Acl .Domain (domain ), role ));
659
+ }
660
+ throw new IllegalArgumentException ("Missing required bucket, domain or role arguments." );
661
+ }
662
+
663
+ @ Override
664
+ public String params () {
665
+ return "<bucket> <path>? <domain> OWNER|READER|WRITER" ;
666
+ }
667
+ }
668
+
669
+ /**
670
+ * This class demonstrates how to add an ACL to a blob or a bucket for either a user (if an email
671
+ * is provided), all users (if {@code allUsers} is provided), or all authenticated users (if
672
+ * {@code allAuthenticatedUsers} is provided).
673
+ *
674
+ * @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
675
+ * Control Lists (ACLs)</a>
676
+ */
677
+ private static class AddUserAclAction extends AclAction {
678
+
679
+ @ Override
680
+ Tuple <BlobId , Acl > parse (String ... args ) {
681
+ if (args .length >= 3 ) {
682
+ BlobId blob ;
683
+ int nextArg ;
684
+ if (args .length == 3 ) {
685
+ blob = BlobId .of (args [0 ], "" );
686
+ nextArg = 1 ;
687
+ } else if (args .length == 4 ) {
688
+ blob = BlobId .of (args [0 ], args [1 ]);
689
+ nextArg = 2 ;
690
+ } else {
691
+ throw new IllegalArgumentException ("Too many arguments." );
692
+ }
693
+ String user = args [nextArg ++];
694
+ Acl .Role role = Acl .Role .valueOf (args [nextArg ]);
695
+ return Tuple .of (blob , Acl .of (new Acl .User (user ), role ));
696
+ }
697
+ throw new IllegalArgumentException ("Missing required bucket, userEmail or role arguments." );
698
+ }
699
+
700
+ @ Override
701
+ public String params () {
702
+ return "<bucket> <path>? <userEmail>|allUsers|allAuthenticatedUsers OWNER|READER|WRITER" ;
703
+ }
704
+ }
705
+
706
+ /**
707
+ * This class demonstrates how to add an ACL to a blob or a bucket for all users that have a
708
+ * specific role in a provided project.
709
+ *
710
+ * @see <a href="https://cloud.google.com/storage/docs/access-control/lists#permissions">Access
711
+ * Control Lists (ACLs)</a>
712
+ */
713
+ private static class AddProjectAclAction extends AclAction {
714
+
715
+ @ Override
716
+ Tuple <BlobId , Acl > parse (String ... args ) {
717
+ if (args .length >= 3 ) {
718
+ BlobId blob ;
719
+ int nextArg ;
720
+ if (args .length == 3 ) {
721
+ blob = BlobId .of (args [0 ], "" );
722
+ nextArg = 1 ;
723
+ } else if (args .length == 4 ) {
724
+ blob = BlobId .of (args [0 ], args [1 ]);
725
+ nextArg = 2 ;
726
+ } else {
727
+ throw new IllegalArgumentException ("Too many arguments." );
728
+ }
729
+ String [] projectAndRole = args [nextArg ++].split (":" );
730
+ if (projectAndRole .length != 2 ) {
731
+ throw new IllegalArgumentException (
732
+ "Project entity must be specified as <projectId>:(OWNERS|READERS|WRITERS)" );
733
+ } else {
734
+ Acl .Project .ProjectRole projectRole = Acl .Project .ProjectRole .valueOf (projectAndRole [1 ]);
735
+ Acl .Role role = Acl .Role .valueOf (args [nextArg ]);
736
+ return Tuple .of (blob , Acl .of (new Acl .Project (projectRole , projectAndRole [0 ]), role ));
737
+ }
738
+ }
739
+ throw new IllegalArgumentException ("Missing required bucket, project or role arguments." );
740
+ }
741
+
742
+ @ Override
743
+ public String params () {
744
+ return "<bucket> <path>? <projectId>:(OWNERS|EDITORS|VIEWERS) OWNER|READER|WRITER" ;
745
+ }
746
+ }
747
+
515
748
static {
516
749
ACTIONS .put ("info" , new InfoAction ());
517
750
ACTIONS .put ("delete" , new DeleteAction ());
@@ -522,6 +755,11 @@ public String params() {
522
755
ACTIONS .put ("compose" , new ComposeAction ());
523
756
ACTIONS .put ("update_metadata" , new UpdateMetadataAction ());
524
757
ACTIONS .put ("sign_url" , new SignUrlAction ());
758
+ ACL_ACTIONS .put ("group" , new AddGroupAclAction ());
759
+ ACL_ACTIONS .put ("domain" , new AddDomainAclAction ());
760
+ ACL_ACTIONS .put ("user" , new AddUserAclAction ());
761
+ ACL_ACTIONS .put ("project" , new AddProjectAclAction ());
762
+ ACTIONS .put ("add-acl" , new ParentAction (ACL_ACTIONS ));
525
763
}
526
764
527
765
private static void printUsage () {
@@ -531,10 +769,11 @@ private static void printUsage() {
531
769
532
770
String param = entry .getValue ().params ();
533
771
if (param != null && !param .isEmpty ()) {
534
- actionAndParams .append (' ' ).append (param );
772
+ // Add extra padding for multi-line action
773
+ actionAndParams .append (' ' ).append (param .replace ("\n " , "\n \t \t " ));
535
774
}
536
775
}
537
- System .out .printf ("Usage: %s [<project_id>] operation <args>*%s%n" ,
776
+ System .out .printf ("Usage: %s [<project_id>] operation [entity] <args>*%s%n" ,
538
777
StorageExample .class .getSimpleName (), actionAndParams );
539
778
}
540
779
0 commit comments