How to Audit Spring data jpa #Query? - spring

To Audit log all the DB changes , we have implemented Hibernate Interceptor(org.hibernate.Interceptor) .
We can able to log the audit for the query executed using JpaRepository
Interceptor We have used- Sample
import java.io.Serializable;
import java.util.Iterator;
import org.hibernate.CallbackException;
import org.hibernate.EntityMode;
import org.hibernate.Interceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;
public class TestInterceptor implements Interceptor {
#Override
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types)
throws CallbackException {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) throws CallbackException {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types)
throws CallbackException {
// TODO Auto-generated method stub
return false;
}
#Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types)
throws CallbackException {
// TODO Auto-generated method stub
}
#Override
public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {
// TODO Auto-generated method stub
}
#Override
public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {
// TODO Auto-generated method stub
}
#Override
public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
// TODO Auto-generated method stub
}
#Override
public void preFlush(Iterator entities) throws CallbackException {
// TODO Auto-generated method stub
}
#Override
public void postFlush(Iterator entities) throws CallbackException {
// TODO Auto-generated method stub
}
#Override
public Boolean isTransient(Object entity) {
// TODO Auto-generated method stub
return null;
}
#Override
public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
// TODO Auto-generated method stub
return null;
}
#Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException {
// TODO Auto-generated method stub
return null;
}
#Override
public String getEntityName(Object object) throws CallbackException {
// TODO Auto-generated method stub
return null;
}
#Override
public Object getEntity(String entityName, Serializable id) throws CallbackException {
// TODO Auto-generated method stub
return null;
}
#Override
public void afterTransactionBegin(Transaction tx) {
// TODO Auto-generated method stub
}
#Override
public void beforeTransactionCompletion(Transaction tx) {
// TODO Auto-generated method stub
}
#Override
public void afterTransactionCompletion(Transaction tx) {
// TODO Auto-generated method stub
}
#Override
public String onPrepareStatement(String sql) {
// TODO Auto-generated method stub
return null;
}
}
But if we run the query via org.springframework.data.jpa.repository.Query that interceptor is not getting called.
Is this possible to Audit/Intercept the Query Executed using org.springframework.data.jpa.repository.Query
i.e I have the following Query in my Repository, this is not triggering Hibernate Interceptor
#Transactional
#Modifying
#Query("DELETE from MyEntity my where my.id =?1")
void deleteById(Long id);

To intercept spring data queries add this prop:
spring.jpa.properties.hibernate.session_factory.interceptor=com.yourpacakge.TestInterceptor
I used an interceptor class that extends from EmptyInterceptor just for simplicity.
public class MyInterceptor extends EmptyInterceptor {
#Override
public String onPrepareStatement(String sql) {
System.out.println("Query intercepted: " + sql);
return super.onPrepareStatement(sql);
}
}
DOCS: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#configurations-session-events

Related

Spring Kafka Consumer seek particular offset to read message

I created a SpringBootApplication to consume a message from Particular offset. But consumer poll method returning zero records. If I run application multiple times it should return same message each time from 108134L offset.
#Configuration
public class FlightEventListener {
#Bean
public void listenForMessage() throws Exception {
TopicPartition tp = new TopicPartition("topic-name", 0);
KafkaConsumer<String, Object> consumer = new KafkaConsumer<>(clusterOneProps);
try {
consumer.subscribe(Collections.singletonList("topic-name"), new ConsumerRebalanceListener() {
#Override
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
// TODO Auto-generated method stub
}
#Override
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
// TODO Auto-generated method stub
consumer.seek(tp, 108134L);
}
});
ConsumerRecords<String, Object> crs = consumer.poll(Duration.ofMillis(100L));
System.out.println(crs.count());
for (ConsumerRecord<String, Object> record : crs) {
System.out.println("consumer Record is >>>>"+record.offset());
System.out.println("consumer Record is >>>>"+record);
}
}catch(Exception e) {
e.printStackTrace();
}finally {
consumer.close();
}
================================================
Implemented ConsumerSeekAware. but method is not invoking. How to invoke the method. I am looking for method invocation during startup
#Configuration
public class MessageSeeker extends AbstractConsumerSeekAware {
#Autowired
private FlightEventKafkaConfiguration clusterOneConfig;
#Override
public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) {
// logic
}

Type mismatch: cannot convert from String to ListenableFuture<String>

I'm trying to implementing non-blocking call. in spring 4, But unfortunately it's throwing the below error.
Type mismatch: cannot convert from String to ListenableFuture
and also same error can not able convert from Map to ListenableFuture>.
My Method call stack is as below.
ListenableFuture<Map<String,String>> unusedQuota = doLogin(userIdentity,request,"0");
doLogin login simply return Map
is there any converter required?
what changes would be required ?
Thanks.
public class MyController {
final DeferredResult<Map<String,String>> deferredResult = new DeferredResult<Map<String,String>>(5000l);
private final Logger log = LoggerFactory.getLogger(MyController.class);
#Inject
RestTemplate restTemplate;
#RequestMapping(value = "/loginservice", method = RequestMethod.GET)
#Timed
public DeferredResult<Map<String,String>> loginRequestService(#RequestParam String userIdentity,HttpServletRequest request) throws Exception {
deferredResult.onTimeout(new Runnable() {
#Override
public void run() { // Retry on timeout
deferredResult.setErrorResult(ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body("Request timeout occurred."));
}
});
#SuppressWarnings("unchecked")
ListenableFuture<Map<String,String>> unusedQuota = doLogin(userIdentity,request);
unusedQuota.addCallback(new ListenableFutureCallback<Map<String,String>>() {
#SuppressWarnings("unchecked")
#Override
public void onSuccess(Map<String, String> result) {
// TODO Auto-generated method stub
deferredResult.setResult((Map<String, String>) ResponseEntity.ok(result));
}
#Override
public void onFailure(Throwable t) {
// TODO Auto-generated method stub
deferredResult.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(t));
}
});
return deferredResult;
}
private Map<String,String> doLogin(String userIdentity,HttpServletRequest request) throws Exception{
Map<String,String> unusedQuota=new HashMap<String,String>();
unusedQuota.put("quota", "100");
return unusedQuota;
}
}
}
You are NOT passing the Map object when there is an exception which is causing the issue, so your controller method needs to be changed as shown below, also move deferredResult object inside the Controller method as you should share the same instance of deferredResult for different user request.
public class MyController {
#Autowired
private TaskExecutor asyncTaskExecutor;
#RequestMapping(value = "/loginservice", method = RequestMethod.GET)
#Timed
public DeferredResult<Map<String,String>> loginRequestService(#RequestParam String userIdentity,HttpServletRequest request) throws Exception {
final DeferredResult<Map<String,String>> deferredResult = new DeferredResult<Map<String,String>>(5000l);
deferredResult.onTimeout(new Runnable() {
#Override
public void run() { // Retry on timeout
Map<String, String> map = new HashMap<>();
//Populate map object with error details with Request timeout occurred.
deferredResult.setErrorResult(new ResponseEntity
<Map<String, String>>(map, null,
HttpStatus.REQUEST_TIMEOUT));
}
});
ListenableFuture<String> task = asyncTaskExecutor.submitListenable(new Callable<String>(){
#Override
public Map<String,String> call() throws Exception {
return doLogin(userIdentity,request);
}
});
unusedQuota.addCallback(new ListenableFutureCallback<Map<String,String>>() {
#SuppressWarnings("unchecked")
#Override
public void onSuccess(Map<String, String> result) {
// TODO Auto-generated method stub
deferredResult.setResult((Map<String, String>) ResponseEntity.ok(result));
}
#Override
public void onFailure(Throwable t) {
Map<String, String> map = new HashMap<>();
//Populate map object with error details
deferredResult.setErrorResult(new ResponseEntity<Map<String, String>>(
map, null, HttpStatus.INTERNAL_SERVER_ERROR));
}
});
return deferredResult;
}
}
Also, you need to ensure that you are configuring the ThreadPoolTaskExecutor as explained in the example here.

Spring Batch: pass data between reader and writer

I would like to get data in the Writer that I've set in the Reader of my step. I know about ExecutionContexts (step and job) and about ExecutionContextPromotionListener via http://docs.spring.io/spring-batch/trunk/reference/html/patterns.html#passingDataToFutureSteps
The problem is that in Writer I'm retrieving a null value of 'npag'.
Line on ItemWriter:
LOG.info("INSIDE WRITE, NPAG: " + nPag);
I've being doing some workarounds without luck, looking answer for other similar questions... Any help? thanks!
Here's my code:
READER
#Component
public class LCItemReader implements ItemReader<String> {
private StepExecution stepExecution;
private int nPag = 1;
#Override
public String read() throws CustomItemReaderException {
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("npag", nPag);
nPag++;
return "content";
}
#BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
}
WRITER
#Component
#StepScope
public class LCItemWriter implements ItemWriter<String> {
private String nPag;
#Override
public void write(List<? extends String> continguts) throws Exception {
try {
LOG.info("INSIDE WRITE, NPAG: " + nPag);
} catch (Throwable ex) {
LOG.error("Error: " + ex.getMessage());
}
}
#BeforeStep
public void retrieveInterstepData(StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
this.nPag = jobContext.get("npag").toString();
}
}
JOB/STEP BATCH CONFIG
#Bean
public Job lCJob() {
return jobs.get("lCJob")
.listener(jobListener)
.start(lCStep())
.build();
}
#Bean
public Step lCStep() {
return steps.get("lCStep")
.<String, String>chunk(1)
.reader(lCItemReader)
.processor(lCProcessor)
.writer(lCItemWriter)
.listener(promotionListener())
.build();
}
LISTENER
#Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener executionContextPromotionListener = new ExecutionContextPromotionListener();
executionContextPromotionListener.setKeys(new String[]{"npag"});
return executionContextPromotionListener;
}
The ExecutionContextPromotionListener specifically states that it works at the end of a step so that would be after the writer executes. So the promotion I think you are counting on does not occur when you think it does.
If i were you I would set it in the step context and get it from the step if you need the value with in a single step. Otherwise I would set it to the job context.
The other aspect is the #BeforeStep. That marks a method for executing before the step context exists. The way you are setting the nPag value in the reader would be after the step had started executing.
You are trying to read the value for nPag even before it is set in the reader, ending up with a default value which is null. You need to read the value on nPag at the time of logging from the execution context directly. You can keep a reference to the jobContext. Try this
#Component
#StepScope
public class LCItemWriter implements ItemWriter<String> {
private String nPag;
private ExecutionContext jobContext;
#Override
public void write(List<? extends String> continguts) throws Exception {
try {
this.nPag = jobContext.get("npag").toString();
LOG.info("INSIDE WRITE, NPAG: " + nPag);
} catch (Throwable ex) {
LOG.error("Error: " + ex.getMessage());
}
}
#BeforeStep
public void retrieveInterstepData(StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
jobContext = jobExecution.getExecutionContext();
}
}
In your Reader and Writer you need to implement ItemStream interface and use ExecutionContext as member variable.Here i have given example with Processor instead of Writer but same is applicable for Writer as well .Its working fine for me and i am able to take values from reader to processor.
I have set the value in context in reader and getting the value in processor.
public class EmployeeItemReader implements ItemReader<Employee>, ItemStream {
ExecutionContext context;
#Override
public Employee read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
context.put("ajay", "i am going well");
Employee emp=new Employee();
emp.setEmpId(1);
emp.setFirstName("ajay");
emp.setLastName("goswami");
return emp;
}
#Override
public void close() throws ItemStreamException {
// TODO Auto-generated method stub
}
#Override
public void open(ExecutionContext arg0) throws ItemStreamException {
context = arg0;
}
#Override
public void update(ExecutionContext arg0) throws ItemStreamException {
// TODO Auto-generated method stub
context = arg0;
}
}
My processor
public class CustomItemProcessor implements ItemProcessor<Employee,ActiveEmployee>,ItemStream{
ExecutionContext context;
#Override
public ActiveEmployee process(Employee emp) throws Exception {
//See this line
System.out.println(context.get("ajay"));
ActiveEmployee actEmp=new ActiveEmployee();
actEmp.setEmpId(emp.getEmpId());
actEmp.setFirstName(emp.getFirstName());
actEmp.setLastName(emp.getLastName());
actEmp.setAdditionalInfo("Employee is processed");
return actEmp;
}
#Override
public void close() throws ItemStreamException {
// TODO Auto-generated method stub
}
#Override
public void open(ExecutionContext arg0) throws ItemStreamException {
// TODO Auto-generated method stub
}
#Override
public void update(ExecutionContext arg0) throws ItemStreamException {
context = arg0;
}
}
Hope this helps.

mapreduce ---custom data type

When i do a mapreduce program,i encounter that the key is a tuple (A,B) (A and B are both integer sets).How can i custom this data type?
public static class MapClass extends Mapper<Object,Text,Tuple,Tuple>....
public class Tuple implements WritableComparable<Tuple>{
#Override
public void readFields(DataInput arg0) throws IOException {
// TODO Auto-generated method stub
}
#Override
public void write(DataOutput arg0) throws IOException {
// TODO Auto-generated method stub
}
#Override
public int compareTo(Tuple o) {
// TODO Auto-generated method stub
return 0;
}
}
You're almost there, just add variables for A and B, and then complete the serialization methods and compareTo:
public class Tuple implements WritableComparable<Tuple>{
public Set<Integer> a = new TreeSet<Integer>;
public Set<Integer> b = new TreeSet<Integer>;
#Override
public void readFields(DataInput arg0) throws IOException {
a.clear();
b.clear();
int count = arg0.readInt();
while (count-- > 0) {
a.add(arg0.readInt());
}
count = arg0.readInt();
while (count-- > 0) {
b.add(arg0.readInt());
}
}
#Override
public void write(DataOutput arg0) throws IOException {
arg0.writeInt(a.size());
for (int v : a) {
arg0.writeInt(v);
}
arg0.writeInt(b.size());
for (int v : b) {
arg0.writeInt(v);
}
}
#Override
public int compareTo(Tuple o) {
// you'll need to implement how you want to compare the two sets between objects
}
}
to implement a custom datatype in hadoop, you must implement WritableComparable interface and provide the custom implementation for readFields() write() method.
Apart from the implementation of readFiled and write methods must override the equals and hashcode method of java object.
In case of custom data type implementation for the keys must implement comparable interface.

OSGI expose An "ClassNotFoundException: org.w3c.dom.***" Error when release

I only wrote the following codes in Activator.start() function
public void start(BundleContext bundleContext) throws Exception {
Activator.context = bundleContext;
Node node = new Node() {
#Override
public Object setUserData(String arg0, Object arg1, UserDataHandler arg2) {
// TODO Auto-generated method stub
return null;
}
#Override
public void setTextContent(String arg0) throws DOMException {
// TODO Auto-generated method stub
}
#Override
public void setPrefix(String arg0) throws DOMException {
// TODO Auto-generated method stub
}
#Override
public void setNodeValue(String arg0) throws DOMException {
// TODO Auto-generated method stub
}
#Override
public Node replaceChild(Node arg0, Node arg1) throws DOMException {
// TODO Auto-generated method stub
return null;
}
#Override
public Node removeChild(Node arg0) throws DOMException {
// TODO Auto-generated method stub
return null;
}
#Override
public void normalize() {
// TODO Auto-generated method stub
System.out.println("normalize 方法调用");
}
#Override
public String lookupPrefix(String arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public String lookupNamespaceURI(String arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isSupported(String arg0, String arg1) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isSameNode(Node arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isEqualNode(Node arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isDefaultNamespace(String arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public Node insertBefore(Node arg0, Node arg1) throws DOMException {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean hasChildNodes() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean hasAttributes() {
// TODO Auto-generated method stub
return false;
}
#Override
public Object getUserData(String arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public String getTextContent() throws DOMException {
// TODO Auto-generated method stub
return null;
}
#Override
public Node getPreviousSibling() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getPrefix() {
// TODO Auto-generated method stub
return null;
}
#Override
public Node getParentNode() {
// TODO Auto-generated method stub
return null;
}
#Override
public Document getOwnerDocument() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getNodeValue() throws DOMException {
// TODO Auto-generated method stub
return null;
}
#Override
public short getNodeType() {
// TODO Auto-generated method stub
return 0;
}
#Override
public String getNodeName() {
// TODO Auto-generated method stub
return null;
}
#Override
public Node getNextSibling() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getNamespaceURI() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getLocalName() {
// TODO Auto-generated method stub
return null;
}
#Override
public Node getLastChild() {
// TODO Auto-generated method stub
return null;
}
#Override
public Node getFirstChild() {
// TODO Auto-generated method stub
return null;
}
#Override
public Object getFeature(String arg0, String arg1) {
// TODO Auto-generated method stub
return null;
}
#Override
public NodeList getChildNodes() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getBaseURI() {
// TODO Auto-generated method stub
return null;
}
#Override
public NamedNodeMap getAttributes() {
// TODO Auto-generated method stub
return null;
}
#Override
public short compareDocumentPosition(Node arg0) throws DOMException {
// TODO Auto-generated method stub
return 0;
}
#Override
public Node cloneNode(boolean arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public Node appendChild(Node arg0) throws DOMException {
// TODO Auto-generated method stub
return null;
}
};
node.normalize();
}
Everything goes well when run in eclipse environment, but, when release the product, ERRORS in log when runs:
Root exception:
java.lang.NoClassDefFoundError: org/w3c/dom/Node
Caused by: java.lang.ClassNotFoundException: org.w3c.dom.Node
Anyone can give some help?
OSGi gives access to system packages but only java.* packages by default, this does not include other packages like: javax.net , javax.xml , com.sun
Thus it is necessary to specify any of such packages for OSGi framework to export them through the system bundle making them accessible to other bundles that import them.
To do that you need to set a configuration property with the additional packages required by your bundles, try setting it as a system property before starting the OSGi framework such that it picks up this property when it first starts.
Assuming you are on OSGi 4.2, that property would be configured like:
org.osgi.framework.system.packages.extra=org.w3c.dom
You may want to check the Apache Felix Framework Configuration Properties for more details, though this property is part of the OSGi spec and thus should be available in other implementations as well
Please update your question to include the bundle's MANIFEST.MF
It looks like org.w3c.dom is not implicitly provided in your production. Check the Import-Package header, may be you don't have Import-Package: org.w3c.dom
If you are using Equinox, you can edit the config.ini and add "org.w3c.dom" to org.osgi.framework.system.packages key and import the same packages in your MANIFEST.MF
in my case adding
org.osgi.framework.bootdelegation=xx...xxx,org.w3c.dom
solved my problem.

Resources