How to log cache hits through #Cacheable annotation? - java

There is a method in a class like this down below :
#Override
#Transactional
#Cacheable(value = "products", key = "#id")
public Product getProduct(long id) throws ApplicationException {
Product product = null;
try {
ProductEntity productEntity = productDAO.getProduct(id);
product = productTransformer.toProduct(productEntity);
} catch (SystemException ex) {
throw new ApplicationException(ex.getCode(), ex.getMessage(), "Problem in DataLayer", "Data Layer Error",
new Object[] { ex });
}
return product;
}
The application is working fine. But I want to have a cache hit log when data is put into the cache. I want to log it through log4j.properties.
How can I configure the application.properties in such a way so that it can be logged ?

Spring internally logs its caching workflow at a TRACE level. To enable this , in your application.properties file, include the following.
logging.level.org.springframework.cache=TRACE

Including the following should help:
logging.level.org.springframework.cache=TRACE

Related

Spring data JPA logging

I want to log the time taken by the JPA repository to save the data into the database.
Currently, I have used the Spring around Aspect to log it but it seems not so accurate because it doesn't commit until the end of #Transactional method.
#Timed(metricName = "inmtPersistence")
public void persistInmt(final List<T> inmtList) {
if (inmtList.size() == 0) {
return;
}
Map<String, E> inmtEntityMapFromDb = getInmtEntitiesFromDb(inmtList);
List<E> inmtEntities = getInmtEntities(inmtList, inmtEntityMapFromDb);
try {
inmtRepository.saveAll(inmtEntities);
} catch (Exception e) {
log.error("Exception ");
throw e;
}
}
You could use P6Spy , which will log out execution time for all individual queries.

DynamoDB - how to get Primary Key (which is random id) from database to make endpoind class?

I've made method that I use to edit Item from database.
This is how my method looks:
public Product editProduct(PrimaryKey primaryKey, Product content) {
UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey(primaryKey).withValueMap(createValueMap(content));
UpdateItemOutcome itemOutcome = databaseController.getTable(PRODUCT_TABLE).updateItem(updateItemSpec);
return convertToProduct(itemOutcome);
}
private Map<String, Object> createValueMap(Product content) {
Map<String, Object> result = new HashMap<>();
result.put("name", content.getName());
result.put("calories", content.getCalories());
result.put("fat", content.getFat());
result.put("carbo", content.getCarbo());
result.put("protein", content.getProtein());
result.put("productKinds", content.getProductKinds());
result.put("author", content.getAuthor());
result.put("media", content.getMedia());
result.put("approved", content.getApproved());
return result;
}
private Product convertToProduct(UpdateItemOutcome itemOutcome) {
Product product = new Product();
product.setName(itemOutcome.getItem().get("name").toString());
product.setCalories(itemOutcome.getItem().getInt("calories"));
product.setFat(itemOutcome.getItem().getDouble("fat"));
product.setCarbo(itemOutcome.getItem().getDouble("carbo"));
product.setProtein(itemOutcome.getItem().getDouble("protein"));
product.setProductKinds(itemOutcome.getItem().getList("productKinds"));
ObjectMapper objectMapper = new ObjectMapper();
try {
Author productAuthor = objectMapper.readValue(itemOutcome.getItem().getString("author"), Author.class);
product.setAuthor(productAuthor);
} catch (IOException e) {
e.printStackTrace();
}
try {
Media productMedia = objectMapper.readValue(itemOutcome.getItem().getString("media"), Media.class);
product.setMedia(productMedia);
} catch (IOException e) {
e.printStackTrace();
}
return product;
}
Now I want to create endpoint class for this method but I have problem, I need to get primarykey as parameter (it's looks like this for example: 2567763a-d21e-4146-8d61-9d52c2561fc0) and I don't know how to do this.
At the moment my class looks like that:
public class EditProductLambda implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {
private LambdaLogger logger;
#Override
public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
logger = context.getLogger();
logger.log(input.toString());
try{
Product product = RequestUtil.parseRequest(input, Product.class);
//PrimaryKey primaryKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
KitchenService kitchenService = new KitchenService(new DatabaseController(context, Regions.EU_CENTRAL_1), logger);
Product editedProduct = kitchenService.editProduct(primaryKey, product);
return ResponseUtil.generateResponse(HttpStatus.SC_CREATED, editedProduct);
} catch (IllegalArgumentException e){
return ResponseUtil.generateResponse(HttpStatus.SC_BAD_REQUEST, e.getMessage());
}
}
Can someone give me some advice how to do that? Or maybe my method is done wrong?
So first you have to create a trigger to Lambda function and ideal prefer here would be an API gateway. You can pass your data as query string or as a request body to API gateway.
You can use body mapping template in the integration request section of API gateway and get request body/query string. Construct a new json at body mapping template, which will have data from request body/query string. As we are adding body mapping template your business logic will get the json we have constructed at body mapping template.
Inside body mapping template to get query string please do ,
$input.params('querystringkey')
For example inside body mapping template (If using query string),
#set($inputRoot = $input.path('$'))
{
"primaryKey" : "$input.params('$.primaryKey')"
}
if passing data as body then,
#set($inputRoot = $input.path('$'))
{
"primaryKey" : "$input.path('$.primaryKey')"
}
Please read https://aws.amazon.com/blogs/compute/tag/mapping-templates/ for more details on body mapping template

Kundera cassandra - Transaction rollback and Entity update

I use Kundera-Cassandra 3.2 and want to use the transaction management from Kundera.
My handling looks like this:
EntityManager manager = repo.getEntityManagerFactory().createEntityManager(CassandraRepository.getProperties());
try{
manager.getTransaction().begin();
this.repo.update(account1, manager); //calls the merge method of the Entitymanager
this.repo.save(account2, manager); //calls the persist method of the Entitymanager
manager.getTransaction().commit();
} catch(Exception e){
if(manager.getTransaction().isActive()){
manager.getTransaction().rollback();
}
} finally {
manager.clear();
manager.close();
}
When an error in the this.repo.save(account2, manager); occurs, the manager rollbacks the transaction, but does not do a update statement, he makes a delete statement for the merge method. The reason for this is, when calling the merge methode, kundera creates an insert statement and not an update. But how to say Kundera to make an update to rollback the transaction also with an update.
Logs:
12:42:41.185 [http-bio-8080-exec-3] INFO com.impetus.client.cassandra.CassandraClientBase - Returning delete query DELETE FROM "account" WHERE "id" = 'MCSP-000000000004'.
12:42:41.211 [http-bio-8080-exec-3] INFO com.impetus.client.cassandra.CassandraClientBase - Returning delete query DELETE FROM "account" WHERE "id" = 'MCSP-000000000005'.
EDIT (my repository):
public class CassandraRepository<T> {
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
public static Map<String, String> getProperties() {
final Map<String, String> properties = new HashMap<String, String>();
properties.put(CassandraConstants.CQL_VERSION, CassandraConstants.CQL_VERSION_3_0);
return properties;
}
public void update(T entity, EntityManager manager) throws Exception{
try {
manager.merge(entity);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
public void save(T entity, EntityManager manager) throws Exception{
try {
manager.persist(entity);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
According to JPA, to update an entity you have to first bring it into managed state (by fetching it)
Example:-
PersonCassandra p = entityManager.find(PersonCassandra.class, "2");
entityManager.getTransaction().begin();
p.setMonth(Month.JAN);
entityManager.merge(p);
entityManager.persist(p3);
entityManager.getTransaction().commit();
Issue is not with INSERT and UPDATE statements since both are similar for Cassandra, under the hood.

JavaEE Transaction rollback

I have got a problem with transaction rollback.
I need to first insert a user into the database, and then insert into another table some kind of log of who inserted the user.
If there is an exception when inserting this log-message, the whole transaction should be rolled back (i.e. user needs to be removed again).
The .ear is deployed on Wildfly 8.1, persistence is achieved through Hibernate with MySQL.
My class looks like this
#Stateless
#Remote(AdministratorBiznesowyService.class)
#Transactional(rollbackOn = Exception.class)
public class AdministratorBiznesowyServiceBean implements AdministratorBiznesowyService {
The method looks like this
#Override
#Transactional(rollbackOn = Exception.class)
public void insertUser(String userSessionId, User user) throws AdministratorBiznesowyException {
checkPermission(userSessionId);
try {
userBusiness.insertUser(user);
log.insertLog(
authenticationObjectBusiness.getUserIdForSessionId(userSessionId),
LogEnum.CREATE, user);
} catch (AuthenticationException e) {
ServerLogModule.logActionError(Messages
.getErrorMessage("server.authorization.noPermission"));
throw new AdministratorBiznesowyException();
} catch (Exception e1) {
ServerLogModule.logActionError(Messages
.getErrorMessage("server.exception"));
throw new AdministratorBiznesowyException();
}*/
}
The insertUser implementation in userBusiness:
#Override
public void insertUser(User user) throws AdministratorBiznesowyException {
try {
UserEntity userEntity = adminConvertUtils.convertUserToEntity(user);
userEntityFacade.create(userEntity);
} catch (Exception e) {
throw new AdministratorBiznesowyException();
}
}
And my log.insertLog currently for test-purposes just throws an exception.
throw new LogException();
and its implementation is like this:
#ApplicationException(rollback=true)
public class LogException extends RuntimeException {
AdministratorBiznesowyException:
#ApplicationException(rollback = true)
public class AdministratorBiznesowyException extends CommunicationException {
CommunicationException:
public class CommunicationException extends Exception {
So now, when I successfully call insertUser and directly after that get an exception, the new user still gets added to the database (I check through MySQL Workbench).
What else can I do to get this to rollback?
If any other code is needed, please comment, thank you in advance.

Removing/deleting from google datastore using endpoints, illegal arguement exception, delete with non-zero content length not supported

I'm trying to delete objects from the datastore (using cloud endpoints)
I know the connection is valid because I'm pulling/inserting objects with no problem
However when I try to delete using various approaches I get the same exception
java.lang.illegalArgumentException:DELETE with non-zero content length is not supported
approach 1(using the raw datastore service and the key I stored when inserting the item):
#ApiMethod(name = "removeRPurchase")
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
DatastoreService d=DatastoreServiceFactory.getDatastoreService();
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
try {
d.delete(k);
} catch (Exception e) {
e.printStackTrace();
purchase=null;
}
return purchase;
}
Approach 2
#ApiMethod(name = "removeRPurchase")
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
EntityManager mgr = getEntityManager();
RPurchase removed=null;
try {
RPurchase rpurchase = mgr.find(RPurchase.class, k);
mgr.remove(rpurchase);
removed=rpurchase;
} finally {
mgr.close();
}
return removed;
}
Ive also tried various variations with the entity manager and the Id, but all with the same exception
The object that i've passed in does contain the namespace in the account, and it does contain the 'KeytoString' of the key associated with the object
the endpoint is called as it should in an AsyncTask endpoint.removeRPurchase(p).execute();
Any help suggestions are appreciated
Make your API method a POST method like this:
#ApiMethod(name = "removeRPurchase" path = "remove_r_purchase", httpMethod = ApiMethod.HttpMethod.POST)
public RPurchase removeRPurchase(RPurchase purchase) {
NamespaceManager.set(purchase.getAccount());
DatastoreService d=DatastoreServiceFactory.getDatastoreService();
Key k=KeyFactory.stringToKey(purchase.getKeyrep());
try {
d.delete(k);
} catch (Exception e) {
e.printStackTrace();
purchase=null;
}
return purchase;
}
I had the same problem because I was using httpMethod = ApiMethod.HttpMethod.DELETE. The error it gives is correct. Simply change it to a POST and do whatever you want inside that API method like delete entities, return entities, etc.
How about trying out the following :
#ApiMethod(
name = "removeRPurchase",
httpMethod = HttpMethod.DELETE
)
public void removeRPurchase(#Named("id") String id) {
//Now take the id and plugin in your datastore code to retrieve / delete
}

Categories