You seem to be asking whether the Region can be dynamically determined at runtime based on a request, such as from a Spring [Web] @Controller
?
Perhaps, something like what was requested in PR #91? Although, I have rejected this PR in favor of a more flexible approach, name DATAGEODE-244 - "Add RegionResolver interface to enable lazy Region resolution when/where needed."
Although, your question is a bit ambiguous and I don't want to assume anything here.
A few points...
1) First, it is true that an application domain object (e.g. GeneralData
, or Employee
) is persisted to a specific, explicitly declared Region w.r.t. to "mapping" (i.e. using the SDG @Region
"mapping" annotation), as resolved by Spring Data Repository abstraction. This is really isn't that different from any other mapping technology (e.g. ORM; JPA using Hibernate) for that matter.
By default, if the @Region
mapping annotation is not specified, then SD[G] will use the simple class name of the application domain object type (e.g. "Employee") to resolve the Region in which the object will be persisted. Generally, it is always better to be explicit, and declare your intentions with the Spring Data [GemFire] mapping annotations, (e.g. @Region
, or @Id
to mark the identifier, etc).
2) Second, of course, this all depends on whether you are using the Spring Data [GemFire] Repository infrastructure in the first place. If not, then the above point is moot. If you are then, I imagine you want something like this...
@Region("Employees")
class Employee { ... }
@Controller
class MyController {
@Autowired
private EmployeeRepository employeeRepository;
@PostMapping("/employees")
public String process(Employee employee) {
// modify employee, then save...
if (employee.isContractor()) {
// save to "Contractors" Region
}
else {
employeeRepository.save(employee);
}
}
}
Of course, you cannot use the EmployeeRepository
to save an Employee object (which is mapped to the "Employees" Region to the "Contractors" Region given the Employee
type is "mapped" to the "Employees" Region using the `@Region" mapping annotation.
SDG did add support sometime ago now allowing users to annotate the Repository interface with the @Region
mapping annotation, for example...
@Region("Contractors")
interface ContractorRepository extends CrudRepository<Employee, Long> { ... }
This would effectively override the @Region
mapping annotation on the application domain object type (e.g. Employee
) and use the @Region
mapping annotation on the Repo instead. This allowed users to have different Repository (interface) declaration for the same application domain object type in order to map the domain object to different Regions.
Still, this is quite cumbersome, if you have a lot of different Regions and dynamic logic based on requests, to have a Repository interface declaration for each potential destination.
Alternatively, you could register different Spring HttpMessageConverters
in your Spring Web MVC configuration to convert the request data to the (entity) type (e.g. Contractor
) that determines its persistent destination, based on where the data belongs.
@Region("Contractors")
class Contractor extends Employee { ... }
Then:
@PostMapping("/employees")
public void process(Contractor contractor) {
// modify contractor, then save...
this.employeeRepository.save(contractor);
}
3) Third, of course, if you are not using the Spring Data Repository abstraction (and SDG extension), then you can exercise more control over where data is persisted by using SDG's GemfireTemplate
.
For example:
@Region("Employees")
class Employee { .. }
@Region("Contractors")
class Contractor extends Employee { ... }
@Configuration
@ClientCacheApplication
class GemFireConfiguration {
@Bean("Employees")
ClientRegionFactoryBean employeesRegion(ClientCache clientCache) { ... }
@Bean("Contractors")
ClientRegionFactoryBean contractorsRegion(ClientCache clientCache) { ... }
@Bean("employeesTemplate) {
GemfireTemplate employeesTemplate(ClientCache clientCache) {
return new GemfireTemplate(clientCache.getRegion("/Employees"));
}
@Bean("contractorsTemplate) {
GemfireTemplate contractorsTemplate(ClientCache clientCache) {
return new GemfireTemplate(clientCache.getRegion("/Contractors"));
}
}
@Controller
class MyController {
@Autowired
@Qualifier("employeeTemplate")
private GemfireTemplate employeesTemplate;
@Autowired
@Qualifier("contractorsTemplate")
private GemfireTemplate contractorsTemplate;
@PostMapping("/employees")
public void process(Employee employee) {
// modify the employee, then save...
if (employee.isContractor()) {
constractorsTemplate.put(employee.getId(), employee);
else {
employeesTemplate.put(employee.getId(), employee);
}
}
}
Of course, you could probably come up with a more creative way to "resolve" which template is needed based on the request using the Strategy pattern or similar effect.
If I understand your UC correctly, then DATAGEODE-244 should provided some relief in the near future, once it has been prioritized relative to other ongoing work (rather soon, actually).
I will say, that I am not really a fan of dynamically changing the persistent location based on the request type. Each entity is carefully crafted to be mapped to a specific target, persistent store.
Also, not that it is the case here (at least not that I think), I am also not a fan of "JUNK" Regions, i.e. Regions that store multiple "types" of data. This less than optimal for querying, which might be 1 argument why you want to persist a single application domain type to different Regions, since those Regions may then be tuned for different types of queries (with Indexes) and/or events.
Anyway, hope this answer provides some direction or ideas until DATAGEODE-244 is ready.
Cheers!