Search code examples
gemfirespring-data-gemfire

GemfireRepository inserting List(Domain Class)


I have scenario need to insert list of domain classes using GemfireRepository but it’s not available, where as, it is available in Cassandra using...

@Autowired
private CassandraOperations cassandraTemplate;
cassandraTemplate.insert(List<DomainClass>);

Follow-up Question...

@EnableAsync
public class GenericWriter<K, V> extends CacheWriterAdapter<K, V> implements Declarable {

    private static Logger log = LoggerFactory.getLogger(GenericWriter.class);

    @Autowired
    private CassandraOperations cassandraOperations;

    ExecutorService executor = null;

    /**
     * Cache Writer get called before any event occurs on the cache, where in
     * EntryEvent interface reference has the helper methods
     */
    @Override
    @Async
    public void beforeCreate(EntryEvent<K, V> e) throws CacheWriterException {

        String eventOperation = e.getOperation().toString();
        log.info("#####inside before create#####");
        executor = Executors.newSingleThreadExecutor();

        executor.submit(() -> {
            log.info("****inside submit*****");
            if (eventOperation.equals("CREATE")) {
                log.info("Cache Writer for " + e.getRegion().getName() + " over Cassandra is activated"
                        + e.getNewValue());
                try {
                    cassandraOperations.insert(e.getNewValue());
                } catch (CassandraConnectionFailureException | CassandraWriteTimeoutException
                        | CassandraInternalException cassException) {
                    cassException.printStackTrace();
                    log.info("Cassandra Exception:" + cassException.toString());
                }
                catch (Exception ex){
                    log.info("Exception--------------------"+ex.getStackTrace());
                    ex.printStackTrace();
                }
            }
        });
        executor.shutdown();
    }

    @Override
    public void init(Properties arg0) {
        // TODO Auto-generated method stub

    }
}

Solution

  • Vigneshwaran-

    First, you are not comparing apples to apples.

    CassandraOperations is not the "equivalent" of SDG's GemfireRepository. That would be SDG's GemfireOperations.

    Spring Data GemFire's o.s.d.g.repository.GemfireRepository interface is an extension of Spring Data Common's o.s.d.repository.CrudRepository interface and part of Spring Data Common's Repository infrastructure/abstraction, which implements the Data Access Object (DAO) pattern with basic CRUD and querying capabilities via a simple interface definition. See here for more details.

    Spring Data Cassandra also extends and implements the SD Commons' Repository infrastructure via CassandraRepository. Therefore, it is CassandraRepository and GemfireRepository that are equivalent.

    Now, as for "inserting a list of application domain types"... well, if you are using SDG's GemfireOperations (implemented by SDG's GemfireTemplate) you can insert multiple application domain objects into GemFire using the gemfireTemplate.putAll(:Map<K, V>) operation.

    As you can see, the putAll(..) method takes a java.util.Map where the key is the identifier and value is your application domain object.

    Let's assume for moment that you have a Customer application domain type...

    @Region("Customers")
    class Customer {
    
      @Id
      private Long id;
    
      private String name;
    
      // constructor(s), getter/setters, equals, hashCode, toString, etc
    }
    

    Then you can...

    @Resource(name = "Customers"
    private Region<Long, Customer> customers;
    
    ...
    
    private GemfireOperations customersTemplate = new GemfireTemplate(customers);
    
    ...
    
    Customer jonDoe = new Customer(1L, "Jon Doe");
    Customer janeDoe = new Customer(2L, "Jane", "Doe");
    
    Map<Long, Customer> customers = ...;
    
    customers.put(jonDoe.getId(), jonDoe);
    customers.put(janeDoe.getId(), janeDoe);
    
    customersTemplate.putAll(customers);
    

    However, that is quite a bit of boilerplate code. It is far simpler to use SDG's Repository abstraction and extension. First you would define a CustomerRepository like so...

    public interface CustomerRepository extends GemfireRepository<Customer, Long> { ... }
    

    Then you can save a java.util.List of Customers using...

    List<Customer> customers = Arrays.asList(jonDoe, janeDoe);
    
    customerRepository.save(customers);
    

    Remember, SDG's GemfireRepository extends SD Common's o.s.d.repository.CrudRepository. SD Common's o.s.d.repository.CrudRepository has a save(:Iterable<S>) method, where...

    S extends T in CrudRepository<T, ID>.

    And, since java.util.List is an Iterable<E>, you have a method to save multiple entities, or application domain objects of a particular type (e.g. Customer).

    The other convenient feature of SDG's Repository infrastructure extension is...

    It will inspect application domain type (e.g. Customer), it will see that Customer is annotated with SDG's @Region annotation and use the value to determine the GemFire Region (i.e. "Customers" from above) in which to persist entities of type Customer and also use the @Id annotated field (or property, such as getId() on Customer) to determine the "key" in the "Customers" Region to which the entity will be mapped.

    Anyway, you just have dig a little deeper, read the docs and look at the API.

    It's all there.

    Hopes this helps!

    -John