11package com .salesforce .multicloudj .iam .model ;
22
33import com .salesforce .multicloudj .common .exceptions .InvalidArgumentException ;
4+ import lombok .Builder ;
45import lombok .Getter ;
6+ import lombok .Singular ;
57
6- import java .util .ArrayList ;
78import java .util .List ;
89import java .util .Objects ;
910
1718 * <p>Usage example:
1819 * <pre>
1920 * PolicyDocument policy = PolicyDocument.builder()
20- * .version("2012-10-17") // Use provider-specific version (AWS example)
21- * .statement("StorageAccess")
21+ * .version("2012-10-17")
22+ * .statement(Statement.builder()
23+ * .sid("StorageAccess")
2224 * .effect("Allow")
23- * .addAction ("storage:GetObject")
24- * .addAction ("storage:PutObject")
25- * .addPrincipal ("arn:aws:iam::123456789012:user/ExampleUser")
26- * .addResource ("storage://my-bucket/*")
27- * .addCondition ("StringEquals", "aws:RequestedRegion", "us-west-2")
28- * .endStatement( )
25+ * .action ("storage:GetObject")
26+ * .action ("storage:PutObject")
27+ * .principal ("arn:aws:iam::123456789012:user/ExampleUser")
28+ * .resource ("storage://my-bucket/*")
29+ * .condition ("StringEquals", "aws:RequestedRegion", "us-west-2")
30+ * .build() )
2931 * .build();
3032 * </pre>
3133 */
@@ -34,18 +36,24 @@ public class PolicyDocument {
3436 private final String version ;
3537 private final List <Statement > statements ;
3638
37- private PolicyDocument (Builder builder ) {
38- this .version = builder .version ;
39- this .statements = new ArrayList <>(builder .statements );
40- }
39+ @ Builder
40+ private PolicyDocument (String version , @ Singular List <Statement > statements ) {
41+ // Validate version is provided
42+ if (version == null ) {
43+ throw new InvalidArgumentException ("Version is required" );
44+ }
45+
46+ // Filter out null statements and validate at least one exists
47+ List <Statement > filteredStatements = statements != null
48+ ? statements .stream ().filter (Objects ::nonNull ).collect (java .util .stream .Collectors .toList ())
49+ : new java .util .ArrayList <>();
50+
51+ if (filteredStatements .isEmpty ()) {
52+ throw new InvalidArgumentException ("At least one statement is required" );
53+ }
4154
42- /**
43- * Creates a new builder for PolicyDocument.
44- *
45- * @return a new Builder instance
46- */
47- public static Builder builder () {
48- return new Builder ();
55+ this .version = version ;
56+ this .statements = filteredStatements ;
4957 }
5058
5159
@@ -71,184 +79,4 @@ public String toString() {
7179 ", statements=" + statements +
7280 '}' ;
7381 }
74-
75- /**
76- * Builder class for PolicyDocument.
77- */
78- public static class Builder {
79- private String version ;
80- private final List <Statement > statements = new ArrayList <>();
81- private Statement .Builder currentStatementBuilder ;
82-
83- private Builder () {
84- this .currentStatementBuilder = Statement .builder ();
85- }
86-
87- /**
88- * Sets the policy version.
89- *
90- * @param version the policy version (required)
91- * @return this Builder instance
92- */
93- public Builder version (String version ) {
94- this .version = version ;
95- return this ;
96- }
97-
98- /**
99- * Starts building a new statement with the given SID.
100- *
101- * @param sid the statement ID
102- * @return this Builder instance configured for statement building
103- */
104- public Builder statement (String sid ) {
105- finalizeCurrentStatement ();
106- this .currentStatementBuilder = Statement .builder ().sid (sid );
107- return this ;
108- }
109-
110- /**
111- * Sets the effect for the current statement.
112- *
113- * @param effect "Allow" or "Deny"
114- * @return this Builder instance
115- */
116- public Builder effect (String effect ) {
117- this .currentStatementBuilder .effect (effect );
118- return this ;
119- }
120-
121- /**
122- * Adds a principal to the current statement.
123- *
124- * @param principal the principal (fully qualified principal required)
125- * @return this Builder instance
126- */
127- public Builder addPrincipal (String principal ) {
128- this .currentStatementBuilder .addPrincipal (principal );
129- return this ;
130- }
131-
132- /**
133- * Adds multiple principals to the current statement.
134- *
135- * @param principals the list of principals
136- * @return this Builder instance
137- */
138- public Builder addPrincipals (List <String > principals ) {
139- this .currentStatementBuilder .addPrincipals (principals );
140- return this ;
141- }
142-
143- /**
144- * Adds an action to the current statement.
145- *
146- * @param action the action in substrate-neutral format
147- * @return this Builder instance
148- */
149- public Builder addAction (String action ) {
150- this .currentStatementBuilder .addAction (action );
151- return this ;
152- }
153-
154- /**
155- * Adds multiple actions to the current statement.
156- *
157- * @param actions the list of actions
158- * @return this Builder instance
159- */
160- public Builder addActions (List <String > actions ) {
161- this .currentStatementBuilder .addActions (actions );
162- return this ;
163- }
164-
165- /**
166- * Adds a resource to the current statement.
167- *
168- * @param resource the resource in URI format
169- * @return this Builder instance
170- */
171- public Builder addResource (String resource ) {
172- this .currentStatementBuilder .addResource (resource );
173- return this ;
174- }
175-
176- /**
177- * Adds multiple resources to the current statement.
178- *
179- * @param resources the list of resources
180- * @return this Builder instance
181- */
182- public Builder addResources (List <String > resources ) {
183- this .currentStatementBuilder .addResources (resources );
184- return this ;
185- }
186-
187- /**
188- * Adds a condition to the current statement.
189- *
190- * @param operator the condition operator
191- * @param key the condition key
192- * @param value the condition value
193- * @return this Builder instance
194- */
195- public Builder addCondition (String operator , String key , Object value ) {
196- this .currentStatementBuilder .addCondition (operator , key , value );
197- return this ;
198- }
199-
200- /**
201- * Ends the current statement and adds it to the policy.
202- *
203- * @return this Builder instance
204- */
205- public Builder endStatement () {
206- finalizeCurrentStatement ();
207- return this ;
208- }
209-
210- /**
211- * Adds a complete statement to the policy document.
212- *
213- * @param statement the statement to add
214- * @return this Builder instance
215- */
216- public Builder addStatement (Statement statement ) {
217- finalizeCurrentStatement ();
218- if (statement != null ) {
219- this .statements .add (statement );
220- }
221- return this ;
222- }
223-
224- /**
225- * Builds and returns a PolicyDocument instance.
226- *
227- * @return a new PolicyDocument instance
228- * @throws InvalidArgumentException if version or statements are missing
229- */
230- public PolicyDocument build () {
231- finalizeCurrentStatement ();
232- if (version == null || version .trim ().isEmpty ()) {
233- throw new InvalidArgumentException ("version is required" );
234- }
235- if (statements .isEmpty ()) {
236- throw new InvalidArgumentException ("at least one statement is required" );
237- }
238- return new PolicyDocument (this );
239- }
240-
241-
242- private void finalizeCurrentStatement () {
243- if (currentStatementBuilder != null ) {
244- // Only finalize statements that have the minimum required content
245- if (currentStatementBuilder .hasMinimumContent ()) {
246- Statement statement = currentStatementBuilder .build ();
247- statements .add (statement );
248- }
249- // Always reinitialize for the next statement
250- currentStatementBuilder = Statement .builder ();
251- }
252- }
253- }
25482}
0 commit comments