How to create a set of user defined types using spring data cassandra? - spring-boot

I am using Spring Data Cassandra 1.5.8.RELEASE to connect with my cassandra db 3.11.2.
I tried creating #Table pojo with a Set as a column field but it is throwing the following errors:
user defined type not found, and
some other cassandra mapping exceptions.
Can somebody help me in data modeling an 'Employee' table having a column that represents a set of Department UDTs? (Using spring boot, spring data cassandra 1.5.8+ and Apache cassandra 3.11.2+)

Firstly, my main problem was with CassandraConfig.java, where I was un-necessarily overriding certain methods, where as the default implementation itself was more than enough.
Here, I am posting my complete solution for the benefit of those who are trying this use-case for the very first time.
Project Folder Structure:
Step 1: Creating cassandra data models:
CREATE KEYSPACE cassandra_sample
WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 3};
CREATE TYPE dept_details (
dept_name text,
dept_address text
);
CREATE TABLE emp_details (
emp_id int PRIMARY KEY,
emp_name text,
emp_designation text,
dept_info set<frozen<dept_details>>
);
Step 2: pom.xml
<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>com.cassandra.sample</groupId>
<artifactId>spring-data-cassandra-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringDataCassandraSample</name>
<description>SpringDataCassandraSample</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
</project>
Step 3: Application.java
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Step 4: application.properties
# ===============================
# == DATA SOURCE
# ===============================
spring.data.cassandra.keyspace-name=cassandra_sample
spring.data.cassandra.contact-points=localhost
spring.data.cassandra.port=9042
spring.data.cassandra.schema-action=create_if_not_exists
Step 5: CassandraConfig.java
package com.cassandra.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
/**
* Created by jt on 10/6/17.
*/
#Configuration
public class CassandraConfig extends AbstractCassandraConfiguration {
#Value("${spring.data.cassandra.keyspace-name}")
private String keyspaceName;
#Override
protected String getKeyspaceName() {
return keyspaceName;
}
}
Step 6: Department.java
package com.cassandra.sample.domain;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.UserDefinedType;
#UserDefinedType("dept_details")
public class Department {
#Column("dept_name")
private String departmentName;
#Column("dept_address")
private String departmentAddress;
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public String getDepartmentAddress() {
return departmentAddress;
}
public void setDepartmentAddress(String departmentAddress) {
this.departmentAddress = departmentAddress;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((departmentAddress == null) ? 0 : departmentAddress.hashCode());
result = prime * result + ((departmentName == null) ? 0 : departmentName.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Department other = (Department) obj;
if (departmentAddress == null) {
if (other.departmentAddress != null)
return false;
} else if (!departmentAddress.equals(other.departmentAddress))
return false;
if (departmentName == null) {
if (other.departmentName != null)
return false;
} else if (!departmentName.equals(other.departmentName))
return false;
return true;
}
}
Step 7: Employee.java
package com.cassandra.sample.domain;
import java.util.Set;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
#Table("emp_details")
public class Employee {
#PrimaryKey("emp_id")
private int employeeId;
#Column("emp_name")
private String employeeName;
#Column("emp_designation")
private String designation;
#Column("dept_info")
private Set<Department> departmentDetails;
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
public Set<Department> getDepartmentDetails() {
return departmentDetails;
}
public void setDepartmentDetails(Set<Department> departmentDetails) {
this.departmentDetails = departmentDetails;
}
}
Step 8: EmployeeRepository.java
package com.cassandra.sample.repository;
import org.springframework.data.cassandra.repository.CassandraRepository;
import com.cassandra.sample.domain.Employee;
public interface EmployeeRepository extends CassandraRepository<Employee> {
Employee findByEmployeeId(int employeeId);
void deleteByEmployeeId(Integer employeeId, Class<Employee> employee) ;
}
Step 9: EmployeeRepositoryTest.java
package com.cassandra.sample.repository;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.cassandra.sample.domain.Department;
import com.cassandra.sample.domain.Employee;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
// Note: Comment or UnComment the test methods as per the db-operation you are performing
/*#Test
public void insertEmployee(){
Employee employee = prepareEmployee();
employeeRepository.save(employee);
}*/
#Test
public void retrieveEmployee(){
Iterable<Employee> employees=employeeRepository.findAll();
for(Employee emp:employees){
System.out.println("Employee name :"+emp.getEmployeeName());
Set<Department> departments=emp.getDepartmentDetails();
for(Department dept:departments){
System.out.println("Department Name :"+dept.getDepartmentName());
}
}
}
/*#Test
public void updateEmployee(){
Employee employee=employeeRepository.findByEmployeeId(421);
employee.setEmployeeName("Test Employee Updated");
employee.setDesignation("SSE");
Set<Department> departments=employee.getDepartmentDetails();
Department department1=new Department();
department1.setDepartmentName("Civil");
department1.setDepartmentAddress("Test Dept Addr 3");
departments.add(department1);
employee.setDepartmentDetails(departments);
employeeRepository.save(employee);
}*/
/*#Test
public void deleteEmployee(){
employeeRepository.delete(employeeRepository.findByEmployeeId(421));
}*/
private Employee prepareEmployee() {
Set<Department> departments = prepareDepartments();
Employee employee=new Employee();
employee.setEmployeeId(421);
employee.setEmployeeName("Test Employee");
employee.setDesignation("Tech Lead");
employee.setDepartmentDetails(departments);
return employee;
}
private Set<Department> prepareDepartments() {
Set<Department> departments=new HashSet<>();
Department department1=new Department();
department1.setDepartmentName("EEE");
department1.setDepartmentAddress("Test Dept Addr 1");
departments.add(department1);
Department department2=new Department();
department2.setDepartmentName("CSE");
department2.setDepartmentAddress("Test Dept Addr 2");
departments.add(department2);
return departments;
}
}

Related

Java Spring Boot Entites not saving to JpaRepository

That's my first project with Spring Boot implemented. I tried going step by step with official Spring tutorial but I'm stuck with a problem that I can't find any answer about.
Whenever I try to call findAll() or find() method on my repository it returns empty array [].
Even with manual preloading enitites like done in tutorial and immediately trying to display database content I get the same result.
I can guess I'm missing something silly, but I can't figure it out for some hours now. What's the cause? Tomcat/jpa/spring version mismatch? Missing annotation somewhere?
Here's my AnimalRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface AnimalRepository extends JpaRepository<Animal, Long> {
}
LoadDatabase.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.Transactional;
#Configuration
class LoadDatabase {
private static final Logger log = LoggerFactory.getLogger(LoadDatabase.class);
#Bean
CommandLineRunner initDatabase(AnimalRepository repository) {
return args -> {
log.info("Preloading " + repository.save(new Lion("Bilbo")));
log.info("Preloading " + repository.save(new Lion("Frodo")));
log.info(repository.findAll().toString()); //try to log content to console
};
}
}
The logging above basically ends up with this console output:
logging result
Probably not as important, but AnimalController.java
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
public class AnimalController {
private final AnimalRepository repository;
AnimalController(AnimalRepository repository) {
this.repository = repository;
}
#GetMapping("/animals")
List<Animal> all() {
repository.save(new Lion("Bilbo")); //this doesn't work either
return repository.findAll();
}
#PostMapping("/animals")
Animal newAnimal(#RequestBody Animal newAnimal) {
return repository.save(newAnimal);
}
#GetMapping("/animals/{id}")
Animal one(#PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new AnimalNotFoundException(id));
}
#PutMapping("/animals/{id}")
Animal replaceAnimal(#RequestBody Animal newAnimal, #PathVariable Long id) {
return repository.findById(id)
.map(animal -> {
animal.setName(newAnimal.getName());
animal.setSpecies(newAnimal.getSpecies());
return repository.save(animal);
})
.orElseGet(() -> {
newAnimal.setId(id);
return repository.save(newAnimal);
});
}
#DeleteMapping("/animals/{id}")
void deleteAnimal(#PathVariable Long id) {
repository.deleteById(id);
}
}
And the finally Lion.java
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import java.util.Objects;
#Entity
public class Lion implements Animal {
private #Id
#GeneratedValue Long id;
private String name;
private String species;
private int requiredFood;
//private Zone zone;
public Lion(String name) {
this.name = name;
this.species = this.getClass().getSimpleName();
this.requiredFood = LION_REQUIRED_FOOD;
}
public Lion() {
}
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
#Override
public String getSpecies() {
return species;
}
#Override
public void setSpecies(String species) {
this.species = species;
}
#Override
public int getRequiredFood() {
return requiredFood;
}
#Override
public void setRequiredFood(int requiredFood) {
this.requiredFood = requiredFood;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Animal animal))
return false;
return Objects.equals(this.id, animal.getId()) && Objects.equals(this.name, animal.getName())
&& Objects.equals(this.species, animal.getSpecies());
}
#Override
public int hashCode() {
return Objects.hash(this.id, this.name, this.species);
}
#Override
public String toString() {
return "Animal{" + "id=" + this.id + ", name='" + this.name + '\'' + ", species='" + this.species + '\'' + '}';
}
}
I tried switching JpaRepository to CrudRepository, but that didn't work out.
I think the problem here is that your data haven't been saved to the database, because of the transaction. try to change your repository.save() to repository.saveAndFlush()

Spring Data for Mongo DB does not throw DuplicateKeyException

I try to throw a DuplicateKeyException in a jUnit 5 Test. The unit test saves two objects to a repository with the same productId. productID is declared #Indexed( unique = true ) in the ProductEntity class. My expectation was to receive a DuplicateKeyException.
This is the test class:
package com.exercim.microservices.core.product;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.exercim.microservices.core.product.persistence.ProductEntity;
import com.exercim.microservices.core.product.persistence.ProductRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.dao.DuplicateKeyException;
#DataMongoTest
public class ProductRepositoryTest {
#Autowired
ProductRepository repository ;
#Test
public void testDuplicateKeyException() {
ProductEntity e1 = new ProductEntity( 1, "name", 1 ) ;
ProductEntity e2 = new ProductEntity( 1, "name", 1 ) ;
repository.deleteAll() ;
repository.save( e1 ) ;
assertThrows(DuplicateKeyException.class, () -> repository.save( e2 ) ) ;
}
}
This is the ProductEntitiy class:
package com.exercim.microservices.core.product.persistence;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
#Document( collection = "products" )
public class ProductEntity {
#Id
private String id ;
#Version
private Integer version ;
#Indexed( unique = true )
private int productId ;
private String name ;
private Integer weight ;
public ProductEntity() {
}
public ProductEntity( int productId, String name, int weight) {
this.productId = productId;
this.name = name;
this.weight = weight;
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
public int getProductId() {
return this.productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getWeight() {
return this.weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
The repository is an interface which extends PagingAndSortingRepository
This is part of my build.gradle file:
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-mongodb'
testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'
The test fails with the message:
org.opentest4j.AssertionFailedError: Expected org.springframework.dao.DuplicateKeyException to be thrown, but nothing was thrown.
at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:71)
Does anyone have an idea? Thanks in advance!
Thanks Joe!
The problem was, that auto index creation was not enabled. This was my original application.yml file:
spring.data.mongodb:
host: localhost
port: 27017
database: product-db
I added the following line:
auto-index-creation: true
That solved the issue.

Not able to save data in cosmos db through spring boot micro service

i'm trying to save entity in cosmos db through spring boot micro service. I'm not getting any error, only 1 warning '[osEventLoop-6-1] c.a.d.c.i.d.rntbd.RntbdRequestManager : ChannelHandlerContext(RntbdRequestManager#0, [id: 0x999bfbac, L:0.0.0.0/0.0.0.0:56979 ! R:cdb-ms-prod-*****-****.documents.azure.com/********]) channelUnregistered exceptionally'
but data is not getting saved in cosmos db. i'm using reactivecosmosrepository.
here is my pom.xml
<properties>
<java.version>1.8</java.version>
<azure.version>2.2.0</azure.version>
</properties>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-cosmosdb-spring-boot-starter</artifactId>
<version>${azure.version}</version>
</dependency>
my entity
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.Document;
#Document(collection = "dashboardsnapshot")
public class DashboardSnapshot {
private String id;
private String clientId;
private String snapshotJSON;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getSnapshotJSON() {
return snapshotJSON;
}
public void setSnapshotJSON(String snapshotJSON) {
this.snapshotJSON = snapshotJSON;
}
#Override
public String toString() {
return "DashboardSnapshot [id=" + id + ", clientId=" + clientId + ", snapshotJSON=" + snapshotJSON + "]";
}
}
my repository
import org.springframework.stereotype.Repository;
import com.ka.concept.dashboardconfig.entity.DashboardSnapshot;
import com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository;
import reactor.core.publisher.Flux;
#Repository
public interface SnapshotDao extends ReactiveCosmosRepository<DashboardSnapshot, String>{
Flux<DashboardSnapshot> findbyClientId(String ClientId);
}
my service
#Service
public class SnapshotServiceImpl implements SnapshotService{
#Autowired
public SnapshotDao snapshotdao;
#Override
public boolean saveSnapshotConfig(DashboardSnapshot snapshotJSON) {
// TODO Auto-generated method stub
snapshotdao.save(snapshotJSON);
return true;
}
}
#AksYou should call subscribe(). The publisher does not do anything till some one subscribes.
snapshotdao.save(snapshotJSON).subscribe();

Repository save() is not working

I am currently playing around with spring-data-neo4j and have a really weird behaviour around persisting data.
I read the Getting Started guide and looked through the Good Relationships: The Spring Data Neo4j Guide Book. Loading existing nodes works, after getting rid of smaller issues and imperfections (like using spring-ogm 1.1.4 to get rid of the neo4j-server dependency).
Let's have a look on my code...
This is entity:
package sdn.test.model;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
#NodeEntity
public class TestUser {
#GraphId
private Long id;
private String username;
private String password;
public TestUser() {
}
public TestUser(Long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TestUser testUser = (TestUser) o;
if (getId() != null ? !getId().equals(testUser.getId()) : testUser.getId() != null) return false;
if (getUsername() != null ? !getUsername().equals(testUser.getUsername()) : testUser.getUsername() != null)
return false;
return getPassword() != null ? getPassword().equals(testUser.getPassword()) : testUser.getPassword() == null;
}
#Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getUsername() != null ? getUsername().hashCode() : 0);
result = 31 * result + (getPassword() != null ? getPassword().hashCode() : 0);
return result;
}
#Override
public String toString() {
return "TestUser{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
"}";
}
}
And this is my repository:
package sdn.test.repository;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import sdn.test.model.TestUser;
#Repository
public interface UserRepository extends GraphRepository<TestUser> {
#Query("MATCH (user:TestUser{username: {username}, password: {password}}) RETURN user")
TestUser findByUsernameAndPassword(#Param("username") String username, #Param("password") String password);
}
Here is the neo4j configuration:
package sdn.test.config;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.server.Neo4jServer;
import org.springframework.data.neo4j.server.RemoteServer;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableNeo4jRepositories("sdn.test.repository")
#EnableTransactionManagement
public class Neo4jConfig extends Neo4jConfiguration {
#Bean
#Override
public Neo4jServer neo4jServer() {
return new RemoteServer("http://localhost:7474", "neo4j", "test");
}
#Bean
#Override
public SessionFactory getSessionFactory() {
return new SessionFactory("sdn.test.model");
}
}
Everything together lives in a simple Spring Boot application and I try to do the entity creation in this test class:
package sdn.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import sdn.test.config.Neo4jConfig;
import sdn.test.model.TestUser;
import sdn.test.repository.UserRepository;
import java.util.Date;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {
Neo4jConfig.class})
public class SimpleNeo4jTests {
#Autowired
private UserRepository userRepository;
#Test
public void createNewUser() {
long timeOffset = (new Date()).getTime();
String username = "test" + timeOffset;
String password = "password#" + timeOffset;
TestUser newUser = new TestUser(timeOffset, username, password);
userRepository.save(newUser);
// Try to load the user
TestUser actualUser = userRepository.findByUsernameAndPassword(username, password);
assertThat(actualUser, equalTo(newUser));
}
}
Last but not least, 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">
<modelVersion>4.0.0</modelVersion>
<groupId>net.h0lg.test</groupId>
<artifactId>simple-sdn4-test</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
There is no error thrown when I call userRepository.save() and checking the "remote" server confirms the red test result.
Explicitly giving the label name with #GraphEntity(label = "TestUser") doesn't help. Using transactions explicitly didn't help either.
Any ideas and hints are highly appreciated.
Looks like you're setting the #GraphId of your TestUser node entity via the test:
TestUser newUser = new TestUser(timeOffset, username, password);
public TestUser(Long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
Application code should never assign a value to the #GraphId. Could you remove that and see if it helps?

Apache cxf basic authentication

I have a running example of apache cxf but when I run this wsdl file provided by my code is not authenticated I don't know how to pass the username and password to soapui
The code is:
ORDER.JAVA
package demo.order;
public class Order {
private String customerID;
private String itemID;
private int qty;
private double price;
// Constructor
public Order() {
}
public String getCustomerID() {
return customerID;
}
public void setCustomerID(String customerID) {
this.customerID = customerID;
}
public String getItemID() {
return itemID;
}
public void setItemID(String itemID) {
this.itemID = itemID;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
package demo.order;
import javax.jws.WebService;
#WebService
public interface OrderProcess {
String processOrder(Order order);
}
package demo.order;
import javax.jws.WebService;
#org.apache.cxf.interceptor.InInterceptors (interceptors = {"demo.order.server.OrderProcessUserCredentialInterceptor" })
#WebService
public class OrderProcessImpl implements OrderProcess {
public String processOrder(Order order) {
System.out.println("Processing order...");
String orderID = validate(order);
return orderID;
}
/**
* Validates the order and returns the order ID
**/
private String validate(Order order) {
String custID = order.getCustomerID();
String itemID = order.getItemID();
int qty = order.getQty();
double price = order.getPrice();
if (custID != null && itemID != null && qty > 0 && price > 0.0) {
return "ORD1234";
}
return null;
}
}
_______________
package demo.order.client;
import demo.order.OrderProcess;
import demo.order.Order;
import org.apache.cxf.frontend.ClientProxy;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Client {
public Client() {
}
public static void main(String args[]) throws Exception {
ClassPathXmlApplicationContext context
= new ClassPathXmlApplicationContext(new String[] {"demo/order/client/client-beans.xml"});
OrderProcess client = (OrderProcess) context.getBean("orderClient");
OrderProcessClientHandler clientInterceptor = new OrderProcessClientHandler();
clientInterceptor.setUserName("John");
clientInterceptor.setPassword("password");
org.apache.cxf.endpoint.Client cxfClient = ClientProxy.getClient(client);
cxfClient.getOutInterceptors().add(clientInterceptor);
Order order = new Order();
order.setCustomerID("C001");
order.setItemID("I001");
order.setQty(100);
order.setPrice(200.00);
String orderID = client.processOrder(order);
String message = (orderID == null) ? "Order not approved" : "Order approved; order ID is " + orderID;
System.out.println(message);
}
}
_____________________
package demo.order.client;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class OrderProcessClientHandler extends AbstractSoapInterceptor {
public String userName;
public String password;
public OrderProcessClientHandler() {
super(Phase.WRITE);
addAfter(SoapPreProtocolOutInterceptor.class.getName());
}
public void handleMessage(SoapMessage message) throws Fault {
System.out.println("OrderProcessClientHandler handleMessage invoked");
DocumentBuilder builder = null;
try {
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
Document doc = builder.newDocument();
Element elementCredentials = doc.createElement("OrderCredentials");
Element elementUser = doc.createElement("username");
elementUser.setTextContent(getUserName());
Element elementPassword = doc.createElement("password");
elementPassword.setTextContent(getPassword());
elementCredentials.appendChild(elementUser);
elementCredentials.appendChild(elementPassword);
// Create Header object
QName qnameCredentials = new QName("OrderCredentials");
Header header = new Header(qnameCredentials, elementCredentials);
message.getHeaders().add(header);
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
_________________________
CLIENTBEAN.XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client id="orderClient" serviceClass="demo.order.OrderProcess" address="http://localhost:8080/OrderProcess" />
</beans>
_______________________
package demo.order.server;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import demo.order.OrderProcess;
import demo.order.OrderProcessImpl;
public class OrderProcessServerStart {
public static void main(String[] args) throws Exception {
OrderProcess orderProcess = new OrderProcessImpl();
JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();
server.setServiceBean(orderProcess);
server.setAddress("http://localhost:8787/OrderProcess");
server.create();
System.out.println("Server ready....");
Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting");
System.exit(0);
}
}
___________________________
package demo.order.server;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class OrderProcessUserCredentialInterceptor extends AbstractSoapInterceptor {
private String userName;
private String password;
public OrderProcessUserCredentialInterceptor() {
super(Phase.PRE_INVOKE);
}
public void handleMessage(SoapMessage message) throws Fault {
System.out.println("OrderProcessUserCredentialInterceptor handleMessage invoked");
QName qnameCredentials = new QName("OrderCredentials");
// Get header based on QNAME
if (message.hasHeader(qnameCredentials )) {
Header header = message.getHeader(qnameCredentials);
Element elementOrderCredential= (Element) header.getObject();
Node nodeUser = elementOrderCredential.getFirstChild();
Node nodePassword = elementOrderCredential.getLastChild();
if (nodeUser != null) {
userName = nodeUser.getTextContent();
}
if (nodePassword != null) {
password = nodePassword.getTextContent();
}
}
System.out.println("userName retrieved from SOAP Header is " + userName);
System.out.println("password retrieved from SOAP Header is " + password);
// Perform dummy validation for John
if ("John".equalsIgnoreCase(userName) && "password".equalsIgnoreCase(password)) {
System.out.println("Authentication successful for John");
} else {
throw new RuntimeException("Invalid user or password");
}
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
_______________
I have these files and the program compile succesfully and creting the wsdl file
but its not working on soapui means username and password are null when requsting through soapui,
please suggest me how to overcome this problem of basic authentication
and how to pass the usename and password to soap ui
For Basic authentication in SOAP UI, navigate to your Request, single click on it will display a panel in the left bottom corner. Your config for BASIC Authentication should be something like this:
Add your username and password to the appropriate fields.
For your client I see you are using Spring. So jaxws:client provides username and password attributes for authentication. You can add them like this:
<jaxws:client id="orderClient"
serviceClass="demo.order.OrderProcess"
address="http://localhost:8080/OrderProcess"
username="yourUsername"
password="yourPassword"/>

Resources