Hibernate OGM Neo4j -Unable to access TransactionManager - neo4j

I trying to build a JSF WebApplication using Neo4j as No-SQL-Databasing. I want to access Neo4j via Hibernate.
My dependencies are
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate.ogm</groupId>
<artifactId>hibernate-ogm-bom</artifactId>
<version>5.0.1.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate.ogm</groupId>
<artifactId>hibernate-ogm-neo4j</artifactId>
</dependency>
My entities look like the following
#Entity
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
private String name;
private Double age;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "owner", cascade = CascadeType.PERSIST)
private Set<Car> cars = new HashSet<>();
...
I save them within in the following class
#Stateless
public class StorageManager {
#PersistenceContext(unitName = "neo4j")
private EntityManager em;
public void savePerson(Person p) {
em.persist(p);
}
public void saveCar(Car c){
em.persist(c);
}
public void save(String personName, Double personAge, String carName) {
Person person = new Person(personName, personAge);
Car car = new Car(carName);
car.setOwner(person);
person.getCars().add(car);
em.persist(person);
}
My Persistence Unit
<persistence-unit name="mongo-ogm" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<class>entities.Person</class>
<class>entities.Car</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.ogm.datastore.provider" value="neo4j_embedded" />
<property name="hibernate.ogm.neo4j.database_path" value="C:\Users\phe\Documents\Neo4j\sample" />
</properties>
</persistence-unit>
When I deploy the WebApp on my Wildlfy 9 and want to save Data I get an Exception
org.hibernate.resource.transaction.backend.jta.internal.JtaPlatformInaccessibleException: Unable to access TransactionManager or UserTransaction to make physical transaction delegate
Researches in the internet ended with no result. There are only a few tutorials. I have tried it with and without transaction-type="JTA" .
Have you any ideas?

I found the solution. As I am deploying to Wildlfy I can add the following to my Persistence Unit.
<property name="hibernate.transaction.jta.platform" value="JBossAS" />
This works for me.

Related

Using #Inject in a Jersey Servlet, for implementing Auth, Auth filter to pass a User object, giving UnsatisfiedDependencyException

I am following the guide: Best practice for REST token-based authentication with JAX-RS and Jersey, for implementing an Authentication and Authorization filter for my RestAPI. I am getting this one error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=User,parent=AuthorizationFilter,qualifiers={#nl.utwente.di.team26.Security.Authentication.User.AuthenticatedUser()},position=-1,optional=false,self=false,unqualified=null,1372104990)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:51)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:188)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:211)
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:334)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:463)
at org.jvnet.hk2.internal.SingletonContext$1.compute(SingletonContext.java:59)
at org.jvnet.hk2.internal.SingletonContext$1.compute(SingletonContext.java:47)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture$1.call(Cache.java:74)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture.run(Cache.java:131)
at org.glassfish.hk2.utilities.cache.Cache.compute(Cache.java:176)
at org.jvnet.hk2.internal.SingletonContext.findOrCreate(SingletonContext.java:98)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2102)
at org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:93)
at org.jvnet.hk2.internal.ServiceHandleImpl.getService(ServiceHandleImpl.java:67)
at org.glassfish.jersey.inject.hk2.AbstractHk2InjectionManager.lambda$getAllServiceHolders$0(AbstractHk2InjectionManager.java:136)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1239)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.glassfish.jersey.inject.hk2.AbstractHk2InjectionManager.getAllServiceHolders(AbstractHk2InjectionManager.java:140)
at org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager.getAllServiceHolders(ImmediateHk2InjectionManager.java:30)
at org.glassfish.jersey.internal.inject.Providers.getServiceHolders(Providers.java:299)
at org.glassfish.jersey.internal.inject.Providers.getAllRankedProviders(Providers.java:182)
at org.glassfish.jersey.server.ProcessingProvidersConfigurator.postInit(ProcessingProvidersConfigurator.java:95)
at org.glassfish.jersey.server.ApplicationHandler.lambda$initialize$2(ApplicationHandler.java:349)
at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4411)
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:349)
at org.glassfish.jersey.server.ApplicationHandler.lambda$initialize$1(ApplicationHandler.java:293)
In essence:
There is an authentication endpoint which checks the login credentials.
It issues a token/cookie as a response, and is all good, (until I implemented the injection part)
So when the makes a request the request is first inspected by this Authentication Filter:
#Secured
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Inject
#AuthenticatedUser
Event<String> userAuthenticatedEvent;
#Context
UriInfo uriInfo;
String userId;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Map<String, Cookie> cookieJar = requestContext.getCookies();
// Validate the Cookie Token
try {
if (!hasCookie(cookieJar)) {
sendToLogin(requestContext);
} else {
// Extract the token from the Cookie
String token = cookieJar.get(CONSTANTS.COOKIENAME).getValue();
try {
// Validate the token
validateToken(token);
userAuthenticatedEvent.fire(userId);
} catch (TokenObsoleteException e) {
e.printStackTrace();
sendToLogin(requestContext);
} catch (AuthenticationDeniedException e) {
e.printStackTrace();
abortWithUnauthorized(requestContext);
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
private boolean hasCookie(Map<String, Cookie> cookieJar) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return cookieJar.containsKey(CONSTANTS.COOKIENAME);
}
private void sendToLogin(ContainerRequestContext requestContext) throws URISyntaxException {
requestContext.abortWith(Response.seeOther(new URI("http://localhost:8080/apiName/")).build());
}
private void abortWithUnauthorized(ContainerRequestContext requestContext) {
// Abort the filter chain with a 401 status code response
requestContext.abortWith(
Response.status(Response.Status.UNAUTHORIZED).build());
}
private void validateToken(String token) throws AuthenticationDeniedException, TokenObsoleteException {
// Check if the token was issued by the server and if it's not expired
// Throw an Exception if the token is invalid
}
public static Claims decodeJWT(String jwt) {
}
}
This filter fires an event such that an Authenticated user can be created.
#RequestScoped
public class AuthenticatedUserProducer {
#Produces
#RequestScoped
#AuthenticatedUser
private User authenticatedUser;
UserDao userDao = new UserDao();
#RequestScoped
public void handleAuthenticationEvent(#Observes #AuthenticatedUser String userId) {
int user = Integer.parseInt(userId);
this.authenticatedUser = findUser(user);
}
private User findUser(int userId) {
User user = null;
// Hit the the database or a service to find a user by its username and return it
// Return the User instance
return user;
}
}
This should produce a User instance, under variable name AuthenticatedUser.
But, when the same code is called for checking User Roles, in the Authorization filter, the error above is shown:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=User,parent=AuthorizationFilter,qualifiers={#nl.utwente.di.team26.Security.Authentication.User.AuthenticatedUser()},position=-1,optional=false,self=false,unqualified=null,1372104990)
The Authorization Filter is:
#Secured
#Provider
#Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
#Inject
#AuthenticatedUser
User authenticatedUser; //<--This is where the error comes from.
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the resource class which matches with the requested URL
// Extract the roles declared by it
Class<?> resourceClass = resourceInfo.getResourceClass();
List<Role> classRoles = extractRoles(resourceClass);
// Get the resource method which matches with the requested URL
// Extract the roles declared by it
Method resourceMethod = resourceInfo.getResourceMethod();
List<Role> methodRoles = extractRoles(resourceMethod);
try {
// Check if the user is allowed to execute the method
// The method annotations override the class annotations
if (methodRoles.isEmpty()) {
checkPermissions(classRoles);
} else {
checkPermissions(methodRoles);
}
} catch (NotAuthorizedException e) {
requestContext.abortWith(
Response.status(Response.Status.FORBIDDEN).build());
}
}
// Extract the roles from the annotated element
private List<Role> extractRoles(AnnotatedElement annotatedElement) {
if (annotatedElement == null) {
return new ArrayList<>();
} else {
Secured secured = annotatedElement.getAnnotation(Secured.class);
if (secured == null) {
return new ArrayList<>();
} else {
Role[] allowedRoles = secured.value();
return Arrays.asList(allowedRoles);
}
}
}
private void checkPermissions(List<Role> allowedRoles) throws NotAuthorizedException {
// Check if the user contains one of the allowed roles
// Throw an Exception if the user has not permission to execute the method
if (authenticatedUser.getClarificationLevel() < allowedRoles.get(0).ordinal()) {
throw new NotAuthorizedException("You shall not pass!");
}
}
}
Some other code:
#Secured Annotation
#NameBinding
#Retention(RUNTIME)
#Target({TYPE, METHOD})
public #interface Secured {
Role[] value() default {};
}
Authenticated User Annotation
#Qualifier
#Retention(RUNTIME)
#Target({ METHOD, FIELD, PARAMETER })
public #interface AuthenticatedUser { }
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
POM
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.utwente.di.app</groupId>
<artifactId>app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.30.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.30.1</version>
</dependency>
<!-- Required only when you are using JAX-RS Client -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.30.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.29.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.12</version>
</dependency>
<!-- For the cookie things-->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0.SP1</version>
</dependency>
<!-- For the token things -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers.glassfish/jersey-gf-cdi -->
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>2.14</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
I have a beans.xml after searching a bit this was recommended, but I am not sure how it works.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
Other things I have read:
Creation of bindings (not sure how this would be implemented)
Something to do with a lot of config files.
I am not using SpringBoot or other fancy things. Only simple Jax-rs, Jersey 2.30.1 and some things regarding tokens like jwt.
By reading the error, it seems only that the injected User is not present, so the program has nothing there to inject, but if the class is present why id the DependencyUnsatisfied?
Have I defined the injection properly?
Have I defined the name bindings properly?
Have I used the right maven imports?
Can anyone help? Feel free to ask any further questions.
Thanks.

spring-data-elasticsearch es6.7.2 save child throw Exception :routing is missing for join field

pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
springboot version 2.1.6.RELEASE
elasticsearch 6.7.2
{ "type": "join", "relations": { "article": "comment" } }
when I save childEntity throw java.lang.IllegalArgumentException: [routing] is missing for join field [info]
My entity:
parent:
public class Article implements Serializable {
#Id
private String id;
private String title;
private String author;
private String content;
private Date created;
private Map<String,Object> comments;
}
child:
public class Comment implements Serializable {
#Id
private String id;
private String name;
private String content;
private Date created;
#Field(includeInParent = true)
#Mapping(mappingPath = "/mapping/mapping.json")
private Map<String, Object> comments;
}
when I user repository save child,throw Excption ,I don't konw how to do config routing perporties for my bean.
at org.elasticsearch.join.mapper.ParentJoinFieldMapper.parse(ParentJoinFieldMapper.java:426)
at org.elasticsearch.index.mapper.DocumentParser.parseObjectOrField(DocumentParser.java:488)
at org.elasticsearch.index.mapper.DocumentParser.parseObject(DocumentParser.java:505)
at org.elasticsearch.index.mapper.DocumentParser.innerParseObject(DocumentParser.java:395)
at org.elasticsearch.index.mapper.DocumentParser.parseObjectOrNested(DocumentParser.java:384)
at org.elasticsearch.index.mapper.DocumentParser.internalParseDocument(DocumentParser.java:96)
at org.elasticsearch.index.mapper.DocumentParser.parseDocument(DocumentParser.java:69)
at org.elasticsearch.index.mapper.DocumentMapper.parse(DocumentMapper.java:281)
at org.elasticsearch.index.shard.IndexShard.prepareIndex(IndexShard.java:799)
at org.elasticsearch.index.shard.IndexShard.applyIndexOperation(IndexShard.java:775)
at org.elasticsearch.index.shard.IndexShard.applyIndexOperationOnPrimary(IndexShard.java:744)
at org.elasticsearch.action.bulk.TransportShardBulkAction.lambda$executeIndexRequestOnPrimary$3(TransportShardBulkAction.java:454)
at org.elasticsearch.action.bulk.TransportShardBulkAction.executeOnPrimaryWhileHandlingMappingUpdates(TransportShardBulkAction.java:477)
at org.elasticsearch.action.bulk.TransportShardBulkAction.executeIndexRequestOnPrimary(TransportShardBulkAction.java:452)
at org.elasticsearch.action.bulk.TransportShardBulkAction.executeBulkItemRequest(TransportShardBulkAction.java:216)
at org.elasticsearch.action.bulk.TransportShardBulkAction.performOnPrimary(TransportShardBulkAction.java:159)
at org.elasticsearch.action.bulk.TransportShardBulkAction.performOnPrimary(TransportShardBulkAction.java:151)
at org.elasticsearch.action.bulk.TransportShardBulkAction.shardOperationOnPrimary(TransportShardBulkAction.java:139)
at org.elasticsearch.action.bulk.TransportShardBulkAction.shardOperationOnPrimary(TransportShardBulkAction.java:79)
at org.elasticsearch.action.support.replication.TransportReplicationAction$PrimaryShardReference.perform(TransportReplicationAction.java:1050)
at org.elasticsearch.action.support.replication.TransportReplicationAction$PrimaryShardReference.perform(TransportReplicationAction.java:1028)
at org.elasticsearch.action.support.replication.ReplicationOperation.execute(ReplicationOperation.java:104)
at org.elasticsearch.action.support.replication.TransportReplicationAction$AsyncPrimaryAction.runWithPrimaryShardReference(TransportReplicationAction.java:424)
at org.elasticsearch.action.support.replication.TransportReplicationAction$AsyncPrimaryAction.lambda$doRun$0(TransportReplicationAction.java:370)
at org.elasticsearch.action.ActionListener$1.onResponse(ActionListener.java:61)
at org.elasticsearch.index.shard.IndexShardOperationPermits.acquire(IndexShardOperationPermits.java:273)
at org.elasticsearch.index.shard.IndexShardOperationPermits.acquire(IndexShardOperationPermits.java:240)
at org.elasticsearch.index.shard.IndexShard.acquirePrimaryOperationPermit(IndexShard.java:2561)
at org.elasticsearch.action.support.replication.TransportReplicationAction.acquirePrimaryOperationPermit(TransportReplicationAction.java:987)
at org.elasticsearch.action.support.replication.TransportReplicationAction$AsyncPrimaryAction.doRun(TransportReplicationAction.java:369)
at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37)
at org.elasticsearch.action.support.replication.TransportReplicationAction$PrimaryOperationTransportHandler.messageReceived(TransportReplicationAction.java:324)
at org.elasticsearch.action.support.replication.TransportReplicationAction$PrimaryOperationTransportHandler.messageReceived(TransportReplicationAction.java:311)
at org.elasticsearch.xpack.security.transport.SecurityServerTransportInterceptor$ProfileSecuredRequestHandler$1.doRun(SecurityServerTransportInterceptor.java:250)
at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37)
at org.elasticsearch.xpack.security.transport.SecurityServerTransportInterceptor$ProfileSecuredRequestHandler.messageReceived(SecurityServerTransportInterceptor.java:308)
at org.elasticsearch.transport.RequestHandlerRegistry.processMessageReceived(RequestHandlerRegistry.java:66)
at org.elasticsearch.transport.TransportService$7.doRun(TransportService.java:692)
at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:751)
at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Unable to connect to cassandra from Docker container using spring-data-cassandra: NoHostAvailableException: All host(s) tried for query failed

I am using spring-data-cassandra to connect to our cassandra db which is in aws cluster. Using CassandraTemplate I am able to connect locally and get the data but while deploying application in docker container I am getting below error
UnsatisfiedDependencyException: Error creating bean with name 'cassandraTemplate' defined in class path resource
[org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.class]:
Unsatisfied dependency expressed through method 'cassandraTemplate' parameter 0;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'session' defined in class path resource [utils/CassandraConfig.class]:
Invocation of init method failed; nested exception is com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed
(tried: /IP:9042 (com.datastax.driver.core.TransportException: [/IP:9042] Error writing))
Here is my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mus-cassadra-read</artifactId>
<groupId>com.rogs.mus</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.rogs.mus</groupId>
<artifactId>external-endpoints</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.rogs.mus</groupId>
<artifactId>model-cassadra-read</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>1.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<!-- cassandra dependency -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
</dependencies>
</project>
CassandraConfig.java
#Configuration
#EnableCassandraRepositories(basePackages = { "org.spring.cassandra.example.repo" })
public class CassandraConfig {
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
#Value("${cassandra.hostnames}")
private String hostnames ;
#Value("${cassandra.username}")
private String username ;
#Value("${cassandra.password}")
private String password ;
#Value("${cassandra.keyspace}")
private String keyspace ;
#Value("${cassandra.isSsl}")
private boolean isSsl ;
#Value("${cassandra.port}")
private int port;
#Bean
Public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
PlainTextAuthProvider authProvider = new PlainTextAuthProvider(username, password);
cluster.setContactPoints(hostnames);
cluster.setPort(port);
cluster.setUsername(username);
cluster.setPassword(password);
return cluster;
}
#Bean
Public CassandraMappingContext mappingContext() {
return new BasicCassandraMappingContext();
}
#Bean
Public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
#Bean
Public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setKeyspaceName(keyspace);
session.setConverter(converter());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
#Bean
Public CassandraOperations cassandraTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}
Please let me know if I am doing anything wrong here.

How to add labels dynamically to nodes in Neo4j from neo4j-ogm or spring-data-neo4j?

When I create a node, I want to add multiple labels, known at run-time, to the node. Is it possible to this in neo4j-ogm or spring-data-neo4j?
This isn't supported in the current version but is on the roadmap.
Add some dependences
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
Create an Enitity with lombok accessors
#NodeEntity
#Data
public class Content{
#Id
#GeneratedValue
private Long id; //Internal Neo4j Identifier. DONT TOUCH
// Your Bns Logic identifier
private Long myId
#Properties
private Map<String, String> properties = new HashMap<>();
#Labels
private List<String> labels = new ArrayList<>();
}
A Repository for your Entity
public interface ContentRepository extends Neo4jRepository<Content, Long> {
}
A simple controller to add your labels and properties in the Node
#RestController
#RequestMapping( produces = MediaType.APPLICATION_JSON_VALUE)
public class ContentController {
#Autowired
ContentRepository contentRepository;
#ApiOperation(value = "Create a Node", notes = "create a node", response = String.class)
#ApiResponses({
#ApiResponse(code = 201, message = "Success", response = String.class)
})
#PostMapping("/api/content")
public ResponseEntity<MyDTO> createNode(#RequestBody MyDTO requestWrapper ) {
//Create Database Entity from DTO
Content content = new Content();
//Add Labels
content.getLabels().addAll(requestWrapper.getLabelList());
//Add properties
requestWrapper.getHmap().forEach((k,v)->content.getProperties().put(k,v));
try {
contentRepository.save(content);
requestWrapper.setId(content.getId());
} catch (Exception e){
//e.printStackTrace();
}
return new ResponseEntity< MyDTO >(requestWrapper, HttpStatus.CREATED);
}

Tests fail with a TransactionRequiredException: no transaction is in progress exception when loading both JPA and Neo4J configurations

I have a JPA web application with some integration tests against the JPA repositories. There are no integration tests against the Neo4J repositories yet.
Now, I have added some Neo4J functionality to this existing JPA web application.
I'm this now using Neo4J repositories, alongside JPA repositories. My entities and repositories are named differently and are sitting in different packages.
My tests all extend the following class:
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { ApplicationConfiguration.class, WebSecurityTestConfiguration.class, WebConfiguration.class })
#Transactional
public abstract class AbstractControllerTest {
...
}
The tests run fine when the application configuration does not have any
Neo4J configuration:
#Configuration
#ComponentScan(basePackages = { "it.robot.rest.config" })
#Import({ DatabaseConfiguration.class, Log4jWeb.class })
public class ApplicationConfiguration {
}
But they error on an exception when adding the Neo4J configuration:
#Configuration
#ComponentScan(basePackages = { "it.robot.rest.config" })
#Import({ DatabaseConfiguration.class, Neo4JRepositoryConfiguration.class, Log4jWeb.class })
public class ApplicationConfiguration {
}
The exception is:
javax.persistence.TransactionRequiredException: no transaction is in progress
Here is the Neo4J configuration (I tried both Neo4jConfiguration and CrossStoreNeo4jConfiguration classes and I get the same exception):
#Configuration
#EnableNeo4jRepositories(basePackages = { "it.robot.data.neo4j.repository" } )
#EnableTransactionManagement
#ComponentScan(basePackages = { "it.robot.data.neo4j.service" })
public class Neo4JRepositoryConfiguration extends Neo4jConfiguration {
public static final String URL = "http://localhost:7474/db/data/";
public static final String LOGIN = "neo4j";
public static final String PASSWORD = "mypassword";
Neo4JRepositoryConfiguration() {
setBasePackage("it.robot.data.neo4j.domain");
}
#Bean
GraphDatabaseService graphDatabaseService() {
return new SpringCypherRestGraphDatabase(URL, LOGIN, PASSWORD);
}
}
Here is the JPA configuration is:
#Configuration
#Import({ JpaService.class, Log4j.class })
#EnableTransactionManagement
#ComponentScan(basePackages = { "it.robot.data.config" })
#EnableJpaRepositories(basePackages = { "it.robot.data.jpa" }, repositoryFactoryBeanClass = it.robot.data.jpa.repository.GenericRepositoryFactoryBean.class)
public class DatabaseConfiguration {
...
}
It looks like the Neo4jConfiguration class transaction manager has the same name ("transactionManager") as the JPA transaction manager, and overrides it.
I would content myself with Neo4J using the JPA transaction manager provided by Spring but I wonder if that is possible.
Some additional information...
I'm using spring-data-neo4j and spring-data-neo4j-rest version 3.3.2.RELEASE
I'm using a server Neo4J database and not an embedded one and of course the Neo4J server is started.
I disabled the authentication on the database since it was standing in my way and my curl request didn't seem to update the password:
curl -H "Accept:application/json"
-H "Content-Type: application/json"
"http://localhost:7474/user/neo4j/password"
-X POST -d "{ \"password\" : \"myownpassword\" }"
The only user I know of doesn't seem to be too vocal:
stephane#stephane-ThinkPad-X301:~> curl -H "Accept:application/json" -H "Content-Type: application/json" "http://localhost:7474/user/neo4j"
stephane#stephane-ThinkPad-X301:~>
stephane#stephane-ThinkPad-X301:~>
I have not created any "schema/structure" in the graph and am not sure if I should do.
The Neo4J entities:
#NodeEntity
#SequenceGenerator(name = "id_generator", sequenceName = "sq_id_part")
public class Neo4JPart extends BaseEntity {
#Column(nullable = false)
private String name;
#Column(nullable = false, unique = true)
private String serialNumber;
private Integer weight;
#ManyToOne
#JoinColumn(name = "manufacturer_id", nullable = false)
private Neo4JManufacturer manufacturer;
#Fetch
#RelatedTo(type = "part", direction = Direction.BOTH)
public Set<Neo4JPart> parts;
public Neo4JPart() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public Neo4JManufacturer getManufacturer() {
return manufacturer;
}
public void setManufacturer(Neo4JManufacturer manufacturer) {
this.manufacturer = manufacturer;
}
public Set<Neo4JPart> getParts() {
return parts;
}
public void setParts(Set<Neo4JPart> parts) {
this.parts = parts;
}
public String toString() {
String results = name + "'s compatible parts include\n";
if (parts != null) {
for (Neo4JPart part : parts) {
results += "\t- " + part.name + "\n";
}
}
return results;
}
}
#MappedSuperclass
public class BaseEntity {
#GraphId
#GeneratedValue(strategy = GenerationType.AUTO, generator = "id_generator")
#Column(name = "id")
private Long id;
#Version
#Column(nullable = false)
private int version;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) {
return false;
}
BaseEntity that = (BaseEntity) obj;
return this.id.equals(that.getId());
}
#Override
public int hashCode() {
return id == null ? 0 : id.hashCode();
}
}
And the Neo4J repositories:
public interface Neo4JPartRepository extends GraphRepository<Neo4JPart> {
public Neo4JPart findByName(String name);
public Neo4JPart findBySerialNumber(String serialNumber);
public Page<Neo4JPart> findByManufacturer(#Param("manufacturer") Neo4JManufacturer manufacturer, Pageable page);
public List<Neo4JPart> findByManufacturer(#Param("manufacturer") Neo4JManufacturer manufacturer);
public Page<Neo4JPart> findByPartsName(String name, Pageable page);
}
public interface Neo4JManufacturerRepository extends GraphRepository<Neo4JManufacturer> {
Neo4JManufacturer findByName(String name);
}
The Maven dependencies are:
<org.springframework.version>4.1.2.RELEASE</org.springframework.version>
<hibernate.version>4.3.6.Final</hibernate.version>
<dependencies>
<dependency>
<groupId>com.thalasoft</groupId>
<artifactId>toolbox</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.172</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.6.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>1.10.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.lazyluke</groupId>
<artifactId>log4jdbc-remix</artifactId>
<version>0.2.7</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.jadira.usertype</groupId>
<artifactId>usertype.jodatime</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>1.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>3.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-rest</artifactId>
<version>3.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-cross-store</artifactId>
<version>3.3.2.RELEASE</version>
</dependency>
</dependencies>
I tried to upgrade to the 3.4.0 version of the newly available release on search.maven.org but the build now gives the following exception:
AnnotationFormatError: Invalid default: public abstract java.lang.Class org.springframework.data.neo4j.config.EnableNeo4jRepositories.repositoryBaseClass()
I could see nothing about that repositoryBaseClass in the reference documentation http://docs.spring.io/spring-data/neo4j/docs/3.4.0.RELEASE/reference/pdf/spring-data-neo4j-reference.pdf
The source code Javadoc only says:
Configure the repository base class to be used to create repository proxies for this particular configuration.
And that left me scratching my head wondering what is a repository proxy and if one is required in my case.
I could solve the issue with the solution provided at Implementing Spring ChainedTransactionManager according to the "best efforts 1PC" pattern with a chained transaction manager, following a tip by Simon at How do I properly set up cross-store persistence using Spring Data JPA + Neo4j?
I just had to change my Neo4j configuration. I didn't even have to touch anything in the other JPA transaction manager.
Here is my Neo4j configuration:
#EnableNeo4jRepositories(basePackages = { "it.robot.data.neo4j.repository" })
#EnableTransactionManagement
#ComponentScan(basePackages = { "it.robot.data.neo4j.service" })
public class Neo4JRepositoryConfiguration extends Neo4jConfiguration {
private static Logger logger = LoggerFactory.getLogger(Neo4JRepositoryConfiguration.class);
public static final String URL = "http://localhost:7474/db/data/";
public static final String LOGIN = "neo4j";
public static final String PASSWORD = "xxxxx";
Neo4JRepositoryConfiguration() {
setBasePackage("it.robot.data.neo4j.domain");
}
#Bean
GraphDatabaseService graphDatabaseService() {
return new SpringCypherRestGraphDatabase(URL, LOGIN, PASSWORD);
}
#Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory;
#Override
public PlatformTransactionManager neo4jTransactionManager(
GraphDatabaseService graphDatabaseService) {
return new ChainedTransactionManager(
new JpaTransactionManager(entityManagerFactory.getObject()),
new JtaTransactionManagerFactoryBean(graphDatabaseService).getObject());
}
}

Resources