How to use MySQL and neo4j in single spring-boot application - mysql

I have created application with spring-boot and neo4j. Following is spring boot application with neo4j
#Configuration
#ComponentScan({ "myproject" })
#EnableAutoConfiguration
#EnableNeo4jRepositories(basePackages = "myproject")
public class Neo4jServer extends Neo4jConfiguration implements CommandLineRunner
{
public Server()
{
setBasePackage("myproject");
}
#Bean
SpringRestGraphDatabase graphDatabaseService()
{
return new SpringRestGraphDatabase("http://localhost:7474/db/data");
}
public void run(String... args) throws Exception
{
}
public static void main(String[] args) throws Exception
{
SpringApplication.run(Neo4jServer.class, args);
}
}
AND following is spring boot application with mysql
#Configuration
#ComponentScan({ "myproject" })
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "myproject.persistence")
#PropertySource("myproject.properties")
public class MySQLServer extends DataSourceAutoConfiguration implements CommandLineRunner
{
public void run(String... args) throws Exception
{
}
public static void main(String[] args) throws Exception
{
SpringApplication.run(MySQLServer.class, args);
}
}
I have created properties file in resource package.
spring.datasource.url=jdbc:mysql://localhost:3306/myDB
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.mysql.jdbc.Driver
So, There are now two application, one is with neo4j ie Neo4jServer.java and one is with MySQL ie MySQLServer.java
How to use both in single application.
Please make me correct if wrong.
Thank you :)

Need to inject MySQL configured DataSource/TransactionManager bean to application class. MySQL Entities/DAO and Neo4j Node/Relationship/DAO needs to be in different packages. Then you can provide those respective packages for scan to MySQL and Neo4j.
Following code shows the configuration :
#Configuration
#ComponentScan({ "myproject" })
#EnableJpaRepositories(basePackages = "myproject.persistence.mysql")
#EnableAutoConfiguration
#EnableNeo4jRepositories(basePackages = "myproject.persistence.neo4j")
public class Application extends Neo4jConfiguration
{
#Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory;
public Application()
{
setBasePackage("myproject.persistence.neo4j");
}
#Bean
SpringRestGraphDatabase graphDatabaseService()
{
return new SpringRestGraphDatabase("http://localhost:7474/db/data");
}
#Bean(destroyMethod = "close")
public DataSource dataSource()
{
DataSource dataSource = new DataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/dbname");
dataSource.setUsername("mysqluser");
dataSource.setPassword("mysqlpassword");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPackagesToScan("myproject.persistence.mysql");
entityManagerFactory.setJpaDialect(new HibernateJpaDialect());
Map<String, String> jpaProperties = new HashMap<String, String>();
jpaProperties.put("hibernate.connection.charSet", "UTF-8");
jpaProperties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.EJB3NamingStrategy");
jpaProperties.put("hibernate.bytecode.provider", "javassist");
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
entityManagerFactory.setJpaPropertyMap(jpaProperties);
entityManagerFactory.setPersistenceProvider(new HibernatePersistence());
return entityManagerFactory;
}
#Override
#Bean(name = "transactionManager")
public PlatformTransactionManager neo4jTransactionManager() throws Exception
{
return new ChainedTransactionManager(new JpaTransactionManager(entityManagerFactory.getObject()),
new JtaTransactionManagerFactoryBean(graphDatabaseService()).getObject());
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation()
{
return new PersistenceExceptionTranslationPostProcessor();
}
}

Related

How to rollback Rabbit-mq message after Junit test?

When you test your code, you send a message to rabbit-mq. How do you get the message back when the test is over?
public interface RabbitProducer {
String OUTPUT = "rabbitmq_producer_channel";
#Output(OUTPUT)
MessageChannel output();
}
public class SysGroupServiceImpl {
#Autowired
private RabbitProducer rabbitProducer;
#Override
public Result remove(Collection<? extends Serializable> idList) {
rabbitProducer.output().send(MessageBuilder.withPayload(idList)
.setHeader("x-delay", 5000)
.setHeader("MessageType", "GroupBatchDelete").build());
return Result.booleanResult(true);
}
}
#SpringBootTest
#Transactional
#Rollback
public class SysGroupServiceTest {
#Autowired
private SysGroupService sysGroupService;
#Test
void removeTest(){
sysGroupService.remove(Stream.of("1").collect(Collectors.toList()));
}
}
I use Spring Cloud Stream to be compatible with RabbitMQ, and all the relevant code is there.Is there a way to mock this out?I tried the following scheme, but due to X-dealy, I got this error:No exchange type x-delayed-message
<dependency>
<groupId>com.github.fridujo</groupId>
<artifactId>rabbitmq-mock</artifactId>
</dependency>
#Component
public class RabbitMqMock {
#Bean
public ConnectionFactory connectionFactory() {
return new CachingConnectionFactory(MockConnectionFactoryFactory.build());
}
}
I know little about mocks. Can mocks create an X-delay exchange?

Spring batch job parameters

My Spring batch configuration is below:
#Configuration
public class SampleConfiguration1 {
#Autowired
protected JobBuilderFactory jobBuilderFactory;
#Autowired
protected StepBuilderFactory stepBuilderFactory;
#Bean
public Job job1() throws Exception {
//how can I get job parameters here
return jobBuilderFactory.get("job1")
.start(step1())
.next(step2())
.build();
}
#Bean
public Step step1() {}
#Bean
public Step step2() {}
}
My application
#EnableBatchProcessing
#SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
When I run my job like below:
java -jar sample.jar parameterkey=parameterValue
My question is how can I get job parameters in job1()? thanks

I need to write JUNIT for Apache camel route

I have camel route as below
public class IncomingBatchFileRoute extends RouteBuilder {
#Value(CCS_PROCESSING_INCOMING_DIRECTORY)
private String source;
#Override
public void configure() throws Exception {
from(sourceLocation)).autoStartup(false).to("encryptionEndPoint");
}
}
I need to write a JUNIT For above camel route and am new to it and created a structure as below
public class IncomingBatchFileRouteTest extends CamelTestSupport{
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
return new IncomingBatchFileRoute();
}
#Test
public void sampleMockTest() {
}
}
Not sure how to complete it. Request you to help me on this
You need to mock your encryptionEndPoint and start your route with a producerTemplate
#Produce(uri = CCS_PROCESSING_INCOMING_DIRECTORY)
protected ProducerTemplate template;
#EndpointInject(uri = "encryptionEndPoint")
protected MockEndpoint resultEndpoint;
#Test
public void sampleMockTest() {
// GIVEN
this.resultEndpoint.expectedMessageCount(1);
// WHEN
this.template.sendBody("Hey");
// THEN
this.resultEndpoint.assertIsSatisfied();
}

Lazy collection in Spring JPA with Jackson and elasticsearch wihtout jsonignore

We have spring boot with elasticsearch and mysql. We have a feature for reindexing all data from the mysql into elasticsearch, which is simple as:
#Service
#Transactional
public class SearchIndexer {
public void reindex(){
elasticsearchRepository.save(jpaRepository.findAll());
}
}
Now we have an entity called invoice, which has a lazy loaded collection with a "derived" calculation:
#Entity
#Table(name = "invoice")
#Document(indexName = "invoice")
public class Invoice implements Serializable {
//... other props
#OneToMany(fetch = FetchType.LAZY, mappedBy = "invoice")
#JsonIgnore
private Set<InvoiceItem> invoiceItems = new LinkedHashSet<>();
// getter and setters for invoiceItems
public boolean isAllSimple() {
if(getInvoiceType()==null){
return false;
}
if(getInvoiceItems()==null){
return false;
}
for(InvoiceItem item : getInvoiceItems()){
if(!item.isSimple()){
return false;
}
}
return true;
}
}
When the rest-controller is used, the resulting json contains correctly a property "allSimple". This is, because we run that with hibernate5module in one transaction.
However, when we call elasticsearchRepository.save(jpaRepository.findAll()) (also in a transaction), the objectmapper for elasticsearch cannot serialize the "allSimple" property, beacause of a LazyInitializationException. The elasticsearch-objectmapper is configured as follows:
#Bean
public ElasticsearchTemplate elasticsearchTemplate(Client client, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder, Hibernate5Module hibernate5Module) {
return new ElasticsearchTemplate(client, new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).modulesToInstall(hibernate5Module).build()));
}
public class CustomEntityMapper implements EntityMapper {
private ObjectMapper objectMapper;
public CustomEntityMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure( DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
#Override
public String mapToString(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}
#Override
public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
return objectMapper.readValue(source, clazz);
}
}
The hibernate5module is loaded and registered, but did not solve the problem.
Normally we would add a "JsonIgnore" to that property, but we need that value, so this is no option.
Any ideas?!
I had a project configurated with this.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.sagasoftware.tracker.*")
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
Hibernate5Module hibernate5Module = new Hibernate5Module();
objectMapper.registerModule(hibernate5Module);
objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
messageConverter.setObjectMapper(objectMapper);
return messageConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
}
}
If you are using spring boot, declaring the bean MappingJackson2HttpMessageConverter and registering the hibernate5module should fix your problem.
I could render a entity throught a rest controller.

Spring Boot with xml and json with jackson only returns xml

Let me thank you in advance for your help!
I have a weird behaviour in an spring boot application. Let me explain it for you:
I'm wrapping some legacy web services (custom xml messages) with some nice rest-json services (via spring-mvc and spring boot and using jackson for serializing stuff)
In order to communicate with the legacy systems, I have created a custom XmlMapper, serializers and deserializers.
And finally, I have created an httpclientconfig, in order to define some http connection properties...
But after starting the app and trying to visit any endpoint (actuator ones for example), the app only returns xml. Event swagger endpoints return xml (what makes swagger-ui going nuts.
These are some of the classes:
#Configuration
public class HttpClientConfig {
private static final Logger logger = LoggerFactory.getLogger(HttpClientConfig.class);
#Value(value = "${app.http.client.max_total_connections}")
public String MAX_TOTAL_CONNECTIONS;
#Value(value = "${app.http.client.max_connections_per_route}")
public String MAX_CONNECTIONS_PER_ROUTE;
#Value(value = "${app.http.client.connection_timeout_milliseconds}")
public String CONNECTION_TIMEOUT_MILLISECONDS;
#Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
#Autowired
private XmlMapper xmlMapper;
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
}
if (converter instanceof MappingJackson2XmlHttpMessageConverter) {
MappingJackson2XmlHttpMessageConverter jsonConverter = (MappingJackson2XmlHttpMessageConverter) converter;
jsonConverter.setObjectMapper(xmlMapper);
}
}
logger.debug("restTemplate object created====================================");
return restTemplate;
}
#Bean
public HttpClient httpClient() {
HttpClient httpClient = null;
try {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// disable SSL check
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
return true;
}
}).build();
httpClientBuilder.setSSLContext(sslContext);
// don't check Hostnames
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory).build();
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connMgr.setMaxTotal(Integer.parseInt(MAX_TOTAL_CONNECTIONS));
connMgr.setDefaultMaxPerRoute(Integer.parseInt(MAX_CONNECTIONS_PER_ROUTE));
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(Integer.parseInt(CONNECTION_TIMEOUT_MILLISECONDS)).build();
httpClientBuilder.setDefaultRequestConfig(config);
httpClientBuilder.setConnectionManager(connMgr);
// to avoid nohttpresponse
httpClientBuilder.setRetryHandler(new HttpRequestRetryHandler() {
#Override
public boolean retryRequest(IOException exception, int executionCount,
org.apache.http.protocol.HttpContext context) {
// TODO Auto-generated method stub
return true;
}
});
httpClient = httpClientBuilder.build();
} catch (Exception e) {
logger.error("Excption creating HttpClient: ", e);
}
return httpClient;
}
}
And the xml mapper
#Configuration
public class XmlMapperConfig{
#Bean
public XmlMapper getXmlMapper() {
XmlMapper mapper=new XmlMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(CafRequestObject.class, new CafRequestObjectSerializer());
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(module);
mapper.findAndRegisterModules();
CafXmlSerializationProvider cafXmlProvider=new CafXmlSerializationProvider(new XmlRootNameLookup());
mapper.setSerializerProvider(cafXmlProvider);
return mapper;
}
}
I call to findAndregisterModules, because I am also developing some libraries which provides additional serializers for services (modularized stuff)
I'm completely lost with this. Any help would be much appreciated...
Regards!
I have solved it extending WebMvcConfigurerAdapter:
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
Thanks again!