mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-08-06 04:23:22 +00:00
docs: update slob
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
---
|
||||
title: Serialized LOB
|
||||
category: Data access
|
||||
language: en
|
||||
tag:
|
||||
- Data access
|
||||
- Data processing
|
||||
- Persistence
|
||||
---
|
||||
|
||||
## Also known as
|
||||
|
||||
* Serialized Large Object
|
||||
* Serialized BLOB
|
||||
* Serialized CLOB
|
||||
|
||||
## Intent
|
||||
|
||||
To manage and store large objects (LOBs) like files, images, or large strings in a database efficiently using serialization.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real-world example
|
||||
|
||||
> Consider a social media platform where users can upload and share images and videos. Instead of storing these large multimedia files on a separate file server, the platform uses the Serialized LOB design pattern to store the files directly in the database. Each uploaded image or video is serialized into a binary large object (BLOB) and stored within the user's record. This approach ensures that the multimedia files are managed within the same transactional context as other user data, providing consistency and simplifying data access and retrieval.
|
||||
|
||||
In plain words
|
||||
|
||||
> The Serialized LOB design pattern manages the storage of large objects, such as files or multimedia, by serializing and storing them directly within a database.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
The Serialized Large Object (LOB) design pattern is a way to handle large objects in a database. It involves serializing an object graph into a single large object (a BLOB or CLOB, for Binary Large Object or Character Large Object, respectively) and storing it in the database. When the object graph needs to be retrieved, it is read from the database and deserialized back into the original object graph.
|
||||
|
||||
Here's a programmatic example of the Serialized LOB design pattern:
|
||||
|
||||
```java
|
||||
public abstract class LobSerializer implements AutoCloseable {
|
||||
// ... omitted for brevity
|
||||
public abstract Object serialize(Forest toSerialize) throws Exception;
|
||||
public abstract Forest deSerialize(Object toDeserialize) throws Exception;
|
||||
// ... omitted for brevity
|
||||
}
|
||||
```
|
||||
|
||||
The `LobSerializer` class is an abstract class that provides the structure for serializing and deserializing objects. It has two abstract methods: `serialize` and `deSerialize`. These methods are implemented by the subclasses `ClobSerializer` and `BlobSerializer`.
|
||||
|
||||
```java
|
||||
public class ClobSerializer extends LobSerializer {
|
||||
// ... omitted for brevity
|
||||
@Override
|
||||
public Object serialize(Forest forest) throws ParserConfigurationException, TransformerException {
|
||||
// ... omitted for brevity
|
||||
}
|
||||
|
||||
@Override
|
||||
public Forest deSerialize(Object toDeserialize)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
// ... omitted for brevity
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ClobSerializer` class provides an implementation for serializing and deserializing objects into XML strings. The `serialize` method converts a `Forest` object into an XML string, and the `deSerialize` method converts an XML string back into a `Forest` object.
|
||||
|
||||
```java
|
||||
public class BlobSerializer extends LobSerializer {
|
||||
// ... omitted for brevity
|
||||
@Override
|
||||
public Object serialize(Forest toSerialize) throws IOException {
|
||||
// ... omitted for brevity
|
||||
}
|
||||
|
||||
@Override
|
||||
public Forest deSerialize(Object toDeserialize) throws IOException, ClassNotFoundException {
|
||||
// ... omitted for brevity
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `BlobSerializer` class provides an implementation for serializing and deserializing objects into binary data. The `serialize` method converts a `Forest` object into binary data, and the `deSerialize` method converts binary data back into a `Forest` object.
|
||||
|
||||
```java
|
||||
// The App class uses the LobSerializer to serialize and deserialize a Forest object.
|
||||
public class App {
|
||||
// ... omitted for brevity
|
||||
public static void main(String[] args) throws SQLException {
|
||||
Forest forest = createForest();
|
||||
LobSerializer serializer = createLobSerializer(args);
|
||||
executeSerializer(forest, serializer);
|
||||
}
|
||||
// ... omitted for brevity
|
||||
}
|
||||
```
|
||||
|
||||
The `App` class uses the `LobSerializer` to serialize and deserialize a `Forest` object. The `main` method creates a `Forest` object, creates a `LobSerializer` (either a `ClobSerializer` or a `BlobSerializer`), and then uses the `LobSerializer` to serialize and deserialize the `Forest` object.
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
* Use when you need to store large objects in a database and want to optimize data access and storage.
|
||||
* Ideal for applications that deal with large binary or character data such as multimedia files, logs, or documents.
|
||||
|
||||
## Known Uses
|
||||
|
||||
* Storing and retrieving images or multimedia files in a database.
|
||||
* Managing large text documents or logs in enterprise applications.
|
||||
* Handling binary data in applications that require efficient data retrieval and storage.
|
||||
|
||||
## Consequences
|
||||
|
||||
Benefits:
|
||||
|
||||
* Simplifies the handling of large objects by leveraging Java serialization.
|
||||
* Reduces the need for external file storage systems.
|
||||
* Ensures consistency by storing LOBs within the same transactional context as other data.
|
||||
|
||||
Trade-offs:
|
||||
|
||||
* Increases database size due to the storage of serialized data.
|
||||
* Potential performance overhead during serialization and deserialization.
|
||||
* Requires careful management of serialization format to maintain backward compatibility.
|
||||
|
||||
## Related Patterns
|
||||
|
||||
* [DAO (Data Access Object)](https://java-design-patterns.com/patterns/dao/): Often used in conjunction with Serialized LOB to encapsulate data access logic.
|
||||
* Active Record: Can use Serialized LOB for managing large data within the same record.
|
||||
* [Repository](https://java-design-patterns.com/patterns/repository/): Uses Serialized LOB to handle complex queries and data manipulation involving large objects.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Effective Java](https://amzn.to/4cGk2Jz)
|
||||
* [Java Persistence with Hibernate](https://amzn.to/44tP1ox)
|
||||
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
|
||||
* [Serialized LOB - Martin Fowler](https://martinfowler.com/eaaCatalog/serializedLOB.html) by Martin Fowler
|
||||
@@ -0,0 +1,122 @@
|
||||
@startuml
|
||||
package com.iluwatar.slob.lob {
|
||||
class Animal {
|
||||
- animalsEaten : Set<Animal>
|
||||
- name : String
|
||||
- plantsEaten : Set<Plant>
|
||||
+ Animal()
|
||||
+ Animal(name : String, plantsEaten : Set<Plant>, animalsEaten : Set<Animal>)
|
||||
# canEqual(other : Object) : boolean
|
||||
+ createObjectFromXml(node : Node)
|
||||
+ equals(o : Object) : boolean
|
||||
+ getAnimalsEaten() : Set<Animal>
|
||||
+ getName() : String
|
||||
+ getPlantsEaten() : Set<Plant>
|
||||
+ hashCode() : int
|
||||
# iterateXmlForAnimalAndPlants(childNodes : NodeList, animalsEaten : Set<Animal>, plantsEaten : Set<Plant>) {static}
|
||||
+ setAnimalsEaten(animalsEaten : Set<Animal>)
|
||||
+ setName(name : String)
|
||||
+ setPlantsEaten(plantsEaten : Set<Plant>)
|
||||
+ toString() : String
|
||||
+ toXmlElement(xmlDoc : Document) : Element
|
||||
}
|
||||
class Forest {
|
||||
- animals : Set<Animal>
|
||||
- name : String
|
||||
- plants : Set<Plant>
|
||||
+ Forest()
|
||||
+ Forest(name : String, animals : Set<Animal>, plants : Set<Plant>)
|
||||
# canEqual(other : Object) : boolean
|
||||
+ createObjectFromXml(document : Document)
|
||||
+ equals(o : Object) : boolean
|
||||
+ getAnimals() : Set<Animal>
|
||||
+ getName() : String
|
||||
+ getPlants() : Set<Plant>
|
||||
- getXmlDoc() : Document
|
||||
+ hashCode() : int
|
||||
+ setAnimals(animals : Set<Animal>)
|
||||
+ setName(name : String)
|
||||
+ setPlants(plants : Set<Plant>)
|
||||
+ toString() : String
|
||||
+ toXmlElement() : Element
|
||||
}
|
||||
class Plant {
|
||||
- name : String
|
||||
- type : String
|
||||
+ Plant()
|
||||
+ Plant(name : String, type : String)
|
||||
# canEqual(other : Object) : boolean
|
||||
+ createObjectFromXml(node : Node)
|
||||
+ equals(o : Object) : boolean
|
||||
+ getName() : String
|
||||
+ getType() : String
|
||||
+ hashCode() : int
|
||||
+ setName(name : String)
|
||||
+ setType(type : String)
|
||||
+ toString() : String
|
||||
+ toXmlElement(xmlDoc : Document) : Element
|
||||
}
|
||||
}
|
||||
package com.iluwatar.slob.serializers {
|
||||
class BlobSerializer {
|
||||
+ TYPE_OF_DATA_FOR_DB : String {static}
|
||||
+ BlobSerializer()
|
||||
+ deSerialize(toDeserialize : Object) : Forest
|
||||
+ serialize(toSerialize : Forest) : Object
|
||||
}
|
||||
class ClobSerializer {
|
||||
+ TYPE_OF_DATA_FOR_DB : String {static}
|
||||
+ ClobSerializer()
|
||||
+ deSerialize(toDeserialize : Object) : Forest
|
||||
- elementToXmlString(node : Element) : String {static}
|
||||
+ serialize(forest : Forest) : Object
|
||||
}
|
||||
abstract class LobSerializer {
|
||||
- databaseService : DatabaseService
|
||||
# LobSerializer(dataTypeDb : String)
|
||||
+ close()
|
||||
+ deSerialize(Object) : Forest {abstract}
|
||||
+ loadFromDb(id : int, columnName : String) : Object
|
||||
+ persistToDb(id : int, name : String, object : Object) : int
|
||||
+ serialize(Forest) : Object {abstract}
|
||||
}
|
||||
}
|
||||
package com.iluwatar.slob.dbservice {
|
||||
class DatabaseService {
|
||||
+ BINARY_DATA : String {static}
|
||||
+ CREATE_BINARY_SCHEMA_DDL : String {static}
|
||||
+ CREATE_TEXT_SCHEMA_DDL : String {static}
|
||||
- DB_URL : String {static}
|
||||
+ DELETE_SCHEMA_SQL : String {static}
|
||||
- INSERT : String {static}
|
||||
- LOGGER : Logger {static}
|
||||
- SELECT : String {static}
|
||||
- dataSource : DataSource {static}
|
||||
+ dataTypeDb : String
|
||||
+ DatabaseService(dataTypeDb : String)
|
||||
- createDataSource() : DataSource {static}
|
||||
+ insert(id : int, name : String, data : Object)
|
||||
+ select(id : long, columnsName : String) : Object
|
||||
+ shutDownService()
|
||||
+ startupService()
|
||||
}
|
||||
}
|
||||
package com.iluwatar.slob {
|
||||
class App {
|
||||
+ CLOB : String {static}
|
||||
- LOGGER : Logger {static}
|
||||
+ App()
|
||||
- createForest() : Forest {static}
|
||||
- createLobSerializer(args : String[]) : LobSerializer {static}
|
||||
- executeSerializer(forest : Forest, lobSerializer : LobSerializer) {static}
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
}
|
||||
Animal --> "-plantsEaten" Plant
|
||||
LobSerializer --> "-databaseService" DatabaseService
|
||||
Forest --> "-animals" Animal
|
||||
Forest --> "-plants" Plant
|
||||
Animal --> "-animalsEaten" Animal
|
||||
BlobSerializer --|> LobSerializer
|
||||
ClobSerializer --|> LobSerializer
|
||||
@enduml
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,122 @@
|
||||
@startuml
|
||||
package com.iluwatar.slob.lob {
|
||||
class Animal {
|
||||
- animalsEaten : Set<Animal>
|
||||
- name : String
|
||||
- plantsEaten : Set<Plant>
|
||||
+ Animal()
|
||||
+ Animal(name : String, plantsEaten : Set<Plant>, animalsEaten : Set<Animal>)
|
||||
# canEqual(other : Object) : boolean
|
||||
+ createObjectFromXml(node : Node)
|
||||
+ equals(o : Object) : boolean
|
||||
+ getAnimalsEaten() : Set<Animal>
|
||||
+ getName() : String
|
||||
+ getPlantsEaten() : Set<Plant>
|
||||
+ hashCode() : int
|
||||
# iterateXmlForAnimalAndPlants(childNodes : NodeList, animalsEaten : Set<Animal>, plantsEaten : Set<Plant>) {static}
|
||||
+ setAnimalsEaten(animalsEaten : Set<Animal>)
|
||||
+ setName(name : String)
|
||||
+ setPlantsEaten(plantsEaten : Set<Plant>)
|
||||
+ toString() : String
|
||||
+ toXmlElement(xmlDoc : Document) : Element
|
||||
}
|
||||
class Forest {
|
||||
- animals : Set<Animal>
|
||||
- name : String
|
||||
- plants : Set<Plant>
|
||||
+ Forest()
|
||||
+ Forest(name : String, animals : Set<Animal>, plants : Set<Plant>)
|
||||
# canEqual(other : Object) : boolean
|
||||
+ createObjectFromXml(document : Document)
|
||||
+ equals(o : Object) : boolean
|
||||
+ getAnimals() : Set<Animal>
|
||||
+ getName() : String
|
||||
+ getPlants() : Set<Plant>
|
||||
- getXmlDoc() : Document
|
||||
+ hashCode() : int
|
||||
+ setAnimals(animals : Set<Animal>)
|
||||
+ setName(name : String)
|
||||
+ setPlants(plants : Set<Plant>)
|
||||
+ toString() : String
|
||||
+ toXmlElement() : Element
|
||||
}
|
||||
class Plant {
|
||||
- name : String
|
||||
- type : String
|
||||
+ Plant()
|
||||
+ Plant(name : String, type : String)
|
||||
# canEqual(other : Object) : boolean
|
||||
+ createObjectFromXml(node : Node)
|
||||
+ equals(o : Object) : boolean
|
||||
+ getName() : String
|
||||
+ getType() : String
|
||||
+ hashCode() : int
|
||||
+ setName(name : String)
|
||||
+ setType(type : String)
|
||||
+ toString() : String
|
||||
+ toXmlElement(xmlDoc : Document) : Element
|
||||
}
|
||||
}
|
||||
package com.iluwatar.slob.serializers {
|
||||
class BlobSerializer {
|
||||
+ TYPE_OF_DATA_FOR_DB : String {static}
|
||||
+ BlobSerializer()
|
||||
+ deSerialize(toDeserialize : Object) : Forest
|
||||
+ serialize(toSerialize : Forest) : Object
|
||||
}
|
||||
class ClobSerializer {
|
||||
+ TYPE_OF_DATA_FOR_DB : String {static}
|
||||
+ ClobSerializer()
|
||||
+ deSerialize(toDeserialize : Object) : Forest
|
||||
- elementToXmlString(node : Element) : String {static}
|
||||
+ serialize(forest : Forest) : Object
|
||||
}
|
||||
abstract class LobSerializer {
|
||||
- databaseService : DatabaseService
|
||||
# LobSerializer(dataTypeDb : String)
|
||||
+ close()
|
||||
+ deSerialize(Object) : Forest {abstract}
|
||||
+ loadFromDb(id : int, columnName : String) : Object
|
||||
+ persistToDb(id : int, name : String, object : Object) : int
|
||||
+ serialize(Forest) : Object {abstract}
|
||||
}
|
||||
}
|
||||
package com.iluwatar.slob.dbservice {
|
||||
class DatabaseService {
|
||||
+ BINARY_DATA : String {static}
|
||||
+ CREATE_BINARY_SCHEMA_DDL : String {static}
|
||||
+ CREATE_TEXT_SCHEMA_DDL : String {static}
|
||||
- DB_URL : String {static}
|
||||
+ DELETE_SCHEMA_SQL : String {static}
|
||||
- INSERT : String {static}
|
||||
- LOGGER : Logger {static}
|
||||
- SELECT : String {static}
|
||||
- dataSource : DataSource {static}
|
||||
+ dataTypeDb : String
|
||||
+ DatabaseService(dataTypeDb : String)
|
||||
- createDataSource() : DataSource {static}
|
||||
+ insert(id : int, name : String, data : Object)
|
||||
+ select(id : long, columnsName : String) : Object
|
||||
+ shutDownService()
|
||||
+ startupService()
|
||||
}
|
||||
}
|
||||
package com.iluwatar.slob {
|
||||
class App {
|
||||
+ CLOB : String {static}
|
||||
- LOGGER : Logger {static}
|
||||
+ App()
|
||||
- createForest() : Forest {static}
|
||||
- createLobSerializer(args : String[]) : LobSerializer {static}
|
||||
- executeSerializer(forest : Forest, lobSerializer : LobSerializer) {static}
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
}
|
||||
Animal --> "-plantsEaten" Plant
|
||||
LobSerializer --> "-databaseService" DatabaseService
|
||||
Forest --> "-animals" Animal
|
||||
Forest --> "-plants" Plant
|
||||
Animal --> "-animalsEaten" Animal
|
||||
BlobSerializer --|> LobSerializer
|
||||
ClobSerializer --|> LobSerializer
|
||||
@enduml
|
||||
@@ -0,0 +1,49 @@
|
||||
@startuml
|
||||
|
||||
!theme plain
|
||||
top to bottom direction
|
||||
skinparam linetype ortho
|
||||
|
||||
class Animal {
|
||||
- animalsEaten: Set<Animal>
|
||||
- name: String
|
||||
- plantsEaten: Set<Plant>
|
||||
animalsEaten: Set<Animal>
|
||||
name: String
|
||||
plantsEaten: Set<Plant>
|
||||
}
|
||||
class App
|
||||
class BlobSerializer
|
||||
class ClobSerializer
|
||||
class DatabaseService
|
||||
class Forest {
|
||||
- animals: Set<Animal>
|
||||
- name: String
|
||||
- plants: Set<Plant>
|
||||
animals: Set<Animal>
|
||||
name: String
|
||||
plants: Set<Plant>
|
||||
xmlDoc: Document
|
||||
}
|
||||
class LobSerializer
|
||||
class Plant {
|
||||
- name: String
|
||||
- type: String
|
||||
name: String
|
||||
type: String
|
||||
}
|
||||
|
||||
Animal -[#595959,dashed]-> Plant : "«create»"
|
||||
Animal "1" *-[#595959,plain]-> "plantsEaten\n*" Plant
|
||||
App -[#595959,dashed]-> Animal : "«create»"
|
||||
App -[#595959,dashed]-> ClobSerializer : "«create»"
|
||||
App -[#595959,dashed]-> Forest : "«create»"
|
||||
App -[#595959,dashed]-> Plant : "«create»"
|
||||
BlobSerializer -[#000082,plain]-^ LobSerializer
|
||||
ClobSerializer -[#595959,dashed]-> Forest : "«create»"
|
||||
ClobSerializer -[#000082,plain]-^ LobSerializer
|
||||
Forest "1" *-[#595959,plain]-> "animals\n*" Animal
|
||||
Forest "1" *-[#595959,plain]-> "plants\n*" Plant
|
||||
LobSerializer "1" *-[#595959,plain]-> "databaseService\n1" DatabaseService
|
||||
LobSerializer -[#595959,dashed]-> DatabaseService : "«create»"
|
||||
@enduml
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
|
||||
The MIT License
|
||||
Copyright © 2014-2022 Ilkka Seppälä
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<artifactId>serialized-lob</artifactId>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.slob.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>h2</artifactId>
|
||||
<groupId>com.h2database</groupId>
|
||||
<version>2.2.224</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob;
|
||||
|
||||
import com.iluwatar.slob.lob.Animal;
|
||||
import com.iluwatar.slob.lob.Forest;
|
||||
import com.iluwatar.slob.lob.Plant;
|
||||
import com.iluwatar.slob.serializers.BlobSerializer;
|
||||
import com.iluwatar.slob.serializers.ClobSerializer;
|
||||
import com.iluwatar.slob.serializers.LobSerializer;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* SLOB Application using {@link LobSerializer} and H2 DB.
|
||||
*/
|
||||
public class App {
|
||||
|
||||
public static final String CLOB = "CLOB";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Main entry point to program.
|
||||
* <p>In the SLOB pattern, the object graph is serialized into a single large object (a BLOB or
|
||||
* CLOB, for Binary Large Object or Character Large Object, respectively) and stored in the
|
||||
* database. When the object graph needs to be retrieved, it is read from the database and
|
||||
* deserialized back into the original object graph.</p>
|
||||
*
|
||||
* <p>A Forest is created using {@link #createForest()} with Animals and Plants along with their
|
||||
* respective relationships.</p>
|
||||
*
|
||||
* <p>Creates a {@link LobSerializer} using the method
|
||||
* {@link #createLobSerializer(String[])}.</p>
|
||||
*
|
||||
* <p>Once created the serializer is passed to the
|
||||
* {@link #executeSerializer(Forest, LobSerializer)} which handles the serialization,
|
||||
* deserialization and persisting and loading from DB.</p>
|
||||
*
|
||||
* @param args if first arg is CLOB then ClobSerializer is used else BlobSerializer is used.
|
||||
*/
|
||||
public static void main(String[] args) throws SQLException {
|
||||
Forest forest = createForest();
|
||||
LobSerializer serializer = createLobSerializer(args);
|
||||
executeSerializer(forest, serializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates a {@link LobSerializer} on the basis of input args. </p>
|
||||
* <p>If input args are not empty and the value equals {@link App#CLOB} then a
|
||||
* {@link ClobSerializer} is created else a {@link BlobSerializer} is created.</p>
|
||||
*
|
||||
* @param args if first arg is {@link App#CLOB} then ClobSerializer is instantiated else
|
||||
* BlobSerializer is instantiated.
|
||||
*/
|
||||
private static LobSerializer createLobSerializer(String[] args) throws SQLException {
|
||||
LobSerializer serializer;
|
||||
if (args.length > 0 && Objects.equals(args[0], CLOB)) {
|
||||
serializer = new ClobSerializer();
|
||||
} else {
|
||||
serializer = new BlobSerializer();
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Forest with {@link Animal} and {@link Plant} along with their respective
|
||||
* relationships.
|
||||
*
|
||||
* <p> The method creates a {@link Forest} with 2 Plants Grass and Oak of type Herb and tree
|
||||
* respectively.</p>
|
||||
*
|
||||
* <p> It also creates 3 animals Zebra and Buffalo which eat the plant grass. Lion consumes the
|
||||
* Zebra and the Buffalo.</p>
|
||||
*
|
||||
* <p>With the above animals and plants and their relationships a forest
|
||||
* object is created which represents the Object Graph.</p>
|
||||
*
|
||||
* @return Forest Object
|
||||
*/
|
||||
private static Forest createForest() {
|
||||
Plant grass = new Plant("Grass", "Herb");
|
||||
Plant oak = new Plant("Oak", "Tree");
|
||||
|
||||
Animal zebra = new Animal("Zebra", Set.of(grass), Collections.emptySet());
|
||||
Animal buffalo = new Animal("Buffalo", Set.of(grass), Collections.emptySet());
|
||||
Animal lion = new Animal("Lion", Collections.emptySet(), Set.of(zebra, buffalo));
|
||||
|
||||
return new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak));
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the input object using the input serializer and persist to DB. After this it loads
|
||||
* the same object back from DB and deserializes using the same serializer.
|
||||
*
|
||||
* @param forest Object to Serialize and Persist
|
||||
* @param lobSerializer Serializer to Serialize and Deserialize Object
|
||||
*/
|
||||
private static void executeSerializer(Forest forest, LobSerializer lobSerializer) {
|
||||
try (LobSerializer serializer = lobSerializer) {
|
||||
|
||||
Object serialized = serializer.serialize(forest);
|
||||
int id = serializer.persistToDb(1, forest.getName(), serialized);
|
||||
|
||||
Object fromDb = serializer.loadFromDb(id, Forest.class.getSimpleName());
|
||||
Forest forestFromDb = serializer.deSerialize(fromDb);
|
||||
|
||||
LOGGER.info(forestFromDb.toString());
|
||||
} catch (SQLException | IOException | TransformerException | ParserConfigurationException
|
||||
| SAXException
|
||||
| ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.dbservice;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.h2.jdbcx.JdbcDataSource;
|
||||
|
||||
/**
|
||||
* Service to handle database operations.
|
||||
*/
|
||||
@Slf4j
|
||||
public class DatabaseService {
|
||||
|
||||
public static final String CREATE_BINARY_SCHEMA_DDL =
|
||||
"CREATE TABLE IF NOT EXISTS FORESTS (ID NUMBER UNIQUE, NAME VARCHAR(30),FOREST VARBINARY)";
|
||||
public static final String CREATE_TEXT_SCHEMA_DDL =
|
||||
"CREATE TABLE IF NOT EXISTS FORESTS (ID NUMBER UNIQUE, NAME VARCHAR(30),FOREST VARCHAR)";
|
||||
public static final String DELETE_SCHEMA_SQL = "DROP TABLE FORESTS IF EXISTS";
|
||||
public static final String BINARY_DATA = "BINARY";
|
||||
private static final String DB_URL = "jdbc:h2:~/test";
|
||||
private static final String INSERT = "insert into FORESTS (id,name, forest) values (?,?,?)";
|
||||
private static final String SELECT = "select FOREST from FORESTS where id = ?";
|
||||
private static final DataSource dataSource = createDataSource();
|
||||
public String dataTypeDb;
|
||||
|
||||
/**
|
||||
* Constructor initializes {@link DatabaseService#dataTypeDb}.
|
||||
*
|
||||
* @param dataTypeDb Type of data that is to be stored in DB can be 'TEXT' or 'BINARY'.
|
||||
*/
|
||||
public DatabaseService(String dataTypeDb) {
|
||||
this.dataTypeDb = dataTypeDb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates Data source.
|
||||
*
|
||||
* @return created data source
|
||||
*/
|
||||
private static DataSource createDataSource() {
|
||||
var dataSource = new JdbcDataSource();
|
||||
dataSource.setURL(DB_URL);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown Sequence executes Query {@link DatabaseService#DELETE_SCHEMA_SQL}.
|
||||
*
|
||||
* @throws SQLException if any issue occurs while executing DROP Query
|
||||
*/
|
||||
public void shutDownService()
|
||||
throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
statement.execute(DELETE_SCHEMA_SQL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initaites startup sequence and executes the query
|
||||
* {@link DatabaseService#CREATE_BINARY_SCHEMA_DDL} if {@link DatabaseService#dataTypeDb} is
|
||||
* binary else will execute the query {@link DatabaseService#CREATE_TEXT_SCHEMA_DDL}.
|
||||
*
|
||||
* @throws SQLException if there are any issues during DDL execution
|
||||
*/
|
||||
public void startupService()
|
||||
throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var statement = connection.createStatement()) {
|
||||
if (dataTypeDb.equals("BINARY")) {
|
||||
statement.execute(CREATE_BINARY_SCHEMA_DDL);
|
||||
} else {
|
||||
statement.execute(CREATE_TEXT_SCHEMA_DDL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the insert query {@link DatabaseService#INSERT}.
|
||||
*
|
||||
* @param id with which row is to be inserted
|
||||
* @param name name to be added in the row
|
||||
* @param data object data to be saved in the row
|
||||
* @throws SQLException if there are any issues in executing insert query
|
||||
* {@link DatabaseService#INSERT}
|
||||
*/
|
||||
public void insert(int id, String name, Object data)
|
||||
throws SQLException {
|
||||
try (var connection = dataSource.getConnection();
|
||||
var insert = connection.prepareStatement(INSERT)) {
|
||||
insert.setInt(1, id);
|
||||
insert.setString(2, name);
|
||||
insert.setObject(3, data);
|
||||
insert.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the select query {@link DatabaseService#SELECT} form the result set returns an
|
||||
* {@link java.io.InputStream} if {@link DatabaseService#dataTypeDb} is 'binary' else will return
|
||||
* the object as a {@link String}.
|
||||
*
|
||||
* @param id with which row is to be selected
|
||||
* @param columnsName column in which the object is stored
|
||||
* @return object found from DB
|
||||
* @throws SQLException if there are any issues in executing insert query *
|
||||
* {@link DatabaseService#SELECT}
|
||||
*/
|
||||
public Object select(final long id, String columnsName) throws SQLException {
|
||||
ResultSet resultSet = null;
|
||||
try (var connection = dataSource.getConnection();
|
||||
var preparedStatement =
|
||||
connection.prepareStatement(SELECT)
|
||||
) {
|
||||
Object result = null;
|
||||
preparedStatement.setLong(1, id);
|
||||
resultSet = preparedStatement.executeQuery();
|
||||
while (resultSet.next()) {
|
||||
if (dataTypeDb.equals(BINARY_DATA)) {
|
||||
result = resultSet.getBinaryStream(columnsName);
|
||||
} else {
|
||||
result = resultSet.getString(columnsName);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
if (resultSet != null) {
|
||||
resultSet.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.lob;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Creates an object Animal with a list of animals and/or plants it consumes.
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Animal implements Serializable {
|
||||
|
||||
private String name;
|
||||
private Set<Plant> plantsEaten = new HashSet<>();
|
||||
private Set<Animal> animalsEaten = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Iterates over the input nodes recursively and adds new plants to {@link Animal#plantsEaten} or
|
||||
* animals to {@link Animal#animalsEaten} found to input sets respectively.
|
||||
*
|
||||
* @param childNodes contains the XML Node containing the Forest
|
||||
* @param animalsEaten set of Animals eaten
|
||||
* @param plantsEaten set of Plants eaten
|
||||
*/
|
||||
protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set<Animal> animalsEaten,
|
||||
Set<Plant> plantsEaten) {
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node child = childNodes.item(i);
|
||||
if (child.getNodeType() == Node.ELEMENT_NODE) {
|
||||
if (child.getNodeName().equals(Animal.class.getSimpleName())) {
|
||||
Animal animalEaten = new Animal();
|
||||
animalEaten.createObjectFromXml(child);
|
||||
animalsEaten.add(animalEaten);
|
||||
} else if (child.getNodeName().equals(Plant.class.getSimpleName())) {
|
||||
Plant plant = new Plant();
|
||||
plant.createObjectFromXml(child);
|
||||
plantsEaten.add(plant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides XML Representation of the Animal.
|
||||
*
|
||||
* @param xmlDoc object to which the XML representation is to be written to
|
||||
* @return XML Element contain the Animal representation
|
||||
*/
|
||||
public Element toXmlElement(Document xmlDoc) {
|
||||
Element root = xmlDoc.createElement(Animal.class.getSimpleName());
|
||||
root.setAttribute("name", name);
|
||||
for (Plant plant : plantsEaten) {
|
||||
Element xmlElement = plant.toXmlElement(xmlDoc);
|
||||
if (xmlElement != null) {
|
||||
root.appendChild(xmlElement);
|
||||
}
|
||||
}
|
||||
for (Animal animal : animalsEaten) {
|
||||
Element xmlElement = animal.toXmlElement(xmlDoc);
|
||||
if (xmlElement != null) {
|
||||
root.appendChild(xmlElement);
|
||||
}
|
||||
}
|
||||
xmlDoc.appendChild(root);
|
||||
return (Element) xmlDoc.getFirstChild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Animal Object from the input XML Node.
|
||||
*
|
||||
* @param node the XML Node from which the Animal Object is to be parsed
|
||||
*/
|
||||
public void createObjectFromXml(Node node) {
|
||||
name = node.getAttributes().getNamedItem("name").getNodeValue();
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
iterateXmlForAnimalAndPlants(childNodes, animalsEaten, plantsEaten);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\nAnimal Name = ").append(name);
|
||||
if (!animalsEaten.isEmpty()) {
|
||||
sb.append("\n\tAnimals Eaten by ").append(name).append(": ");
|
||||
}
|
||||
for (Animal animal : animalsEaten) {
|
||||
sb.append("\n\t\t").append(animal);
|
||||
}
|
||||
sb.append("\n");
|
||||
if (!plantsEaten.isEmpty()) {
|
||||
sb.append("\n\tPlants Eaten by ").append(name).append(": ");
|
||||
}
|
||||
for (Plant plant : plantsEaten) {
|
||||
sb.append("\n\t\t").append(plant);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.lob;
|
||||
|
||||
import static com.iluwatar.slob.lob.Animal.iterateXmlForAnimalAndPlants;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Creates an object Forest which contains animals and plants as its constituents. Animals may eat
|
||||
* plants or other animals in the forest.
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Forest implements Serializable {
|
||||
|
||||
private String name;
|
||||
private Set<Animal> animals = new HashSet<>();
|
||||
private Set<Plant> plants = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Provides the representation of Forest in XML form.
|
||||
*
|
||||
* @return XML Element
|
||||
*/
|
||||
public Element toXmlElement() throws ParserConfigurationException {
|
||||
Document xmlDoc = getXmlDoc();
|
||||
|
||||
Element forestXml = xmlDoc.createElement("Forest");
|
||||
forestXml.setAttribute("name", name);
|
||||
|
||||
Element animalsXml = xmlDoc.createElement("Animals");
|
||||
for (Animal animal : animals) {
|
||||
Element animalXml = animal.toXmlElement(xmlDoc);
|
||||
animalsXml.appendChild(animalXml);
|
||||
}
|
||||
forestXml.appendChild(animalsXml);
|
||||
|
||||
Element plantsXml = xmlDoc.createElement("Plants");
|
||||
for (Plant plant : plants) {
|
||||
Element plantXml = plant.toXmlElement(xmlDoc);
|
||||
plantsXml.appendChild(plantXml);
|
||||
}
|
||||
forestXml.appendChild(plantsXml);
|
||||
return forestXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns XMLDoc to use for XML creation.
|
||||
*
|
||||
* @return XML DOC Object
|
||||
* @throws ParserConfigurationException {@inheritDoc}
|
||||
*/
|
||||
private Document getXmlDoc() throws ParserConfigurationException {
|
||||
return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Forest Object from the input XML Document.
|
||||
*
|
||||
* @param document the XML document from which the Forest is to be parsed
|
||||
*/
|
||||
public void createObjectFromXml(Document document) {
|
||||
name = document.getDocumentElement().getAttribute("name");
|
||||
NodeList nodeList = document.getElementsByTagName("*");
|
||||
iterateXmlForAnimalAndPlants(nodeList, animals, plants);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("\n");
|
||||
sb.append("Forest Name = ").append(name).append("\n");
|
||||
sb.append("Animals found in the ").append(name).append(" Forest: \n");
|
||||
for (Animal animal : animals) {
|
||||
sb.append("\n--------------------------\n");
|
||||
sb.append(animal.toString());
|
||||
sb.append("\n--------------------------\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
sb.append("Plants in the ").append(name).append(" Forest: \n");
|
||||
for (Plant plant : plants) {
|
||||
sb.append("\n--------------------------\n");
|
||||
sb.append(plant.toString());
|
||||
sb.append("\n--------------------------\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.lob;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.StringJoiner;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Creates an object Plant which contains its name and type.
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Plant implements Serializable {
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* Provides XML Representation of the Plant.
|
||||
*
|
||||
* @param xmlDoc to which the XML representation is to be written to
|
||||
* @return XML Element contain the Animal representation
|
||||
*/
|
||||
public Element toXmlElement(Document xmlDoc) {
|
||||
Element root = xmlDoc.createElement(Plant.class.getSimpleName());
|
||||
root.setAttribute("name", name);
|
||||
root.setAttribute("type", type);
|
||||
xmlDoc.appendChild(root);
|
||||
return xmlDoc.getDocumentElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Plant Object from the input XML Node.
|
||||
*
|
||||
* @param node the XML Node from which the Animal Object is to be parsed
|
||||
*/
|
||||
public void createObjectFromXml(Node node) {
|
||||
NamedNodeMap attributes = node.getAttributes();
|
||||
name = attributes.getNamedItem("name").getNodeValue();
|
||||
type = attributes.getNamedItem("type").getNodeValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringJoiner stringJoiner = new StringJoiner(",");
|
||||
stringJoiner.add("Name = " + name);
|
||||
stringJoiner.add("Type = " + type);
|
||||
return stringJoiner.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.serializers;
|
||||
|
||||
import com.iluwatar.slob.lob.Forest;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Creates a Serializer that uses Binary serialization and deserialization of objects graph to and
|
||||
* from their Binary Representation.
|
||||
*/
|
||||
public class BlobSerializer extends LobSerializer {
|
||||
|
||||
public static final String TYPE_OF_DATA_FOR_DB = "BINARY";
|
||||
|
||||
public BlobSerializer() throws SQLException {
|
||||
super(TYPE_OF_DATA_FOR_DB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the input object graph to its Binary Representation using Object Stream.
|
||||
*
|
||||
* @param toSerialize Object which is to be serialized
|
||||
* @return Serialized object
|
||||
* @throws IOException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Object serialize(Forest toSerialize) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(toSerialize);
|
||||
oos.close();
|
||||
return new ByteArrayInputStream(baos.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the input Byte Array Stream using Object Stream and return its Object Graph
|
||||
* Representation.
|
||||
*
|
||||
* @param toDeserialize Input Object to De-serialize
|
||||
* @return Deserialized Object
|
||||
* @throws ClassNotFoundException {@inheritDoc}
|
||||
* @throws IOException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Forest deSerialize(Object toDeserialize) throws IOException, ClassNotFoundException {
|
||||
InputStream bis = (InputStream) toDeserialize;
|
||||
Forest forest;
|
||||
try (ObjectInput in = new ObjectInputStream(bis)) {
|
||||
forest = (Forest) in.readObject();
|
||||
}
|
||||
return forest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.serializers;
|
||||
|
||||
import com.iluwatar.slob.lob.Forest;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.SQLException;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Creates a Serializer that uses Character based serialization and deserialization of objects graph
|
||||
* to and from XML Representation.
|
||||
*/
|
||||
public class ClobSerializer extends LobSerializer {
|
||||
|
||||
public static final String TYPE_OF_DATA_FOR_DB = "TEXT";
|
||||
|
||||
public ClobSerializer() throws SQLException {
|
||||
super(TYPE_OF_DATA_FOR_DB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the input node to its XML String Representation.
|
||||
*
|
||||
* @param node XML Node that is to be converted to string
|
||||
* @return String representation of XML parsed from the Node
|
||||
* @throws TransformerException If any issues occur in Transformation from Node to XML
|
||||
*/
|
||||
private static String elementToXmlString(Element node) throws TransformerException {
|
||||
StringWriter sw = new StringWriter();
|
||||
Transformer t = TransformerFactory.newDefaultInstance().newTransformer();
|
||||
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||
t.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
t.transform(new DOMSource(node), new StreamResult(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the input object graph to its XML Representation using DOM Elements.
|
||||
*
|
||||
* @param forest Object which is to be serialized
|
||||
* @return Serialized object
|
||||
* @throws ParserConfigurationException If any issues occur in parsing input object
|
||||
* @throws TransformerException If any issues occur in Transformation from Node to XML
|
||||
*/
|
||||
@Override
|
||||
public Object serialize(Forest forest) throws ParserConfigurationException, TransformerException {
|
||||
Element xmlElement = forest.toXmlElement();
|
||||
return elementToXmlString(xmlElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the input XML string using DOM Parser and return its Object Graph Representation.
|
||||
*
|
||||
* @param toDeserialize Input Object to De-serialize
|
||||
* @return Deserialized Object
|
||||
* @throws ParserConfigurationException If any issues occur in parsing input object
|
||||
* @throws IOException if any issues occur during reading object
|
||||
* @throws SAXException If any issues occur in Transformation from Node to XML
|
||||
*/
|
||||
@Override
|
||||
public Forest deSerialize(Object toDeserialize)
|
||||
throws ParserConfigurationException, IOException, SAXException {
|
||||
DocumentBuilder documentBuilder = DocumentBuilderFactory.newDefaultInstance()
|
||||
.newDocumentBuilder();
|
||||
var stream = new ByteArrayInputStream(toDeserialize.toString().getBytes());
|
||||
Document parsed = documentBuilder.parse(stream);
|
||||
Forest forest = new Forest();
|
||||
forest.createObjectFromXml(parsed);
|
||||
return forest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob.serializers;
|
||||
|
||||
import com.iluwatar.slob.dbservice.DatabaseService;
|
||||
import com.iluwatar.slob.lob.Forest;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* A LobSerializer can be used to create an instance of a serializer which can serialize and
|
||||
* deserialize an object and persist and load that object into a DB. from their Binary
|
||||
* Representation.
|
||||
*/
|
||||
public abstract class LobSerializer implements Serializable, Closeable {
|
||||
|
||||
private final transient DatabaseService databaseService;
|
||||
|
||||
/**
|
||||
* Constructor initializes {@link LobSerializer#databaseService}.
|
||||
*
|
||||
* @param dataTypeDb Input provides type of Data to be stored by the Data Base Service
|
||||
* @throws SQLException If any issue occurs during instantiation of DB Service or during startup.
|
||||
*/
|
||||
protected LobSerializer(String dataTypeDb) throws SQLException {
|
||||
databaseService = new DatabaseService(dataTypeDb);
|
||||
databaseService.startupService();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the specification to Serialize the input object.
|
||||
*
|
||||
* @param toSerialize Input Object to serialize
|
||||
* @return Serialized Object
|
||||
* @throws ParserConfigurationException if any issue occurs during parsing of input object
|
||||
* @throws TransformerException if any issue occurs during Transformation
|
||||
* @throws IOException if any issues occur during reading object
|
||||
*/
|
||||
public abstract Object serialize(Forest toSerialize)
|
||||
throws ParserConfigurationException, TransformerException, IOException;
|
||||
|
||||
/**
|
||||
* Saves the object to DB with the provided ID.
|
||||
*
|
||||
* @param id key to be sent to DB service
|
||||
* @param name Object name to store in DB
|
||||
* @param object Object to store in DB
|
||||
* @return ID with which the object is stored in DB
|
||||
* @throws SQLException if any issue occurs while saving to DB
|
||||
*/
|
||||
public int persistToDb(int id, String name, Object object) throws SQLException {
|
||||
databaseService.insert(id, name, object);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the object from db using the ID and column name.
|
||||
*
|
||||
* @param id to query the DB
|
||||
* @param columnName column from which object is to be extracted
|
||||
* @return Object from DB
|
||||
* @throws SQLException if any issue occurs while loading from DB
|
||||
*/
|
||||
public Object loadFromDb(int id, String columnName) throws SQLException {
|
||||
return databaseService.select(id, columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the specification to Deserialize the input object.
|
||||
*
|
||||
* @param toDeserialize object to deserialize
|
||||
* @return Deserialized Object
|
||||
* @throws ParserConfigurationException If issue occurs during parsing of input object
|
||||
* @throws IOException if any issues occur during reading object
|
||||
* @throws SAXException if any issues occur during reading object for XML parsing
|
||||
*/
|
||||
public abstract Forest deSerialize(Object toDeserialize)
|
||||
throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
databaseService.shutDownService();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||
*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2022 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.slob;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
import com.iluwatar.slob.lob.Animal;
|
||||
import com.iluwatar.slob.lob.Forest;
|
||||
import com.iluwatar.slob.lob.Plant;
|
||||
import com.iluwatar.slob.serializers.BlobSerializer;
|
||||
import com.iluwatar.slob.serializers.ClobSerializer;
|
||||
import com.iluwatar.slob.serializers.LobSerializer;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* SLOB Application test
|
||||
*/
|
||||
@Slf4j
|
||||
class AppTest {
|
||||
|
||||
/**
|
||||
* Creates a Forest with Animals and Plants along with their respective relationships.
|
||||
* <p> The method creates a forest with 2 Plants Grass and Oak of type Herb and tree
|
||||
* respectively.</p>
|
||||
* <p> It also creates 3 animals Zebra and Buffalo which eat the plant grass. Lion consumes the
|
||||
* Zebra and the Buffalo.</p>
|
||||
* <p>With the above animals and plants and their relationships a forest
|
||||
* object is created which represents the Object Graph.</p>
|
||||
*
|
||||
* @return Forest Object
|
||||
*/
|
||||
private static Forest createForest() {
|
||||
Plant grass = new Plant("Grass", "Herb");
|
||||
Plant oak = new Plant("Oak", "Tree");
|
||||
|
||||
Animal zebra = new Animal("Zebra", Set.of(grass), Collections.emptySet());
|
||||
Animal buffalo = new Animal("Buffalo", Set.of(grass), Collections.emptySet());
|
||||
Animal lion = new Animal("Lion", Collections.emptySet(), Set.of(zebra, buffalo));
|
||||
|
||||
return new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the {@link App} without passing any argument in the args to test the
|
||||
* {@link ClobSerializer}.
|
||||
*/
|
||||
@Test
|
||||
void shouldExecuteWithoutExceptionClob() {
|
||||
assertDoesNotThrow(() -> App.main(new String[]{"CLOB"}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the {@link App} without passing any argument in the args to test the
|
||||
* {@link BlobSerializer}.
|
||||
*/
|
||||
@Test
|
||||
void shouldExecuteWithoutExceptionBlob() {
|
||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the serialization of the input object using the {@link ClobSerializer} and persists the
|
||||
* serialized object to DB, then load the object back from DB and deserializes it using the
|
||||
* provided {@link ClobSerializer}.<p>After loading the object back from DB the test matches the
|
||||
* hash of the input object with the hash of the object that was loaded from DB and deserialized.
|
||||
*/
|
||||
@Test
|
||||
void clobSerializerTest() {
|
||||
Forest forest = createForest();
|
||||
try (LobSerializer serializer = new ClobSerializer()) {
|
||||
|
||||
Object serialized = serializer.serialize(forest);
|
||||
int id = serializer.persistToDb(1, forest.getName(), serialized);
|
||||
|
||||
Object fromDb = serializer.loadFromDb(id, Forest.class.getSimpleName());
|
||||
Forest forestFromDb = serializer.deSerialize(fromDb);
|
||||
|
||||
Assertions.assertEquals(forest.hashCode(), forestFromDb.hashCode(),
|
||||
"Hashes of objects after Serializing and Deserializing are the same");
|
||||
} catch (SQLException | IOException | TransformerException | ParserConfigurationException |
|
||||
SAXException |
|
||||
ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the serialization of the input object using the {@link BlobSerializer} and persists the
|
||||
* serialized object to DB, then loads the object back from DB and deserializes it using the
|
||||
* {@link BlobSerializer}.<p>After loading the object back from DB the test matches the hash of
|
||||
* the input object with the hash of the object that was loaded from DB and deserialized.
|
||||
*/
|
||||
@Test
|
||||
void blobSerializerTest() {
|
||||
Forest forest = createForest();
|
||||
try (LobSerializer serializer = new BlobSerializer()) {
|
||||
|
||||
Object serialized = serializer.serialize(forest);
|
||||
int id = serializer.persistToDb(1, forest.getName(), serialized);
|
||||
|
||||
Object fromDb = serializer.loadFromDb(id, Forest.class.getSimpleName());
|
||||
Forest forestFromDb = serializer.deSerialize(fromDb);
|
||||
|
||||
Assertions.assertEquals(forest.hashCode(), forestFromDb.hashCode(),
|
||||
"Hashes of objects after Serializing and Deserializing are the same");
|
||||
} catch (SQLException | IOException | TransformerException | ParserConfigurationException |
|
||||
SAXException |
|
||||
ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user