Skip to content

Commit 65c8ca8

Browse files
feat: Improve code quality by adding final modifiers and enhancing documentation across multiple classes
Signed-off-by: Mario Serrano <[email protected]>
1 parent 55302bd commit 65c8ca8

27 files changed

+795
-56
lines changed

sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAPIConfig.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,31 @@
2121
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2222
import org.springframework.context.annotation.Bean;
2323
import org.springframework.context.annotation.Configuration;
24-
import tools.dynamia.integration.ms.MessageService;
2524

2625
/**
27-
* Default Account SaaS configuration
26+
* Default Spring configuration for the SaaS Account API module.
27+
* <p>
28+
* This configuration class sets up the essential beans required for multi-tenant
29+
* account management, including the custom account scope and a fallback no-op
30+
* implementation of {@link AccountServiceAPI}.
31+
* <p>
32+
* The configuration is automatically loaded when the module is present in the classpath,
33+
* and provides sensible defaults that can be overridden by custom implementations.
34+
*
35+
* @author Mario Serrano Leones
2836
*/
2937
@Configuration
3038
public class AccountAPIConfig {
3139

32-
3340
/**
34-
* This bean is used to register the AccountScope in the application context.
35-
* @return CustomScopeConfigurer
41+
* Registers the custom "account" scope with the Spring container.
42+
* <p>
43+
* This bean configures the {@link AccountScope} which enables beans to be scoped
44+
* at the account level, ensuring proper isolation in multi-tenant environments.
45+
* Once registered, beans can use {@code @Scope("account")} to be managed at the account level.
46+
*
47+
* @return a {@link CustomScopeConfigurer} with the account scope registered
48+
* @see AccountScope
3649
*/
3750
@Bean
3851
public CustomScopeConfigurer accountScopeConfigurer() {
@@ -42,10 +55,14 @@ public CustomScopeConfigurer accountScopeConfigurer() {
4255
}
4356

4457
/**
45-
* If no AccountServiceAPI is configured, this bean will be used as a default.
46-
* This is useful for testing.
58+
* Provides a no-op implementation of {@link AccountServiceAPI} as a fallback.
59+
* <p>
60+
* This bean is only created if no other {@link AccountServiceAPI} implementation
61+
* is found in the application context. It's primarily useful for testing scenarios
62+
* or when the SaaS features are not fully configured.
4763
*
48-
* @return NoOpAccountServiceAPI instance
64+
* @return a {@link NoOpAccountServiceAPI} instance
65+
* @see NoOpAccountServiceAPI
4966
*/
5067
@Bean
5168
@ConditionalOnMissingBean(AccountServiceAPI.class)

sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminAction.java

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,49 @@
2222
import tools.dynamia.actions.ActionSelfFilter;
2323
import tools.dynamia.integration.Containers;
2424

25+
/**
26+
* Base class for administrative actions that require authorization in a SaaS environment.
27+
* <p>
28+
* This class extends {@link AbstractAction} and provides built-in support for authorization
29+
* checks before executing administrative operations. It integrates with
30+
* {@link AccountAdminActionAuthorizationProvider} to enforce security policies.
31+
* <p>
32+
* Actions extending this class can require authorization by setting the
33+
* {@code authorizationRequired} flag. When enabled, the action will delegate to the
34+
* configured authorization provider before executing.
35+
* <p>
36+
* Example usage:
37+
* <pre>{@code
38+
* public class DeleteAccountAction extends AccountAdminAction {
39+
* public DeleteAccountAction() {
40+
* setName("Delete Account");
41+
* setAuthorizationRequired(true);
42+
* }
43+
*
44+
* @Override
45+
* public void actionPerformed(ActionEvent evt) {
46+
* // Delete account logic
47+
* }
48+
* }
49+
* }</pre>
50+
*
51+
* @author Mario Serrano Leones
52+
* @see AccountAdminActionAuthorizationProvider
53+
* @see AbstractAction
54+
*/
2555
public abstract class AccountAdminAction extends AbstractAction implements ActionSelfFilter {
2656

2757
private boolean authorizationRequired;
2858

29-
59+
/**
60+
* Hook method executed before the action is performed.
61+
* <p>
62+
* If authorization is required, this method will delegate to the
63+
* {@link AccountAdminActionAuthorizationProvider} to perform authorization checks.
64+
* The actual action will only execute if authorization is granted.
65+
*
66+
* @param evt the action event
67+
*/
3068
@Override
3169
public void beforeActionPerformed(ActionEvent evt) {
3270
if (isAuthorizationRequired()) {
@@ -39,15 +77,33 @@ public void beforeActionPerformed(ActionEvent evt) {
3977
}
4078
}
4179

80+
/**
81+
* Hook method executed after the action is performed.
82+
* <p>
83+
* This implementation does nothing and can be overridden by subclasses
84+
* to add post-execution logic.
85+
*
86+
* @param evt the action event
87+
*/
4288
@Override
4389
public void afterActionPerformed(ActionEvent evt) {
4490
//do nothing
4591
}
4692

93+
/**
94+
* Checks if authorization is required before executing this action.
95+
*
96+
* @return true if authorization is required, false otherwise
97+
*/
4798
public boolean isAuthorizationRequired() {
4899
return authorizationRequired;
49100
}
50101

102+
/**
103+
* Sets whether authorization is required before executing this action.
104+
*
105+
* @param authorizationRequired true to require authorization, false otherwise
106+
*/
51107
public void setAuthorizationRequired(boolean authorizationRequired) {
52108
this.authorizationRequired = authorizationRequired;
53109
}

sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAdminActionAuthorizationProvider.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,51 @@
44
import tools.dynamia.actions.ActionEvent;
55
import tools.dynamia.commons.Callback;
66

7+
/**
8+
* Interface for providing custom authorization logic for administrative actions in a SaaS environment.
9+
* <p>
10+
* This interface allows modules to implement custom authorization checks before executing
11+
* administrative actions on accounts. It provides a hook point for adding security layers,
12+
* audit requirements, or business rules that must be validated before an action proceeds.
13+
* <p>
14+
* The authorization process is asynchronous, using a callback mechanism to either grant or deny access.
15+
* This design allows for complex authorization workflows, including user confirmations, multi-factor
16+
* authentication, or external authorization services.
17+
* <p>
18+
* Example usage:
19+
* <pre>{@code
20+
* @Component
21+
* public class MFAAuthorizationProvider implements AccountAdminActionAuthorizationProvider {
22+
* @Override
23+
* public void authorize(Action action, ActionEvent evt, Callback onAuthorization) {
24+
* if (requiresMFA(action)) {
25+
* promptForMFA(success -> {
26+
* if (success) {
27+
* onAuthorization.doSomething();
28+
* }
29+
* });
30+
* } else {
31+
* onAuthorization.doSomething();
32+
* }
33+
* }
34+
* }
35+
* }</pre>
36+
*
37+
* @author Mario Serrano Leones
38+
*/
739
public interface AccountAdminActionAuthorizationProvider {
840

41+
/**
42+
* Performs authorization checks for an administrative action.
43+
* <p>
44+
* This method is called before executing administrative actions on accounts.
45+
* Implementations should perform any necessary authorization checks and invoke
46+
* the callback if authorization is granted. If authorization is denied, the
47+
* callback should not be invoked.
48+
*
49+
* @param action the action being authorized
50+
* @param evt the event context containing information about the action execution
51+
* @param onAuthorization callback to invoke if authorization is granted
52+
*/
953
void authorize(Action action, ActionEvent evt, Callback onAuthorization);
1054
}

sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountAware.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,45 @@
1919
package tools.dynamia.modules.saas.api;
2020

2121
/**
22+
* Interface for entities or components that belong to a specific account in a multi-tenant SaaS environment.
23+
* <p>
24+
* Implementing this interface allows objects to be associated with an account, enabling proper data isolation
25+
* and tenant-specific operations. This is a fundamental interface for multi-tenancy support, ensuring that
26+
* each entity knows which account it belongs to.
27+
* <p>
28+
* Example usage:
29+
* <pre>{@code
30+
* @Entity
31+
* public class Customer implements AccountAware {
32+
* @Column
33+
* private Long accountId;
34+
*
35+
* public Long getAccountId() {
36+
* return accountId;
37+
* }
38+
*
39+
* public void setAccountId(Long accountId) {
40+
* this.accountId = accountId;
41+
* }
42+
* }
43+
* }</pre>
2244
*
2345
* @author Mario Serrano Leones
2446
*/
2547
public interface AccountAware {
2648

49+
/**
50+
* Returns the unique identifier of the account this entity belongs to.
51+
*
52+
* @return the account ID
53+
*/
2754
Long getAccountId();
2855

56+
/**
57+
* Sets the account this entity belongs to.
58+
*
59+
* @param account the account ID to assign to this entity
60+
*/
2961
void setAccountId(Long account);
3062

3163
}

sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountFeatureProvider.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,48 @@
1717

1818
package tools.dynamia.modules.saas.api;
1919

20+
/**
21+
* Provider interface for defining account features in a SaaS multi-tenant environment.
22+
* <p>
23+
* This interface allows modules to register features that can be enabled or disabled
24+
* per account. Features can be used to control access to specific functionality,
25+
* allowing different subscription tiers or custom feature sets for different accounts.
26+
* <p>
27+
* Implementations should be registered as Spring beans and will be automatically
28+
* discovered by the SaaS module to populate the available features list.
29+
* <p>
30+
* Example usage:
31+
* <pre>{@code
32+
* @Component
33+
* public class AdvancedReportsFeature implements AccountFeatureProvider {
34+
* public String getId() {
35+
* return "advanced-reports";
36+
* }
37+
*
38+
* public String getName() {
39+
* return "Advanced Reports";
40+
* }
41+
* }
42+
* }</pre>
43+
*
44+
* @author Mario Serrano Leones
45+
*/
2046
public interface AccountFeatureProvider {
2147

48+
/**
49+
* Returns the unique identifier for this feature.
50+
* This ID is used to reference the feature programmatically throughout the application.
51+
*
52+
* @return the feature identifier (e.g., "advanced-reports", "api-access")
53+
*/
2254
String getId();
2355

56+
/**
57+
* Returns the human-readable name of this feature.
58+
* This name is typically displayed in the user interface for feature management.
59+
*
60+
* @return the feature display name
61+
*/
2462
String getName();
2563

2664
}

sources/api/src/main/java/tools/dynamia/modules/saas/api/AccountInitializer.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,75 @@
2727
import java.util.Locale;
2828

2929
/**
30+
* Interface for components that perform initialization tasks when a new account is created in a SaaS environment.
31+
* <p>
32+
* Implementations of this interface are automatically discovered and executed during account creation,
33+
* allowing modules to set up initial data, configurations, or resources for new accounts.
34+
* Multiple initializers can be chained together, with execution order controlled by priority.
35+
* <p>
36+
* Common use cases include:
37+
* <ul>
38+
* <li>Creating default entities or master data</li>
39+
* <li>Setting up initial configurations</li>
40+
* <li>Creating default user roles</li>
41+
* <li>Initializing account-specific resources</li>
42+
* </ul>
43+
* <p>
44+
* Example usage:
45+
* <pre>{@code
46+
* @Component
47+
* public class DefaultRolesInitializer implements AccountInitializer {
48+
* @Override
49+
* public void init(AccountDTO accountDTO) {
50+
* // Create default roles for the new account
51+
* createRole(accountDTO, "ADMIN");
52+
* createRole(accountDTO, "USER");
53+
* }
54+
*
55+
* @Override
56+
* public int getPriority() {
57+
* return 100; // Execute after basic setup
58+
* }
59+
* }
60+
* }</pre>
61+
*
3062
* @author Mario Serrano Leones
3163
*/
3264
public interface AccountInitializer {
3365

66+
/**
67+
* Performs initialization tasks for a newly created account.
68+
* <p>
69+
* This method is called automatically after an account is created and persisted.
70+
* Implementations should create any necessary initial data or configurations
71+
* required for the account to function properly.
72+
*
73+
* @param accountDTO the newly created account's data transfer object
74+
*/
3475
void init(AccountDTO accountDTO);
3576

3677
/**
37-
* Define account initializer priority or order. Lower value is high priority
78+
* Defines the execution priority for this initializer.
79+
* <p>
80+
* When multiple initializers exist, they are executed in order from lowest to highest priority value.
81+
* Lower values indicate higher priority and will execute first.
3882
*
39-
* @return
83+
* @return the priority value (default is 0, lower values execute first)
4084
*/
4185
default int getPriority() {
4286
return 0;
4387
}
4488

45-
89+
/**
90+
* Retrieves a localized message for the account's configured locale.
91+
* <p>
92+
* This helper method simplifies obtaining localized strings during account initialization,
93+
* using the account's locale setting if available, or falling back to the system default.
94+
*
95+
* @param key the message key to retrieve
96+
* @param accountDTO the account containing locale information
97+
* @return the localized message string, or the key itself if no translation is found
98+
*/
4699
default String localizedMessage(String key, AccountDTO accountDTO) {
47100
try {
48101
var provider = Containers.get().findObjects(LocalizedMessagesProvider.class)

0 commit comments

Comments
 (0)