Use Multiple DataSource(With CosmosDB) In Spring boot JPA - azure

I'm setting up kind of API with Spring boot, jpa.
At First, I made one CosmosDB and put all things together.
However, now I want to use multiple database one for user with MySQL & one for merchandise with CosmosDB.
How can I make proper config?
In formal case If I want to use multiple datasource in Spring boot with JPA
(For Example, Use MySQL For UserInfo & Use h2 for merchandise data
or
Use MySQL For UserInfo & Use PostgreSQL for merchandise data
or)
I set the properties & just make two Kinds of Config like this
And It works fine.
#configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"====.repository"})
public class CustomerDataSourceConfig {
#primary
#bean(name = "dataSource")
#ConfigurationProperties(prefix = "====.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#primary
#bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, #qualifier("dataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("=====.domain")
.persistenceUnit("customer")
.build();
}
#primary
#bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
#qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
But If I want to use Multiple DataSource(With CosmosDB) this kind of work doesn't work anymore.
I should make different kind of config for CosmosDB?
or
Is there any way I can use multiple datasource with CosmosDB?
(ex. Use MySQL For UserInfo & Use CosmosDB for merchandise data)
thx.

I solved this problem.
below is my github issue.
so someone want to know the answer.
plz check it.
https://github.com/microsoft/spring-data-cosmosdb/issues/403

Related

How write the Mockito Junit Test Cases for JDBC Template in Spring Boot Application?

public List<User> getAllUsers() {
String sql = "select * from user_data";
List<User> users = jdbcTemplate.query(sql, new UserRowMapper());
return users;
}
public User getAUser(int userId) {
String sql = "select * from user_data where userid=?";
User user = jdbcTemplate.queryForObject(sql, new Object[] { userId }, new UserRowMapper());
return user;
}
public User addUser(User user) {
String SQL = "INSERT INTO user_data(user_first_name,user_last_name,mobile_no,about) VALUES (?,?,?,?)";
jdbcTemplate.update(SQL, user.getFirstName(), user.getLastName(), user.getMobileNumber(), user.getAbout());
return user;
}
This is my Code. Can anyone please help me how to write Junit Mockito Test cases for that.
For SQL request's testing, you cannot write unit tests. You have to write integration tests.
Two possible strategies :
You can test with an in-memory database with tools like DbUnit (it's an old tool, I think you can find better nowadays)
You can use an integration database. In a test, you execute your code, then you read the database to verify and finally you clean your database (you can use a transaction with rollback to clean automatically your operations).
Don't hesite to ask for advice when you advance in these ways.

AutoPopulate attribute not working on AutoQuery DTO

I am trying to get the new AutoPopulate attribute to work but I am having some difficulty understanding the new AutoQuery functionality.
To test it out I am aiming to replace this service that is a standard AutoQuery endpoint but it also filters by the logged in users ID. I want to replace it so it works completely with just the model definition.
public class DevExtremeService : ServiceBase
{
public IAutoQueryDb AutoQuery { get; set; }
public QueryResponse<DeWatchedUrlResponse> Any(WatchedUrlDevExRequest request)
{
var q = AutoQuery.CreateDevXQuery(request, Request.GetRequestParams(), Request);
q.Where(x => x.UserAuthCustomId == GetUserId());
var response = AutoQuery.Execute(request, q, base.Request);
return response;
}
}
[Route("/de/watched-urls")]
public class WatchedUrlDevExRequest : QueryDb<WatchedUrlRecord, DeWatchedUrlResponse>
{
}
So I deleted the service and updated model to:
[ValidateIsAuthenticated]
[AutoPopulate(nameof(WatchedUrlDevExRequest.UserAuthCustomId), Eval = "userAuthId")]
[Route("/de/watched-urls")]
public class WatchedUrlDevExRequest : QueryDb<WatchedUrlRecord, DeWatchedUrlResponse>
{
public long UserAuthCustomId { get; set; }
}
My understanding from reading the release notes is that userAuthId is a variable declared in the AutoQuery #script context that is added by default.
I have tried a few different variations and I cannot get the property to populate. The docs seem focused on audit history and multitenancy but really I am just looking for a quick way to make endpoints.
I have 2 main questions:
Why is the auto populate not working on this property?
Where can I see the default #script definition so I can see how things like userAuthId are defined and better get an understanding how to add my own?
edit
I re-read docs and I gues this only works when writing data to db. I really like the concept of being able to apply #script to a request model via attribute. Is that possible?
AutoQuery CRUD's [AutoPopulate] attribute initially only populated AutoQuery CRUD's Data Model when performing CRUD operations, e.g. Inserting, Updating or Deleting entities.
For ensuring a query only returns a users records, it's recommended to use an AutoFilter instead, which behaves as expected ensuring the query is always applied to the Data Model, e.g:
[ValidateIsAuthenticated]
[Route("/de/watched-urls")]
[AutoFilter(QueryTerm.Ensure, nameof(WatchedUrlRecord.UserAuthCustomId),
Eval = "userAuthId")]
public class WatchedUrlDevExRequest : QueryDb<WatchedUrlRecord, DeWatchedUrlResponse>
{
}
However as I can see it's a useful feature I've also just added support for [AutoPopulate] & [AutoMap] attributes on Query DTOs in this commit where your AutoQuery DTO would work as expected where it populates the Request DTO property:
[ValidateIsAuthenticated]
[AutoPopulate(nameof(WatchedUrlDevExRequest.UserAuthCustomId), Eval = "userAuthId")]
[Route("/de/watched-urls")]
public class WatchedUrlDevExRequest : QueryDb<WatchedUrlRecord, DeWatchedUrlResponse>
{
public long UserAuthCustomId { get; set; }
}
This change is available from v5.10.3 that's now available on MyGet.
An alternative approach to populate AutoQuery's Request DTO you could have a custom AutoQuery implementation like you have, an Extensible Query Filter or custom base class or I'd personally go with a Global Request Filter that updates all Request DTOs with a shared interface, e.g:
GlobalRequestFilters.Add((req, res, dto) => {
if (dto is IHasUserAuthCustomId authDto)
{
var session = req.GetSession();
if (session.IsAuthenticated)
authDto.UserAuthCustomId = session.UserAuthId;
}
});
Or you could wrap this logic in a Request Filter Attribute and apply the behavior to Request DTOs that way.
Note: userAuthId is a ServiceStack #Script method that returns the currently authenticated User Id.

Insert data into cassandra using datastax driver

We are trying to insert data from CSV file into Cassandra using the DataStax driver for Java. What are the available methods to do so?
We are currently using running cqlsh to load from a CSV file.
The question is quite vague. Usually, you should be able to provide code, and give an example of something that isn't working quite right for you.
That being said, I just taught a class (this week) on this subject for our developers at work. So I can give you some quick examples.
First of all, you should have a separate class built to handle your Cassandra connection objects. I usually build it with a couple of constructors so that it can be called in a couple different ways. But each essentially calls a connect method, which looks something like this:
public void connect(String[] nodes, String user, String pwd, String dc) {
QueryOptions qo = new QueryOptions();
qo.setConsistencyLevel(ConsistencyLevel.LOCAL_ONE);
cluster = Cluster.builder()
.addContactPoints(nodes)
.withCredentials(user,pwd)
.withQueryOptions(qo)
.withLoadBalancingPolicy(
new TokenAwarePolicy(
DCAwareRoundRobinPolicy.builder()
.withLocalDc(dc)
.build()
)
)
.build();
session = cluster.connect();
With that in place, I also write a few simple methods to expose some functionality of the of the session object:
public ResultSet query(String strCQL) {
return session.execute(strCQL);
}
public PreparedStatement prepare(String strCQL) {
return session.prepare(strCQL);
}
public ResultSet query(BoundStatement bStatement) {
return session.execute(bStatement);
}
With those in-place, I can then call these methods from within a service layer. A simple INSERT (with preparing a statement and binding values to it) looks like this:
String[] nodes = {"10.6.8.2","10.6.6.4"};
CassandraConnection conn = new CassandraConnection(nodes, "aploetz", "flynnLives", "West-DC");
String userID = "Aaron";
String value = "whatever";
String strINSERT = "INSERT INTO stackoverflow.timestamptest "
+ "(userid, activetime, value) "
+ "VALUES (?,dateof(now()),?)";
PreparedStatement pIStatement = conn.prepare(strINSERT);
BoundStatement bIStatement = new BoundStatement(pIStatement);
bIStatement.bind(userID, value);
conn.query(bIStatement);
In addition, the DataStax Java Driver has a folder called "examples" in their Git repo. Here's a link to the "basic" examples, which I recommend reading further.

Custom Fields for IdentityUser

I am trying to add custom fields for my IdentityUser. I have been through the documentation and also several articles that I've found online. I was able to figure out how to add custom fields, but I'm not sure how to set constraints on them. None of the articles I've found have covered this topic.
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public DateTime RegistrationDate { get; set; }
public string IPAddress { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
My code example is above. I have added 2 fields. RegistrationDate and IPAddress. I've used PowerShell to create the migrations and update the database.
My questions are this:
How do I set a default value for RegistrationDate? I wanted it to be SQL Now(). I can make the change in the database after the migration, but that gets my code and database out of sync.
On IPAddress, I want to have the maximum size be 39 characters. When I update the database, the field is created as NVARCHAR(MAX) NULL. I want it to be NVARCHAR(39) NOT NULL. I can't see anyway to do that in the IdentityUser.
Lastly, what if I wanted to store the IPAddress as VARBINARY or BINARY? That's not even a data type that C# will accept.
I am able to go into the migration files and make some changes after creating the migration, but those changes are not reflected in the database. If I try to re-run Update-database from PowerShell, I get an error saying that there are no changes to update.
On top of that. I don't know if I should be manually updating the migration files, since they are generated code.
public partial class IPAddress : DbMigration
{
public override void Up()
{
AddColumn("dbo.AspNetUsers", "IPAddress", c => c.String(nullable: false, maxLength: 39));
}
public override void Down()
{
DropColumn("dbo.AspNetUsers", "IPAddress");
}
}
I'm using Visual Studio 2015 and version 4.6.
Thanks
1) To have a default date on your RegistrationDate you need to create a default constructor of ApplicationUser that sets your date to be whatever you need:
public ApplicationUser()
{
RegistrationDate = DateTime.Now();
}
2) To change the size of the field you need to apply [MaxLength(39)] attribute on your IPAddress field:
[MaxLength(39)]
public string IPAddress { get; set; }
3) To get BINARY you need to use byte[] type in C#. (ref: https://stackoverflow.com/a/1158670/809357)
4) You should not change the scripts for migrations manually - migrations contain XML snapshot of the database and keeps that snapshot in the __MigrationsHistory table. So if you change the migration script, the snapshot will not be re-generated and EF won't pick up your changes.
When you change your data model you either create a new migration via add-migration NewMigrationName or rollback your DB to a previous migration state via update-database -Target PreviousMigrationName and then re-generate existing migration via add-migration ExistingMigrationName -Force and then do Update-database

Spring Data REST - content & actions based on user & role

Spring Data REST exposes data and actions through the methods defined in respositories. This is all good and dandy. However we have a use case where in we need to control the contents and actions(HTTP methods) that could be invoked based on the user and roles. Any pointers on how to approach this?
Adding security to REST API could be done using Oauth2.
There is an example in the Spring Data Github.
Please look at https://github.com/spring-projects/spring-data-examples/tree/master/rest/security.
In adition to the #JR Utily correct's answer which secures at Spring Security Configuration level, another option is to use the Spring DATA Rest Event Handlers which allows adding more operations like the following example.
Just define and annotated Handler with PrePost Spring's security annotations in the annotated
#Component
#RepositoryEventHandler(Item.class)
public class ItemEventHandler {
private Logger logger = LoggerFactory.getLogger(ItemEventHandler.class);
#HandleBeforeCreate
#Preauthorize("hasRole('ROLE_ADMIN') or hasAuthority('ACTION_CREATE_ITEM')")
public void handleItemBeforeCreate(Item item) {
//POST operation available for ADMINs and Users with ACTION_CREATE_ITEM privilege
logger.info("Creating item: " + item.toString());
//more stuff if neccessary
}
#HandleBeforeSave
#Preauthorize("hasRole('ROLE_ADMIN') or hasAuthority('ACTION_UPDATE_ITEM')")
public void handleItemBeforeSave(Item item) {
//PUT operation available for ADMINs and Users with ACTION_UPDATE_ITEM privilege
logger.info("Updating item: " + item.toString());
//more stuff if neccessary
}
#HandleBeforeDelete
#Preauthorize("hasRole('ROLE_ADMIN') or hasAuthority('ACTION_DELETE_ITEM')")
public void handleItemBeforeDelete(Item item) {
//DELETE operation available for ADMINs and Users with ACTION_DELETE_ITEM privilege
logger.info("Deleting item: " + item.toString());
//more stuff if neccessary
}
}
This is the full list of Spring DATA Rest event handlers:
BeforeCreateEvent
AfterCreateEvent
BeforeSaveEvent
AfterSaveEvent
BeforeSaveEvent
BeforeLinkSaveEvent
AfterLinkSaveEvent
BeforeDeleteEvent
AfterDeleteEvent
More information found in Spring DATA Rest Reference for event handling

Resources