H2 not creating/updating table in my Spring Boot app. Something's wrong with my Entity?
Asked Answered
B

12

22

I want to keep some data in H2 database by making a CRUD repository, using Hibernate.

I can't get the database to store my entries whatsoever. Currently, I'm trying to achieve that during updating the db by making a sample entry. Entry is looking good in the logs, but table is not created/updated/generated.

Why Hibernate is not unable to create a table in this case? (if the problem lies in structure of my data)

Here's my Entity, Game.java class (I've tried without @Column annotations, no difference. Id is not auto-generated, I need to be able to enter my own ID everytime):

@Entity
@Table(name = "GAME")
public class Game {

    @Id
    @Column (name = "ID")
    private long id;

    @Column (name = "NAME")
    private String name;

    @Column(name = "STORYLINE", length = 4000)
    private String storyline;

    @Column(name = "AGGREGATED_RATING")
    @JsonProperty("aggregated_rating")
    private double aggregatedRating;

    @Column(name = "FIRST_RELEASE_DATE")
    @JsonProperty("first_release_date")
    private long firstReleaseDate;

    @Embedded
    private Cover cover;

    public Game(){

    }

    public Game(long id, String name, String storyline, double aggregatedRating, long firstReleaseDate, Cover cover) {
        this.id = id;
        this.name = name;
        this.storyline = storyline;
        this.aggregatedRating = aggregatedRating;
        this.firstReleaseDate = firstReleaseDate;
        this.cover = cover;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getStoryline() {
        return storyline;
    }

    public double getAggregatedRating() {
        return aggregatedRating;
    }

    public long getFirstReleaseDate() {
        return firstReleaseDate;
    }

    public Cover getCover() {
        return cover;
    }


}

And here's Cover.java class:

@Embeddable
public class Cover {

    @Column (name = "URL")
    private String url;
    @JsonProperty("cloudinary_id")
    @Column (name = "CLOUDINARY_ID")
    private String cloudinaryId;
    @Column (name = "WIDTH")
    private Integer width;
    @Column (name = "HEIGHT")
    private Integer height;

    public Cover(){
    }

    public Cover(String url, String cloudinaryId, Integer width, Integer height) {
        this.url = url;
        this.cloudinaryId = cloudinaryId;
        this.width = width;
        this.height = height;
}

    public String getUrl() {
        return url;
    }

    public String getCloudinaryId() {
        return cloudinaryId;
    }

    public Integer getWidth() {
        return width;
    }

    public Integer getHeight() {
        return height;
    }

}

I configured H2 database here, in application.properties file:

spring.h2.console.enabled=true
spring.h2.console.path=/h2_console
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Repository is configured like this:

import org.springframework.data.repository.CrudRepository;

import java.util.List;

public interface GameRepository extends CrudRepository<Game, Long> {
    List<Game> findAllByName(String name);
}

I test my repository by going under localhost:8080/test, where a sample entry should be inserted into table:

@RequestMapping("/test")
public String saveSth(){
    gameRepository.save(new Game(127, "Assassin's Creed II", "The lineage continues as this new chapter introduces Ezio, inheritor of the talents and creed of the Assassins. His family murdered by rival families, Ezio resolves to learn the ancient art of the Assassin in order to seek revenge. He will not do so alone though, allying with historical figures such as philosopher and writer Niccolò Machiavelli. You will also be able to master the art of the assassin with all new weapons and instruments created by the renowned inventor and genius of the Renaissance, Leonardo Da Vinci himself.", 90.25, 1258416000000L, new Cover("//images.igdb.com/igdb/image/upload/t_thumb/doczeiofd1ckpapdhqs7.jpg", "doczeiofd1ckpapdhqs7", 1000, 1426)));
    return "success";
}

I get the following log:

2017-07-25 13:09:58.873 DEBUG 9442 --- [nio-8080-exec-1] org.hibernate.SQL                        : select game0_.id as id1_0_0_, game0_.aggregated_rating as aggregat2_0_0_, game0_.cloudinary_id as cloudina3_0_0_, game0_.height as height4_0_0_, game0_.url as url5_0_0_, game0_.width as width6_0_0_, game0_.first_release_date as first_re7_0_0_, game0_.name as name8_0_0_, game0_.storyline as storylin9_0_0_ from game game0_ where game0_.id=?
Hibernate: select game0_.id as id1_0_0_, game0_.aggregated_rating as aggregat2_0_0_, game0_.cloudinary_id as cloudina3_0_0_, game0_.height as height4_0_0_, game0_.url as url5_0_0_, game0_.width as width6_0_0_, game0_.first_release_date as first_re7_0_0_, game0_.name as name8_0_0_, game0_.storyline as storylin9_0_0_ from game game0_ where game0_.id=?
2017-07-25 13:09:58.875 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [127]
2017-07-25 13:09:58.894 DEBUG 9442 --- [nio-8080-exec-1] org.hibernate.SQL                        : insert into game (aggregated_rating, cloudinary_id, height, url, width, first_release_date, name, storyline, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into game (aggregated_rating, cloudinary_id, height, url, width, first_release_date, name, storyline, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
2017-07-25 13:09:58.895 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [DOUBLE] - [90.25]
2017-07-25 13:09:58.896 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [doczeiofd1ckpapdhqs7]
2017-07-25 13:09:58.896 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [INTEGER] - [1426]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [VARCHAR] - [//images.igdb.com/igdb/image/upload/t_thumb/doczeiofd1ckpapdhqs7.jpg]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [5] as [INTEGER] - [1000]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [6] as [BIGINT] - [1258416000000]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [7] as [VARCHAR] - [Assassin's Creed II]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [8] as [VARCHAR] - [The lineage continues as this new chapter introduces Ezio, inheritor of the talents and creed of the Assassins. His family murdered by rival families, Ezio resolves to learn the ancient art of the Assassin in order to seek revenge. He will not do so alone though, allying with historical figures such as philosopher and writer Niccolò Machiavelli. You will also be able to master the art of the assassin with all new weapons and instruments created by the renowned inventor and genius of the Renaissance, Leonardo Da Vinci himself.]
2017-07-25 13:09:58.897 TRACE 9442 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [9] as [BIGINT] - [127]

It looks like data is binded to parameters, but in H2 console SELECT * FROM GAME returns me: SELECT * FROM GAME; Table "GAME" not found; SQL statement: SELECT * FROM GAME [42102-193] 42S02/42102 (Help)

I've tried other H2 modes such as create-drop or create, but no success. What worries me is that, I can't even get the database to create an empty table with the correct rows, ready for entries.

I think that something's wrong either with my Entity or missing from my GameRepository configuration, but I have no more ideas to fix this error.

I want to achieve what's here: http://javasampleapproach.com/spring-framework/spring-boot/integrate-h2-database-springboot-spring-jpa-embedded-mode And here: http://www.simplecodestuffs.com/value-object-entity-object-in-hibernate-mapping/

Also, I've tried this set of tutorials for a change: https://springframework.guru/using-the-h2-database-console-in-spring-boot-with-spring-security/ https://springframework.guru/spring-boot-web-application-part-3-spring-data-jpa/

But no luck so far.

Bullyboy answered 25/7, 2017 at 11:37 Comment(9)
select * from game returns nothing means there is no data, not there is not tableBumgardner
how is there no data if the parameters are binded? the table isn't there because Hibernate refuses to create it, since something's not right in the data.Bullyboy
can you share your package structure?Bumgardner
sure: i.imgur.com/3hMQEUT.pngBullyboy
Add dialect property and use create not update. I know update should create the table but at least give a tryLibbylibeccio
like that? spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto = createBullyboy
didn't make a difference, ehBullyboy
Found this while looking at something similiar - not sure if this was resolved but I had problems setting the database name and couldn't see the tables, but if I looked in testdb for the in-memory database, I found my tables and data.Misread
it was resolved, thanks to the answer and comments below my postBullyboy
L
22

It looks like data is binded to parameters, but in H2 console SELECT * FROM GAME returns me nothing. The table doesn't exist.

You are using an in-memory instance of H2 :

spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

In this mode, you cannot see the content of the changes from another client that which one that started the in-memory database.
To see the changes from other clients, you have to use the TCP mode.

You have two solutions :

  • using a file to persist the instance of H2.

Where are the Database Files Stored?

When using database URLs like jdbc:h2:~/test, the database is stored in the user directory. For Windows, this is usually C:\Documents and Settings\ or C:\Users\. If the base directory is not set (as in jdbc:h2:./test), the database files are stored in the directory where the application is started (the current working directory). When using the H2 Console application from the start menu, this is /bin. The base directory can be set in the database URL. A fixed or relative path can be used. When using the URL jdbc:h2:file:./data/sample, the database is stored in the directory data (relative to the current working directory). The directory is created automatically if it does not yet exist. It is also possible to use the fully qualified directory name (and for Windows, drive name). Example: jdbc:h2:file:C:/data/test

  • keeping to use an in-memory instance but using the TCP mode.

Replace :

spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

by :

spring.datasource.url=jdbc:h2:tcp://localhost/~/test

Generally, I switch to this mode during JPA entity unit testing when I really want to know which was inserted in the database.

From the official documentation :

In-Memory Databases

For certain use cases (for example: rapid prototyping, testing, high performance operations, read-only databases), it may not be required to persist data, or persist changes to the data. This database supports the in-memory mode, where the data is not persisted. ...

In some cases, only one connection to a in-memory database is required. This means the database to be opened is private. In this case, the database URL is jdbc:h2:mem: Opening two connections within the same virtual machine means opening two different (private) databases.

Sometimes multiple connections to the same in-memory database are required. In this case, the database URL must include a name. Example: jdbc:h2:mem:db1. Accessing the same database using this URL only works within the same virtual machine and class loader environment.

To access an in-memory database from another process or from another computer, you need to start a TCP server in the same process as the in-memory database was created. The other processes then need to access the database over TCP/IP or TLS, using a database URL such as: jdbc:h2:tcp://localhost/mem:db1.


Alternative to standalone H2 Console : using the H2 console accessible from the Spring Boot application

Indeed the H2 database provides a browser-based console that Spring Boot can auto-configure for you. The console is auto-configured when these conditions are met :

  • You are developing a servlet-based web application.
  • com.h2database:h2 is on the classpath.
  • You are using Spring Boot’s developer tools.

So it means that will be accessible only in dev. What generally you want.

By default, the console is available at /h2-console.
Set the spring.h2.console.path property to change that.

Luxuriate answered 25/7, 2017 at 11:53 Comment(10)
2017-07-25 13:58:41.311 ERROR 10690 --- [ restartedMain] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool. org.h2.jdbc.JdbcSQLException: Connection is broken: "java.net.ConnectException: Connection refused (Connection refused): localhost" [90067-193]Bullyboy
/~/test is because I'm testing the db under localhost:8080/test?Bullyboy
No it doesn't. I think that you have an already opened connection. Try to kill Spring Boot processes that are executing. And try again.Luxuriate
I've stopped my app in IntelliJ and killed Tomcat in Terminal - still errors with 'connection refused', though.Bullyboy
I switched to the following: spring.datasource.url=jdbc:h2:file:~/h2/testBullyboy
With the result: 2017-07-25 14:08:42.511 DEBUG 11125 --- [ restartedMain] org.hibernate.SQL : create table game (id bigint not null, aggregated_rating double, cloudinary_id varchar(255), height integer, url varchar(255), width integer, first_release_date bigint, name varchar(255), storyline varchar(4000), primary key (id)) Hibernate: create table game (id bigint not null, aggregated_rating double, cloudinary_id varchar(255), height integer, url varchar(255), width integer, first_release_date bigint, name varchar(255), storyline varchar(4000), primary key (id))Bullyboy
It looks promising, but I'm still not able to access the table. Maybe lower-case is the problem now?Bullyboy
after switching to file? the same, SELECT * FROM GAME returns me: SELECT * FROM GAME; Table "GAME" not found; SQL statement: SELECT * FROM GAME [42102-193] 42S02/42102 (Help)Bullyboy
turns out I had to log in to H2 with the same URL as specified in application.properties - everything's working, thanks a lot!Bullyboy
With the same URL, it is of course much better :) You are welcome.Luxuriate
F
30

Just go to the H2 console for example at: http://localhost:9090/h2-console/ and In the JDBC URL field, type jdbc:h2:mem:testdb to configure the connection to the testdb database in RAM.

Fortyniner answered 21/7, 2018 at 11:27 Comment(0)
L
22

It looks like data is binded to parameters, but in H2 console SELECT * FROM GAME returns me nothing. The table doesn't exist.

You are using an in-memory instance of H2 :

spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

In this mode, you cannot see the content of the changes from another client that which one that started the in-memory database.
To see the changes from other clients, you have to use the TCP mode.

You have two solutions :

  • using a file to persist the instance of H2.

Where are the Database Files Stored?

When using database URLs like jdbc:h2:~/test, the database is stored in the user directory. For Windows, this is usually C:\Documents and Settings\ or C:\Users\. If the base directory is not set (as in jdbc:h2:./test), the database files are stored in the directory where the application is started (the current working directory). When using the H2 Console application from the start menu, this is /bin. The base directory can be set in the database URL. A fixed or relative path can be used. When using the URL jdbc:h2:file:./data/sample, the database is stored in the directory data (relative to the current working directory). The directory is created automatically if it does not yet exist. It is also possible to use the fully qualified directory name (and for Windows, drive name). Example: jdbc:h2:file:C:/data/test

  • keeping to use an in-memory instance but using the TCP mode.

Replace :

spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

by :

spring.datasource.url=jdbc:h2:tcp://localhost/~/test

Generally, I switch to this mode during JPA entity unit testing when I really want to know which was inserted in the database.

From the official documentation :

In-Memory Databases

For certain use cases (for example: rapid prototyping, testing, high performance operations, read-only databases), it may not be required to persist data, or persist changes to the data. This database supports the in-memory mode, where the data is not persisted. ...

In some cases, only one connection to a in-memory database is required. This means the database to be opened is private. In this case, the database URL is jdbc:h2:mem: Opening two connections within the same virtual machine means opening two different (private) databases.

Sometimes multiple connections to the same in-memory database are required. In this case, the database URL must include a name. Example: jdbc:h2:mem:db1. Accessing the same database using this URL only works within the same virtual machine and class loader environment.

To access an in-memory database from another process or from another computer, you need to start a TCP server in the same process as the in-memory database was created. The other processes then need to access the database over TCP/IP or TLS, using a database URL such as: jdbc:h2:tcp://localhost/mem:db1.


Alternative to standalone H2 Console : using the H2 console accessible from the Spring Boot application

Indeed the H2 database provides a browser-based console that Spring Boot can auto-configure for you. The console is auto-configured when these conditions are met :

  • You are developing a servlet-based web application.
  • com.h2database:h2 is on the classpath.
  • You are using Spring Boot’s developer tools.

So it means that will be accessible only in dev. What generally you want.

By default, the console is available at /h2-console.
Set the spring.h2.console.path property to change that.

Luxuriate answered 25/7, 2017 at 11:53 Comment(10)
2017-07-25 13:58:41.311 ERROR 10690 --- [ restartedMain] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool. org.h2.jdbc.JdbcSQLException: Connection is broken: "java.net.ConnectException: Connection refused (Connection refused): localhost" [90067-193]Bullyboy
/~/test is because I'm testing the db under localhost:8080/test?Bullyboy
No it doesn't. I think that you have an already opened connection. Try to kill Spring Boot processes that are executing. And try again.Luxuriate
I've stopped my app in IntelliJ and killed Tomcat in Terminal - still errors with 'connection refused', though.Bullyboy
I switched to the following: spring.datasource.url=jdbc:h2:file:~/h2/testBullyboy
With the result: 2017-07-25 14:08:42.511 DEBUG 11125 --- [ restartedMain] org.hibernate.SQL : create table game (id bigint not null, aggregated_rating double, cloudinary_id varchar(255), height integer, url varchar(255), width integer, first_release_date bigint, name varchar(255), storyline varchar(4000), primary key (id)) Hibernate: create table game (id bigint not null, aggregated_rating double, cloudinary_id varchar(255), height integer, url varchar(255), width integer, first_release_date bigint, name varchar(255), storyline varchar(4000), primary key (id))Bullyboy
It looks promising, but I'm still not able to access the table. Maybe lower-case is the problem now?Bullyboy
after switching to file? the same, SELECT * FROM GAME returns me: SELECT * FROM GAME; Table "GAME" not found; SQL statement: SELECT * FROM GAME [42102-193] 42S02/42102 (Help)Bullyboy
turns out I had to log in to H2 with the same URL as specified in application.properties - everything's working, thanks a lot!Bullyboy
With the same URL, it is of course much better :) You are welcome.Luxuriate
D
14

Putting this line: spring.jpa.hibernate.ddl-auto = update in your application.properties file start population data in in-memory database and in file based database for H2 data-base.Hope this helps anyone.

Discomfit answered 12/2, 2020 at 18:54 Comment(1)
Had to scroll way too far down for that. Thanks!Lout
C
7

Check if you main class(Spring boot application class) is able to scan the entities defined. This usually happens when the entities are in a different package than that of the main class.

Catima answered 24/4, 2018 at 9:30 Comment(2)
The problem was solved already, year ago (like I've written in the comments to the accepted answer back then). Thanks for your help nevertheless.Bullyboy
VapeKop, People add answers after the problem was solved because of change in versions and several other reason. So a new post may help some one else.Skerl
S
3

use @EntityScan("com.db.jpasample.entity")

@SpringBootApplication
@EntityScan("com.db.jpasample.entity")
public class GsoftApplication {

  public static void main(String[] args) {
    SpringApplication.run(GsoftApplication.class, args);
  }

}

application.properties

server.port = 9090
spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:socialdb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto = create
Skaggs answered 26/3, 2020 at 20:40 Comment(0)
S
2

The DataSource Initialization feature for SQL Script has been redesigned in Spring Boot 2.5.


By default, data.sql scripts are now run before Hibernate is initialized. This aligns the behavior of basic script-based initialization with that of Flyway and Liquibase. If you want to use data.sql to populate a schema created by Hibernate, set spring.jpa.defer-datasource-initialization to true. While mixing database initialization technologies is not recommended, this will also allow you to use a schema.sql script to build upon a Hibernate-created schema before it’s populated via data.sql.

Reference:

Spring Boot 2.5 Release Notes

Serriform answered 18/1, 2022 at 15:30 Comment(0)
T
1

In the application.properties file, try to use spring.jpa.defer-datasource-initialization=true.

Tycho answered 26/7, 2021 at 13:20 Comment(0)
A
1

Same problem i faced and i added below changes to resolve it,

i added below version for H2 dependencies in pom.xml

    <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.193</version>
    </dependency>

And added below configuration in application.properties file

spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.driverClassName = org.h2.Driver
spring.datasource.url=jdbc:h2:file:~/test;
spring.datasource.username=sa
spring.datasource.password=
Ambrogio answered 21/10, 2021 at 11:58 Comment(0)
H
1

May not be the best answer but u might want to use @Column (name = "\"WIDTH\"") and force usage of reserved words. Im using file instead of memory,

#Allow viewing H2 database via web browser e.g. "http://localhost:8085/testdb"
spring.h2.console.enabled=true
spring.h2.console.path=/testdb

spring.datasource.username=sa
spring.datasource.password=
#First create an empty file "testdb.mv.db" in the file system that will act as the database storage. Check database error for location
spring.datasource.url=jdbc:h2:file:~/testdb;
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create    

If using a file storage use jdbc:h2:file:~/testdb or jdbc:h2:~/testdb but jdbc:h2:mem:testdb will not connect.

enter image description here

Himyaritic answered 21/7, 2023 at 9:37 Comment(0)
C
0

Missing ddl script

i was also facing the same but it seemed i didnt added the ddl part

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:~/test
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=   //empty as i didnt has password in h2
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto = create //add this to create table first time then use 'update'
Careycarfare answered 14/5, 2022 at 7:20 Comment(0)
P
0

It should work with your in-memory instance of H2 if you load the data and call all operations within the same JVM session.

It has a lot to do with the design of the connection.

Please check both these:

  • the url to setup the connection
  • the validation and export of schema DDL to the database with the good choice of the parameter of hibernate.hbm2ddl.auto

One has to act on these two parameters, it could require some time.

More options for in memory db.

Popularity answered 23/8, 2022 at 11:13 Comment(0)
T
0

One of the reasons ,Spring boot is not creating your tables is ,that Your Entity classes are under a different package than the SpringBootApplication class.

Solution#1

Create your Entity classes under the SpringBootApplication class's package.

Eg:

package com.jpademo.learning.jpa;
@SpringBootApplication
public class JpaIn10StepsApplication {
  ......
}

package com.jpademo.learning.jpa.entity;

@Entity(name = "jpa_user")
public class User {

....
}

Solution#2

Add @EntityScan to your SpringBootApplication class,giving the package name,in case the entity class's package cannot be changed.

    package com.jpademo.learning.jpa;
    @SpringBootApplication
    @EntityScan("com.jpademo.myentities.jpa.entity")
    public class JpaIn10StepsApplication {
      ......
    }
    
    package com.jpademo.myentities.jpa.entity;
    
    @Entity(name = "jpa_user")
    public class User {
    
    ....
    }
Twill answered 25/6 at 15:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.