0

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

    }
}
John Blum
  • 7,381
  • 1
  • 20
  • 30
Vigneshwaran
  • 229
  • 1
  • 3
  • 14

1 Answers1

0

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

John Blum
  • 7,381
  • 1
  • 20
  • 30
  • Thanks John. After converting from GemfireRepository to CrudRepository able to save list of Domain object in gemfire. Using CacheWriter to save the list of domain objects in Cassandra but records are not saving. – Vigneshwaran Jun 23 '17 at 17:27
  • Not sure I am following you. `GemfireRepository` extends `CrudRepository`, so given an instance of `GemfireRepository`, you should be able to `gemfireRepository.save(listOfCustomers);` – John Blum Jun 23 '17 at 17:35
  • Looking at your `CacheWriter` above... Any reason why you are trying to make the `CacheWriter` writing to Cassandra asynchronous? The whole purpose of the `CacheWriter` is to be a synchronous operation, to update the external data source prior to updating the cache Region to which the `CacheWriter` is registered. In that way, the `CacheWriter` has a means to veto the cache Region update if the `CacheWriter` is unsuccessful, by throwing a `CacheWriterException`. ... – John Blum Jun 23 '17 at 17:41
  • All of this is explained in the Javadoc for `CacheWriter` here (http://gemfire-90-javadocs.docs.pivotal.io/org/apache/geode/cache/CacheWriter.html). If you truly want to make the operations between GemFire and Cassandra asynchronous (and disjointed), then you should use an `AsyncEventQueue` (AEQ) and attach a `AsyncEventListener` to the AEQ to perform the Cassandra operation. Then your Cassandra code will be updated "asynchronously" in the AEQ Listener. You won't need to explicitly code a potentially error prone Executor. This is what is referred to as asynchronous "write-behind"... – John Blum Jun 23 '17 at 17:46
  • As opposed to a synchronous, "write-through", which is the purpose of the `CacheWriter`. More information on AEQ + Listeners can be found here ( http://gemfire82.docs.pivotal.io/docs-gemfire/developing/events/implementing_write_behind_event_handler.html). – John Blum Jun 23 '17 at 17:48
  • Next time, please post your follow-up question as a new post. The synchronous/asynchronous business of updating Cassandra, whether in a `CacheWriter` or AEQ Listener has nothing to do with SD[G] Repositories and templates. Thanks. – John Blum Jun 23 '17 at 17:49
  • I totally agreed cache writer should be sync. Will make change my code accordingly. Gemfire was able to insert list of domain class whereas data was not able to insert into cassandra using cachewriter – Vigneshwaran Jun 23 '17 at 21:19
  • I was able to handle list of domain object after adding additional condition in CacheWriter eventOperation.equalsIgnoreCase("PUTALL_CREATE") – Vigneshwaran Jun 26 '17 at 19:32
  • some of data was missing while inserting/updating in GemFire and added serialization in the domain and now it worked good. Thanks John. – Vigneshwaran Jun 26 '17 at 19:33