From 78f72ec4ca6bd2827d19a44809451acd9f2143fd Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 17:14:54 +0530 Subject: [PATCH 01/44] #1596:Adding module for SLOB Pattern --- pom.xml | 1 + slob/README.md | 21 +++++ slob/etc/slob.urm.puml | 84 +++++++++++++++++++ slob/pom.xml | 64 ++++++++++++++ slob/src/main/java/com/iluwatar/slob/App.java | 35 ++++++++ .../test/java/com/iluwatar/slob/AppTest.java | 40 +++++++++ 6 files changed, 245 insertions(+) create mode 100644 slob/README.md create mode 100644 slob/etc/slob.urm.puml create mode 100644 slob/pom.xml create mode 100644 slob/src/main/java/com/iluwatar/slob/App.java create mode 100644 slob/src/test/java/com/iluwatar/slob/AppTest.java diff --git a/pom.xml b/pom.xml index 4169976ff444..b5430c7b44f3 100644 --- a/pom.xml +++ b/pom.xml @@ -208,6 +208,7 @@ thread-local-storage optimistic-offline-lock crtp + slob diff --git a/slob/README.md b/slob/README.md new file mode 100644 index 000000000000..659da6e31968 --- /dev/null +++ b/slob/README.md @@ -0,0 +1,21 @@ +--- +title: Step Builder +category: Creational +language: en +tag: + - Instantiation +--- + +## Intent +An extension of the Builder pattern that fully guides the user through the creation of the object with no chances of confusion. +The user experience will be much more improved by the fact that he will only see the next step methods available, NO build method until is the right time to build the object. + +## Class diagram +![alt text](./etc/step-builder.png "Step Builder") + +## Applicability +Use the Step Builder pattern when the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled the construction process must allow different representations for the object that's constructed when in the process of constructing the order is important. + +## Credits + +* [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html) diff --git a/slob/etc/slob.urm.puml b/slob/etc/slob.urm.puml new file mode 100644 index 000000000000..e9137a61c94d --- /dev/null +++ b/slob/etc/slob.urm.puml @@ -0,0 +1,84 @@ +@startuml +package com.iluwatar.stepbuilder { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Character { + - abilities : List + - fighterClass : String + - name : String + - spell : String + - weapon : String + - wizardClass : String + + Character(name : String) + + getAbilities() : List + + getFighterClass() : String + + getName() : String + + getSpell() : String + + getWeapon() : String + + getWizardClass() : String + + setAbilities(abilities : List) + + setFighterClass(fighterClass : String) + + setName(name : String) + + setSpell(spell : String) + + setWeapon(weapon : String) + + setWizardClass(wizardClass : String) + + toString() : String + } + class CharacterStepBuilder { + - CharacterStepBuilder() + + newBuilder() : NameStep {static} + } + interface AbilityStep { + + noAbilities() : BuildStep {abstract} + + noMoreAbilities() : BuildStep {abstract} + + withAbility(String) : AbilityStep {abstract} + } + interface BuildStep { + + build() : Character {abstract} + } + -class CharacterSteps { + - abilities : List + - fighterClass : String + - name : String + - spell : String + - weapon : String + - wizardClass : String + - CharacterSteps() + + build() : Character + + fighterClass(fighterClass : String) : WeaponStep + + name(name : String) : ClassStep + + noAbilities() : BuildStep + + noMoreAbilities() : BuildStep + + noSpell() : BuildStep + + noWeapon() : BuildStep + + withAbility(ability : String) : AbilityStep + + withSpell(spell : String) : AbilityStep + + withWeapon(weapon : String) : AbilityStep + + wizardClass(wizardClass : String) : SpellStep + } + interface ClassStep { + + fighterClass(String) : WeaponStep {abstract} + + wizardClass(String) : SpellStep {abstract} + } + interface NameStep { + + name(String) : ClassStep {abstract} + } + interface SpellStep { + + noSpell() : BuildStep {abstract} + + withSpell(String) : AbilityStep {abstract} + } + interface WeaponStep { + + noWeapon() : BuildStep {abstract} + + withWeapon(String) : AbilityStep {abstract} + } +} +CharacterSteps ..|> NameStep +CharacterSteps ..|> ClassStep +CharacterSteps ..|> WeaponStep +CharacterSteps ..|> SpellStep +CharacterSteps ..|> AbilityStep +CharacterSteps ..|> BuildStep +@enduml \ No newline at end of file diff --git a/slob/pom.xml b/slob/pom.xml new file mode 100644 index 000000000000..a1f5bd0bb6f3 --- /dev/null +++ b/slob/pom.xml @@ -0,0 +1,64 @@ + + + + slob + + + + maven-assembly-plugin + + + + + + com.iluwatar.slob.App + + + + + + org.apache.maven.plugins + + + + + + junit-jupiter-engine + org.junit.jupiter + test + + + 4.0.0 + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java new file mode 100644 index 000000000000..7380ba18c8cb --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -0,0 +1,35 @@ +/* + * 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; + +/** + * Application. + */ +public class App { + + public static void main(String[] args) { + // TODO Completion + } +} diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java new file mode 100644 index 000000000000..67a63265cc19 --- /dev/null +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -0,0 +1,40 @@ +/* + * 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 org.junit.jupiter.api.Test; + +/** + * Application test + */ +class AppTest { + + @Test + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} From 4db8fad5e62c2aa7aa893f51dc75ea90cf5a0b73 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:49:48 +0530 Subject: [PATCH 02/44] #1596:Adding Interface for Serializers --- .../slob/serializers/LobSerializer.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java new file mode 100644 index 000000000000..6964743995d5 --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -0,0 +1,43 @@ +package com.iluwatar.slob.serializers; + +import com.iluwatar.slob.lob.Customer; +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; + +public abstract class LobSerializer implements Serializable, Closeable { + + public static final DatabaseService databaseService = new DatabaseService(); + + protected LobSerializer() throws SQLException { + databaseService.startupService(); + } + + public abstract Object serialize(Customer toSerialize) + throws SQLException, ParserConfigurationException, TransformerException; + + public int persistToDb(int id, String name, Object customer) throws SQLException { + databaseService.insert(id, name, customer); + return id; + } + + public Object loadFromDb(int id, String columnName) throws SQLException { + return databaseService.select(id, columnName); + } + + public abstract Customer deSerialize(Object toSerialize) + throws ParserConfigurationException, IOException, SAXException; + + @Override + public void close() throws IOException { + try { + databaseService.shutDownService(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} From fb9dd9671901e0317021c758feb2be09b37f84ea Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:50:25 +0530 Subject: [PATCH 03/44] #1596:Adding Objects --- .../java/com/iluwatar/slob/lob/Customer.java | 71 +++++++++++++++++++ .../java/com/iluwatar/slob/lob/Product.java | 60 ++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 slob/src/main/java/com/iluwatar/slob/lob/Customer.java create mode 100644 slob/src/main/java/com/iluwatar/slob/lob/Product.java diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java b/slob/src/main/java/com/iluwatar/slob/lob/Customer.java new file mode 100644 index 000000000000..b61b53b143a5 --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/lob/Customer.java @@ -0,0 +1,71 @@ +/* + * 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.util.ArrayList; +import java.util.List; +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.Node; + +/** + * Application. + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Customer { + + private String name; + private List products; + + public Element departmentsToXmlElement(Document xmlDoc) throws ParserConfigurationException { + Element root = xmlDoc.createElement("departments"); + for (Product product : products) { + Element xmlElement = product.toXmlElement(xmlDoc); + if (xmlElement != null) { + root.appendChild(xmlElement); + } + } + xmlDoc.appendChild(root); + return (Element) xmlDoc.getFirstChild(); + } + + public Customer readDepartments(Element source) { + List result = new ArrayList(); + Node child = source.getFirstChild(); + while (child != null) { + if (child.getNodeType() == 1) { + System.out.println(child); + } + child = child.getNextSibling(); + } + return null; + } +} diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Product.java b/slob/src/main/java/com/iluwatar/slob/lob/Product.java new file mode 100644 index 000000000000..8b498e33f8ce --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/lob/Product.java @@ -0,0 +1,60 @@ +/* + * 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.util.List; +import javax.xml.parsers.ParserConfigurationException; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Application. + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Product { + + private String name; + private List products; + + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + Element root = xmlDoc.createElement("department"); + root.setAttribute("name", name); + if (products != null) { + for (Product product : products) { + Element productXmlElement = product.toXmlElement(xmlDoc); + if (productXmlElement != null) { + root.appendChild(productXmlElement); + } + } + } + xmlDoc.appendChild(root); + return xmlDoc.getDocumentElement(); + } +} From 04379bbcb93982bf5a1071a8657eb27afd1a6c9e Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:51:09 +0530 Subject: [PATCH 04/44] #1596:Adding BLOB Based Serializer --- .../slob/serializers/BlobSerializer.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java new file mode 100644 index 000000000000..83b9fe1c428d --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -0,0 +1,22 @@ +package com.iluwatar.slob.serializers; + +import com.iluwatar.slob.lob.Customer; +import java.sql.SQLException; + +public class BlobSerializer extends LobSerializer { + + protected BlobSerializer() throws SQLException { + } + + @Override + public Object serialize(Customer toSerialize) { + // TODO: Yet to do + return 0; + } + + @Override + public Customer deSerialize(Object toSerialize) { + // TODO: Yet to do + return null; + } +} From e1d4a9bf1ccbc77aa7c1810e51731ad40430fb7d Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:51:52 +0530 Subject: [PATCH 05/44] #1596:Implemented Clob Based Serializer --- .../slob/serializers/ClobSerializer.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java new file mode 100644 index 000000000000..86a845c5512e --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -0,0 +1,58 @@ +package com.iluwatar.slob.serializers; + +import com.iluwatar.slob.lob.Customer; +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; + +public class ClobSerializer extends LobSerializer { + + public ClobSerializer() throws SQLException { + super(); + } + + 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(); + } + + @Override + public Object serialize(Customer customer) + throws ParserConfigurationException, TransformerException { + Document xmlDoc = getXmlDoc(); + return elementToXmlString(customer.departmentsToXmlElement(xmlDoc)); + } + + private Document getXmlDoc() throws ParserConfigurationException { + return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); + } + + @Override + public Customer deSerialize(Object toDeSerialize) + throws ParserConfigurationException, IOException, SAXException { + DocumentBuilder documentBuilder = DocumentBuilderFactory.newDefaultInstance() + .newDocumentBuilder(); + var stream = new ByteArrayInputStream(toDeSerialize.toString().getBytes()); + Document parse = documentBuilder.parse(stream); + Customer customer = new Customer(); + customer.readDepartments(parse.getDocumentElement()); + return null; + } +} From e8eefa422fa643637a785d1240fa1ff5a35eb233 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:52:53 +0530 Subject: [PATCH 06/44] #1596:Implemented Service for DB operations --- .../slob/serializers/DatabaseService.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java new file mode 100644 index 000000000000..0dbdd57f5c1e --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java @@ -0,0 +1,76 @@ +package com.iluwatar.slob.serializers; + +import java.sql.ResultSet; +import java.sql.SQLException; +import javax.sql.DataSource; +import lombok.extern.slf4j.Slf4j; +import org.h2.jdbcx.JdbcDataSource; + +@Slf4j +public class DatabaseService { + + public static final String CREATE_SCHEMA_SQL = + "CREATE TABLE IF NOT EXISTS CUSTOMERS (ID NUMBER UNIQUE, NAME" + + " VARCHAR(30),PRODUCTS VARCHAR)"; + public static final String DELETE_SCHEMA_SQL = "DROP TABLE CUSTOMERS IF " + + "EXISTS"; + private static final String DB_URL = "jdbc:h2:~/test"; + private static final String INSERT = "insert into customers (id,name, products) values (?,?,?)"; + + private static final String SELECT = "select products from customers where id = ?"; + + private static final DataSource dataSource = createDataSource(); + + private static DataSource createDataSource() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + return dataSource; + } + + public void shutDownService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + statement.execute(DELETE_SCHEMA_SQL); + } + } + + public void startupService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + statement.execute(CREATE_SCHEMA_SQL); + } + } + + 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(); + } + } + + protected Object select(final long id1, String columnsName) throws SQLException { + ResultSet resultSet = null; + try (var connection = dataSource.getConnection(); + var preparedStatement = + connection.prepareStatement(SELECT) + ) { + var result = ""; + preparedStatement.setLong(1, id1); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + result = resultSet.getString(columnsName); + } + return result; + } finally { + if (resultSet != null) { + resultSet.close(); + } + } + } +} From b52130d325f97641164e0667bcede7663b4c27aa Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:53:25 +0530 Subject: [PATCH 07/44] #1596:Implemented basic flow using Clob Serializer --- slob/src/main/java/com/iluwatar/slob/App.java | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 7380ba18c8cb..3d4ad0049824 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -24,12 +24,47 @@ */ package com.iluwatar.slob; +import com.iluwatar.slob.lob.Customer; +import com.iluwatar.slob.lob.Product; +import com.iluwatar.slob.serializers.ClobSerializer; +import com.iluwatar.slob.serializers.LobSerializer; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import lombok.extern.slf4j.Slf4j; +import org.xml.sax.SAXException; + /** * Application. */ +@Slf4j public class App { - public static void main(String[] args) { - // TODO Completion + public static void main(String[] args) throws SQLException { + + Product product = new Product("Mountains", List.of(new Product("Iron", null))); + Customer customer = new Customer("Ram", List.of(product)); + + LobSerializer serializer = new ClobSerializer(); + executeSerializer(customer, serializer); + + } + + private static void executeSerializer(Customer customer, LobSerializer lobSerializer) { + try (LobSerializer serializer = lobSerializer) { + + Object serialized = serializer.serialize(customer); + int id = serializer.persistToDb(1, customer.getName(), serialized); + + Object fromDb = serializer.loadFromDb(id, "products"); + Customer customerFromDb = serializer.deSerialize(fromDb); + + System.out.println(customerFromDb); + } catch (SQLException | IOException | TransformerException | ParserConfigurationException | + SAXException e) { + throw new RuntimeException(e); + } } } From d46e771f8315e1ff45a98b80ffe240e9d6ee462a Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 22 Oct 2023 20:53:56 +0530 Subject: [PATCH 08/44] #1596:Added H2 DB Dependency --- slob/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/slob/pom.xml b/slob/pom.xml index a1f5bd0bb6f3..15122c385db1 100644 --- a/slob/pom.xml +++ b/slob/pom.xml @@ -54,6 +54,10 @@ org.junit.jupiter test + + h2 + com.h2database + 4.0.0 From 338d0ea84cf0e6ea7ce60ea7bbfe758683a48c29 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Tue, 24 Oct 2023 20:42:31 +0530 Subject: [PATCH 09/44] #1596:Added Java Doc Stubs --- slob/pom.xml | 5 ++++ slob/src/main/java/com/iluwatar/slob/App.java | 18 +++++++++-- .../java/com/iluwatar/slob/lob/Customer.java | 13 ++++++-- .../java/com/iluwatar/slob/lob/Product.java | 5 ++++ .../slob/serializers/BlobSerializer.java | 8 +++++ .../slob/serializers/ClobSerializer.java | 25 ++++++++++++++-- .../slob/serializers/LobSerializer.java | 30 +++++++++++++++++++ 7 files changed, 97 insertions(+), 7 deletions(-) diff --git a/slob/pom.xml b/slob/pom.xml index 15122c385db1..a5dd1c338c0a 100644 --- a/slob/pom.xml +++ b/slob/pom.xml @@ -58,6 +58,11 @@ h2 com.h2database + + lombok + org.projectlombok + provided + 4.0.0 diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 3d4ad0049824..5d2bca94d128 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -34,6 +34,8 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; /** @@ -42,6 +44,12 @@ @Slf4j public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * @param args + * @throws SQLException + */ public static void main(String[] args) throws SQLException { Product product = new Product("Mountains", List.of(new Product("Iron", null))); @@ -52,6 +60,10 @@ public static void main(String[] args) throws SQLException { } + /** + * @param customer + * @param lobSerializer + */ private static void executeSerializer(Customer customer, LobSerializer lobSerializer) { try (LobSerializer serializer = lobSerializer) { @@ -61,9 +73,9 @@ private static void executeSerializer(Customer customer, LobSerializer lobSerial Object fromDb = serializer.loadFromDb(id, "products"); Customer customerFromDb = serializer.deSerialize(fromDb); - System.out.println(customerFromDb); - } catch (SQLException | IOException | TransformerException | ParserConfigurationException | - SAXException e) { + LOGGER.info(customerFromDb.toString()); + } catch (SQLException | IOException | TransformerException | ParserConfigurationException + | SAXException e) { throw new RuntimeException(e); } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java b/slob/src/main/java/com/iluwatar/slob/lob/Customer.java index b61b53b143a5..1daeb25158ee 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Customer.java @@ -45,6 +45,11 @@ public class Customer { private String name; private List products; + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ public Element departmentsToXmlElement(Document xmlDoc) throws ParserConfigurationException { Element root = xmlDoc.createElement("departments"); for (Product product : products) { @@ -57,12 +62,16 @@ public Element departmentsToXmlElement(Document xmlDoc) throws ParserConfigurati return (Element) xmlDoc.getFirstChild(); } + /** + * @param source + * @return + */ public Customer readDepartments(Element source) { List result = new ArrayList(); Node child = source.getFirstChild(); while (child != null) { - if (child.getNodeType() == 1) { - System.out.println(child); + if (child.getNodeType() == Node.ELEMENT_NODE && child.getTextContent() != null) { + System.out.println(child.getAttributes()); } child = child.getNextSibling(); } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Product.java b/slob/src/main/java/com/iluwatar/slob/lob/Product.java index 8b498e33f8ce..557eeecbba30 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Product.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Product.java @@ -43,6 +43,11 @@ public class Product { private String name; private List products; + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { Element root = xmlDoc.createElement("department"); root.setAttribute("name", name); diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 83b9fe1c428d..eedebe685bfa 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -8,12 +8,20 @@ public class BlobSerializer extends LobSerializer { protected BlobSerializer() throws SQLException { } + /** + * @param toSerialize + * @return + */ @Override public Object serialize(Customer toSerialize) { // TODO: Yet to do return 0; } + /** + * @param toSerialize + * @return + */ @Override public Customer deSerialize(Object toSerialize) { // TODO: Yet to do diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 86a845c5512e..77572da6ba82 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -24,6 +24,11 @@ public ClobSerializer() throws SQLException { super(); } + /** + * @param node + * @return + * @throws TransformerException + */ private static String elementToXmlString(Element node) throws TransformerException { StringWriter sw = new StringWriter(); Transformer t = TransformerFactory.newDefaultInstance().newTransformer(); @@ -33,6 +38,12 @@ private static String elementToXmlString(Element node) throws TransformerExcepti return sw.toString(); } + /** + * @param customer + * @return + * @throws ParserConfigurationException + * @throws TransformerException + */ @Override public Object serialize(Customer customer) throws ParserConfigurationException, TransformerException { @@ -40,10 +51,21 @@ public Object serialize(Customer customer) return elementToXmlString(customer.departmentsToXmlElement(xmlDoc)); } + /** + * @return + * @throws ParserConfigurationException + */ private Document getXmlDoc() throws ParserConfigurationException { return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); } + /** + * @param toDeSerialize + * @return + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ @Override public Customer deSerialize(Object toDeSerialize) throws ParserConfigurationException, IOException, SAXException { @@ -52,7 +74,6 @@ public Customer deSerialize(Object toDeSerialize) var stream = new ByteArrayInputStream(toDeSerialize.toString().getBytes()); Document parse = documentBuilder.parse(stream); Customer customer = new Customer(); - customer.readDepartments(parse.getDocumentElement()); - return null; + return customer.readDepartments(parse.getDocumentElement()); } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 6964743995d5..f9e6fa397444 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -13,22 +13,52 @@ public abstract class LobSerializer implements Serializable, Closeable { public static final DatabaseService databaseService = new DatabaseService(); + /** + * @throws SQLException + */ protected LobSerializer() throws SQLException { databaseService.startupService(); } + /** + * @param toSerialize + * @return + * @throws SQLException + * @throws ParserConfigurationException + * @throws TransformerException + */ public abstract Object serialize(Customer toSerialize) throws SQLException, ParserConfigurationException, TransformerException; + /** + * @param id + * @param name + * @param customer + * @return + * @throws SQLException + */ public int persistToDb(int id, String name, Object customer) throws SQLException { databaseService.insert(id, name, customer); return id; } + /** + * @param id + * @param columnName + * @return + * @throws SQLException + */ public Object loadFromDb(int id, String columnName) throws SQLException { return databaseService.select(id, columnName); } + /** + * @param toSerialize + * @return + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ public abstract Customer deSerialize(Object toSerialize) throws ParserConfigurationException, IOException, SAXException; From 26789e567c982fc09e6531df4a8996db208f4b20 Mon Sep 17 00:00:00 2001 From: SHRADDHAP18 <87650482+SHRADDHAP18@users.noreply.github.com> Date: Thu, 21 Dec 2023 20:45:16 +0530 Subject: [PATCH 10/44] Updating Objects --- .../java/com/iluwatar/slob/lob/Customer.java | 22 ++++++--- .../java/com/iluwatar/slob/lob/Product.java | 48 +++++++++++-------- .../slob/serializers/ClobSerializer.java | 1 + 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java b/slob/src/main/java/com/iluwatar/slob/lob/Customer.java index 1daeb25158ee..b91e4c556a58 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Customer.java @@ -32,6 +32,7 @@ import lombok.NoArgsConstructor; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** @@ -51,14 +52,17 @@ public class Customer { * @throws ParserConfigurationException */ public Element departmentsToXmlElement(Document xmlDoc) throws ParserConfigurationException { - Element root = xmlDoc.createElement("departments"); + Element customers = xmlDoc.createElement(Customer.class.getSimpleName()+'s'); for (Product product : products) { Element xmlElement = product.toXmlElement(xmlDoc); if (xmlElement != null) { - root.appendChild(xmlElement); + Element customer = xmlDoc.createElement(Customer.class.getSimpleName()); + customer.setAttribute("name",this.getName()); + customer.appendChild(xmlElement); + customers.appendChild(customer); } } - xmlDoc.appendChild(root); + xmlDoc.appendChild(customers); return (Element) xmlDoc.getFirstChild(); } @@ -67,14 +71,18 @@ public Element departmentsToXmlElement(Document xmlDoc) throws ParserConfigurati * @return */ public Customer readDepartments(Element source) { - List result = new ArrayList(); + Customer customer = new Customer(); Node child = source.getFirstChild(); while (child != null) { - if (child.getNodeType() == Node.ELEMENT_NODE && child.getTextContent() != null) { - System.out.println(child.getAttributes()); + if (child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(Customer.class.getSimpleName())) { + NamedNodeMap attributes = child.getAttributes(); + customer.setName(child.getAttributes().getNamedItem("name").getNodeValue()); + for (int i = 0; i < attributes.getLength(); i++) { + System.out.println(child.getAttributes().item(i)); + } } child = child.getNextSibling(); } - return null; + return customer; } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Product.java b/slob/src/main/java/com/iluwatar/slob/lob/Product.java index 557eeecbba30..494aafdc67ce 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Product.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Product.java @@ -26,6 +26,7 @@ import java.util.List; import javax.xml.parsers.ParserConfigurationException; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -40,26 +41,35 @@ @NoArgsConstructor public class Product { - private String name; - private List products; + private String name; + private List products; + + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + Element productsNode = xmlDoc.createElement(Product.class.getSimpleName() + "s"); + + addToProducts(xmlDoc, productsNode, this); + xmlDoc.appendChild(productsNode); + return xmlDoc.getDocumentElement(); + } - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { - Element root = xmlDoc.createElement("department"); - root.setAttribute("name", name); - if (products != null) { - for (Product product : products) { - Element productXmlElement = product.toXmlElement(xmlDoc); - if (productXmlElement != null) { - root.appendChild(productXmlElement); + private Element addToProducts(Document xmlDoc, Element productsNode, Product productI) throws ParserConfigurationException { + Element productNode = null; + if (productI != null) { + productNode = xmlDoc.createElement(Product.class.getSimpleName()); + productNode.setAttribute("name", name); + productsNode.appendChild(productNode); + if (productI.getProducts() != null) { + for (Product product : productI.getProducts()) { + Element productXmlElement = product.addToProducts(xmlDoc, productsNode, product); + productsNode.appendChild(productXmlElement); + } + } } - } + return productNode; } - xmlDoc.appendChild(root); - return xmlDoc.getDocumentElement(); - } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 77572da6ba82..4dc577d9941f 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -74,6 +74,7 @@ public Customer deSerialize(Object toDeSerialize) var stream = new ByteArrayInputStream(toDeSerialize.toString().getBytes()); Document parse = documentBuilder.parse(stream); Customer customer = new Customer(); + parse.getDocumentElement().normalize(); return customer.readDepartments(parse.getDocumentElement()); } } From eedf641f33cb9c324a0bdc6b54abaed883418634 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sat, 20 Jan 2024 17:17:35 +0530 Subject: [PATCH 11/44] #1596:Completed Clob Serializer along with Tests --- slob/pom.xml | 93 ++++++------- slob/src/main/java/com/iluwatar/slob/App.java | 77 ++++++----- .../slob/dbservice/DatabaseService.java | 79 ++++++++++++ .../java/com/iluwatar/slob/lob/Animal.java | 122 ++++++++++++++++++ .../java/com/iluwatar/slob/lob/Forest.java | 78 +++++++++++ .../slob/lob/{Customer.java => Plant.java} | 66 +++++----- .../java/com/iluwatar/slob/lob/Product.java | 65 ---------- .../slob/serializers/ClobSerializer.java | 113 ++++++++-------- .../slob/serializers/DatabaseService.java | 76 ----------- .../slob/serializers/LobSerializer.java | 115 +++++++++-------- .../test/java/com/iluwatar/slob/AppTest.java | 77 ++++++++++- 11 files changed, 585 insertions(+), 376 deletions(-) create mode 100644 slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java create mode 100644 slob/src/main/java/com/iluwatar/slob/lob/Animal.java create mode 100644 slob/src/main/java/com/iluwatar/slob/lob/Forest.java rename slob/src/main/java/com/iluwatar/slob/lob/{Customer.java => Plant.java} (60%) delete mode 100644 slob/src/main/java/com/iluwatar/slob/lob/Product.java delete mode 100644 slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java diff --git a/slob/pom.xml b/slob/pom.xml index a5dd1c338c0a..5f95d4c1b2c2 100644 --- a/slob/pom.xml +++ b/slob/pom.xml @@ -26,48 +26,53 @@ --> - slob - - - - maven-assembly-plugin - - - - - - com.iluwatar.slob.App - - - - - - org.apache.maven.plugins - - - - - - junit-jupiter-engine - org.junit.jupiter - test - - - h2 - com.h2database - - - lombok - org.projectlombok - provided - - - 4.0.0 - - java-design-patterns - com.iluwatar - 1.26.0-SNAPSHOT - + 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"> + + slob + 4.0.0 + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + + + + + maven-assembly-plugin + + + + + + com.iluwatar.slob.App + + + + + + org.apache.maven.plugins + + + + + + + junit-jupiter-engine + org.junit.jupiter + test + + + h2 + com.h2database + 2.2.220 + + + lombok + org.projectlombok + provided + + + diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 5d2bca94d128..1a899761b840 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -24,59 +24,70 @@ */ package com.iluwatar.slob; -import com.iluwatar.slob.lob.Customer; -import com.iluwatar.slob.lob.Product; +import com.iluwatar.slob.lob.Animal; +import com.iluwatar.slob.lob.Forest; +import com.iluwatar.slob.lob.Plant; import com.iluwatar.slob.serializers.ClobSerializer; import com.iluwatar.slob.serializers.LobSerializer; -import java.io.IOException; -import java.sql.SQLException; -import java.util.List; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Set; + /** * Application. */ @Slf4j public class App { - private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); - /** - * @param args - * @throws SQLException - */ - public static void main(String[] args) throws SQLException { + /** + * @param args + * @throws SQLException + */ + public static void main(String[] args) throws SQLException { - Product product = new Product("Mountains", List.of(new Product("Iron", null))); - Customer customer = new Customer("Ram", List.of(product)); + Plant grass = new Plant("Grass", "Herb"); + Plant oak = new Plant("Oak", "Tree"); - LobSerializer serializer = new ClobSerializer(); - executeSerializer(customer, serializer); + 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)); - } + Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); + + LobSerializer serializer = new ClobSerializer(); + executeSerializer(forest, serializer); + } - /** - * @param customer - * @param lobSerializer - */ - private static void executeSerializer(Customer customer, LobSerializer lobSerializer) { - try (LobSerializer serializer = lobSerializer) { + /** + * @param forest + * @param lobSerializer + */ + private static void executeSerializer(Forest forest, LobSerializer lobSerializer) { + try (LobSerializer serializer = lobSerializer) { - Object serialized = serializer.serialize(customer); - int id = serializer.persistToDb(1, customer.getName(), serialized); + Object serialized = serializer.serialize(forest); + int id = serializer.persistToDb(1, forest.getName(), serialized); - Object fromDb = serializer.loadFromDb(id, "products"); - Customer customerFromDb = serializer.deSerialize(fromDb); + Object fromDb = serializer.loadFromDb(id, Forest.class.getSimpleName()); + Forest forestFromDb = serializer.deSerialize(fromDb); - LOGGER.info(customerFromDb.toString()); - } catch (SQLException | IOException | TransformerException | ParserConfigurationException - | SAXException e) { - throw new RuntimeException(e); + LOGGER.info(forestFromDb.toString()); + if (forest.hashCode() == forestFromDb.hashCode()) { + LOGGER.info("Objects Before And After Serialization are Same"); + } + } catch (SQLException | IOException | TransformerException | ParserConfigurationException | SAXException | + ClassNotFoundException e) { + throw new RuntimeException(e); + } } - } } diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java new file mode 100644 index 000000000000..ca96184a7b34 --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -0,0 +1,79 @@ +package com.iluwatar.slob.dbservice; + +import lombok.extern.slf4j.Slf4j; +import org.h2.jdbcx.JdbcDataSource; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; + +@Slf4j +public class DatabaseService { + + public static final String CREATE_SCHEMA_SQL = + "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"; + 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(); + + private static DataSource createDataSource() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + return dataSource; + } + + public void shutDownService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + statement.execute(DELETE_SCHEMA_SQL); + } + } + + public void startupService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + statement.execute(CREATE_SCHEMA_SQL); + } + } + + public boolean insert(int id, String name, Object data) + throws SQLException { + boolean execute; + try (var connection = dataSource.getConnection(); + var insert = connection.prepareStatement(INSERT)) { + insert.setInt(1, id); + insert.setString(2, name); + insert.setObject(3, data); + execute = insert.execute(); + } + return execute; + } + + public Object select(final long id1, String columnsName) throws SQLException { + ResultSet resultSet = null; + try (var connection = dataSource.getConnection(); + var preparedStatement = + connection.prepareStatement(SELECT) + ) { + var result = ""; + preparedStatement.setLong(1, id1); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + result = resultSet.getString(columnsName); + } + return result; + } finally { + if (resultSet != null) { + resultSet.close(); + } + } + } +} diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java new file mode 100644 index 000000000000..27e95a5f819b --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -0,0 +1,122 @@ +/* + * 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 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; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * Application. + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Animal implements Serializable { + + private String name; + private Set plantsEaten = new HashSet<>(); + private Set animalsEaten = new HashSet<>(); + + protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animalsEaten, Set 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); + } + } + } + } + + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + 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(); + } + + /** + * @param node + * @return + */ + 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(); + } +} diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Forest.java b/slob/src/main/java/com/iluwatar/slob/lob/Forest.java new file mode 100644 index 000000000000..01bdbb662a28 --- /dev/null +++ b/slob/src/main/java/com/iluwatar/slob/lob/Forest.java @@ -0,0 +1,78 @@ +package com.iluwatar.slob.lob; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import static com.iluwatar.slob.lob.Animal.iterateXmlForAnimalAndPlants; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Forest implements Serializable { + + private String name; + private Set animals = new HashSet<>(); + private Set plants = new HashSet<>(); + + 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; + } + + private Document getXmlDoc() throws ParserConfigurationException { + return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); + } + + 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(); + } +} diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java similarity index 60% rename from slob/src/main/java/com/iluwatar/slob/lob/Customer.java rename to slob/src/main/java/com/iluwatar/slob/lob/Plant.java index 1daeb25158ee..4d49d055ca00 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Customer.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java @@ -24,57 +24,53 @@ */ package com.iluwatar.slob.lob; -import java.util.ArrayList; -import java.util.List; -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.NamedNodeMap; import org.w3c.dom.Node; +import javax.xml.parsers.ParserConfigurationException; +import java.io.Serializable; +import java.util.StringJoiner; + /** * Application. */ @Data @AllArgsConstructor @NoArgsConstructor -public class Customer { +public class Plant implements Serializable { - private String name; - private List products; + private String name; + private String type; + + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + Element root = xmlDoc.createElement(Plant.class.getSimpleName()); + root.setAttribute("name", name); + root.setAttribute("type", type); + xmlDoc.appendChild(root); + return xmlDoc.getDocumentElement(); + } - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element departmentsToXmlElement(Document xmlDoc) throws ParserConfigurationException { - Element root = xmlDoc.createElement("departments"); - for (Product product : products) { - Element xmlElement = product.toXmlElement(xmlDoc); - if (xmlElement != null) { - root.appendChild(xmlElement); - } + public void createObjectFromXml(Node node) { + NamedNodeMap attributes = node.getAttributes(); + name = attributes.getNamedItem("name").getNodeValue(); + type = attributes.getNamedItem("type").getNodeValue(); } - xmlDoc.appendChild(root); - return (Element) xmlDoc.getFirstChild(); - } - /** - * @param source - * @return - */ - public Customer readDepartments(Element source) { - List result = new ArrayList(); - Node child = source.getFirstChild(); - while (child != null) { - if (child.getNodeType() == Node.ELEMENT_NODE && child.getTextContent() != null) { - System.out.println(child.getAttributes()); - } - child = child.getNextSibling(); + @Override + public String toString() { + StringJoiner stringJoiner = new StringJoiner(","); + stringJoiner.add("Name = " + name); + stringJoiner.add("Type = " + type); + return stringJoiner.toString(); } - return null; - } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Product.java b/slob/src/main/java/com/iluwatar/slob/lob/Product.java deleted file mode 100644 index 557eeecbba30..000000000000 --- a/slob/src/main/java/com/iluwatar/slob/lob/Product.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.util.List; -import javax.xml.parsers.ParserConfigurationException; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -/** - * Application. - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class Product { - - private String name; - private List products; - - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { - Element root = xmlDoc.createElement("department"); - root.setAttribute("name", name); - if (products != null) { - for (Product product : products) { - Element productXmlElement = product.toXmlElement(xmlDoc); - if (productXmlElement != null) { - root.appendChild(productXmlElement); - } - } - } - xmlDoc.appendChild(root); - return xmlDoc.getDocumentElement(); - } -} diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 77572da6ba82..6636d2dd932f 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -1,10 +1,10 @@ package com.iluwatar.slob.serializers; -import com.iluwatar.slob.lob.Customer; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.sql.SQLException; +import com.iluwatar.slob.lob.Forest; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -14,66 +14,57 @@ 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; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.sql.SQLException; public class ClobSerializer extends LobSerializer { - public ClobSerializer() throws SQLException { - super(); - } - - /** - * @param node - * @return - * @throws TransformerException - */ - 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(); - } + public ClobSerializer() throws SQLException { + super(); + } - /** - * @param customer - * @return - * @throws ParserConfigurationException - * @throws TransformerException - */ - @Override - public Object serialize(Customer customer) - throws ParserConfigurationException, TransformerException { - Document xmlDoc = getXmlDoc(); - return elementToXmlString(customer.departmentsToXmlElement(xmlDoc)); - } + /** + * @param node + * @return + * @throws TransformerException + */ + 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(); + } - /** - * @return - * @throws ParserConfigurationException - */ - private Document getXmlDoc() throws ParserConfigurationException { - return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); - } + /** + * @param forest + * @return + * @throws ParserConfigurationException + * @throws TransformerException + */ + @Override + public Object serialize(Forest forest) + throws ParserConfigurationException, TransformerException { + Element xmlElement = forest.toXmlElement(); + return elementToXmlString(xmlElement); + } - /** - * @param toDeSerialize - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException - */ - @Override - public Customer deSerialize(Object toDeSerialize) - throws ParserConfigurationException, IOException, SAXException { - DocumentBuilder documentBuilder = DocumentBuilderFactory.newDefaultInstance() - .newDocumentBuilder(); - var stream = new ByteArrayInputStream(toDeSerialize.toString().getBytes()); - Document parse = documentBuilder.parse(stream); - Customer customer = new Customer(); - return customer.readDepartments(parse.getDocumentElement()); - } + /** + * @return + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + @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; + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java deleted file mode 100644 index 0dbdd57f5c1e..000000000000 --- a/slob/src/main/java/com/iluwatar/slob/serializers/DatabaseService.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.iluwatar.slob.serializers; - -import java.sql.ResultSet; -import java.sql.SQLException; -import javax.sql.DataSource; -import lombok.extern.slf4j.Slf4j; -import org.h2.jdbcx.JdbcDataSource; - -@Slf4j -public class DatabaseService { - - public static final String CREATE_SCHEMA_SQL = - "CREATE TABLE IF NOT EXISTS CUSTOMERS (ID NUMBER UNIQUE, NAME" - + " VARCHAR(30),PRODUCTS VARCHAR)"; - public static final String DELETE_SCHEMA_SQL = "DROP TABLE CUSTOMERS IF " - + "EXISTS"; - private static final String DB_URL = "jdbc:h2:~/test"; - private static final String INSERT = "insert into customers (id,name, products) values (?,?,?)"; - - private static final String SELECT = "select products from customers where id = ?"; - - private static final DataSource dataSource = createDataSource(); - - private static DataSource createDataSource() { - var dataSource = new JdbcDataSource(); - dataSource.setURL(DB_URL); - return dataSource; - } - - public void shutDownService() - throws SQLException { - try (var connection = dataSource.getConnection(); - var statement = connection.createStatement()) { - statement.execute(DELETE_SCHEMA_SQL); - } - } - - public void startupService() - throws SQLException { - try (var connection = dataSource.getConnection(); - var statement = connection.createStatement()) { - statement.execute(CREATE_SCHEMA_SQL); - } - } - - 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(); - } - } - - protected Object select(final long id1, String columnsName) throws SQLException { - ResultSet resultSet = null; - try (var connection = dataSource.getConnection(); - var preparedStatement = - connection.prepareStatement(SELECT) - ) { - var result = ""; - preparedStatement.setLong(1, id1); - resultSet = preparedStatement.executeQuery(); - while (resultSet.next()) { - result = resultSet.getString(columnsName); - } - return result; - } finally { - if (resultSet != null) { - resultSet.close(); - } - } - } -} diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index f9e6fa397444..4780018485a5 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -1,73 +1,76 @@ package com.iluwatar.slob.serializers; -import com.iluwatar.slob.lob.Customer; +import com.iluwatar.slob.dbservice.DatabaseService; +import com.iluwatar.slob.lob.Forest; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; 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; public abstract class LobSerializer implements Serializable, Closeable { - public static final DatabaseService databaseService = new DatabaseService(); + public static final DatabaseService databaseService = new DatabaseService(); - /** - * @throws SQLException - */ - protected LobSerializer() throws SQLException { - databaseService.startupService(); - } + /** + * @throws SQLException + */ + protected LobSerializer() throws SQLException { + databaseService.startupService(); + } - /** - * @param toSerialize - * @return - * @throws SQLException - * @throws ParserConfigurationException - * @throws TransformerException - */ - public abstract Object serialize(Customer toSerialize) - throws SQLException, ParserConfigurationException, TransformerException; + /** + * @param toSerialize + * @return + * @throws SQLException + * @throws ParserConfigurationException + * @throws TransformerException + */ + public abstract Object serialize(Forest toSerialize) + throws SQLException, ParserConfigurationException, TransformerException, IOException; - /** - * @param id - * @param name - * @param customer - * @return - * @throws SQLException - */ - public int persistToDb(int id, String name, Object customer) throws SQLException { - databaseService.insert(id, name, customer); - return id; - } + /** + * @param id + * @param name + * @param customer + * @return + * @throws SQLException + */ + public int persistToDb(int id, String name, Object customer) throws SQLException { + databaseService.insert(id, name, customer); + return id; - /** - * @param id - * @param columnName - * @return - * @throws SQLException - */ - public Object loadFromDb(int id, String columnName) throws SQLException { - return databaseService.select(id, columnName); - } + } + + /** + * @param id + * @param columnName + * @return + * @throws SQLException + */ + public Object loadFromDb(int id, String columnName) throws SQLException { + return databaseService.select(id, columnName); + } - /** - * @param toSerialize - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException - */ - public abstract Customer deSerialize(Object toSerialize) - throws ParserConfigurationException, IOException, SAXException; + /** + * @param toSerialize + * @return + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + public abstract Forest deSerialize(Object toSerialize) + throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; - @Override - public void close() throws IOException { - try { - databaseService.shutDownService(); - } catch (SQLException e) { - throw new RuntimeException(e); + @Override + public void close() throws IOException { + try { + databaseService.shutDownService(); + } catch (SQLException e) { + throw new RuntimeException(e); + } } - } } diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index 67a63265cc19..6941eb599215 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -24,17 +24,82 @@ */ 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 lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; /** * Application test */ +@Slf4j class AppTest { - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); - } + 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)); + } + + @Test + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } + + @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); + } + } + + @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); + } + } } From dc5658a70cf01c5d4bc5c678751765d8bbf483cd Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sat, 20 Jan 2024 22:06:17 +0530 Subject: [PATCH 12/44] #1596:Completed Slob Serializer along with Tests --- .../slob/dbservice/DatabaseService.java | 6 +- .../slob/serializers/BlobSerializer.java | 56 ++++++++++++------- .../test/java/com/iluwatar/slob/AppTest.java | 1 - 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index ca96184a7b34..d255b24ba64b 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -11,10 +11,8 @@ public class DatabaseService { public static final String CREATE_SCHEMA_SQL = - "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"; + "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"; private static final String DB_URL = "jdbc:h2:~/test"; private static final String INSERT = "insert into FORESTS (id,name, forest) values (?,?,?)"; diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index eedebe685bfa..fbd4fd13820e 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -1,30 +1,44 @@ package com.iluwatar.slob.serializers; -import com.iluwatar.slob.lob.Customer; +import com.iluwatar.slob.lob.Forest; + +import java.io.*; import java.sql.SQLException; +import java.util.Base64; public class BlobSerializer extends LobSerializer { - protected BlobSerializer() throws SQLException { - } + /** + * @throws SQLException + */ + public BlobSerializer() throws SQLException { + } - /** - * @param toSerialize - * @return - */ - @Override - public Object serialize(Customer toSerialize) { - // TODO: Yet to do - return 0; - } + /** + * @param toSerialize + * @return + */ + @Override + public Object serialize(Forest toSerialize) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(toSerialize); + oos.close(); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } - /** - * @param toSerialize - * @return - */ - @Override - public Customer deSerialize(Object toSerialize) { - // TODO: Yet to do - return null; - } + /** + * @param toDeserialize + * @return + */ + @Override + public Forest deSerialize(Object toDeserialize) throws IOException, ClassNotFoundException { + byte[] decoded = Base64.getDecoder().decode(toDeserialize.toString()); + InputStream bis = new ByteArrayInputStream(decoded); + Forest forest; + try (ObjectInput in = new ObjectInputStream(bis)) { + forest = (Forest) in.readObject(); + } + return forest; + } } diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index 6941eb599215..c5ba8e5eaffe 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -68,7 +68,6 @@ void shouldExecuteWithoutException() { @Test void clobSerializerTest() { - Forest forest = createForest(); try (LobSerializer serializer = new ClobSerializer()) { From 133ed50af5e26c5a59cb76fb35e5201713372f48 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sat, 20 Jan 2024 22:06:17 +0530 Subject: [PATCH 13/44] #1596:Completed Blob Serializer along with Tests --- .../slob/dbservice/DatabaseService.java | 6 +- .../slob/serializers/BlobSerializer.java | 56 ++++++++++++------- .../test/java/com/iluwatar/slob/AppTest.java | 1 - 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index ca96184a7b34..d255b24ba64b 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -11,10 +11,8 @@ public class DatabaseService { public static final String CREATE_SCHEMA_SQL = - "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"; + "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"; private static final String DB_URL = "jdbc:h2:~/test"; private static final String INSERT = "insert into FORESTS (id,name, forest) values (?,?,?)"; diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index eedebe685bfa..fbd4fd13820e 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -1,30 +1,44 @@ package com.iluwatar.slob.serializers; -import com.iluwatar.slob.lob.Customer; +import com.iluwatar.slob.lob.Forest; + +import java.io.*; import java.sql.SQLException; +import java.util.Base64; public class BlobSerializer extends LobSerializer { - protected BlobSerializer() throws SQLException { - } + /** + * @throws SQLException + */ + public BlobSerializer() throws SQLException { + } - /** - * @param toSerialize - * @return - */ - @Override - public Object serialize(Customer toSerialize) { - // TODO: Yet to do - return 0; - } + /** + * @param toSerialize + * @return + */ + @Override + public Object serialize(Forest toSerialize) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(toSerialize); + oos.close(); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } - /** - * @param toSerialize - * @return - */ - @Override - public Customer deSerialize(Object toSerialize) { - // TODO: Yet to do - return null; - } + /** + * @param toDeserialize + * @return + */ + @Override + public Forest deSerialize(Object toDeserialize) throws IOException, ClassNotFoundException { + byte[] decoded = Base64.getDecoder().decode(toDeserialize.toString()); + InputStream bis = new ByteArrayInputStream(decoded); + Forest forest; + try (ObjectInput in = new ObjectInputStream(bis)) { + forest = (Forest) in.readObject(); + } + return forest; + } } diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index 6941eb599215..c5ba8e5eaffe 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -68,7 +68,6 @@ void shouldExecuteWithoutException() { @Test void clobSerializerTest() { - Forest forest = createForest(); try (LobSerializer serializer = new ClobSerializer()) { From 9fd27e15ea00adf86a13c0337b9d857cca901d78 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 11:02:12 +0530 Subject: [PATCH 14/44] #1596:Updated DatabaseService to handle Blob and Clob Data --- .../slob/dbservice/DatabaseService.java | 26 ++++++++++++++----- .../slob/serializers/BlobSerializer.java | 9 ++++--- .../slob/serializers/ClobSerializer.java | 4 ++- .../slob/serializers/LobSerializer.java | 5 ++-- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index d255b24ba64b..9ce16cb096f9 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -9,16 +9,20 @@ @Slf4j public class DatabaseService { - - public static final String CREATE_SCHEMA_SQL = + public static final String CREATE_BLOB_SCHEMA_SQL = + "CREATE TABLE IF NOT EXISTS FORESTS (ID NUMBER UNIQUE, NAME VARCHAR(30),FOREST VARBINARY)"; + public static final String CREATE_CLOB_SCHEMA_SQL = "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"; 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 typeOfDataForDB; + + public DatabaseService(String typeOfDataForDB) { + this.typeOfDataForDB = typeOfDataForDB; + } private static DataSource createDataSource() { var dataSource = new JdbcDataSource(); @@ -38,7 +42,11 @@ public void startupService() throws SQLException { try (var connection = dataSource.getConnection(); var statement = connection.createStatement()) { - statement.execute(CREATE_SCHEMA_SQL); + if (typeOfDataForDB.equals("BLOB")) { + statement.execute(CREATE_BLOB_SCHEMA_SQL); + } else { + statement.execute(CREATE_CLOB_SCHEMA_SQL); + } } } @@ -61,11 +69,15 @@ public Object select(final long id1, String columnsName) throws SQLException { var preparedStatement = connection.prepareStatement(SELECT) ) { - var result = ""; + Object result = null; preparedStatement.setLong(1, id1); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { - result = resultSet.getString(columnsName); + if (typeOfDataForDB.equals("BLOB")) { + result = resultSet.getBinaryStream(columnsName); + } else { + result = resultSet.getString(columnsName); + } } return result; } finally { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index fbd4fd13820e..306fb5fc9dbf 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -4,14 +4,16 @@ import java.io.*; import java.sql.SQLException; -import java.util.Base64; public class BlobSerializer extends LobSerializer { + public static final String typeOfDataForDB = "BLOB"; + /** * @throws SQLException */ public BlobSerializer() throws SQLException { + super(typeOfDataForDB); } /** @@ -24,7 +26,7 @@ public Object serialize(Forest toSerialize) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(toSerialize); oos.close(); - return Base64.getEncoder().encodeToString(baos.toByteArray()); + return new ByteArrayInputStream(baos.toByteArray()); } /** @@ -33,8 +35,7 @@ public Object serialize(Forest toSerialize) throws IOException { */ @Override public Forest deSerialize(Object toDeserialize) throws IOException, ClassNotFoundException { - byte[] decoded = Base64.getDecoder().decode(toDeserialize.toString()); - InputStream bis = new ByteArrayInputStream(decoded); + InputStream bis = (InputStream) toDeserialize; Forest forest; try (ObjectInput in = new ObjectInputStream(bis)) { forest = (Forest) in.readObject(); diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 6636d2dd932f..115c9b1bb975 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -21,8 +21,10 @@ public class ClobSerializer extends LobSerializer { + public static final String typeOfDataForDB = "CLOB"; + public ClobSerializer() throws SQLException { - super(); + super(typeOfDataForDB); } /** diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 4780018485a5..a6b9faf6677e 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -13,12 +13,13 @@ public abstract class LobSerializer implements Serializable, Closeable { - public static final DatabaseService databaseService = new DatabaseService(); + public final DatabaseService databaseService; /** * @throws SQLException */ - protected LobSerializer() throws SQLException { + protected LobSerializer(String typeOfDataForDB) throws SQLException { + databaseService = new DatabaseService(typeOfDataForDB); databaseService.startupService(); } From bb3059c485c50628a716d14579b476f883097de8 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 11:24:46 +0530 Subject: [PATCH 15/44] #1596:Added UML and updated README.md --- slob/README.md | 28 ++++++--- slob/etc/slob.urm.png | Bin 0 -> 40078 bytes slob/etc/slob.urm.puml | 129 +++++++++++++++-------------------------- 3 files changed, 67 insertions(+), 90 deletions(-) create mode 100644 slob/etc/slob.urm.png diff --git a/slob/README.md b/slob/README.md index 659da6e31968..60504d5f9381 100644 --- a/slob/README.md +++ b/slob/README.md @@ -1,21 +1,33 @@ --- -title: Step Builder -category: Creational +title: Serialized LOB +category: Structural language: en tag: - - Instantiation + - Object Instantiation --- ## Intent -An extension of the Builder pattern that fully guides the user through the creation of the object with no chances of confusion. -The user experience will be much more improved by the fact that he will only see the next step methods available, NO build method until is the right time to build the object. + +Object models often contain complicated graphs of small objects. Much of the +information in these structures isn’t in the objects but in the links between +them. Objects don’t have to be persisted as table rows related to each other. +Another form of persistence is serialization, where a whole graph of objects is +written out as a single large object (LOB) in a table. ## Class diagram -![alt text](./etc/step-builder.png "Step Builder") + +![alt text](./etc/slob.urm.png "Serialized LOB") ## Applicability -Use the Step Builder pattern when the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled the construction process must allow different representations for the object that's constructed when in the process of constructing the order is important. + +Serialized LOB isn’t considered as often as it might be. XML makes it much more +attractive since it yields a easy-to-implement textual approach. Its main disadvantage is that you can’t query the +structure using SQL. +SQL extensions appear to get at XML data within a field, but that’s still not the same (or portable). +This pattern works best when you can chop out a piece of the object model and use it to represent the LOB. Think of a +LOB as a way to take a bunch of +objects that aren’t likely to be queried from any SQL route outside the application. This graph can then be hooked into +the SQL schema. ## Credits -* [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html) diff --git a/slob/etc/slob.urm.png b/slob/etc/slob.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..e852dfb21d0858e2b10fb712bce5a6606e0d267b GIT binary patch literal 40078 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 TXR63eH!w!jW)aO{m6-sq}){Pd|Xk=6F-9LzB8 zUCBP?F>gs~DsI7HixmG_b}P>HMirqdQ%m+MEFilCv!o!>w=-1Nh}MLj*M9lFSQKy% znMqx^{BT=m+Z|r1+t0pMm)5)3n} z_kj}^lloq%cD{~uu$EG&6j{|a7JwM_1LN7JF_+Zg+1@X_l3GW;$_UH@=)zaT8)$Tq~0IOq(=72hB8IrcB@Hmf`vJUGOKU zsMyKM8o70EEr?L2mT!vGnX;JPyB>kG%GA0)#!{{%#AByfp`G4s9Z7IPnRlZ1{u$#M zp#Re3E%n@OQ<=CCkuB`KxH{kMbxMTvY-pCY`kPv8fq}ba2oZ>po|>9e`-GyN1u>(^6|x|D==)YsRef+Ur_-j?mw zG%JVfDtXJCy&9n=&ukLsG~cE2a>UV0y^l`s-zXFwVDef?qsP;IA!h%3#k3n($?{Zv zEmi+=Z*sq*+`k=L-=7fo_jz7)t{%Ug5{ZU_s9XJZd5eDa&!Jl?epB$krS_77C4R_f zk^cMHzs&m5cX$0iJ8pfny^WMfv?|vK$qfug&81sf&*)KE=QqR1HOpE3bO>I~>_qsI z0p2-NA<5uoF6WC&eQlMsDgB5z0Wd#4wb0`F~pV!-UWb8yOeog zvns}_m-GJeQSMzj;R8Op$DqgyDUa9`eGXiWab#S9nHn31vLOavu3$@{;S=#Pw_3Stj<8p*0J>nKx~5=#Ey3((k9g~BwGzV z2&K%LiG9f&v-tQL&XeR_6rI#OCmKvE9;9Mm;TL~uE-1i56k;Az-b#=5s5R}%syO)c z5;7scOFKJ?-A6m*->Bj2UcLjBIFxjE8Q-um6%rD%^!a(n9sGw~KxsMi_7-q_B_lDN zSDBjCMZFq=)4mYLgvKkB)N|2x$+$6bdZ_spO1Tmz=fB^pic$hPiC{Xj+#cV<(n_#g zEG^#y;94u9`&BRVJc{iXHvjw0%<6*lj)oyd+TI6yLzlY>1u9gJO?T=ML;VU9XTwH9 zHs_u3+Pj>Y3{GI-ZOqaO9)}?%#^4GHKK

mA2!mP{u5l9)S15t+zWj-|K)fu0!sI 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 rbp1(wZRBN)BvL*V`g`pz@Eb literal 0 HcmV?d00001 diff --git a/slob/etc/slob.urm.puml b/slob/etc/slob.urm.puml index e9137a61c94d..1d9de1e46d3b 100644 --- a/slob/etc/slob.urm.puml +++ b/slob/etc/slob.urm.puml @@ -1,84 +1,49 @@ @startuml -package com.iluwatar.stepbuilder { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - class Character { - - abilities : List - - fighterClass : String - - name : String - - spell : String - - weapon : String - - wizardClass : String - + Character(name : String) - + getAbilities() : List - + getFighterClass() : String - + getName() : String - + getSpell() : String - + getWeapon() : String - + getWizardClass() : String - + setAbilities(abilities : List) - + setFighterClass(fighterClass : String) - + setName(name : String) - + setSpell(spell : String) - + setWeapon(weapon : String) - + setWizardClass(wizardClass : String) - + toString() : String - } - class CharacterStepBuilder { - - CharacterStepBuilder() - + newBuilder() : NameStep {static} - } - interface AbilityStep { - + noAbilities() : BuildStep {abstract} - + noMoreAbilities() : BuildStep {abstract} - + withAbility(String) : AbilityStep {abstract} - } - interface BuildStep { - + build() : Character {abstract} - } - -class CharacterSteps { - - abilities : List - - fighterClass : String - - name : String - - spell : String - - weapon : String - - wizardClass : String - - CharacterSteps() - + build() : Character - + fighterClass(fighterClass : String) : WeaponStep - + name(name : String) : ClassStep - + noAbilities() : BuildStep - + noMoreAbilities() : BuildStep - + noSpell() : BuildStep - + noWeapon() : BuildStep - + withAbility(ability : String) : AbilityStep - + withSpell(spell : String) : AbilityStep - + withWeapon(weapon : String) : AbilityStep - + wizardClass(wizardClass : String) : SpellStep - } - interface ClassStep { - + fighterClass(String) : WeaponStep {abstract} - + wizardClass(String) : SpellStep {abstract} - } - interface NameStep { - + name(String) : ClassStep {abstract} - } - interface SpellStep { - + noSpell() : BuildStep {abstract} - + withSpell(String) : AbilityStep {abstract} - } - interface WeaponStep { - + noWeapon() : BuildStep {abstract} - + withWeapon(String) : AbilityStep {abstract} - } + +!theme plain +top to bottom direction +skinparam linetype ortho + +class Animal { + - animalsEaten: Set + - name: String + - plantsEaten: Set + animalsEaten: Set + name: String + plantsEaten: Set } -CharacterSteps ..|> NameStep -CharacterSteps ..|> ClassStep -CharacterSteps ..|> WeaponStep -CharacterSteps ..|> SpellStep -CharacterSteps ..|> AbilityStep -CharacterSteps ..|> BuildStep -@enduml \ No newline at end of file +class App +class BlobSerializer +class ClobSerializer +class DatabaseService +class Forest { + - animals: Set + - name: String + - plants: Set + animals: Set + name: String + plants: Set + 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 From b19d34c978fc0429ba908c22fa47224e35c8d613 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 11:42:02 +0530 Subject: [PATCH 16/44] #1596:Updated data types for DB --- .../iluwatar/slob/dbservice/DatabaseService.java | 13 +++++++------ .../iluwatar/slob/serializers/BlobSerializer.java | 2 +- .../iluwatar/slob/serializers/ClobSerializer.java | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index 9ce16cb096f9..95b8ff403c3f 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -9,11 +9,12 @@ @Slf4j public class DatabaseService { - public static final String CREATE_BLOB_SCHEMA_SQL = + 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_CLOB_SCHEMA_SQL = + 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 = ?"; @@ -42,10 +43,10 @@ public void startupService() throws SQLException { try (var connection = dataSource.getConnection(); var statement = connection.createStatement()) { - if (typeOfDataForDB.equals("BLOB")) { - statement.execute(CREATE_BLOB_SCHEMA_SQL); + if (typeOfDataForDB.equals("BINARY")) { + statement.execute(CREATE_BINARY_SCHEMA_DDL); } else { - statement.execute(CREATE_CLOB_SCHEMA_SQL); + statement.execute(CREATE_TEXT_SCHEMA_DDL); } } } @@ -73,7 +74,7 @@ public Object select(final long id1, String columnsName) throws SQLException { preparedStatement.setLong(1, id1); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { - if (typeOfDataForDB.equals("BLOB")) { + if (typeOfDataForDB.equals(BINARY_DATA)) { result = resultSet.getBinaryStream(columnsName); } else { result = resultSet.getString(columnsName); diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 306fb5fc9dbf..097776f4f62e 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -7,7 +7,7 @@ public class BlobSerializer extends LobSerializer { - public static final String typeOfDataForDB = "BLOB"; + public static final String typeOfDataForDB = "BINARY"; /** * @throws SQLException diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 115c9b1bb975..3c7b6034d7c9 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -21,7 +21,7 @@ public class ClobSerializer extends LobSerializer { - public static final String typeOfDataForDB = "CLOB"; + public static final String typeOfDataForDB = "TEXT"; public ClobSerializer() throws SQLException { super(typeOfDataForDB); From 5ac8d14197c002397fec570bd44f55e303fa8e63 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 13:23:21 +0530 Subject: [PATCH 17/44] #1596:Code Style Formatting Cnames --- .../java/com/iluwatar/slob/serializers/ClobSerializer.java | 3 +-- .../java/com/iluwatar/slob/serializers/LobSerializer.java | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 3c7b6034d7c9..e5ef5b540742 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -48,8 +48,7 @@ private static String elementToXmlString(Element node) throws TransformerExcepti * @throws TransformerException */ @Override - public Object serialize(Forest forest) - throws ParserConfigurationException, TransformerException { + public Object serialize(Forest forest) throws ParserConfigurationException, TransformerException { Element xmlElement = forest.toXmlElement(); return elementToXmlString(xmlElement); } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index a6b9faf6677e..53229656c7e0 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -30,8 +30,7 @@ protected LobSerializer(String typeOfDataForDB) throws SQLException { * @throws ParserConfigurationException * @throws TransformerException */ - public abstract Object serialize(Forest toSerialize) - throws SQLException, ParserConfigurationException, TransformerException, IOException; + public abstract Object serialize(Forest toSerialize) throws SQLException, ParserConfigurationException, TransformerException, IOException; /** * @param id @@ -63,8 +62,7 @@ public Object loadFromDb(int id, String columnName) throws SQLException { * @throws IOException * @throws SAXException */ - public abstract Forest deSerialize(Object toSerialize) - throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; + public abstract Forest deSerialize(Object toSerialize) throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; @Override public void close() throws IOException { From 3e9cb86fbb639dc2bb72c39eff45af4a6f5fd59a Mon Sep 17 00:00:00 2001 From: SHRADDHAP18 <87650482+SHRADDHAP18@users.noreply.github.com> Date: Sun, 21 Jan 2024 14:58:33 +0530 Subject: [PATCH 18/44] Adding Java Docs --- slob/src/main/java/com/iluwatar/slob/App.java | 13 ++++--- .../slob/serializers/BlobSerializer.java | 27 ++++++++++----- .../slob/serializers/ClobSerializer.java | 34 ++++++++++++------- .../slob/serializers/LobSerializer.java | 6 +++- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 1a899761b840..69cc11fe8701 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -42,7 +42,7 @@ import java.util.Set; /** - * Application. + * SLOB Application using Serializer. */ @Slf4j public class App { @@ -50,8 +50,7 @@ public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** - * @param args - * @throws SQLException + * @param args NA */ public static void main(String[] args) throws SQLException { @@ -69,8 +68,12 @@ public static void main(String[] args) throws SQLException { } /** - * @param forest - * @param lobSerializer + * Serialize the input object using the input serializer and persist to DB, then load the object + * back from DB and deserializing using the provided input Serializer. + * After loading from DB the method matches the hash of the input object with the hash of the object + * that was loaded from DB and deserialized. + * @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) { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 097776f4f62e..69bcd83a9f12 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -1,24 +1,30 @@ package com.iluwatar.slob.serializers; import com.iluwatar.slob.lob.Forest; +import org.xml.sax.SAXException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; import java.io.*; 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 typeOfDataForDB = "BINARY"; + public static final String TYPE_OF_DATA_FOR_DB = "BINARY"; - /** - * @throws SQLException - */ public BlobSerializer() throws SQLException { - super(typeOfDataForDB); + super(TYPE_OF_DATA_FOR_DB); } /** - * @param toSerialize - * @return + * Serialize 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 { @@ -30,8 +36,11 @@ public Object serialize(Forest toSerialize) throws IOException { } /** - * @param toDeserialize - * @return + * Deserialize 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 { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index e5ef5b540742..d4c6aab74fa1 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -19,18 +19,23 @@ import java.io.StringWriter; import java.sql.SQLException; +/** + * 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 typeOfDataForDB = "TEXT"; + public static final String TYPE_OF_DATA_FOR_DB = "TEXT"; public ClobSerializer() throws SQLException { - super(typeOfDataForDB); + super(TYPE_OF_DATA_FOR_DB); } /** - * @param node - * @return - * @throws TransformerException + * 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(); @@ -42,10 +47,11 @@ private static String elementToXmlString(Element node) throws TransformerExcepti } /** - * @param forest - * @return - * @throws ParserConfigurationException - * @throws TransformerException + * Serialize 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 { @@ -54,10 +60,12 @@ public Object serialize(Forest forest) throws ParserConfigurationException, Tran } /** - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException + * Deserialize 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 { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 53229656c7e0..3fca6b2772ca 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -11,9 +11,13 @@ import java.io.Serializable; import java.sql.SQLException; +/** + * Creates a Serializer that uses Binary serialization and deserialization of objects + * graph to and from their Binary Representation. + */ public abstract class LobSerializer implements Serializable, Closeable { - public final DatabaseService databaseService; + private final transient DatabaseService databaseService; /** * @throws SQLException From efe71f1f557d5a3f67ce5ace0c2571337e39cfd3 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 15:12:21 +0530 Subject: [PATCH 19/44] #1596:Reformatted as per Code Style --- slob/src/main/java/com/iluwatar/slob/App.java | 87 +++++------ .../slob/dbservice/DatabaseService.java | 142 +++++++++--------- .../java/com/iluwatar/slob/lob/Animal.java | 142 +++++++++--------- .../java/com/iluwatar/slob/lob/Forest.java | 107 +++++++------ .../java/com/iluwatar/slob/lob/Plant.java | 59 ++++---- .../slob/serializers/BlobSerializer.java | 85 ++++++----- .../slob/serializers/ClobSerializer.java | 118 ++++++++------- .../slob/serializers/LobSerializer.java | 115 +++++++------- .../test/java/com/iluwatar/slob/AppTest.java | 97 ++++++------ 9 files changed, 482 insertions(+), 470 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 69cc11fe8701..360bdb1325f9 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -29,17 +29,16 @@ import com.iluwatar.slob.lob.Plant; import com.iluwatar.slob.serializers.ClobSerializer; import com.iluwatar.slob.serializers.LobSerializer; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; 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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; /** * SLOB Application using Serializer. @@ -47,50 +46,52 @@ @Slf4j public class App { - private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); - /** - * @param args NA - */ - public static void main(String[] args) throws SQLException { + /** + * @param args NA + */ + public static void main(String[] args) throws SQLException { - Plant grass = new Plant("Grass", "Herb"); - Plant oak = new Plant("Oak", "Tree"); + 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)); + 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)); - Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); + Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); - LobSerializer serializer = new ClobSerializer(); - executeSerializer(forest, serializer); - } + LobSerializer serializer = new ClobSerializer(); + executeSerializer(forest, serializer); + } - /** - * Serialize the input object using the input serializer and persist to DB, then load the object - * back from DB and deserializing using the provided input Serializer. - * After loading from DB the method matches the hash of the input object with the hash of the object - * that was loaded from DB and deserialized. - * @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) { + /** + * Serialize the input object using the input serializer and persist to DB, then load the object + * back from DB and deserializing using the provided input Serializer. After loading from DB the + * method matches the hash of the input object with the hash of the object that was loaded from DB + * and deserialized. + * + * @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 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); + Object fromDb = serializer.loadFromDb(id, Forest.class.getSimpleName()); + Forest forestFromDb = serializer.deSerialize(fromDb); - LOGGER.info(forestFromDb.toString()); - if (forest.hashCode() == forestFromDb.hashCode()) { - LOGGER.info("Objects Before And After Serialization are Same"); - } - } catch (SQLException | IOException | TransformerException | ParserConfigurationException | SAXException | - ClassNotFoundException e) { - throw new RuntimeException(e); - } + LOGGER.info(forestFromDb.toString()); + if (forest.hashCode() == forestFromDb.hashCode()) { + LOGGER.info("Objects Before And After Serialization are Same"); + } + } catch (SQLException | IOException | TransformerException | ParserConfigurationException | + SAXException | + ClassNotFoundException e) { + throw new RuntimeException(e); } + } } diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index 95b8ff403c3f..c421b5745346 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -1,90 +1,90 @@ package com.iluwatar.slob.dbservice; -import lombok.extern.slf4j.Slf4j; -import org.h2.jdbcx.JdbcDataSource; - -import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; +import javax.sql.DataSource; +import lombok.extern.slf4j.Slf4j; +import org.h2.jdbcx.JdbcDataSource; @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 typeOfDataForDB; - public DatabaseService(String typeOfDataForDB) { - this.typeOfDataForDB = typeOfDataForDB; - } + 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 typeOfDataForDB; - private static DataSource createDataSource() { - var dataSource = new JdbcDataSource(); - dataSource.setURL(DB_URL); - return dataSource; - } + public DatabaseService(String typeOfDataForDB) { + this.typeOfDataForDB = typeOfDataForDB; + } - public void shutDownService() - throws SQLException { - try (var connection = dataSource.getConnection(); - var statement = connection.createStatement()) { - statement.execute(DELETE_SCHEMA_SQL); - } + private static DataSource createDataSource() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + return dataSource; + } + + public void shutDownService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + statement.execute(DELETE_SCHEMA_SQL); } + } - public void startupService() - throws SQLException { - try (var connection = dataSource.getConnection(); - var statement = connection.createStatement()) { - if (typeOfDataForDB.equals("BINARY")) { - statement.execute(CREATE_BINARY_SCHEMA_DDL); - } else { - statement.execute(CREATE_TEXT_SCHEMA_DDL); - } - } + public void startupService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + if (typeOfDataForDB.equals("BINARY")) { + statement.execute(CREATE_BINARY_SCHEMA_DDL); + } else { + statement.execute(CREATE_TEXT_SCHEMA_DDL); + } } + } - public boolean insert(int id, String name, Object data) - throws SQLException { - boolean execute; - try (var connection = dataSource.getConnection(); - var insert = connection.prepareStatement(INSERT)) { - insert.setInt(1, id); - insert.setString(2, name); - insert.setObject(3, data); - execute = insert.execute(); - } - return execute; + public boolean insert(int id, String name, Object data) + throws SQLException { + boolean execute; + try (var connection = dataSource.getConnection(); + var insert = connection.prepareStatement(INSERT)) { + insert.setInt(1, id); + insert.setString(2, name); + insert.setObject(3, data); + execute = insert.execute(); } + return execute; + } - public Object select(final long id1, String columnsName) throws SQLException { - ResultSet resultSet = null; - try (var connection = dataSource.getConnection(); - var preparedStatement = - connection.prepareStatement(SELECT) - ) { - Object result = null; - preparedStatement.setLong(1, id1); - resultSet = preparedStatement.executeQuery(); - while (resultSet.next()) { - if (typeOfDataForDB.equals(BINARY_DATA)) { - result = resultSet.getBinaryStream(columnsName); - } else { - result = resultSet.getString(columnsName); - } - } - return result; - } finally { - if (resultSet != null) { - resultSet.close(); - } + public Object select(final long id1, String columnsName) throws SQLException { + ResultSet resultSet = null; + try (var connection = dataSource.getConnection(); + var preparedStatement = + connection.prepareStatement(SELECT) + ) { + Object result = null; + preparedStatement.setLong(1, id1); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + if (typeOfDataForDB.equals(BINARY_DATA)) { + result = resultSet.getBinaryStream(columnsName); + } else { + result = resultSet.getString(columnsName); } + } + return result; + } finally { + if (resultSet != null) { + resultSet.close(); + } } + } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index 27e95a5f819b..ec160f05fdb1 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -24,6 +24,10 @@ */ package com.iluwatar.slob.lob; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -32,11 +36,6 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import javax.xml.parsers.ParserConfigurationException; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - /** * Application. */ @@ -45,78 +44,79 @@ @NoArgsConstructor public class Animal implements Serializable { - private String name; - private Set plantsEaten = new HashSet<>(); - private Set animalsEaten = new HashSet<>(); + private String name; + private Set plantsEaten = new HashSet<>(); + private Set animalsEaten = new HashSet<>(); - protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animalsEaten, Set 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); - } - } + protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animalsEaten, + Set 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); } + } } + } - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { - 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(); + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + 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); + } } - - /** - * @param node - * @return - */ - public void createObjectFromXml(Node node) { - name = node.getAttributes().getNamedItem("name").getNodeValue(); - NodeList childNodes = node.getChildNodes(); - iterateXmlForAnimalAndPlants(childNodes, animalsEaten, plantsEaten); + for (Animal animal : animalsEaten) { + Element xmlElement = animal.toXmlElement(xmlDoc); + if (xmlElement != null) { + root.appendChild(xmlElement); + } } + xmlDoc.appendChild(root); + return (Element) xmlDoc.getFirstChild(); + } - @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(); + /** + * @param node + * @return + */ + 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(); + } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Forest.java b/slob/src/main/java/com/iluwatar/slob/lob/Forest.java index 01bdbb662a28..ce95083f7d00 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Forest.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Forest.java @@ -1,5 +1,12 @@ 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; @@ -7,72 +14,64 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - -import static com.iluwatar.slob.lob.Animal.iterateXmlForAnimalAndPlants; - @Data @NoArgsConstructor @AllArgsConstructor public class Forest implements Serializable { - private String name; - private Set animals = new HashSet<>(); - private Set plants = new HashSet<>(); + private String name; + private Set animals = new HashSet<>(); + private Set plants = new HashSet<>(); - public Element toXmlElement() throws ParserConfigurationException { - Document xmlDoc = getXmlDoc(); + public Element toXmlElement() throws ParserConfigurationException { + Document xmlDoc = getXmlDoc(); - Element forestXml = xmlDoc.createElement("Forest"); - forestXml.setAttribute("name", name); + 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; + Element animalsXml = xmlDoc.createElement("Animals"); + for (Animal animal : animals) { + Element animalXml = animal.toXmlElement(xmlDoc); + animalsXml.appendChild(animalXml); } + forestXml.appendChild(animalsXml); - private Document getXmlDoc() throws ParserConfigurationException { - return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); + Element plantsXml = xmlDoc.createElement("Plants"); + for (Plant plant : plants) { + Element plantXml = plant.toXmlElement(xmlDoc); + plantsXml.appendChild(plantXml); } + forestXml.appendChild(plantsXml); + return forestXml; + } - public void createObjectFromXml(Document document) { - name = document.getDocumentElement().getAttribute("name"); - NodeList nodeList = document.getElementsByTagName("*"); - iterateXmlForAnimalAndPlants(nodeList, animals, plants); - } + private Document getXmlDoc() throws ParserConfigurationException { + return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); + } - @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(); + 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(); + } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java index 4d49d055ca00..80d65d6fd35f 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java @@ -24,6 +24,9 @@ */ package com.iluwatar.slob.lob; +import java.io.Serializable; +import java.util.StringJoiner; +import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -32,10 +35,6 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import javax.xml.parsers.ParserConfigurationException; -import java.io.Serializable; -import java.util.StringJoiner; - /** * Application. */ @@ -44,33 +43,33 @@ @NoArgsConstructor public class Plant implements Serializable { - private String name; - private String type; + private String name; + private String type; - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { - Element root = xmlDoc.createElement(Plant.class.getSimpleName()); - root.setAttribute("name", name); - root.setAttribute("type", type); - xmlDoc.appendChild(root); - return xmlDoc.getDocumentElement(); - } + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + Element root = xmlDoc.createElement(Plant.class.getSimpleName()); + root.setAttribute("name", name); + root.setAttribute("type", type); + xmlDoc.appendChild(root); + return xmlDoc.getDocumentElement(); + } - public void createObjectFromXml(Node node) { - NamedNodeMap attributes = node.getAttributes(); - name = attributes.getNamedItem("name").getNodeValue(); - type = attributes.getNamedItem("type").getNodeValue(); - } + 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(); - } + @Override + public String toString() { + StringJoiner stringJoiner = new StringJoiner(","); + stringJoiner.add("Name = " + name); + stringJoiner.add("Type = " + type); + return stringJoiner.toString(); + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 69bcd83a9f12..b104a5d63f59 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -1,54 +1,59 @@ package com.iluwatar.slob.serializers; import com.iluwatar.slob.lob.Forest; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import java.io.*; +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. + * 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 static final String TYPE_OF_DATA_FOR_DB = "BINARY"; - public BlobSerializer() throws SQLException { - super(TYPE_OF_DATA_FOR_DB); - } + public BlobSerializer() throws SQLException { + super(TYPE_OF_DATA_FOR_DB); + } - /** - * Serialize 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()); - } + /** + * Serialize 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()); + } - /** - * Deserialize 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; + /** + * Deserialize 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; + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index d4c6aab74fa1..b4151f51afe7 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -1,10 +1,10 @@ package com.iluwatar.slob.serializers; import com.iluwatar.slob.lob.Forest; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - +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; @@ -14,66 +14,70 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.sql.SQLException; +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. + * 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 static final String TYPE_OF_DATA_FOR_DB = "TEXT"; - public ClobSerializer() throws SQLException { - super(TYPE_OF_DATA_FOR_DB); - } + 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(); - } + /** + * 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(); + } - /** - * Serialize 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); - } + /** + * Serialize 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); + } - /** - * Deserialize 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; - } + /** + * Deserialize 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; + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 3fca6b2772ca..3f2619f1ed9a 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -2,78 +2,79 @@ import com.iluwatar.slob.dbservice.DatabaseService; import com.iluwatar.slob.lob.Forest; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; 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; /** - * Creates a Serializer that uses Binary serialization and deserialization of objects - * graph to and from their Binary Representation. + * Creates a Serializer that uses Binary serialization and deserialization of objects graph to and + * from their Binary Representation. */ public abstract class LobSerializer implements Serializable, Closeable { - private final transient DatabaseService databaseService; + private final transient DatabaseService databaseService; - /** - * @throws SQLException - */ - protected LobSerializer(String typeOfDataForDB) throws SQLException { - databaseService = new DatabaseService(typeOfDataForDB); - databaseService.startupService(); - } + /** + * @throws SQLException + */ + protected LobSerializer(String typeOfDataForDB) throws SQLException { + databaseService = new DatabaseService(typeOfDataForDB); + databaseService.startupService(); + } - /** - * @param toSerialize - * @return - * @throws SQLException - * @throws ParserConfigurationException - * @throws TransformerException - */ - public abstract Object serialize(Forest toSerialize) throws SQLException, ParserConfigurationException, TransformerException, IOException; + /** + * @param toSerialize + * @return + * @throws SQLException + * @throws ParserConfigurationException + * @throws TransformerException + */ + public abstract Object serialize(Forest toSerialize) + throws SQLException, ParserConfigurationException, TransformerException, IOException; - /** - * @param id - * @param name - * @param customer - * @return - * @throws SQLException - */ - public int persistToDb(int id, String name, Object customer) throws SQLException { - databaseService.insert(id, name, customer); - return id; + /** + * @param id + * @param name + * @param customer + * @return + * @throws SQLException + */ + public int persistToDb(int id, String name, Object customer) throws SQLException { + databaseService.insert(id, name, customer); + return id; - } + } - /** - * @param id - * @param columnName - * @return - * @throws SQLException - */ - public Object loadFromDb(int id, String columnName) throws SQLException { - return databaseService.select(id, columnName); - } + /** + * @param id + * @param columnName + * @return + * @throws SQLException + */ + public Object loadFromDb(int id, String columnName) throws SQLException { + return databaseService.select(id, columnName); + } - /** - * @param toSerialize - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException - */ - public abstract Forest deSerialize(Object toSerialize) throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; + /** + * @param toSerialize + * @return + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + public abstract Forest deSerialize(Object toSerialize) + throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; - @Override - public void close() throws IOException { - try { - databaseService.shutDownService(); - } catch (SQLException e) { - throw new RuntimeException(e); - } + @Override + public void close() throws IOException { + try { + databaseService.shutDownService(); + } catch (SQLException e) { + throw new RuntimeException(e); } + } } diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index c5ba8e5eaffe..0835ea701dc5 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -24,25 +24,24 @@ */ 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 lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; import java.io.IOException; import java.sql.SQLException; import java.util.Collections; import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +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; /** * Application test @@ -50,55 +49,59 @@ @Slf4j class AppTest { - private static Forest createForest() { - Plant grass = new Plant("Grass", "Herb"); - Plant oak = new Plant("Oak", "Tree"); + 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)); + 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)); - } + return new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); + } - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); - } + @Test + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } - @Test - void clobSerializerTest() { - Forest forest = createForest(); - try (LobSerializer serializer = new ClobSerializer()) { + @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 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); + 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); - } + 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); } + } - @Test - void blobSerializerTest() { - Forest forest = createForest(); - try (LobSerializer serializer = new BlobSerializer()) { + @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 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); + 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); - } + 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); } + } } From 1831f1f1d4f69055a177d823e46bd73fe03b1e0b Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 15:38:49 +0530 Subject: [PATCH 20/44] #1596:Updating Java Doc --- slob/src/main/java/com/iluwatar/slob/App.java | 4 +- .../slob/serializers/ClobSerializer.java | 6 +- .../slob/serializers/LobSerializer.java | 67 +++++++++++-------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 360bdb1325f9..6cb8acd604e3 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -41,7 +41,7 @@ import org.xml.sax.SAXException; /** - * SLOB Application using Serializer. + * SLOB Application using Serializer and H2 DB. */ @Slf4j public class App { @@ -49,6 +49,8 @@ public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** + * Main entry point to program + * * @param args NA */ public static void main(String[] args) throws SQLException { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index b4151f51afe7..fcd9911c7a03 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -63,18 +63,18 @@ public Object serialize(Forest forest) throws ParserConfigurationException, Tran /** * Deserialize the input XML string using DOM Parser and return its Object Graph Representation * - * @param toDeSerialize Input Object to De-serialize + * @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) + public Forest deSerialize(Object toDeserialize) throws ParserConfigurationException, IOException, SAXException { DocumentBuilder documentBuilder = DocumentBuilderFactory.newDefaultInstance() .newDocumentBuilder(); - var stream = new ByteArrayInputStream(toDeSerialize.toString().getBytes()); + var stream = new ByteArrayInputStream(toDeserialize.toString().getBytes()); Document parsed = documentBuilder.parse(stream); Forest forest = new Forest(); forest.createObjectFromXml(parsed); diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 3f2619f1ed9a..0b3cf61d921a 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -11,62 +11,71 @@ import org.xml.sax.SAXException; /** - * Creates a Serializer that uses Binary serialization and deserialization of objects graph to and - * from their Binary Representation. + * 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; /** - * @throws SQLException + * @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 typeOfDataForDB) throws SQLException { - databaseService = new DatabaseService(typeOfDataForDB); + protected LobSerializer(String dataTypeDb) throws SQLException { + databaseService = new DatabaseService(dataTypeDb); databaseService.startupService(); } /** - * @param toSerialize - * @return - * @throws SQLException - * @throws ParserConfigurationException - * @throws TransformerException + * Provide 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 SQLException, ParserConfigurationException, TransformerException, IOException; + throws ParserConfigurationException, TransformerException, IOException; /** - * @param id - * @param name - * @param customer - * @return - * @throws SQLException + * Save 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 customer) throws SQLException { - databaseService.insert(id, name, customer); + public int persistToDb(int id, String name, Object object) throws SQLException { + databaseService.insert(id, name, object); return id; - } /** - * @param id - * @param columnName - * @return - * @throws SQLException + * Load 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); } /** - * @param toSerialize - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException + * Provide 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 toSerialize) + public abstract Forest deSerialize(Object toDeserialize) throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; @Override From 859a42381b13d47457ef8751d17b9a1fe9c3ba54 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 15:51:42 +0530 Subject: [PATCH 21/44] #1596:Updating Main function to handle both Serializers --- slob/src/main/java/com/iluwatar/slob/App.java | 24 +++++++++++++++---- .../test/java/com/iluwatar/slob/AppTest.java | 7 +++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 6cb8acd604e3..d3df3dc427a6 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -27,11 +27,13 @@ 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; @@ -51,10 +53,25 @@ public class App { /** * Main entry point to program * - * @param args NA + * @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; + if (args.length > 0 && Objects.equals(args[0], "CLOB")) { + serializer = new ClobSerializer(); + } else { + serializer = new BlobSerializer(); + } + executeSerializer(forest, serializer); + } + /** + * Creates a Forest with Animals and Plants along with their respective relationships + * + * @return Forest Object + */ + private static Forest createForest() { Plant grass = new Plant("Grass", "Herb"); Plant oak = new Plant("Oak", "Tree"); @@ -62,10 +79,7 @@ public static void main(String[] args) throws SQLException { Animal buffalo = new Animal("Buffalo", Set.of(grass), Collections.emptySet()); Animal lion = new Animal("Lion", Collections.emptySet(), Set.of(zebra, buffalo)); - Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); - - LobSerializer serializer = new ClobSerializer(); - executeSerializer(forest, serializer); + return new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); } /** diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index 0835ea701dc5..ae84ec42cb52 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -61,7 +61,12 @@ private static Forest createForest() { } @Test - void shouldExecuteWithoutException() { + void shouldExecuteWithoutExceptionClob() { + assertDoesNotThrow(() -> App.main(new String[]{"CLOB"})); + } + + @Test + void shouldExecuteWithoutExceptionBlob() { assertDoesNotThrow(() -> App.main(new String[]{})); } From 565c718778c5bcd0b37ca218ad578a38fca84aa6 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:10:09 +0530 Subject: [PATCH 22/44] #1596:Updated Java Docs --- .../java/com/iluwatar/slob/lob/Animal.java | 24 +++++++++++++------ .../java/com/iluwatar/slob/lob/Forest.java | 20 ++++++++++++++++ .../java/com/iluwatar/slob/lob/Plant.java | 17 ++++++++----- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index ec160f05fdb1..b0b46c136254 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -27,7 +27,6 @@ import java.io.Serializable; import java.util.HashSet; import java.util.Set; -import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -37,7 +36,7 @@ import org.w3c.dom.NodeList; /** - * Application. + * Creates an object Animal with a list of animals and/or plants it consumes. */ @Data @AllArgsConstructor @@ -48,6 +47,14 @@ public class Animal implements Serializable { private Set plantsEaten = new HashSet<>(); private Set animalsEaten = new HashSet<>(); + /** + * Iterates over the input nodes recursively and adds new plants or animals 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 animalsEaten, Set plantsEaten) { for (int i = 0; i < childNodes.getLength(); i++) { @@ -67,11 +74,12 @@ protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animals = new HashSet<>(); private Set plants = new HashSet<>(); + /** + * Provides the representation of Forest in XML form. + * + * @return XML Element + */ public Element toXmlElement() throws ParserConfigurationException { Document xmlDoc = getXmlDoc(); @@ -45,10 +54,21 @@ public Element toXmlElement() throws ParserConfigurationException { 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("*"); diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java index 80d65d6fd35f..aeee0cfd2d33 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java @@ -26,7 +26,6 @@ import java.io.Serializable; import java.util.StringJoiner; -import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -36,7 +35,7 @@ import org.w3c.dom.Node; /** - * Application. + * Creates an object Plant which contains its name and type */ @Data @AllArgsConstructor @@ -47,11 +46,12 @@ public class Plant implements Serializable { private String type; /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException + * 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) throws ParserConfigurationException { + public Element toXmlElement(Document xmlDoc) { Element root = xmlDoc.createElement(Plant.class.getSimpleName()); root.setAttribute("name", name); root.setAttribute("type", type); @@ -59,6 +59,11 @@ public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException 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(); From 494aa8c532255bdcd550146750697842c7f16111 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:10:42 +0530 Subject: [PATCH 23/44] #1596:Updated Java Docs --- slob/src/main/java/com/iluwatar/slob/lob/Animal.java | 1 - 1 file changed, 1 deletion(-) diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index b0b46c136254..38ae874c34dc 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -102,7 +102,6 @@ public Element toXmlElement(Document xmlDoc) { * Parses the Animal Object from the input XML Node. * * @param node the XML Node from which the Animal Object is to be parsed - * @return */ public void createObjectFromXml(Node node) { name = node.getAttributes().getNamedItem("name").getNodeValue(); From 2862cb6e0179f4993f8c43d0e09f7088536e611b Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:49:05 +0530 Subject: [PATCH 24/44] #1596:Updated Java Docs and formatting --- slob/src/main/java/com/iluwatar/slob/App.java | 21 ++--- .../slob/dbservice/DatabaseService.java | 88 ++++++++++++++++--- .../java/com/iluwatar/slob/lob/Animal.java | 6 +- .../java/com/iluwatar/slob/lob/Forest.java | 26 +++++- .../java/com/iluwatar/slob/lob/Plant.java | 4 +- .../slob/serializers/BlobSerializer.java | 28 +++++- .../slob/serializers/ClobSerializer.java | 30 ++++++- .../slob/serializers/LobSerializer.java | 38 ++++++-- .../test/java/com/iluwatar/slob/AppTest.java | 27 +++++- 9 files changed, 226 insertions(+), 42 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index d3df3dc427a6..5507ffe33088 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -37,7 +37,6 @@ import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; -import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; @@ -45,13 +44,12 @@ /** * SLOB Application using Serializer and H2 DB. */ -@Slf4j public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** - * Main entry point to program + * Main entry point to program. * * @param args if first arg is CLOB then ClobSerializer is used else BlobSerializer is used. */ @@ -67,7 +65,7 @@ public static void main(String[] args) throws SQLException { } /** - * Creates a Forest with Animals and Plants along with their respective relationships + * Creates a Forest with Animals and Plants along with their respective relationships. * * @return Forest Object */ @@ -83,10 +81,8 @@ private static Forest createForest() { } /** - * Serialize the input object using the input serializer and persist to DB, then load the object - * back from DB and deserializing using the provided input Serializer. After loading from DB the - * method matches the hash of the input object with the hash of the object that was loaded from DB - * and deserialized. + * 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 provided serializer. * * @param forest Object to Serialize and Persist * @param lobSerializer Serializer to Serialize and Deserialize Object @@ -101,12 +97,9 @@ private static void executeSerializer(Forest forest, LobSerializer lobSerializer Forest forestFromDb = serializer.deSerialize(fromDb); LOGGER.info(forestFromDb.toString()); - if (forest.hashCode() == forestFromDb.hashCode()) { - LOGGER.info("Objects Before And After Serialization are Same"); - } - } catch (SQLException | IOException | TransformerException | ParserConfigurationException | - SAXException | - ClassNotFoundException e) { + } catch (SQLException | IOException | TransformerException | ParserConfigurationException + | SAXException + | ClassNotFoundException e) { throw new RuntimeException(e); } } diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index c421b5745346..53b53cf0a82f 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -1,3 +1,27 @@ +/* + * 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; @@ -6,6 +30,9 @@ import lombok.extern.slf4j.Slf4j; import org.h2.jdbcx.JdbcDataSource; +/** + * Service to handle database operations. + */ @Slf4j public class DatabaseService { @@ -19,18 +46,33 @@ public class DatabaseService { 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 typeOfDataForDB; + public String dataTypeDb; - public DatabaseService(String typeOfDataForDB) { - this.typeOfDataForDB = typeOfDataForDB; + /** + * 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(); @@ -39,11 +81,18 @@ public void shutDownService() } } + /** + * 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 (typeOfDataForDB.equals("BINARY")) { + if (dataTypeDb.equals("BINARY")) { statement.execute(CREATE_BINARY_SCHEMA_DDL); } else { statement.execute(CREATE_TEXT_SCHEMA_DDL); @@ -51,7 +100,16 @@ public void startupService() } } - public boolean insert(int id, String name, Object data) + /** + * 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 { boolean execute; try (var connection = dataSource.getConnection(); @@ -59,22 +117,32 @@ public boolean insert(int id, String name, Object data) insert.setInt(1, id); insert.setString(2, name); insert.setObject(3, data); - execute = insert.execute(); + insert.execute(); } - return execute; } - public Object select(final long id1, String columnsName) throws SQLException { + /** + * 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, id1); + preparedStatement.setLong(1, id); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { - if (typeOfDataForDB.equals(BINARY_DATA)) { + if (dataTypeDb.equals(BINARY_DATA)) { result = resultSet.getBinaryStream(columnsName); } else { result = resultSet.getString(columnsName); diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index 38ae874c34dc..770543cc5cf3 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -48,8 +48,8 @@ public class Animal implements Serializable { private Set animalsEaten = new HashSet<>(); /** - * Iterates over the input nodes recursively and adds new plants or animals found to input sets - * respectively + * 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 @@ -74,7 +74,7 @@ protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set 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}.

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(); @@ -90,6 +109,12 @@ void clobSerializerTest() { } } + /** + * 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}.

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(); From 09c70e90893a8e81fce5eca03e3a149940d36aec Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:49:38 +0530 Subject: [PATCH 25/44] #1596:Updated Java Docs and formatting --- .../main/java/com/iluwatar/slob/dbservice/DatabaseService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index 53b53cf0a82f..ea54592c99d1 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -111,7 +111,6 @@ public void startupService() */ public void insert(int id, String name, Object data) throws SQLException { - boolean execute; try (var connection = dataSource.getConnection(); var insert = connection.prepareStatement(INSERT)) { insert.setInt(1, id); From 94e689b8b5f6546e35a476152b67d5820ca85584 Mon Sep 17 00:00:00 2001 From: SHRADDHAP18 <87650482+SHRADDHAP18@users.noreply.github.com> Date: Sun, 21 Jan 2024 14:58:33 +0530 Subject: [PATCH 26/44] #1596:Adding Java Docs --- slob/src/main/java/com/iluwatar/slob/App.java | 13 ++++--- .../slob/serializers/BlobSerializer.java | 27 ++++++++++----- .../slob/serializers/ClobSerializer.java | 34 ++++++++++++------- .../slob/serializers/LobSerializer.java | 6 +++- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 1a899761b840..69cc11fe8701 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -42,7 +42,7 @@ import java.util.Set; /** - * Application. + * SLOB Application using Serializer. */ @Slf4j public class App { @@ -50,8 +50,7 @@ public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** - * @param args - * @throws SQLException + * @param args NA */ public static void main(String[] args) throws SQLException { @@ -69,8 +68,12 @@ public static void main(String[] args) throws SQLException { } /** - * @param forest - * @param lobSerializer + * Serialize the input object using the input serializer and persist to DB, then load the object + * back from DB and deserializing using the provided input Serializer. + * After loading from DB the method matches the hash of the input object with the hash of the object + * that was loaded from DB and deserialized. + * @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) { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 097776f4f62e..69bcd83a9f12 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -1,24 +1,30 @@ package com.iluwatar.slob.serializers; import com.iluwatar.slob.lob.Forest; +import org.xml.sax.SAXException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; import java.io.*; 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 typeOfDataForDB = "BINARY"; + public static final String TYPE_OF_DATA_FOR_DB = "BINARY"; - /** - * @throws SQLException - */ public BlobSerializer() throws SQLException { - super(typeOfDataForDB); + super(TYPE_OF_DATA_FOR_DB); } /** - * @param toSerialize - * @return + * Serialize 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 { @@ -30,8 +36,11 @@ public Object serialize(Forest toSerialize) throws IOException { } /** - * @param toDeserialize - * @return + * Deserialize 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 { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index e5ef5b540742..d4c6aab74fa1 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -19,18 +19,23 @@ import java.io.StringWriter; import java.sql.SQLException; +/** + * 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 typeOfDataForDB = "TEXT"; + public static final String TYPE_OF_DATA_FOR_DB = "TEXT"; public ClobSerializer() throws SQLException { - super(typeOfDataForDB); + super(TYPE_OF_DATA_FOR_DB); } /** - * @param node - * @return - * @throws TransformerException + * 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(); @@ -42,10 +47,11 @@ private static String elementToXmlString(Element node) throws TransformerExcepti } /** - * @param forest - * @return - * @throws ParserConfigurationException - * @throws TransformerException + * Serialize 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 { @@ -54,10 +60,12 @@ public Object serialize(Forest forest) throws ParserConfigurationException, Tran } /** - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException + * Deserialize 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 { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 53229656c7e0..3fca6b2772ca 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -11,9 +11,13 @@ import java.io.Serializable; import java.sql.SQLException; +/** + * Creates a Serializer that uses Binary serialization and deserialization of objects + * graph to and from their Binary Representation. + */ public abstract class LobSerializer implements Serializable, Closeable { - public final DatabaseService databaseService; + private final transient DatabaseService databaseService; /** * @throws SQLException From fd0e1a4e1ff348df72b0cbabab62999454e299ac Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 15:12:21 +0530 Subject: [PATCH 27/44] #1596:Reformatted as per Code Style --- slob/src/main/java/com/iluwatar/slob/App.java | 87 +++++------ .../slob/dbservice/DatabaseService.java | 142 +++++++++--------- .../java/com/iluwatar/slob/lob/Animal.java | 142 +++++++++--------- .../java/com/iluwatar/slob/lob/Forest.java | 107 +++++++------ .../java/com/iluwatar/slob/lob/Plant.java | 59 ++++---- .../slob/serializers/BlobSerializer.java | 85 ++++++----- .../slob/serializers/ClobSerializer.java | 118 ++++++++------- .../slob/serializers/LobSerializer.java | 115 +++++++------- .../test/java/com/iluwatar/slob/AppTest.java | 97 ++++++------ 9 files changed, 482 insertions(+), 470 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 69cc11fe8701..360bdb1325f9 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -29,17 +29,16 @@ import com.iluwatar.slob.lob.Plant; import com.iluwatar.slob.serializers.ClobSerializer; import com.iluwatar.slob.serializers.LobSerializer; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; 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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; /** * SLOB Application using Serializer. @@ -47,50 +46,52 @@ @Slf4j public class App { - private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); - /** - * @param args NA - */ - public static void main(String[] args) throws SQLException { + /** + * @param args NA + */ + public static void main(String[] args) throws SQLException { - Plant grass = new Plant("Grass", "Herb"); - Plant oak = new Plant("Oak", "Tree"); + 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)); + 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)); - Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); + Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); - LobSerializer serializer = new ClobSerializer(); - executeSerializer(forest, serializer); - } + LobSerializer serializer = new ClobSerializer(); + executeSerializer(forest, serializer); + } - /** - * Serialize the input object using the input serializer and persist to DB, then load the object - * back from DB and deserializing using the provided input Serializer. - * After loading from DB the method matches the hash of the input object with the hash of the object - * that was loaded from DB and deserialized. - * @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) { + /** + * Serialize the input object using the input serializer and persist to DB, then load the object + * back from DB and deserializing using the provided input Serializer. After loading from DB the + * method matches the hash of the input object with the hash of the object that was loaded from DB + * and deserialized. + * + * @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 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); + Object fromDb = serializer.loadFromDb(id, Forest.class.getSimpleName()); + Forest forestFromDb = serializer.deSerialize(fromDb); - LOGGER.info(forestFromDb.toString()); - if (forest.hashCode() == forestFromDb.hashCode()) { - LOGGER.info("Objects Before And After Serialization are Same"); - } - } catch (SQLException | IOException | TransformerException | ParserConfigurationException | SAXException | - ClassNotFoundException e) { - throw new RuntimeException(e); - } + LOGGER.info(forestFromDb.toString()); + if (forest.hashCode() == forestFromDb.hashCode()) { + LOGGER.info("Objects Before And After Serialization are Same"); + } + } catch (SQLException | IOException | TransformerException | ParserConfigurationException | + SAXException | + ClassNotFoundException e) { + throw new RuntimeException(e); } + } } diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index 95b8ff403c3f..c421b5745346 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -1,90 +1,90 @@ package com.iluwatar.slob.dbservice; -import lombok.extern.slf4j.Slf4j; -import org.h2.jdbcx.JdbcDataSource; - -import javax.sql.DataSource; import java.sql.ResultSet; import java.sql.SQLException; +import javax.sql.DataSource; +import lombok.extern.slf4j.Slf4j; +import org.h2.jdbcx.JdbcDataSource; @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 typeOfDataForDB; - public DatabaseService(String typeOfDataForDB) { - this.typeOfDataForDB = typeOfDataForDB; - } + 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 typeOfDataForDB; - private static DataSource createDataSource() { - var dataSource = new JdbcDataSource(); - dataSource.setURL(DB_URL); - return dataSource; - } + public DatabaseService(String typeOfDataForDB) { + this.typeOfDataForDB = typeOfDataForDB; + } - public void shutDownService() - throws SQLException { - try (var connection = dataSource.getConnection(); - var statement = connection.createStatement()) { - statement.execute(DELETE_SCHEMA_SQL); - } + private static DataSource createDataSource() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + return dataSource; + } + + public void shutDownService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + statement.execute(DELETE_SCHEMA_SQL); } + } - public void startupService() - throws SQLException { - try (var connection = dataSource.getConnection(); - var statement = connection.createStatement()) { - if (typeOfDataForDB.equals("BINARY")) { - statement.execute(CREATE_BINARY_SCHEMA_DDL); - } else { - statement.execute(CREATE_TEXT_SCHEMA_DDL); - } - } + public void startupService() + throws SQLException { + try (var connection = dataSource.getConnection(); + var statement = connection.createStatement()) { + if (typeOfDataForDB.equals("BINARY")) { + statement.execute(CREATE_BINARY_SCHEMA_DDL); + } else { + statement.execute(CREATE_TEXT_SCHEMA_DDL); + } } + } - public boolean insert(int id, String name, Object data) - throws SQLException { - boolean execute; - try (var connection = dataSource.getConnection(); - var insert = connection.prepareStatement(INSERT)) { - insert.setInt(1, id); - insert.setString(2, name); - insert.setObject(3, data); - execute = insert.execute(); - } - return execute; + public boolean insert(int id, String name, Object data) + throws SQLException { + boolean execute; + try (var connection = dataSource.getConnection(); + var insert = connection.prepareStatement(INSERT)) { + insert.setInt(1, id); + insert.setString(2, name); + insert.setObject(3, data); + execute = insert.execute(); } + return execute; + } - public Object select(final long id1, String columnsName) throws SQLException { - ResultSet resultSet = null; - try (var connection = dataSource.getConnection(); - var preparedStatement = - connection.prepareStatement(SELECT) - ) { - Object result = null; - preparedStatement.setLong(1, id1); - resultSet = preparedStatement.executeQuery(); - while (resultSet.next()) { - if (typeOfDataForDB.equals(BINARY_DATA)) { - result = resultSet.getBinaryStream(columnsName); - } else { - result = resultSet.getString(columnsName); - } - } - return result; - } finally { - if (resultSet != null) { - resultSet.close(); - } + public Object select(final long id1, String columnsName) throws SQLException { + ResultSet resultSet = null; + try (var connection = dataSource.getConnection(); + var preparedStatement = + connection.prepareStatement(SELECT) + ) { + Object result = null; + preparedStatement.setLong(1, id1); + resultSet = preparedStatement.executeQuery(); + while (resultSet.next()) { + if (typeOfDataForDB.equals(BINARY_DATA)) { + result = resultSet.getBinaryStream(columnsName); + } else { + result = resultSet.getString(columnsName); } + } + return result; + } finally { + if (resultSet != null) { + resultSet.close(); + } } + } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index 27e95a5f819b..ec160f05fdb1 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -24,6 +24,10 @@ */ package com.iluwatar.slob.lob; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -32,11 +36,6 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import javax.xml.parsers.ParserConfigurationException; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - /** * Application. */ @@ -45,78 +44,79 @@ @NoArgsConstructor public class Animal implements Serializable { - private String name; - private Set plantsEaten = new HashSet<>(); - private Set animalsEaten = new HashSet<>(); + private String name; + private Set plantsEaten = new HashSet<>(); + private Set animalsEaten = new HashSet<>(); - protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animalsEaten, Set 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); - } - } + protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animalsEaten, + Set 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); } + } } + } - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { - 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(); + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + 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); + } } - - /** - * @param node - * @return - */ - public void createObjectFromXml(Node node) { - name = node.getAttributes().getNamedItem("name").getNodeValue(); - NodeList childNodes = node.getChildNodes(); - iterateXmlForAnimalAndPlants(childNodes, animalsEaten, plantsEaten); + for (Animal animal : animalsEaten) { + Element xmlElement = animal.toXmlElement(xmlDoc); + if (xmlElement != null) { + root.appendChild(xmlElement); + } } + xmlDoc.appendChild(root); + return (Element) xmlDoc.getFirstChild(); + } - @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(); + /** + * @param node + * @return + */ + 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(); + } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Forest.java b/slob/src/main/java/com/iluwatar/slob/lob/Forest.java index 01bdbb662a28..ce95083f7d00 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Forest.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Forest.java @@ -1,5 +1,12 @@ 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; @@ -7,72 +14,64 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - -import static com.iluwatar.slob.lob.Animal.iterateXmlForAnimalAndPlants; - @Data @NoArgsConstructor @AllArgsConstructor public class Forest implements Serializable { - private String name; - private Set animals = new HashSet<>(); - private Set plants = new HashSet<>(); + private String name; + private Set animals = new HashSet<>(); + private Set plants = new HashSet<>(); - public Element toXmlElement() throws ParserConfigurationException { - Document xmlDoc = getXmlDoc(); + public Element toXmlElement() throws ParserConfigurationException { + Document xmlDoc = getXmlDoc(); - Element forestXml = xmlDoc.createElement("Forest"); - forestXml.setAttribute("name", name); + 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; + Element animalsXml = xmlDoc.createElement("Animals"); + for (Animal animal : animals) { + Element animalXml = animal.toXmlElement(xmlDoc); + animalsXml.appendChild(animalXml); } + forestXml.appendChild(animalsXml); - private Document getXmlDoc() throws ParserConfigurationException { - return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); + Element plantsXml = xmlDoc.createElement("Plants"); + for (Plant plant : plants) { + Element plantXml = plant.toXmlElement(xmlDoc); + plantsXml.appendChild(plantXml); } + forestXml.appendChild(plantsXml); + return forestXml; + } - public void createObjectFromXml(Document document) { - name = document.getDocumentElement().getAttribute("name"); - NodeList nodeList = document.getElementsByTagName("*"); - iterateXmlForAnimalAndPlants(nodeList, animals, plants); - } + private Document getXmlDoc() throws ParserConfigurationException { + return DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().newDocument(); + } - @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(); + 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(); + } } diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java index 4d49d055ca00..80d65d6fd35f 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java @@ -24,6 +24,9 @@ */ package com.iluwatar.slob.lob; +import java.io.Serializable; +import java.util.StringJoiner; +import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -32,10 +35,6 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import javax.xml.parsers.ParserConfigurationException; -import java.io.Serializable; -import java.util.StringJoiner; - /** * Application. */ @@ -44,33 +43,33 @@ @NoArgsConstructor public class Plant implements Serializable { - private String name; - private String type; + private String name; + private String type; - /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException - */ - public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { - Element root = xmlDoc.createElement(Plant.class.getSimpleName()); - root.setAttribute("name", name); - root.setAttribute("type", type); - xmlDoc.appendChild(root); - return xmlDoc.getDocumentElement(); - } + /** + * @param xmlDoc + * @return + * @throws ParserConfigurationException + */ + public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException { + Element root = xmlDoc.createElement(Plant.class.getSimpleName()); + root.setAttribute("name", name); + root.setAttribute("type", type); + xmlDoc.appendChild(root); + return xmlDoc.getDocumentElement(); + } - public void createObjectFromXml(Node node) { - NamedNodeMap attributes = node.getAttributes(); - name = attributes.getNamedItem("name").getNodeValue(); - type = attributes.getNamedItem("type").getNodeValue(); - } + 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(); - } + @Override + public String toString() { + StringJoiner stringJoiner = new StringJoiner(","); + stringJoiner.add("Name = " + name); + stringJoiner.add("Type = " + type); + return stringJoiner.toString(); + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 69bcd83a9f12..b104a5d63f59 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -1,54 +1,59 @@ package com.iluwatar.slob.serializers; import com.iluwatar.slob.lob.Forest; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import java.io.*; +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. + * 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 static final String TYPE_OF_DATA_FOR_DB = "BINARY"; - public BlobSerializer() throws SQLException { - super(TYPE_OF_DATA_FOR_DB); - } + public BlobSerializer() throws SQLException { + super(TYPE_OF_DATA_FOR_DB); + } - /** - * Serialize 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()); - } + /** + * Serialize 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()); + } - /** - * Deserialize 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; + /** + * Deserialize 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; + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index d4c6aab74fa1..b4151f51afe7 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -1,10 +1,10 @@ package com.iluwatar.slob.serializers; import com.iluwatar.slob.lob.Forest; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - +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; @@ -14,66 +14,70 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.sql.SQLException; +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. + * 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 static final String TYPE_OF_DATA_FOR_DB = "TEXT"; - public ClobSerializer() throws SQLException { - super(TYPE_OF_DATA_FOR_DB); - } + 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(); - } + /** + * 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(); + } - /** - * Serialize 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); - } + /** + * Serialize 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); + } - /** - * Deserialize 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; - } + /** + * Deserialize 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; + } } diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 3fca6b2772ca..3f2619f1ed9a 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -2,78 +2,79 @@ import com.iluwatar.slob.dbservice.DatabaseService; import com.iluwatar.slob.lob.Forest; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; 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; /** - * Creates a Serializer that uses Binary serialization and deserialization of objects - * graph to and from their Binary Representation. + * Creates a Serializer that uses Binary serialization and deserialization of objects graph to and + * from their Binary Representation. */ public abstract class LobSerializer implements Serializable, Closeable { - private final transient DatabaseService databaseService; + private final transient DatabaseService databaseService; - /** - * @throws SQLException - */ - protected LobSerializer(String typeOfDataForDB) throws SQLException { - databaseService = new DatabaseService(typeOfDataForDB); - databaseService.startupService(); - } + /** + * @throws SQLException + */ + protected LobSerializer(String typeOfDataForDB) throws SQLException { + databaseService = new DatabaseService(typeOfDataForDB); + databaseService.startupService(); + } - /** - * @param toSerialize - * @return - * @throws SQLException - * @throws ParserConfigurationException - * @throws TransformerException - */ - public abstract Object serialize(Forest toSerialize) throws SQLException, ParserConfigurationException, TransformerException, IOException; + /** + * @param toSerialize + * @return + * @throws SQLException + * @throws ParserConfigurationException + * @throws TransformerException + */ + public abstract Object serialize(Forest toSerialize) + throws SQLException, ParserConfigurationException, TransformerException, IOException; - /** - * @param id - * @param name - * @param customer - * @return - * @throws SQLException - */ - public int persistToDb(int id, String name, Object customer) throws SQLException { - databaseService.insert(id, name, customer); - return id; + /** + * @param id + * @param name + * @param customer + * @return + * @throws SQLException + */ + public int persistToDb(int id, String name, Object customer) throws SQLException { + databaseService.insert(id, name, customer); + return id; - } + } - /** - * @param id - * @param columnName - * @return - * @throws SQLException - */ - public Object loadFromDb(int id, String columnName) throws SQLException { - return databaseService.select(id, columnName); - } + /** + * @param id + * @param columnName + * @return + * @throws SQLException + */ + public Object loadFromDb(int id, String columnName) throws SQLException { + return databaseService.select(id, columnName); + } - /** - * @param toSerialize - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException - */ - public abstract Forest deSerialize(Object toSerialize) throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; + /** + * @param toSerialize + * @return + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + */ + public abstract Forest deSerialize(Object toSerialize) + throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; - @Override - public void close() throws IOException { - try { - databaseService.shutDownService(); - } catch (SQLException e) { - throw new RuntimeException(e); - } + @Override + public void close() throws IOException { + try { + databaseService.shutDownService(); + } catch (SQLException e) { + throw new RuntimeException(e); } + } } diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index c5ba8e5eaffe..0835ea701dc5 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -24,25 +24,24 @@ */ 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 lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.xml.sax.SAXException; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; import java.io.IOException; import java.sql.SQLException; import java.util.Collections; import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +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; /** * Application test @@ -50,55 +49,59 @@ @Slf4j class AppTest { - private static Forest createForest() { - Plant grass = new Plant("Grass", "Herb"); - Plant oak = new Plant("Oak", "Tree"); + 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)); + 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)); - } + return new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); + } - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); - } + @Test + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } - @Test - void clobSerializerTest() { - Forest forest = createForest(); - try (LobSerializer serializer = new ClobSerializer()) { + @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 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); + 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); - } + 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); } + } - @Test - void blobSerializerTest() { - Forest forest = createForest(); - try (LobSerializer serializer = new BlobSerializer()) { + @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 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); + 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); - } + 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); } + } } From e7df198b4c421f9bb0981fd3905e61297461ed59 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 15:38:49 +0530 Subject: [PATCH 28/44] #1596:Updating Java Doc --- slob/src/main/java/com/iluwatar/slob/App.java | 4 +- .../slob/serializers/ClobSerializer.java | 6 +- .../slob/serializers/LobSerializer.java | 67 +++++++++++-------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 360bdb1325f9..6cb8acd604e3 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -41,7 +41,7 @@ import org.xml.sax.SAXException; /** - * SLOB Application using Serializer. + * SLOB Application using Serializer and H2 DB. */ @Slf4j public class App { @@ -49,6 +49,8 @@ public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** + * Main entry point to program + * * @param args NA */ public static void main(String[] args) throws SQLException { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index b4151f51afe7..fcd9911c7a03 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -63,18 +63,18 @@ public Object serialize(Forest forest) throws ParserConfigurationException, Tran /** * Deserialize the input XML string using DOM Parser and return its Object Graph Representation * - * @param toDeSerialize Input Object to De-serialize + * @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) + public Forest deSerialize(Object toDeserialize) throws ParserConfigurationException, IOException, SAXException { DocumentBuilder documentBuilder = DocumentBuilderFactory.newDefaultInstance() .newDocumentBuilder(); - var stream = new ByteArrayInputStream(toDeSerialize.toString().getBytes()); + var stream = new ByteArrayInputStream(toDeserialize.toString().getBytes()); Document parsed = documentBuilder.parse(stream); Forest forest = new Forest(); forest.createObjectFromXml(parsed); diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index 3f2619f1ed9a..0b3cf61d921a 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -11,62 +11,71 @@ import org.xml.sax.SAXException; /** - * Creates a Serializer that uses Binary serialization and deserialization of objects graph to and - * from their Binary Representation. + * 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; /** - * @throws SQLException + * @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 typeOfDataForDB) throws SQLException { - databaseService = new DatabaseService(typeOfDataForDB); + protected LobSerializer(String dataTypeDb) throws SQLException { + databaseService = new DatabaseService(dataTypeDb); databaseService.startupService(); } /** - * @param toSerialize - * @return - * @throws SQLException - * @throws ParserConfigurationException - * @throws TransformerException + * Provide 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 SQLException, ParserConfigurationException, TransformerException, IOException; + throws ParserConfigurationException, TransformerException, IOException; /** - * @param id - * @param name - * @param customer - * @return - * @throws SQLException + * Save 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 customer) throws SQLException { - databaseService.insert(id, name, customer); + public int persistToDb(int id, String name, Object object) throws SQLException { + databaseService.insert(id, name, object); return id; - } /** - * @param id - * @param columnName - * @return - * @throws SQLException + * Load 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); } /** - * @param toSerialize - * @return - * @throws ParserConfigurationException - * @throws IOException - * @throws SAXException + * Provide 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 toSerialize) + public abstract Forest deSerialize(Object toDeserialize) throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException; @Override From 4e8b9951560bf92542aa70cf0ae8c2616a6f7773 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 15:51:42 +0530 Subject: [PATCH 29/44] #1596:Updating Main function to handle both Serializers --- slob/src/main/java/com/iluwatar/slob/App.java | 24 +++++++++++++++---- .../test/java/com/iluwatar/slob/AppTest.java | 7 +++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 6cb8acd604e3..d3df3dc427a6 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -27,11 +27,13 @@ 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; @@ -51,10 +53,25 @@ public class App { /** * Main entry point to program * - * @param args NA + * @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; + if (args.length > 0 && Objects.equals(args[0], "CLOB")) { + serializer = new ClobSerializer(); + } else { + serializer = new BlobSerializer(); + } + executeSerializer(forest, serializer); + } + /** + * Creates a Forest with Animals and Plants along with their respective relationships + * + * @return Forest Object + */ + private static Forest createForest() { Plant grass = new Plant("Grass", "Herb"); Plant oak = new Plant("Oak", "Tree"); @@ -62,10 +79,7 @@ public static void main(String[] args) throws SQLException { Animal buffalo = new Animal("Buffalo", Set.of(grass), Collections.emptySet()); Animal lion = new Animal("Lion", Collections.emptySet(), Set.of(zebra, buffalo)); - Forest forest = new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); - - LobSerializer serializer = new ClobSerializer(); - executeSerializer(forest, serializer); + return new Forest("Amazon", Set.of(lion, buffalo, zebra), Set.of(grass, oak)); } /** diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index 0835ea701dc5..ae84ec42cb52 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -61,7 +61,12 @@ private static Forest createForest() { } @Test - void shouldExecuteWithoutException() { + void shouldExecuteWithoutExceptionClob() { + assertDoesNotThrow(() -> App.main(new String[]{"CLOB"})); + } + + @Test + void shouldExecuteWithoutExceptionBlob() { assertDoesNotThrow(() -> App.main(new String[]{})); } From d02b34ef1839dd08eacd1ac9a502211e47f71d65 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:10:09 +0530 Subject: [PATCH 30/44] #1596:Updated Java Docs --- .../java/com/iluwatar/slob/lob/Animal.java | 24 +++++++++++++------ .../java/com/iluwatar/slob/lob/Forest.java | 20 ++++++++++++++++ .../java/com/iluwatar/slob/lob/Plant.java | 17 ++++++++----- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index ec160f05fdb1..b0b46c136254 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -27,7 +27,6 @@ import java.io.Serializable; import java.util.HashSet; import java.util.Set; -import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -37,7 +36,7 @@ import org.w3c.dom.NodeList; /** - * Application. + * Creates an object Animal with a list of animals and/or plants it consumes. */ @Data @AllArgsConstructor @@ -48,6 +47,14 @@ public class Animal implements Serializable { private Set plantsEaten = new HashSet<>(); private Set animalsEaten = new HashSet<>(); + /** + * Iterates over the input nodes recursively and adds new plants or animals 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 animalsEaten, Set plantsEaten) { for (int i = 0; i < childNodes.getLength(); i++) { @@ -67,11 +74,12 @@ protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set animals = new HashSet<>(); private Set plants = new HashSet<>(); + /** + * Provides the representation of Forest in XML form. + * + * @return XML Element + */ public Element toXmlElement() throws ParserConfigurationException { Document xmlDoc = getXmlDoc(); @@ -45,10 +54,21 @@ public Element toXmlElement() throws ParserConfigurationException { 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("*"); diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java index 80d65d6fd35f..aeee0cfd2d33 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Plant.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Plant.java @@ -26,7 +26,6 @@ import java.io.Serializable; import java.util.StringJoiner; -import javax.xml.parsers.ParserConfigurationException; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -36,7 +35,7 @@ import org.w3c.dom.Node; /** - * Application. + * Creates an object Plant which contains its name and type */ @Data @AllArgsConstructor @@ -47,11 +46,12 @@ public class Plant implements Serializable { private String type; /** - * @param xmlDoc - * @return - * @throws ParserConfigurationException + * 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) throws ParserConfigurationException { + public Element toXmlElement(Document xmlDoc) { Element root = xmlDoc.createElement(Plant.class.getSimpleName()); root.setAttribute("name", name); root.setAttribute("type", type); @@ -59,6 +59,11 @@ public Element toXmlElement(Document xmlDoc) throws ParserConfigurationException 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(); From fddafd09da684588a6d9df5967c6b8a80c0eadff Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:10:42 +0530 Subject: [PATCH 31/44] #1596:Updated Java Docs --- slob/src/main/java/com/iluwatar/slob/lob/Animal.java | 1 - 1 file changed, 1 deletion(-) diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index b0b46c136254..38ae874c34dc 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -102,7 +102,6 @@ public Element toXmlElement(Document xmlDoc) { * Parses the Animal Object from the input XML Node. * * @param node the XML Node from which the Animal Object is to be parsed - * @return */ public void createObjectFromXml(Node node) { name = node.getAttributes().getNamedItem("name").getNodeValue(); From d0fe0c796f6f328f4dbda8842d67a8915f64d643 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:49:05 +0530 Subject: [PATCH 32/44] #1596:Updated Java Docs and formatting --- slob/src/main/java/com/iluwatar/slob/App.java | 21 ++--- .../slob/dbservice/DatabaseService.java | 88 ++++++++++++++++--- .../java/com/iluwatar/slob/lob/Animal.java | 6 +- .../java/com/iluwatar/slob/lob/Forest.java | 26 +++++- .../java/com/iluwatar/slob/lob/Plant.java | 4 +- .../slob/serializers/BlobSerializer.java | 28 +++++- .../slob/serializers/ClobSerializer.java | 30 ++++++- .../slob/serializers/LobSerializer.java | 38 ++++++-- .../test/java/com/iluwatar/slob/AppTest.java | 27 +++++- 9 files changed, 226 insertions(+), 42 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index d3df3dc427a6..5507ffe33088 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -37,7 +37,6 @@ import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; -import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; @@ -45,13 +44,12 @@ /** * SLOB Application using Serializer and H2 DB. */ -@Slf4j public class App { private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** - * Main entry point to program + * Main entry point to program. * * @param args if first arg is CLOB then ClobSerializer is used else BlobSerializer is used. */ @@ -67,7 +65,7 @@ public static void main(String[] args) throws SQLException { } /** - * Creates a Forest with Animals and Plants along with their respective relationships + * Creates a Forest with Animals and Plants along with their respective relationships. * * @return Forest Object */ @@ -83,10 +81,8 @@ private static Forest createForest() { } /** - * Serialize the input object using the input serializer and persist to DB, then load the object - * back from DB and deserializing using the provided input Serializer. After loading from DB the - * method matches the hash of the input object with the hash of the object that was loaded from DB - * and deserialized. + * 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 provided serializer. * * @param forest Object to Serialize and Persist * @param lobSerializer Serializer to Serialize and Deserialize Object @@ -101,12 +97,9 @@ private static void executeSerializer(Forest forest, LobSerializer lobSerializer Forest forestFromDb = serializer.deSerialize(fromDb); LOGGER.info(forestFromDb.toString()); - if (forest.hashCode() == forestFromDb.hashCode()) { - LOGGER.info("Objects Before And After Serialization are Same"); - } - } catch (SQLException | IOException | TransformerException | ParserConfigurationException | - SAXException | - ClassNotFoundException e) { + } catch (SQLException | IOException | TransformerException | ParserConfigurationException + | SAXException + | ClassNotFoundException e) { throw new RuntimeException(e); } } diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index c421b5745346..53b53cf0a82f 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -1,3 +1,27 @@ +/* + * 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; @@ -6,6 +30,9 @@ import lombok.extern.slf4j.Slf4j; import org.h2.jdbcx.JdbcDataSource; +/** + * Service to handle database operations. + */ @Slf4j public class DatabaseService { @@ -19,18 +46,33 @@ public class DatabaseService { 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 typeOfDataForDB; + public String dataTypeDb; - public DatabaseService(String typeOfDataForDB) { - this.typeOfDataForDB = typeOfDataForDB; + /** + * 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(); @@ -39,11 +81,18 @@ public void shutDownService() } } + /** + * 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 (typeOfDataForDB.equals("BINARY")) { + if (dataTypeDb.equals("BINARY")) { statement.execute(CREATE_BINARY_SCHEMA_DDL); } else { statement.execute(CREATE_TEXT_SCHEMA_DDL); @@ -51,7 +100,16 @@ public void startupService() } } - public boolean insert(int id, String name, Object data) + /** + * 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 { boolean execute; try (var connection = dataSource.getConnection(); @@ -59,22 +117,32 @@ public boolean insert(int id, String name, Object data) insert.setInt(1, id); insert.setString(2, name); insert.setObject(3, data); - execute = insert.execute(); + insert.execute(); } - return execute; } - public Object select(final long id1, String columnsName) throws SQLException { + /** + * 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, id1); + preparedStatement.setLong(1, id); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { - if (typeOfDataForDB.equals(BINARY_DATA)) { + if (dataTypeDb.equals(BINARY_DATA)) { result = resultSet.getBinaryStream(columnsName); } else { result = resultSet.getString(columnsName); diff --git a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java index 38ae874c34dc..770543cc5cf3 100644 --- a/slob/src/main/java/com/iluwatar/slob/lob/Animal.java +++ b/slob/src/main/java/com/iluwatar/slob/lob/Animal.java @@ -48,8 +48,8 @@ public class Animal implements Serializable { private Set animalsEaten = new HashSet<>(); /** - * Iterates over the input nodes recursively and adds new plants or animals found to input sets - * respectively + * 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 @@ -74,7 +74,7 @@ protected static void iterateXmlForAnimalAndPlants(NodeList childNodes, Set 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}.

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(); @@ -90,6 +109,12 @@ void clobSerializerTest() { } } + /** + * 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}.

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(); From 7c92e4e54ef5744e487dd6dff3c9bf0ecb59e984 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:49:38 +0530 Subject: [PATCH 33/44] #1596:Updated Java Docs and formatting --- .../main/java/com/iluwatar/slob/dbservice/DatabaseService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java index 53b53cf0a82f..ea54592c99d1 100644 --- a/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java +++ b/slob/src/main/java/com/iluwatar/slob/dbservice/DatabaseService.java @@ -111,7 +111,6 @@ public void startupService() */ public void insert(int id, String name, Object data) throws SQLException { - boolean execute; try (var connection = dataSource.getConnection(); var insert = connection.prepareStatement(INSERT)) { insert.setInt(1, id); From 336654ab6e80188e7efb979ebe432aed2bbdc8ae Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:55:07 +0530 Subject: [PATCH 34/44] #1596:Updated Java Docs and formatting --- slob/src/main/java/com/iluwatar/slob/App.java | 2 +- .../java/com/iluwatar/slob/serializers/LobSerializer.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 5507ffe33088..0c7f8b14b34a 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -42,7 +42,7 @@ import org.xml.sax.SAXException; /** - * SLOB Application using Serializer and H2 DB. + * SLOB Application using {@link LobSerializer} and H2 DB. */ public class App { diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java index e581351356ec..54e9c8ba52ec 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/LobSerializer.java @@ -55,7 +55,7 @@ protected LobSerializer(String dataTypeDb) throws SQLException { } /** - * Provide specification to Serialize the input object. + * Provides the specification to Serialize the input object. * * @param toSerialize Input Object to serialize * @return Serialized Object @@ -67,7 +67,7 @@ public abstract Object serialize(Forest toSerialize) throws ParserConfigurationException, TransformerException, IOException; /** - * Save the object to DB with the provided ID. + * 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 @@ -81,7 +81,7 @@ public int persistToDb(int id, String name, Object object) throws SQLException { } /** - * Load the object from db using the ID and column name. + * 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 @@ -93,7 +93,7 @@ public Object loadFromDb(int id, String columnName) throws SQLException { } /** - * Provide specification to Deserialize the input object. + * Provides the specification to Deserialize the input object. * * @param toDeserialize object to deserialize * @return Deserialized Object From 38e6e6b833a1d87ae2ef7f851d4b38d19dd454b3 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 16:56:21 +0530 Subject: [PATCH 35/44] #1596:Updated Java Docs and formatting --- .../java/com/iluwatar/slob/serializers/BlobSerializer.java | 4 ++-- .../java/com/iluwatar/slob/serializers/ClobSerializer.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java index 2ed2fa399747..c3858a84a9b6 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/BlobSerializer.java @@ -47,7 +47,7 @@ public BlobSerializer() throws SQLException { } /** - * Serialize the input object graph to its Binary Representation using Object Stream. + * Serializes the input object graph to its Binary Representation using Object Stream. * * @param toSerialize Object which is to be serialized * @return Serialized object @@ -63,7 +63,7 @@ public Object serialize(Forest toSerialize) throws IOException { } /** - * Deserialize the input Byte Array Stream using Object Stream and return its Object Graph + * Deserializes the input Byte Array Stream using Object Stream and return its Object Graph * Representation. * * @param toDeserialize Input Object to De-serialize diff --git a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java index 375b1a8bc7ba..1734447194d0 100644 --- a/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java +++ b/slob/src/main/java/com/iluwatar/slob/serializers/ClobSerializer.java @@ -71,7 +71,7 @@ private static String elementToXmlString(Element node) throws TransformerExcepti } /** - * Serialize the input object graph to its XML Representation using DOM Elements. + * Serializes the input object graph to its XML Representation using DOM Elements. * * @param forest Object which is to be serialized * @return Serialized object @@ -85,7 +85,7 @@ public Object serialize(Forest forest) throws ParserConfigurationException, Tran } /** - * Deserialize the input XML string using DOM Parser and return its Object Graph Representation. + * Deserializes the input XML string using DOM Parser and return its Object Graph Representation. * * @param toDeserialize Input Object to De-serialize * @return Deserialized Object From dc56f7c12ec06f2b52bef2e77634bffc0f5fc498 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 22:53:58 +0530 Subject: [PATCH 36/44] #1596:Updated README.md --- slob/README.md | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/slob/README.md b/slob/README.md index 60504d5f9381..f97c40b82e60 100644 --- a/slob/README.md +++ b/slob/README.md @@ -8,11 +8,24 @@ tag: ## Intent -Object models often contain complicated graphs of small objects. Much of the -information in these structures isn’t in the objects but in the links between -them. Objects don’t have to be persisted as table rows related to each other. -Another form of persistence is serialization, where a whole graph of objects is -written out as a single large object (LOB) in a table. +* Object models often contain complicated graphs of small objects. Much of the information in these + structures isn’t in the objects but in the links between them. +* Objects don’t have to be persisted as table rows related to each other. +* Another form of persistence is serialization, where a whole graph of objects is written out as a + single large object (LOB) in a table. + +## Explanation + +* Forest here represents the object graph. +* A forest contains animals and plants. As is in real life the forest object contains plants and + animals + where some animals eat other animals and some eat only plants. +* These relationships are maintained in the Forest Object. +* There are 2 types of Serializers available ClobSerializer and BlobSerializer. +* ClobSerializer uses character or textual based serialization, here the Object graph is converted + to XML and then stored as text in DB. +* BlobSerializer uses binary data for serialization, here the Object graph is converted to Byte + Array and then stored as a blob in DB. ## Class diagram @@ -20,14 +33,16 @@ written out as a single large object (LOB) in a table. ## Applicability -Serialized LOB isn’t considered as often as it might be. XML makes it much more -attractive since it yields a easy-to-implement textual approach. Its main disadvantage is that you can’t query the -structure using SQL. -SQL extensions appear to get at XML data within a field, but that’s still not the same (or portable). -This pattern works best when you can chop out a piece of the object model and use it to represent the LOB. Think of a -LOB as a way to take a bunch of -objects that aren’t likely to be queried from any SQL route outside the application. This graph can then be hooked into -the SQL schema. +* Serialized LOB isn’t considered as often as it might be. XML makes it much more attractive since + it yields a easy-to-implement textual approach. +* Its main disadvantage is that you can’t query the structure using SQL. +* SQL extensions appear to get at XML data within a field, but that’s still not the same (or + portable). +* This pattern works best when you can chop out a piece of the object model and use it to represent + the LOB. Think of a LOB as a way to take a bunch of objects that aren’t likely to be queried from + any SQL route outside the application. +* This graph can then be hooked into the SQL schema. ## Credits +* [Serialized LOB](https://martinfowler.com/eaaCatalog/serializedLOB.html) by Martin Fowler From 7e8acad0914801003e5d960c8e1ff1cb1e0460f2 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 23:04:48 +0530 Subject: [PATCH 37/44] #1596:Updated Java Docs and README.md --- slob/README.md | 2 +- slob/src/main/java/com/iluwatar/slob/App.java | 6 ++++++ slob/src/test/java/com/iluwatar/slob/AppTest.java | 8 +++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/slob/README.md b/slob/README.md index f97c40b82e60..33251499335e 100644 --- a/slob/README.md +++ b/slob/README.md @@ -16,7 +16,7 @@ tag: ## Explanation -* Forest here represents the object graph. +* The Forest here represents the object graph. * A forest contains animals and plants. As is in real life the forest object contains plants and animals where some animals eat other animals and some eat only plants. diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 0c7f8b14b34a..2008d2c32130 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -66,6 +66,12 @@ public static void main(String[] args) throws SQLException { /** * Creates a Forest with Animals and Plants along with their respective relationships. + *

The method creates a forest with 2 Plants Grass and Oak of type Herb and tree + * respectively.

+ *

It also creates 3 animals Zebra and Buffalo which eat the plant grass. Lion consumes the + * Zebra and the Buffalo.

+ *

With the above animals and plants and their relationships a forest + * object is created which represents the Object Graph.

* * @return Forest Object */ diff --git a/slob/src/test/java/com/iluwatar/slob/AppTest.java b/slob/src/test/java/com/iluwatar/slob/AppTest.java index 795c5b63e877..f8332a128020 100644 --- a/slob/src/test/java/com/iluwatar/slob/AppTest.java +++ b/slob/src/test/java/com/iluwatar/slob/AppTest.java @@ -50,7 +50,13 @@ class AppTest { /** - * Creates a Forest with Animals and Plants along with their respective relationships + * Creates a Forest with Animals and Plants along with their respective relationships. + *

The method creates a forest with 2 Plants Grass and Oak of type Herb and tree + * respectively.

+ *

It also creates 3 animals Zebra and Buffalo which eat the plant grass. Lion consumes the + * Zebra and the Buffalo.

+ *

With the above animals and plants and their relationships a forest + * object is created which represents the Object Graph.

* * @return Forest Object */ From e988f6aeef31bf43b9a084136fdc7ac839b69897 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 23:07:38 +0530 Subject: [PATCH 38/44] #1596:Updated Extension --- slob/etc/{slob.urm.puml => slob.urm.uml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename slob/etc/{slob.urm.puml => slob.urm.uml} (100%) diff --git a/slob/etc/slob.urm.puml b/slob/etc/slob.urm.uml similarity index 100% rename from slob/etc/slob.urm.puml rename to slob/etc/slob.urm.uml From 88ab371fe6cb662bc691f800943dd057bde10e14 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 21 Jan 2024 23:12:15 +0530 Subject: [PATCH 39/44] #1596:Updated README.md --- slob/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/slob/README.md b/slob/README.md index 33251499335e..a2c23449fb70 100644 --- a/slob/README.md +++ b/slob/README.md @@ -33,15 +33,17 @@ tag: ## Applicability +* This pattern works best when you can chop out a piece of the object model and use it to represent + the LOB. +* Think of a LOB as a way to take a bunch of objects that aren’t likely to be queried from any SQL + route outside the application. +* This graph can then be hooked into the SQL schema. Serialized LOB works poorly when you have + objects outside the LOB reference objects buried in it. * Serialized LOB isn’t considered as often as it might be. XML makes it much more attractive since - it yields a easy-to-implement textual approach. + it yields an easy-to-implement textual approach. * Its main disadvantage is that you can’t query the structure using SQL. * SQL extensions appear to get at XML data within a field, but that’s still not the same (or portable). -* This pattern works best when you can chop out a piece of the object model and use it to represent - the LOB. Think of a LOB as a way to take a bunch of objects that aren’t likely to be queried from - any SQL route outside the application. -* This graph can then be hooked into the SQL schema. ## Credits From db87f73503c85c58ebf75296c71a5a33745a459f Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 10 Mar 2024 13:53:55 +0530 Subject: [PATCH 40/44] #1596:Updated Documentation as per review comments --- slob/README.md | 407 +++++++++++++++++- slob/src/main/java/com/iluwatar/slob/App.java | 38 +- 2 files changed, 429 insertions(+), 16 deletions(-) diff --git a/slob/README.md b/slob/README.md index a2c23449fb70..59514efab17c 100644 --- a/slob/README.md +++ b/slob/README.md @@ -3,7 +3,7 @@ title: Serialized LOB category: Structural language: en tag: - - Object Instantiation + - Data access --- ## Intent @@ -16,16 +16,401 @@ tag: ## Explanation -* The Forest here represents the object graph. -* A forest contains animals and plants. As is in real life the forest object contains plants and - animals - where some animals eat other animals and some eat only plants. -* These relationships are maintained in the Forest Object. -* There are 2 types of Serializers available ClobSerializer and BlobSerializer. -* ClobSerializer uses character or textual based serialization, here the Object graph is converted - to XML and then stored as text in DB. -* BlobSerializer uses binary data for serialization, here the Object graph is converted to Byte - Array and then stored as a blob in DB. +**In plain words** + +> The Forest here represents the object graph. +> A forest contains animals and plants. As is in real life the forest object contains plants and +> animals where some animals eat other animals and some eat only plants. +> * These relationships are maintained in the Forest Object. +> * There are 2 types of Serializers available ClobSerializer and BlobSerializer. +> * ClobSerializer uses character or textual based serialization, here the Object graph is converted +> * to XML and then stored as text in DB. +> * BlobSerializer uses binary data for serialization, here the Object graph is converted to Byte +> * Array and then stored as a blob in DB. + +**Wikipedia says** + +> TODO + +**Programmatic Example** + +* Here is the `Animal` class. It represents the Animal object in the Forest. It contains the name of + the animals in the forest and details of what they eat from the forest plants/animals or both. + +```java +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 animals = new HashSet<>(); + private Set 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(); + } +} +``` + +* Here is the `LobSerializer` abstract class. It provides the specification to serialize and + deserialize the input object and persist and load that object into a DB. + +```java +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); + } + } +} +``` + +* Here is the `ClobSerializer` class. It extends the `LobSerializer` abstract class and provides the + implementation to serialize and deserialize the input object and persist and load that object into + a DB using ClobSerializer. +* Objects are serialized using character or textual based serialization + using XML to represent the object graph. + +```java +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() { + 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; + } +} +``` + +* Here is the `SlobSerializer` class. It extends the `LobSerializer` abstract class and provides the + implementation to serialize and deserialize the input object and persist and load that object into + a DB using ClobSerializer. +* Objects are serialized using binary data based serialization objects a persisted as a BINARY/BLOB + in DB. + +```java +/* + * 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; + } +} +``` ## Class diagram diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 2008d2c32130..0cffa0b4dfba 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -46,30 +46,58 @@ */ public class App { + public static final String CLOB = "CLOB"; private static final Logger LOGGER = LoggerFactory.getLogger(App.class); /** * Main entry point to program. * + *

A Forest is created using {@link #createForest()} with Animals and Plants along with their + * respective relationships.

+ * + *

Creates a {@link LobSerializer} using the method + * {@link #createLobSerializer(String[])}.

+ * + *

Once created the serializer is passed to the + * {@link #executeSerializer(Forest, LobSerializer)} which handles the serialization, + * deserialization and persisting and loading from DB.

+ * * @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); + } + + /** + *

Creates a {@link LobSerializer} on the basis of input args.

+ *

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.

+ * + * @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")) { + if (args.length > 0 && Objects.equals(args[0], CLOB)) { serializer = new ClobSerializer(); } else { serializer = new BlobSerializer(); } - executeSerializer(forest, serializer); + return serializer; } /** - * Creates a Forest with Animals and Plants along with their respective relationships. - *

The method creates a forest with 2 Plants Grass and Oak of type Herb and tree + * Creates a Forest with {@link Animal} and {@link Plant} along with their respective + * relationships. + * + *

The method creates a {@link Forest} with 2 Plants Grass and Oak of type Herb and tree * respectively.

+ * *

It also creates 3 animals Zebra and Buffalo which eat the plant grass. Lion consumes the * Zebra and the Buffalo.

+ * *

With the above animals and plants and their relationships a forest * object is created which represents the Object Graph.

* @@ -88,7 +116,7 @@ private static Forest createForest() { /** * 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 provided serializer. + * 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 From 5ef36a3ab7a3bc4c348fd83e7faa5e4980e44c3e Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 10 Mar 2024 13:57:15 +0530 Subject: [PATCH 41/44] #1596:Updated Documentation as per review comments --- slob/src/main/java/com/iluwatar/slob/App.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/slob/src/main/java/com/iluwatar/slob/App.java b/slob/src/main/java/com/iluwatar/slob/App.java index 0cffa0b4dfba..743cc8293f1f 100644 --- a/slob/src/main/java/com/iluwatar/slob/App.java +++ b/slob/src/main/java/com/iluwatar/slob/App.java @@ -51,6 +51,10 @@ public class App { /** * Main entry point to program. + *

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.

* *

A Forest is created using {@link #createForest()} with Animals and Plants along with their * respective relationships.

From c61639c719d6d3093bf3be66d4f887adbd55ff22 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Sun, 10 Mar 2024 19:29:52 +0530 Subject: [PATCH 42/44] #1596: Updated README.md --- slob/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/slob/README.md b/slob/README.md index 59514efab17c..bc4bbc6f6358 100644 --- a/slob/README.md +++ b/slob/README.md @@ -28,10 +28,6 @@ tag: > * BlobSerializer uses binary data for serialization, here the Object graph is converted to Byte > * Array and then stored as a blob in DB. -**Wikipedia says** - -> TODO - **Programmatic Example** * Here is the `Animal` class. It represents the Animal object in the Forest. It contains the name of From 7e7869ddc001e733f1e55b553630c95b9cb30929 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Mon, 18 Mar 2024 17:37:22 +0530 Subject: [PATCH 43/44] #1596:Updated Documentation as per review comments --- slob/README.md | 81 ++------------------------------------------------ 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/slob/README.md b/slob/README.md index 59514efab17c..724ac09e427b 100644 --- a/slob/README.md +++ b/slob/README.md @@ -38,20 +38,6 @@ tag: the animals in the forest and details of what they eat from the forest plants/animals or both. ```java -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. @@ -62,8 +48,8 @@ import org.w3c.dom.NodeList; public class Forest implements Serializable { private String name; - private Set animals = new HashSet<>(); - private Set plants = new HashSet<>(); + private final Set animals = new HashSet<>(); + private final Set plants = new HashSet<>(); /** * Provides the representation of Forest in XML form. @@ -139,16 +125,6 @@ public class Forest implements Serializable { deserialize the input object and persist and load that object into a DB. ```java -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 @@ -237,23 +213,6 @@ public abstract class LobSerializer implements Serializable, Closeable { using XML to represent the object graph. ```java -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 @@ -327,42 +286,6 @@ public class ClobSerializer extends LobSerializer { in DB. ```java -/* - * 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. From eaf438dfeaf169ba27ddb0c182ca891536ec83e8 Mon Sep 17 00:00:00 2001 From: Kishalay Pandey Date: Mon, 25 Mar 2024 00:15:54 +0530 Subject: [PATCH 44/44] #1596: Added SLOB Module --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 44178fd1af54..2e1b3312b38b 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,7 @@ single-table-inheritance dynamic-proxy gateway + slob