spring boot drools ConstraintEvaluationException with multiple drl files - spring-boot

spring boot 2.x, kie-ci 7.59.0.Final
package com.collyer.rest.config;
import org.kie.api.KieServices;
import org.kie.api.builder.*;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
#Configuration
public class DroolsConfig {
private static final String RULES_PATH = "rule/";
#Bean
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
}
return kieFileSystem;
}
private Resource[] getRuleFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
}
#Bean
public KieContainer kieContainer() throws IOException {
final KieRepository kieRepository = getKieServices().getRepository();
kieRepository.addKieModule(new KieModule() {
public ReleaseId getReleaseId() {
return kieRepository.getDefaultReleaseId();
}
});
KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
}
private KieServices getKieServices() {
return KieServices.Factory.get();
}
}
I have one d.drl file under the src/main/resources/rule, it looks like:
package com.my.rest.service;
//set import and global
rule "groupA_A_0"
agenda-group "groupA"
activation-group "groupA_A"
when
$j : JSONObject(aSize == 1)
then
System.out.println("####A-0");
....
end
the code to fire is:
#Autowired
private KieContainer kieContainer;
public testA() {
KieSession kSession = kieContainer.newKieSession();
//...set global
JSONObject json = new JSONObject();
json.put("aSize", 1);
kSession.getAgenda().getAgendaGroup("groupA").setFocus();
kSession.insert(json);
kSession.fireAllRules();
}
it works fine.
However, if I add another a.drl whose is
package com.my.rest.service;
//set import and global
rule "groupB_A_0"
agenda-group "groupB"
activation-group "groupB_A"
when
$j : JSONObject(bSize == 1)
then
System.out.println("####A-0");
....
end
the corresponding code to fire is:
public testB() {
KieSession kSession = kieContainer.newKieSession();
//...set global
JSONObject json = new JSONObject();
json.put("bSize", 2);
kSession.getAgenda().getAgendaGroup("groupB").setFocus();
kSession.insert(json);
kSession.fireAllRules();
}
the error thrown when executing testB() which is used to fire rules of a.drl:
org.drools.mvel.ConstraintEvaluationException: Error evaluating constraint 'aSize == 1' in [Rule "groupA_A_0" in rule/d.drl]
JSONObject is net.sf.json.JSONObject(like a Map), aSize is put into JSONObject when fire rules of d.drl while bSize is put when fire rules of a.drl.
i just want to fire rules of a.drl, why it said the error of d.drl?(and at this time, fire rules of d.drl is successed)
how to fix it?

Related

Spring Boot: Add a specific HTTP header in a SOAP request based on Web Service Security (WS-Security, WSS) username

I am exposing a SOAP web service using Spring Boot. This web service is secured using Web Service Security (WSS) which is configured with this security_policy.xml:
<xwss:SecurityConfiguration
xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:RequireUsernameToken
passwordDigestRequired="true" nonceRequired="true" />
</xwss:SecurityConfiguration>
Until this point, the application is working just fine. It is able to authenticate successfully.
Now, I need to add a specific HTTP header based on the WSS username. It is, adds the HTTP header "x-auth-type" with the values:
"test-auth-type" when the username is "test"
"production-auth-type" when the username is "production"
"undefined-auth-type" otherwise
I thought it was easy to add an EndpointInterceptor in which I can set the HTTP header based on the user, but is not been possible to me until now.
My Web Service Configuration class looks like this:
package com.godev.soapwebserviceswithspring;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
import org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor;
import org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler;
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
private static final String WS_SCHEMA_PATH = "godev_contract.xsd";
private static final String NAMESPACE_URI = "http://godev.com/soap/webservices/demo";
#Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(
ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
#Bean(name = "xml_message")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema billsSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("XmlMessagePort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace(NAMESPACE_URI);
wsdl11Definition.setSchema(billsSchema);
return wsdl11Definition;
}
#Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource(WS_SCHEMA_PATH));
}
#Bean
PayloadLoggingInterceptor payloadLoggingInterceptor() {
return new PayloadLoggingInterceptor();
}
#Bean
PayloadValidatingInterceptor payloadValidatingInterceptor() {
final PayloadValidatingInterceptor payloadValidatingInterceptor = new PayloadValidatingInterceptor();
payloadValidatingInterceptor.setSchema(new ClassPathResource(WS_SCHEMA_PATH));
return payloadValidatingInterceptor;
}
#Bean
XwsSecurityInterceptor securityInterceptor() {
XwsSecurityInterceptor securityInterceptor = new XwsSecurityInterceptor();
securityInterceptor.setCallbackHandler(callbackHandler());
securityInterceptor.setPolicyConfiguration(new ClassPathResource("security_policy.xml"));
return securityInterceptor;
}
#Bean
SimplePasswordValidationCallbackHandler callbackHandler() {
SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
callbackHandler.setUsersMap(Collections.singletonMap("admin", "pwd123"));
return callbackHandler;
}
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(payloadLoggingInterceptor());
interceptors.add(payloadValidatingInterceptor());
interceptors.add(securityInterceptor());
}
}
My Web Service Endpoint class looks like this:
package com.godev.soapwebserviceswithspring;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import com.godev.soap.webservices.demo.GetXmlMessageRequest;
import com.godev.soap.webservices.demo.GetXmlMessageResponse;
#Endpoint
public class XmlMessageEndpoint {
private static final String NAMESPACE_URI = "http://godev.com/soap/webservices/demo";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getXmlMessageRequest")
#ResponsePayload
public GetXmlMessageResponse getXmlDocument(#RequestPayload GetXmlMessageRequest request) {
GetXmlMessageResponse response = new GetXmlMessageResponse();
response.setXmlMessage("<xml>empty document</xml>");
return response;
}
}
Any advice will be very appreciated!
It works for me:
Inject the Security element present in the SOAP header in the Endpoint:
#Endpoint
public class XmlMessageEndpoint {
private static final String NAMESPACE_URI = "http://godev.com/soap/webservices/demo";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getXmlMessageRequest")
#ResponsePayload
public GetXmlMessageResponse getXmlDocument(#RequestPayload GetXmlMessageRequest request, #SoapHeader("{" + Security.SECURITY_NAMESPACE + "}Security") SoapHeaderElement securityHeader) {
GetXmlMessageResponse response = new GetXmlMessageResponse();
response.setXmlMessage("<xml>empty document</xml>");
return response;
}
In order to parse the securityHeader into something usable, you need to define a couple of POJOs. In my case, I only need the username
POJO for Security element:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = Security.SECURITY_NAMESPACE, name = "Security")
#Getter
#Setter
public class Security {
public static final String SECURITY_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
#XmlElement(namespace = Security.SECURITY_NAMESPACE, name = "UsernameToken")
private UsernameToken usernameToken;
}
POJO for UsernameToken element:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = Security.SECURITY_NAMESPACE, name = "UsernameToken")
#Getter
#Setter
public class UsernameToken {
#XmlElement(namespace = Security.SECURITY_NAMESPACE, name = "Username")
private String username;
}
And finally, you can parse the securityHeader using something like this:
public class SoapParser {
public static Security parseSecurityElement(SoapHeaderElement soapHeaderElement) {
Security securityElement = null;
try {
JAXBContext context = JAXBContext.newInstance(Security.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
securityElement = (Security) unmarshaller.unmarshal(soapHeaderElement.getSource());
} catch (JAXBException e) {
e.printStackTrace();
}
return securityElement;
}
}
I hope, it helps!

I have to call a microservice from a batch launched from another microservice using spring-batch and openfeign

I don't know if it's possible, but this is my question:
I hava a batch developed using spring-boot and spring-batch, and I have to call another microservice using Feign...
...help!
this is my class Reader
package it.batch.step;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.client.feign.EmailAccountClient;
import it.dto.feign.mail.account.AccountOutDto;
import it.dto.feign.mail.account.SearchAccountFilterDto;
import it.dto.feign.mail.account.SearchAccountResponseDto;
public class Reader implements ItemReader <String> {
private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class);
private int count = 0;
#Autowired
private EmailAccountClient emailAccountClient;
#Override
public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
LOGGER.info("read - begin ");
SearchAccountResponseDto clientResponse = emailAccountClient.searchAccount(getFilter());
if (count < clientResponse.getAccounts().size()) {
return convertToJsonString(clientResponse.getAccounts().get(count++));
} else {
count = 0;
}
return null;
}
private static SearchAccountFilterDto getFilter() {
SearchAccountFilterDto filter = new SearchAccountFilterDto();
return filter;
}
private String convertToJsonString(AccountOutDto account) {
ObjectMapper mapper = new ObjectMapper();
String jsonString = "";
try {
jsonString = mapper.writeValueAsString(account);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
LOGGER.info("Contenuto JSON: " + jsonString);
return jsonString;
}
}
...
when I launch the batch I have this error:
java.lang.NullPointerException: null
at it.batch.step.Reader.read(Reader.java:32) ~[classes/:?]
where line 32 is:
SearchAccountResponseDto clientResponse = emailAccountClient.searchAccount(getFilter());
EmailAccountClient is null
Your client is null: your reader is not a #Component so Spring can't autowire the client. You must use a workaround like passing the autowired client through the constructor when you instantiate the reader, like this:
private EmailAccountClient client;
public reader(EmailAccountClient client){
this.client=client;
}
in the other class:
#Autowired
private EmailAccountClient client;
#Bean
public ItemReader<String> reader(){
return new Reader(client)
}

AWS lambda spring . Not able to load properties file

I have problem with loading the properties file where i reference the values from. Locally I am able to run it as expected. But AWS lambda function does not seem to work as expected since it is not able to laod properties file. Below is the handler written. I deploy MainHanlder.java function on lambda.
#Component
public class TestHandler implements RequestHandler<SNSEvent, Object> {
#Override
public String handleRequest(SNSEvent snsEvent, Context context) {
TestClient testClient = Application.getBean("pp",TestClient);
return null;
}
}
MainHandler.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.amazonaws.services.lambda.runtime.events.SNSEvent;
import com.test.lambda.ApplicationConfiguration;
public class MainHandler extends SpringRequestHandler<SNSEvent, Object> {
/**
* Here we create the Spring {#link ApplicationContext} that will
* be used throughout our application.
*/
private static final ApplicationContext context =
new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
#Override
public ApplicationContext getApplicationContext() {
return context;
}
}
SpringRequestHandler.java
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import org.springframework.context.ApplicationContext;
#SuppressWarnings("unchecked")
public abstract class SpringRequestHandler<I, O> implements RequestHandler<I, O>, ApplicationContextProvider {
private final RequestHandler<I, O> handler;
public SpringRequestHandler() {
handler = getApplicationContext().getBean(RequestHandler.class);
}
#Override
public O handleRequest(final I input, final Context context) {
return (O) handler.handleRequest(input, context);
}
}
Application.java
public class Application {
private static final AnnotationConfigApplicationContext springContext = new AnnotationConfigApplicationContext();
private static boolean flag = Boolean.TRUE;
private static final XLogger logger = XLoggerFactory.getXLogger(Application.class);
public static <T> T getBean(String env, Class<T> clazz) {
InputStream i1 = null;
InputStream i2 = null;
if(flag) {
Properties rp = new Properties();
Properties ap = new Properties();
try {
System.out.println("print env " + env);
i1 = Application.class.getResourceAsStream(“/application-” + env + ".properties");
rp.load(i1);
i2 = Application.class.getResourceAsStream("/application-" + env + ".properties");
ap.load(i2);
PropertyPlaceholderConfigurer propertyOverrideConfigurer = new PropertyPlaceholderConfigurer();
propertyOverrideConfigurer.setPropertiesArray(new Properties[]{rp,ap});
springContext.scan(new String[]{"com.pinto.lambda"});
springContext.addBeanFactoryPostProcessor(propertyOverrideConfigurer);
try {
springContext.refresh();
}catch(IllegalStateException e) {
}
flag = Boolean.FALSE;
} catch (Exception e) {
logger.error("Exception in the Application - " +e.getMessage());
throw new RuntimeException("Unable to load properties " + e.getMessage());
}
return springContext.getBean(clazz);
}
ERROR TRACE - AWS CONSOLE LOGS
==================== FUNCTION OUTPUT ====================
{"errorMessage":"Unable to load properties null","errorType":"java.lang.RuntimeException","stackTrace":["com.pinto.lambda.Application.getBean(Application.java:65)","com.pinto.lambda.handler.GetWarehouseInventoryHandler.handleRequest(TestHandler.java:44)","com.pinto.lambda.handler.GetWarehouseInventoryHandler.handleRequest(TestHandler.java:1)","com.pinto.lambda.handler.SpringRequestHandler.handleRequest(SpringRequestHandler.java:19)"]}
==================== FUNCTION LOG OUTPUT ====================
print env pp
[ERROR] Exception in the Application - null
Unable to load properties null: java.lang.RuntimeException
java.lang.RuntimeException: Unable to load properties null
at com.pinto.lambda.Application.getBean(Application.java:65)
at com.pinto.lambda.handler.TestHandler.handleRequest(TestHandler.java:44)
at com.pinto.lambda.handler.TestHandler.handleRequest(TestHandler.java:1)
at com.pinto.lambda.handler.SpringRequestHandler.handleRequest(SpringRequestHandler.java:19)

How to use Apache CachingHttpAsyncClient with Spring AsyncRestTemplate?

Is it possible to use CachingHttpAsyncClient with AsyncRestTemplate? HttpComponentsAsyncClientHttpRequestFactory expects a CloseableHttpAsyncClient but CachingHttpAsyncClient does not extend it.
This is known as issue SPR-15664 for versions up to 4.3.9 and 5.0.RC2 - fixed in 4.3.10 and 5.0.RC3. The only way around is is creating a custom AsyncClientHttpRequestFactory implementation that is based on the existing HttpComponentsAsyncClientHttpRequestFactory:
// package required for HttpComponentsAsyncClientHttpRequest visibility
package org.springframework.http.client;
import java.io.IOException;
import java.net.URI;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.cache.CacheConfig;
import org.apache.http.impl.client.cache.CachingHttpAsyncClient;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.protocol.HttpContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
// TODO add support for other CachingHttpAsyncClient otpions, e.g. HttpCacheStorage
public class HttpComponentsCachingAsyncClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory implements AsyncClientHttpRequestFactory, InitializingBean {
private final CloseableHttpAsyncClient wrappedHttpAsyncClient;
private final CachingHttpAsyncClient cachingHttpAsyncClient;
public HttpComponentsCachingAsyncClientHttpRequestFactory() {
this(HttpAsyncClients.createDefault(), CacheConfig.DEFAULT);
}
public HttpComponentsCachingAsyncClientHttpRequestFactory(final CacheConfig config) {
this(HttpAsyncClients.createDefault(), config);
}
public HttpComponentsCachingAsyncClientHttpRequestFactory(final CloseableHttpAsyncClient client) {
this(client, CacheConfig.DEFAULT);
}
public HttpComponentsCachingAsyncClientHttpRequestFactory(final CloseableHttpAsyncClient client, final CacheConfig config) {
Assert.notNull(client, "HttpAsyncClient must not be null");
wrappedHttpAsyncClient = client;
cachingHttpAsyncClient = new CachingHttpAsyncClient(client, config);
}
#Override
public void afterPropertiesSet() {
startAsyncClient();
}
private void startAsyncClient() {
if (!wrappedHttpAsyncClient.isRunning()) {
wrappedHttpAsyncClient.start();
}
}
#Override
public ClientHttpRequest createRequest(final URI uri, final HttpMethod httpMethod) throws IOException {
throw new IllegalStateException("Synchronous execution not supported");
}
#Override
public AsyncClientHttpRequest createAsyncRequest(final URI uri, final HttpMethod httpMethod) throws IOException {
startAsyncClient();
final HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
postProcessHttpRequest(httpRequest);
HttpContext context = createHttpContext(httpMethod, uri);
if (context == null) {
context = HttpClientContext.create();
}
// Request configuration not set in the context
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
// Use request configuration given by the user, when available
RequestConfig config = null;
if (httpRequest instanceof Configurable) {
config = ((Configurable) httpRequest).getConfig();
}
if (config == null) {
config = createRequestConfig(cachingHttpAsyncClient);
}
if (config != null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
}
}
return new HttpComponentsAsyncClientHttpRequest(cachingHttpAsyncClient, httpRequest, context);
}
#Override
public void destroy() throws Exception {
try {
super.destroy();
} finally {
wrappedHttpAsyncClient.close();
}
}
}

Spring QueryDSL set Session from Spring Context

I'm studying the QueryDSL library and implementing it into my DAL project.
What is clear to me is that I need to instantiate a HibernateQuery object and use the QueryDSL methods to define the source of data (from() clause) and the conditions (where() with the BooleanExpressions).
For example consider a User Entity which has a name field and suppose we want to test whether the user with a name equal to "Richie" exists into the DB. I would write the following code to make things done
public boolean richieExists()
{
QUser qUser = QUser.user;
HibernateQuery query = new HibernateQuery(session); // I need a session instance here!
User richie = query.from(qUser).where(qUser.name.eq("Richie")).uniqueResult(qUser);
return (richie!=null);
}
The problem is that the above code should be the method of a Spring's Service object which uses a Repository to execute CRUD operations. This means that I need to retrieve the Session from the EntityManager instance I'm using in the Application Context to instantiate the HibernateQuery object, and this is a problem because the Service object doesn't have a way to return the used EntityManager.
What is the right way/place to write QueryDSL queries?
Here is my DAOConfig.java class with the Spring configuration (here we define the EntityManagerFactoryBean used by Spring for the Repository operations)
package my.dal.service.dal.config;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#ComponentScan(basePackages = { "my.dal" })
#PropertySource("classpath:dbconnection.properties")
#EnableJpaRepositories("my.dal.repository")
#EnableTransactionManagement
public class DALConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver_class";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_POOL_INITIAL_SIZE = "pool.initialsize";
private static final String PROPERTY_NAME_POOL_MAX_IDLE = "pool.maxidle";
private static final String PROPERTY_NAME_DAL_CLASSES_PACKAGE = "entities.packages_to_scan";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.showsql";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
#Resource
private Environment environment;
#Bean
public DataSource dataSource()
{
Properties props = new Properties();
props.put("driverClassName", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
props.put("url", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
props.put("username", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
props.put("password", environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
props.put("initialSize", environment.getRequiredProperty(PROPERTY_NAME_POOL_INITIAL_SIZE));
props.put("maxIdle", environment.getRequiredProperty(PROPERTY_NAME_POOL_MAX_IDLE));
BasicDataSource bds = null;
try {
bds = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bds;
}
#Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor()
{
PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
return b;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator(){
return new HibernateExceptionTranslator();
}
#Bean
public PlatformTransactionManager transactionManager() throws ClassNotFoundException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_DAL_CLASSES_PACKAGE));
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
Properties jpaProperties = new Properties();
jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
}
This is my repository interface
package my.dal.repository;
import my.domain.dal.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface IUserRepository extends CrudRepository<User, String>{
}
This is the UserService Service class in which I have to implement the "richieExists" query method
package my.dal.service;
import my.dal.repository.IUserRepository;
import my.domain.dal.QUser;
import my.domain.dal.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import com.mysema.query.jpa.hibernate.HibernateQuery;
#Service
public class UserService {
#Autowired
private IUserRepository repository;
public User find(String username) throws DataRetrievalFailureException
{
User user = null;
user= repository.findOne(username);
if (user == null)
throw new DataRetrievalFailureException("User with username = \"" + username + "\" not found");
else
return user;
}
public User insert(User user) throws DuplicateKeyException
{
if (repository.findOne(user.getUsername()) != null)
throw new DuplicateKeyException("User with username = \"" + user.getUsername() + "\" already exists");
return repository.save(user);
}
public void delete(String username) throws DataRetrievalFailureException
{
if (repository.findOne(username) == null)
throw new DataRetrievalFailureException("User with username =\"" + username + "\" not found");
repository.delete(username);
}
public User update(User user) throws DataRetrievalFailureException
{
if (repository.findOne(user.getUsername()) == null)
throw new DataRetrievalFailureException("User with username = \"" + user.getUsername() + "\" not found");
return repository.save(user);
}
public boolean richieExists()
{
QUser qUser = QUser.user;
HibernateQuery query = new HibernateQuery(session); // I need a session instance here!
User richie = query.from(qUser).where(qUser.username.eq("richie")).uniqueResult(qUser);
return (richie!=null);
}
}
Thank you
I solved this way:
Got the current EntityManager from the persistence context by mean of the proper annotation
#PersistenceContext
EntityManager em;
Next I used the JPAQuery class (not the HibernateQuery one) to build the queries
JPQLQuery query = new JPAQuery(em); // Now just use the query object
Hope this help

Resources