From a3717d963a57cab610ae2f0036d37cc6caea6f5d Mon Sep 17 00:00:00 2001 From: Robert Vokac Date: Sat, 18 Mar 2023 11:23:42 +0100 Subject: [PATCH] Started working on power-framework 2.0.0 --- CHANGELOG.md | 4 + README.md | 37 +- pom.xml | 154 +- power-ai/pom.xml | 54 + power-ai/src/main/java/module-info.java | 29 + .../org/nanoboot/powerframework/ai}/.gitkeep | 0 {src => power-ai/src}/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/ai/.gitkeep | 0 power-bean/pom.xml | 54 + power-bean/src/main/java/module-info.java | 29 + .../org/nanoboot/powerframework/bean/.gitkeep | 0 power-bean/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/bean/.gitkeep | 0 power-blockchain/pom.xml | 122 ++ .../src/main/java/module-info.java | 34 + .../powerframework/blockchain/.gitkeep | 0 .../blockchain/api/BlockDeserializer.java | 33 + .../blockchain/api/BlockSerializer.java | 33 + .../powerframework/blockchain/core/Block.java | 132 ++ .../blockchain/core/BlockChainException.java | 35 + .../blockchain/core/BlockchainEngine.java | 40 + .../core/BlockchainEngineVersion.java | 54 + .../blockchain/core/BlockchainProtocol.java | 56 + .../blockchain/impl/JsonBlockSerializer.java | 40 + .../blockchain/impl/StringSerializer.java | 45 + .../blockchain/orig/api/BlockData.java | 31 + .../orig/api/BlockDeserializer.java | 33 + .../blockchain/orig/api/BlockMiner.java | 35 + .../blockchain/orig/api/BlockSerializer.java | 33 + .../blockchain/orig/api/BlockValidator.java | 35 + .../blockchain/orig/base/Block.java | 117 ++ .../blockchain/orig/base/BlockChain.java | 100 ++ .../orig/base/BlockChainEngine.java | 55 + .../blockchain/orig/base/BlockFragment.java | 42 + .../blockchain/orig/base/BlockHeader.java | 60 + .../blockchain/orig/base/BlockType.java | 55 + .../orig/base/BlockTypeVersionList.java | 47 + .../blockchain/orig/cash/Transaction.java | 29 + .../orig/cash/TransactionValidator.java | 29 + .../blockchain/orig/cash/Wallet.java | 29 + .../blockchain/orig/core/Main.java | 48 + .../orig/impl/JsonBlockSerializer.java | 41 + .../blockchain/orig/impl/SimpleBlockData.java | 40 + .../orig/impl/TestCash_1_0_Block.java | 36 + .../orig/impl/TestCash_1_0_BlockMiner.java | 95 ++ .../orig/impl/TestCash_1_0_BlockType.java | 39 + .../orig/impl/TestCash_BlockChainEngine.java | 136 ++ power-blockchain/src/main/resources/.gitkeep | 0 .../powerframework/blockchain/.gitkeep | 0 power-collections/pom.xml | 73 + .../src/main/java/module-info.java | 37 + .../collections/BinaryTreeNode.java | 176 +++ .../collections/BinaryTreeNodeType.java | 46 + .../collections/CollectionException.java | 43 + .../collections/DoubleLinkedList.java | 319 ++++ .../collections/DoubleLinkedListNode.java | 166 ++ .../DoubleLinkedListNodeReferenceType.java | 64 + .../powerframework/collections/KeyValue.java | 71 + .../collections/PowerCollection.java | 215 +++ .../powerframework/collections/PowerList.java | 193 +++ .../powerframework/collections/PowerMap.java | 266 ++++ .../collections/PowerQueue.java | 87 ++ .../powerframework/collections/PowerSet.java | 144 ++ .../collections/PowerStack.java | 68 + .../collections/Properties.java | 132 ++ .../collections/SingleLinkedList.java | 442 ++++++ .../collections/SingleLinkedListNode.java | 86 + .../powerframework/collections/StackI.java | 63 +- .../powerframework/collections/Table.java | 62 + .../powerframework/collections/Tree.java | 48 +- .../powerframework/collections/TreeNode.java | 105 ++ .../collections/arrays/Array.java | 1264 +++++++++++++++ .../collections/arrays/ArrayException.java | 38 + .../collections/arrays/ArrayType.java | 43 + .../collections/arrays/ByteArray.java | 67 + .../collections/arrays/IntArray.java | 100 ++ .../collections/arrays/ObjectArray.java | 75 + .../collections/arrays/package-info.java | 27 + .../collections/buffer/CharBuffer.java | 64 + .../collections/graphs/.gitkeep | 0 .../internal/AbstractLinkedList.java | 171 ++ .../internal/AbstractLinkedListNode.java | 45 + .../internal/AbstractTreeNode.java | 53 + .../collections/internal/package-info.java | 27 + .../collections/package-info.java | 27 + power-collections/src/main/resources/.gitkeep | 0 .../collections/PowerMapTest.java | 412 +++++ .../collections/PropertiesTest.java | 120 ++ .../powerframework/collections/QueueTest.java | 188 ++- .../collections/SingleLinkedListNodeTest.java | 164 ++ .../collections/SingleLinkedListTest.java | 782 ++++++++++ .../powerframework/collections/StackTest.java | 169 +- power-core/pom.xml | 57 + power-core/src/lombok.config | 4 + power-core/src/main/java/module-info.java | 32 + .../powerframework/core/CoreException.java | 41 + .../powerframework/core/PowerException.java | 55 + .../powerframework/core/PowerFramework.java | 75 + .../powerframework/core/PowerObject.java | 50 + .../NotYetImplementedException.java | 43 + .../UnsupportedMethodException.java | 45 + .../core/exceptions/package-info.java | 27 + .../powerframework/core/package-info.java | 29 + .../powerframework/core/version/Version.java | 341 ++++ .../core/version/VersionNumberType.java | 66 + .../core/version/VersionType.java | 127 ++ .../core/version/package-info.java | 27 + power-core/src/main/resources/.gitkeep | 0 .../src/main/resources/version.properties | 1 + .../core/CoreExceptionTest.java | 40 + .../core/PowerExceptionTest.java | 50 + .../core/PowerFrameworkTest.java | 38 + .../powerframework/core/PowerObjectTest.java | 38 + .../NotYetImplementedExceptionTest.java | 39 + .../UnsupportedMethodExceptionTest.java | 40 + .../core/version/VersionNumberTypeTest.java | 38 + .../core/version/VersionTest.java | 293 ++++ .../core/version/VersionTypeTest.java | 91 ++ power-db/pom.xml | 75 + power-db/src/main/java/module-info.java | 35 + .../db/engines/AbstractSqlEngine.java | 61 + .../powerframework/db/engines/sqlite/.gitkeep | 0 .../db/manager/CommandStore.java | 32 +- .../powerframework/db/manager/Database.java | 515 ++++++ .../db/manager/DatabaseException.java | 38 + .../manager/DatabaseOperatingException.java | 38 + .../powerframework/db/manager/Databases.java | 73 +- .../powerframework/db/manager/Table.java | 37 +- power-db/src/main/resources/.gitkeep | 0 .../powerframework/db/engines/.gitkeep | 0 .../db/manager/CommandStoreTest.java | 44 +- .../db/manager}/DatabaseConnectionTest.java | 70 +- .../db/manager}/DatabaseTest.java | 81 +- .../powerframework/db/manager/TableTest.java | 45 +- power-io/pom.xml | 68 + power-io/src/main/java/module-info.java | 36 + .../nanoboot/powerframework/io/bit/Blob.java | 228 +++ .../nanoboot/powerframework/io/bit/Byte.java | 74 + .../io/bit/DigitalInformationUnit.java | 127 ++ .../powerframework/io/bit/TextCoder.java | 291 ++++ .../io/bit/base64/Base64Coder.java | 86 + .../io/bit/base64/Base64Convertor.java | 63 + .../io/bit/base64/Base64Implementation.java | 35 + .../io/bit/base64/Base64Padding.java | 88 ++ .../io/bit/base64/JavaBase64Coder.java | 53 + .../io/bit/base64/OkayBase64Decoder.java | 132 ++ .../io/bit/base64/OkayBase64Encoder.java | 87 ++ .../io/bit/base64/package-info.java | 29 + .../powerframework/io/fs/BinaryFile.java | 32 + .../powerframework/io/fs/Directory.java | 41 + .../nanoboot/powerframework/io/fs/Disk.java | 32 + .../nanoboot/powerframework/io/fs/File.java | 35 + .../powerframework/io/fs/FileSystem.java | 85 + .../powerframework/io/fs/FileType.java | 41 + .../powerframework/io/fs/PowerFileSystem.java | 66 + .../powerframework/io/fs/TextFile.java | 31 + .../io/fs/virtualfilesystem/.gitkeep | 0 power-io/src/main/resources/.gitkeep | 0 .../powerframework/io/bit/BlobTest.java | 418 +++++ .../powerframework/io/bit/ByteTest.java | 204 +++ power-json/pom.xml | 62 + power-json/src/main/java/module-info.java | 32 + .../json/ArrayWithItemsSplitByComma.java | 62 + .../powerframework/json/CommasFinder.java | 92 ++ .../powerframework/json/JsonArray.java | 238 +-- .../powerframework/json/JsonArrayParser.java | 62 +- .../powerframework/json/JsonArrayPrinter.java | 49 +- .../json/JsonArraySerializable.java | 45 + .../powerframework/json/JsonBoolean.java | 27 +- .../powerframework/json/JsonChar.java | 27 +- .../powerframework/json/JsonConstants.java | 48 + .../powerframework/json/JsonDouble.java | 23 +- .../powerframework/json/JsonException.java | 41 + .../powerframework/json/JsonFloat.java | 23 +- .../nanoboot/powerframework/json/JsonInt.java | 23 +- .../powerframework/json/JsonLong.java | 23 +- .../powerframework/json/JsonObject.java | 708 +++++++++ .../json/JsonObjectDeserializable.java | 37 + .../json/JsonObjectKeyValue.java | 84 + .../powerframework/json/JsonObjectParser.java | 78 + .../json/JsonObjectPrinter.java | 69 +- .../json/JsonObjectSerializable.java | 40 + .../json/JsonObjectValidator.java | 11 +- .../powerframework/json/JsonParser.java | 53 + .../powerframework/json/JsonPrint.java | 39 + .../powerframework/json/JsonPrinter.java | 26 +- .../powerframework/json/JsonString.java | 30 +- .../powerframework/json/JsonValue.java | 364 +++++ .../powerframework/json/JsonValueType.java | 5 +- .../powerframework/json/package-info.java | 27 + power-json/src/main/resources/.gitkeep | 0 .../json/ArrayWithItemsSplitByCommaTest.java | 66 + .../powerframework/json/CommasFinderTest.java | 64 + .../powerframework/json/JsonArrayTest.java | 20 +- .../powerframework/json/JsonObjectTest.java | 114 +- .../powerframework/json/JsonValueTest.java | 83 +- power-log/pom.xml | 64 + power-log/src/main/java/module-info.java | 31 + .../nanoboot/powerframework/log/Level.java | 106 ++ .../powerframework/log/LogRowCreator.java | 78 + .../nanoboot/powerframework/log/Logger.java | 294 ++++ .../log/MethodStartMessageCreator.java | 83 + .../nanoboot/powerframework/log/Target.java | 50 + power-log/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/log/.gitkeep | 0 power-mail/.gitignore | 9 + power-mail/README.md | 2 + power-mail/bin/.gitignore | 2 + power-mail/bin/backup.sql | 16 + power-mail/bin/backupfile.sh | 12 + power-mail/bin/mailer.jar | Bin 0 -> 755057 bytes power-mail/bin/mailer.properties.template | 6 + power-mail/bin/mailer.sh | 46 + power-mail/bin/mailerrv.sh | 5 + power-mail/environment-startup.txt | 0 power-mail/pom.xml | 110 ++ power-mail/src/main/java/module-info.java | 31 + .../nanoboot/powerframework/mail/MailBox.java | 111 ++ .../powerframework/mail/MailMessage.java | 38 + .../powerframework/mail/MailMessageType.java | 30 + .../nanoboot/powerframework/mail/Main.java | 111 ++ .../powerframework/mail/SmtpServer.java | 36 + .../powerframework/mail/SmtpUser.java | 34 + power-mail/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/mail/.gitkeep | 0 power-persistence/pom.xml | 69 + .../src/main/java/module-info.java | 34 + .../persistence/AttributeType.java | 84 + .../persistence/BaseColumns.java | 56 + .../persistence/EntityAttribute.java | 141 ++ .../persistence/EntityManager.java | 286 ++++ .../persistence/EntityPointer.java | 61 + .../persistence/EntitySchema.java | 216 +++ .../persistence/EntityStorage.java | 86 + .../persistence/JavaSqlConvertor.java | 104 ++ .../persistence/MethodInvocation.java | 173 +++ .../persistence/PersistenceException.java | 37 + .../powerframework/persistence/Utils.java | 118 ++ .../persistence/annotations/Attribute.java | 37 + .../annotations/AttributeName.java | 38 + .../persistence/annotations/Entity.java | 38 + .../persistence/annotations/EntityName.java | 40 + .../annotations/ForeignEntity.java | 40 + .../persistence/annotations/NotNull.java | 40 + .../persistence/annotations/UUID.java | 36 + .../persistence/annotations/Unmodifiable.java | 38 + power-persistence/src/main/resources/.gitkeep | 0 .../powerframework/persistence/.gitkeep | 0 power-random/pom.xml | 59 + power-random/src/main/java/module-info.java | 37 + .../random/RandomException.java | 43 + .../random/choicegenerators/ChoiceEntry.java | 43 + .../choicegenerators/ChoiceGenerator.java | 95 ++ .../ProbabilityGenerator.java | 80 + .../random/choicegenerators/package-info.java | 27 + .../random/generators/RandomGenerator.java | 233 +++ .../CPlusPlus11LinearCongruentGenerator.java | 79 + .../linearcongruent/DummyGenerator.java | 64 + .../LinearCongruentGenerator.java | 123 ++ .../combined/w5/W5GeneratorsFactory.java | 36 + .../combined/w5/W5GeneratorsFactoryImpl.java | 161 ++ .../combined/w5/W5GeneratorsProcessor.java | 37 + .../w5/W5GeneratorsProcessorImpl.java | 76 + .../combined/w5/W5RandomGenerator.java | 112 ++ .../combined/w5/package-info.java | 26 + .../linearcongruent/package-info.java | 27 + .../random/generators/package-info.java | 27 + .../random/internal/RandomNumberUtils.java | 97 ++ .../random/internal/RandomTextUtils.java | 130 ++ .../random/internal/package-info.java | 26 + .../powerframework/random/package-info.java | 27 + power-random/src/main/resources/.gitkeep | 0 .../random/RandomExceptionTest.java | 38 + .../choicegenerators/ChoiceGeneratorTest.java | 222 +++ .../ProbabilityGeneratorTest.java | 153 ++ .../generators/RandomGeneratorTest.java | 1379 +++++++++++++++++ ...lusPlus11LinearCongruentGeneratorTest.java | 53 + .../LinearCongruentGeneratorTest.java | 103 ++ .../w5/W5GeneratorsFactoryImplTest.java | 59 + .../w5/W5GeneratorsProcessorImplTest.java | 51 + .../combined/w5/W5RandomGeneratorTest.java | 59 + .../random/internal/RandomTextUtilsTest.java | 49 + power-redmond/pom.xml | 58 + power-redmond/src/main/java/module-info.java | 32 + .../nanoboot/powerframework/redmond/.gitkeep | 0 power-redmond/src/main/resources/.gitkeep | 0 .../nanoboot/powerframework/redmond/.gitkeep | 0 power-reflection/pom.xml | 57 + .../src/main/java/module-info.java | 31 + .../powerframework/reflection/BeanMethod.java | 51 + .../reflection/ReflectionUtils.java | 211 +++ power-reflection/src/main/resources/.gitkeep | 0 .../reflection/ReflectionUtilsTest.java | 131 ++ ...TestClassWithBadConstructorAndMethods.java | 46 + power-security/pom.xml | 51 + power-security/src/main/java/module-info.java | 32 + .../security/SecurityException.java | 34 + .../security/hash/api/HashCalculator.java | 114 ++ .../hash/impl/AbstractShaHashCalculator.java | 59 + .../hash/impl/Sha1HashCalculator.java | 41 + .../hash/impl/Sha256HashCalculator.java | 41 + .../hash/locator/HashCalculatorLocator.java | 66 + .../security/hash/locator/HashImpl.java | 42 + power-security/src/main/resources/.gitkeep | 0 .../nanoboot/powerframework/security/.gitkeep | 0 power-shark/pom.xml | 52 + power-shark/src/main/java/module-info.java | 33 + .../shark/compiler/ByteCode.java | 33 + .../shark/compiler/Compiler.java | 42 + .../shark/language/MoleCode.java | 31 + .../language/expressions/FunctionCall.java | 32 + .../shark/language/keywords/KeyWords.java | 169 ++ .../shark/language/literals/BigDec.java | 32 + .../shark/language/literals/BigNum.java | 32 + .../shark/language/literals/Bool.java | 32 + .../shark/language/literals/Char.java | 32 + .../shark/language/literals/Dec.java | 32 + .../shark/language/literals/Num.java | 33 + .../shark/language/literals/Str.java | 31 + .../shark/language/operators/Add.java | 32 + .../shark/language/operators/And.java | 32 + .../language/operators/DecrementByOne.java | 32 + .../shark/language/operators/Divide.java | 32 + .../language/operators/IncrementByOne.java | 32 + .../shark/language/operators/Multiply.java | 32 + .../shark/language/operators/Not.java | 33 + .../shark/language/operators/Or.java | 31 + .../shark/language/statements/Break.java | 32 + .../shark/language/statements/Continue.java | 32 + .../shark/language/statements/DoBlock.java | 32 + .../shark/language/statements/Function.java | 37 + .../shark/language/statements/IfBlock.java | 32 + .../shark/language/statements/Import.java | 32 + .../shark/language/statements/Return.java | 30 + .../language/statements/StatementParser.java | 31 + .../shark/language/statements/Struct.java | 31 + .../language/statements/SwitchBlock.java | 31 + .../statements/VariableAssignment.java | 31 + .../statements/VariableDeclaration.java | 33 + .../shark/language/statements/WhileBlock.java | 31 + .../shark/language/syntax/SharkFunction.java | 32 + .../syntax/SharkFunctionArgument.java | 34 + .../nanoboot/powerframework/shark/todo.txt | 1 + .../shark/virtualmachine/VirtualMachine.java | 31 + .../virtualmachine/instructions/.gitkeep | 0 power-shark/src/main/resources/.gitkeep | 0 .../nanoboot/powerframework/shark/.gitkeep | 0 power-sound/pom.xml | 58 + power-sound/src/main/java/module-info.java | 31 + .../nanoboot/powerframework/sound/.gitkeep | 0 power-sound/src/main/resources/.gitkeep | 0 .../nanoboot/powerframework/sound/.gitkeep | 0 power-sql/pom.xml | 64 + power-sql/src/main/java/module-info.java | 32 + .../sql/core/ColumnNameValue.java | 57 + .../powerframework/sql/core/OrderBy.java | 57 + .../powerframework/sql/core/OrderByType.java | 31 + .../sql/core/SqlStatementCreator.java | 130 ++ .../sql/filter/AbstractFilter.java | 40 + .../sql/filter/SqlConjunction.java | 69 + .../powerframework/sql/filter/SqlFilter.java | 43 + .../sql/filter/SqlOperation.java | 92 ++ power-sql/src/main/resources/.gitkeep | 0 power-sql/src/test/java/.gitkeep | 0 power-stat/pom.xml | 58 + power-stat/src/main/java/module-info.java | 31 + .../org/nanoboot/powerframework/stat/.gitkeep | 0 power-stat/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/stat/.gitkeep | 0 power-svg/pom.xml | 58 + power-svg/src/main/java/module-info.java | 32 + .../org/nanoboot/powerframework/svg/.gitkeep | 0 power-svg/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/svg/.gitkeep | 0 power-template/.gitkeep | 0 power-template/pom.xml | 58 + power-template/src/main/java/module-info.java | 32 + .../nanoboot/powerframework/template/.gitkeep | 0 power-template/src/main/resources/.gitkeep | 0 .../nanoboot/powerframework/template/.gitkeep | 0 power-text/pom.xml | 54 + power-text/src/main/java/module-info.java | 31 + .../powerframework/text/AsciiCharacter.java | 623 ++++++++ .../powerframework/text/CharacterRange.java | 186 +++ .../powerframework/text/CharacterType.java | 54 + .../powerframework/text/TextException.java | 44 + .../powerframework/text/package-info.java | 27 + power-text/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/text/.gitkeep | 0 .../text/AsciiCharacterTest.java | 103 ++ .../text/CharacterRangeTest.java | 150 ++ .../text/TextExceptionTest.java | 39 + power-time/pom.xml | 84 + power-time/src/main/java/module-info.java | 35 + .../time/SimpleDateTimeFormatByTimeZone.java | 43 + .../powerframework/time}/TimeSource.java | 53 +- .../time/duration/Duration.java | 429 +++++ .../powerframework/time/duration/Period.java | 182 +++ .../time/duration/SimpleStopWatch.java | 141 ++ .../time/duration/StopWatch.java | 128 ++ .../time/duration/StopWatchState.java | 45 + .../powerframework/time/module-info.java.txt | 7 + .../powerframework/time/moment/DateTime.java | 261 ++++ .../time/moment}/LocalDate.java | 118 +- .../time/moment/LocalDateTime.java | 167 ++ .../powerframework/time/moment/LocalTime.java | 138 ++ .../powerframework/time/moment}/TimeZone.java | 50 +- .../time/moment}/UniversalDateTime.java | 116 +- .../time/moment}/ZonedDateTime.java | 108 +- .../time/utils/AbstractValidator.java | 37 + .../time/utils}/DateUnitsValidator.java | 137 +- .../time/utils/LocalSettings.java | 55 + .../utils/RandomDateTimeUnitsGenerator.java | 31 + .../time/utils/RemainingTimeCalculator.java | 68 + .../time/utils/TimeException.java | 16 +- .../powerframework/time/utils/TimeUnit.java | 203 +++ .../time/utils/TimeUnitConvertor.java | 96 ++ .../time/utils}/TimeUnitsValidator.java | 158 +- power-time/src/main/resources/.gitkeep | 0 .../time/duration/DurationTest.java | 877 +++++++++++ .../time/duration/StopWatchTest.java | 279 ++++ .../time/moment}/DateTimeTest.java | 91 +- .../time/moment}/LocalDateTest.java | 104 +- .../time/moment/LocalDateTimeTest.java | 167 ++ .../time/moment}/LocalTimeTest.java | 79 +- .../time/moment}/TimeZoneTest.java | 27 +- .../time/moment/UniversalDateTimeTest.java | 146 ++ .../time/moment/ZonedDateTimeTest.java | 155 ++ .../time/utils}/DateUnitsValidatorTest.java | 14 +- .../time/utils/TimeUnitsValidatorTest.java | 286 ++++ power-utils/pom.xml | 69 + power-utils/src/main/java/module-info.java | 36 + .../powerframework/utils/CommandReader.java | 252 +++ .../utils/NamingConvention.java | 73 + .../utils/NamingConventionConvertor.java | 287 ++++ .../powerframework/utils/StringTemplate.java | 65 + .../powerframework/utils/StringUtils.java | 84 + .../powerframework/utils/UtilsException.java | 42 + .../utils/annotations/Done.java | 32 + .../utils/annotations/InProgress.java | 36 + .../utils/annotations/ToDo.java | 35 + .../utils/annotations/ToRemove.java | 32 + .../utils/annotations/package-info.java | 27 + .../utils/builder/AbstractBuilder.java | 43 + .../powerframework/utils/builder/Builder.java | 36 + .../utils/builder/package-info.java | 27 + .../utils/collections/ListSplitter.java | 67 + .../powerframework/utils/compression/.gitkeep | 0 .../utils/dependencies/DependencyNode.java | 53 + .../dependencies/DependencyResolver.java | 34 + .../DependencyResolverJGraphTImpl.java | 61 + .../powerframework/utils/minitext/.gitkeep | 0 .../powerframework/utils/package-info.java | 27 + .../utils/proxy/MethodInvoker.java | 33 + .../utils/proxy/ProxyUtils.java | 136 ++ power-utils/src/main/resources/.gitkeep | 0 power-utils/src/test/java/.gitkeep | 0 .../utils/CommandReaderTest.java | 263 ++++ .../utils/NamingConventionConvertorTest.java | 224 +++ .../powerframework/utils/StringUtilsTest.java | 55 + .../utils/UtilsExceptionTest.java | 37 + .../DependencyResolverJGraphTImplTest.java | 83 + power-view/pom.xml | 66 + power-view/src/main/java/module-info.java | 38 + .../powerframework/view}/EnumColour.java | 33 +- .../view}/JavaFXApplication.java | 21 +- .../powerframework/view/PowerApplication.java | 43 + .../nanoboot/powerframework/view}/Screen.java | 33 +- .../nanoboot/powerframework/view/View.java | 56 +- .../powerframework/view/ViewException.java | 41 + .../powerframework/view/ViewRunner.java | 11 +- .../powerframework/view}/boxes/AlertBox.java | 38 +- .../powerframework/view}/boxes/Box.java | 43 +- .../view}/boxes/MessageBox.java | 41 +- .../view/clocks/AnalogClock.java | 32 + .../powerframework/view/clocks/Clock.java | 32 + .../view/clocks/DigitalClock.java | 32 + .../view/layouts}/CellLayout.java | 64 +- .../powerframework/view/layouts}/SLayout.java | 28 +- .../powerframework/view/package-info.java | 27 + .../nanoboot/powerframework/view/svg/.gitkeep | 0 .../view}/window/ColourVariant.java | 7 +- .../view}/window/MoveableArea.java | 26 +- .../view}/window/ResizingGrid.java | 18 +- .../view}/window/ResizingGridRectangle.java | 15 +- .../powerframework/view}/window/TitleBar.java | 28 +- .../view}/window/TitleIcon.java | 19 +- .../powerframework/view}/window/Window.java | 110 +- .../view}/window/WindowColourSkin.java | 23 +- .../view}/window/WindowSizeMode.java | 7 +- .../view}/window/controls/Button.java | 26 +- .../window/controls/NumericMinusPlus.java | 7 +- .../view}/window/controls/PasswordField.java | 18 +- .../view}/window/controls/RadioButton.java | 29 +- .../window/controls/RadioButtonGroup.java | 10 +- .../view}/window/controls/SCheckBox.java | 42 +- .../view}/window/controls/SComboBox.java | 19 +- .../view}/window/controls/SLabel.java | 21 +- .../view}/window/controls/TabPane.java | 11 +- .../view}/window/controls/TextField.java | 31 +- .../window/titlebuttons/CloseButton.java | 25 +- .../titlebuttons/LineInWindowTitleButton.java | 14 +- .../titlebuttons/MaximizeRestoreButton.java | 57 +- .../window/titlebuttons/MinimizeButton.java | 22 +- .../titlebuttons/WindowTitleButton.java | 22 +- power-view/src/main/resources/.gitkeep | 0 power-view/src/test/java/.gitkeep | 0 power-web/pom.xml | 67 + power-web/src/main/java/module-info.java | 36 + .../powerframework/web/PowerWebException.java | 32 + .../powerframework/web/PrettyPrinter.java | 37 + .../nanoboot/powerframework/web/TestMain.java | 66 + .../powerframework/web/css/CssStyle.java | 62 + .../powerframework/web/css/CssStyles.java | 117 ++ .../web/css/CssStylesSelector.java | 42 + .../web/css/CssStylesSelectors.java | 53 + .../powerframework/web/html/WebElement.java | 71 + .../powerframework/web/html/WebPage.java | 119 ++ .../web/html/attributes/Action.java | 40 + .../web/html/attributes/Charset.java | 41 + .../web/html/attributes/Class.java | 40 + .../web/html/attributes/Content.java | 40 + .../web/html/attributes/Height.java | 40 + .../web/html/attributes/Href.java | 40 + .../web/html/attributes/HttpEquiv.java | 41 + .../web/html/attributes/Id.java | 40 + .../web/html/attributes/Method.java | 40 + .../web/html/attributes/Name.java | 41 + .../web/html/attributes/Rel.java | 40 + .../web/html/attributes/Src.java | 40 + .../web/html/attributes/Style.java | 60 + .../web/html/attributes/Template.java | 40 + .../web/html/attributes/Title.java | 40 + .../web/html/attributes/Type.java | 39 + .../web/html/attributes/Value.java | 39 + .../web/html/attributes/Width.java | 39 + .../powerframework/web/html/tags/A.java | 73 + .../powerframework/web/html/tags/Body.java | 59 + .../powerframework/web/html/tags/Br.java | 43 + .../powerframework/web/html/tags/Div.java | 59 + .../powerframework/web/html/tags/Form.java | 83 + .../web/html/tags/FormMethod.java | 32 + .../powerframework/web/html/tags/H1.java | 62 + .../powerframework/web/html/tags/H2.java | 62 + .../powerframework/web/html/tags/H3.java | 62 + .../powerframework/web/html/tags/Head.java | 57 + .../web/html/tags/HiddenInput.java | 34 + .../powerframework/web/html/tags/Hr.java | 55 + .../powerframework/web/html/tags/Html.java | 54 + .../web/html/tags/HtmlElement.java | 65 + .../powerframework/web/html/tags/Img.java | 63 + .../powerframework/web/html/tags/Input.java | 101 ++ .../web/html/tags/InputType.java | 32 + .../powerframework/web/html/tags/Label.java | 58 + .../powerframework/web/html/tags/Li.java | 60 + .../powerframework/web/html/tags/Link.java | 63 + .../powerframework/web/html/tags/Meta.java | 57 + .../powerframework/web/html/tags/Ol.java | 56 + .../powerframework/web/html/tags/Option.java | 74 + .../powerframework/web/html/tags/Select.java | 65 + .../powerframework/web/html/tags/Span.java | 60 + .../powerframework/web/html/tags/Style.java | 64 + .../web/html/tags/SubmitInput.java | 33 + .../powerframework/web/html/tags/TBody.java | 64 + .../powerframework/web/html/tags/Table.java | 63 + .../web/html/tags/TagTemplate.java | 64 + .../powerframework/web/html/tags/Td.java | 60 + .../powerframework/web/html/tags/Th.java | 60 + .../powerframework/web/html/tags/Title.java | 43 + .../powerframework/web/html/tags/Tr.java | 63 + .../powerframework/web/html/tags/Ul.java | 56 + .../powerframework/web/javascript/.gitkeep | 0 power-web/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/web/.gitkeep | 0 power-wiki/pom.xml | 52 + power-wiki/src/main/java/module-info.java | 31 + .../nanoboot/powerframework/wiki/Block.java | 170 ++ .../powerframework/wiki/BlockList.java | 70 + .../powerframework/wiki/BlockType.java | 158 ++ .../powerframework/wiki/HtmlTags.java | 117 ++ .../nanoboot/powerframework/wiki/Macro.java | 65 + .../powerframework/wiki/StringSource.java | 75 + .../powerframework/wiki/TextFormatter.java | 81 + .../powerframework/wiki/TextProcessorI.java | 34 + .../powerframework/wiki/WikiException.java | 53 + .../powerframework/wiki/WikiMarks.java | 108 ++ .../powerframework/wiki/WikiParser.java | 192 +++ .../wiki/convertors/ListConvertor.java | 89 ++ .../wiki/macroprocessors/.gitkeep | 0 power-wiki/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/wiki/.gitkeep | 0 power-xml/pom.xml | 62 + power-xml/src/main/java/module-info.java | 31 + .../org/nanoboot/powerframework/xml/.gitkeep | 0 .../powerframework/xml/Attribute.java | 76 + .../powerframework/xml/Attributes.java | 208 +++ .../powerframework/xml/Buildable.java | 39 + .../powerframework/xml/Constants.java | 32 + .../nanoboot/powerframework/xml/Element.java | 220 +++ .../powerframework/xml/ElementType.java | 31 + .../nanoboot/powerframework/xml/Elements.java | 163 ++ .../powerframework/xml/NoElement.java | 50 + .../powerframework/xml/XmlComment.java | 47 + .../nanoboot/powerframework/xml/XmlType.java | 30 + .../nanoboot/powerframework/xml/XmlTypeI.java | 30 + .../nanoboot/powerframework/xml/XmlUtils.java | 52 + power-xml/src/main/resources/.gitkeep | 0 .../org/nanoboot/powerframework/xml/.gitkeep | 0 .../collections/Dictionary.java | 214 --- .../collections/DictionaryKeyIterator.java | 87 -- .../powerframework/collections/Queue.java | 107 -- .../powerframework/collections/Stack.java | 141 -- .../database/DatabaseConnection.java | 351 ----- .../powerframework/datetime/DateTime.java | 189 --- .../powerframework/datetime/Duration.java | 626 -------- .../datetime/LocalDateTime.java | 112 -- .../powerframework/datetime/LocalTime.java | 115 -- .../powerframework/datetime/package-info.java | 4 - .../powerframework/json/JsonObject.java | 540 ------- .../powerframework/json/JsonObjectParser.java | 110 -- .../powerframework/json/JsonParser.java | 176 --- .../json/JsonSpecialCharSequences.java | 99 -- .../powerframework/json/JsonValue.java | 290 ---- .../nanoboot/powerframework/package-info.java | 5 - .../pseudorandom/PseudoRandomGenerator.java | 131 -- .../DictionaryKeyIteratorTest.java | 205 --- .../collections/DictionaryNodeTest.java | 137 -- .../collections/DictionaryTest.java | 381 ----- .../powerframework/datetime/DurationTest.java | 878 ----------- .../datetime/LocalDateTimeTest.java | 166 -- .../datetime/TimeUnitsValidatorTest.java | 288 ---- .../datetime/UniversalDateTimeTest.java | 148 -- .../datetime/ZonedDateTimeTest.java | 157 -- .../PseudoRandomGeneratorTest.java | 125 -- .../powerframework/pseudorandom/SeedTest.java | 71 - 635 files changed, 41426 insertions(+), 7534 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 power-ai/pom.xml create mode 100644 power-ai/src/main/java/module-info.java rename {src/main/java/org/nanoboot/powerframework/utilities => power-ai/src/main/java/org/nanoboot/powerframework/ai}/.gitkeep (100%) rename {src => power-ai/src}/main/resources/.gitkeep (100%) create mode 100644 power-ai/src/test/java/org/nanoboot/powerframework/ai/.gitkeep create mode 100644 power-bean/pom.xml create mode 100644 power-bean/src/main/java/module-info.java create mode 100644 power-bean/src/main/java/org/nanoboot/powerframework/bean/.gitkeep create mode 100644 power-bean/src/main/resources/.gitkeep create mode 100644 power-bean/src/test/java/org/nanoboot/powerframework/bean/.gitkeep create mode 100644 power-blockchain/pom.xml create mode 100644 power-blockchain/src/main/java/module-info.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/.gitkeep create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockDeserializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockSerializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/Block.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockChainException.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngine.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngineVersion.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainProtocol.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/JsonBlockSerializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/StringSerializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockData.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockDeserializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockMiner.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockSerializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockValidator.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/Block.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChain.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChainEngine.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockFragment.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockHeader.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockType.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockTypeVersionList.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Transaction.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/TransactionValidator.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Wallet.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/core/Main.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/JsonBlockSerializer.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/SimpleBlockData.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_Block.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockMiner.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockType.java create mode 100644 power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_BlockChainEngine.java create mode 100644 power-blockchain/src/main/resources/.gitkeep create mode 100644 power-blockchain/src/test/java/org/nanoboot/powerframework/blockchain/.gitkeep create mode 100644 power-collections/pom.xml create mode 100644 power-collections/src/main/java/module-info.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNode.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNodeType.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/CollectionException.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedList.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNode.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNodeReferenceType.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/KeyValue.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerCollection.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerList.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerMap.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerQueue.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerSet.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerStack.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/Properties.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedList.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedListNode.java rename src/main/java/org/nanoboot/powerframework/collections/DictionaryNode.java => power-collections/src/main/java/org/nanoboot/powerframework/collections/StackI.java (58%) create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/Table.java rename src/main/java/org/nanoboot/powerframework/pseudorandom/Seed.java => power-collections/src/main/java/org/nanoboot/powerframework/collections/Tree.java (61%) create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/TreeNode.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/Array.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayException.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayType.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ByteArray.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/IntArray.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ObjectArray.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/package-info.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/buffer/CharBuffer.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/graphs/.gitkeep create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedList.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedListNode.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractTreeNode.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/package-info.java create mode 100644 power-collections/src/main/java/org/nanoboot/powerframework/collections/package-info.java create mode 100644 power-collections/src/main/resources/.gitkeep create mode 100644 power-collections/src/test/java/org/nanoboot/powerframework/collections/PowerMapTest.java create mode 100644 power-collections/src/test/java/org/nanoboot/powerframework/collections/PropertiesTest.java rename {src => power-collections/src}/test/java/org/nanoboot/powerframework/collections/QueueTest.java (54%) create mode 100644 power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListNodeTest.java create mode 100644 power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListTest.java rename {src => power-collections/src}/test/java/org/nanoboot/powerframework/collections/StackTest.java (59%) create mode 100644 power-core/pom.xml create mode 100644 power-core/src/lombok.config create mode 100644 power-core/src/main/java/module-info.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/CoreException.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/PowerException.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/PowerFramework.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/PowerObject.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedException.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodException.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/package-info.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/package-info.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/version/Version.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionNumberType.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionType.java create mode 100644 power-core/src/main/java/org/nanoboot/powerframework/core/version/package-info.java create mode 100644 power-core/src/main/resources/.gitkeep create mode 100644 power-core/src/main/resources/version.properties create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/CoreExceptionTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/PowerExceptionTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/PowerFrameworkTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/PowerObjectTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedExceptionTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodExceptionTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionNumberTypeTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTest.java create mode 100644 power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTypeTest.java create mode 100644 power-db/pom.xml create mode 100644 power-db/src/main/java/module-info.java create mode 100644 power-db/src/main/java/org/nanoboot/powerframework/db/engines/AbstractSqlEngine.java create mode 100644 power-db/src/main/java/org/nanoboot/powerframework/db/engines/sqlite/.gitkeep rename src/main/java/org/nanoboot/powerframework/database/SqlCommandQueue.java => power-db/src/main/java/org/nanoboot/powerframework/db/manager/CommandStore.java (65%) create mode 100644 power-db/src/main/java/org/nanoboot/powerframework/db/manager/Database.java create mode 100644 power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseException.java create mode 100644 power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseOperatingException.java rename src/main/java/org/nanoboot/powerframework/database/Database.java => power-db/src/main/java/org/nanoboot/powerframework/db/manager/Databases.java (63%) rename src/main/java/org/nanoboot/powerframework/database/ResultOfSqlQuery.java => power-db/src/main/java/org/nanoboot/powerframework/db/manager/Table.java (80%) create mode 100644 power-db/src/main/resources/.gitkeep create mode 100644 power-db/src/test/java/org/nanoboot/powerframework/db/engines/.gitkeep rename src/test/java/org/nanoboot/powerframework/database/SqlCommandQueueTest.java => power-db/src/test/java/org/nanoboot/powerframework/db/manager/CommandStoreTest.java (75%) rename {src/test/java/org/nanoboot/powerframework/database => power-db/src/test/java/org/nanoboot/powerframework/db/manager}/DatabaseConnectionTest.java (78%) rename {src/test/java/org/nanoboot/powerframework/database => power-db/src/test/java/org/nanoboot/powerframework/db/manager}/DatabaseTest.java (68%) rename src/test/java/org/nanoboot/powerframework/database/ResultOfSqlQueryTest.java => power-db/src/test/java/org/nanoboot/powerframework/db/manager/TableTest.java (87%) create mode 100644 power-io/pom.xml create mode 100644 power-io/src/main/java/module-info.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/Blob.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/Byte.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/DigitalInformationUnit.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/TextCoder.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Coder.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Convertor.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Implementation.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Padding.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/JavaBase64Coder.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Decoder.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Encoder.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/package-info.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/BinaryFile.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/Directory.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/Disk.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/File.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileSystem.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileType.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/PowerFileSystem.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/TextFile.java create mode 100644 power-io/src/main/java/org/nanoboot/powerframework/io/fs/virtualfilesystem/.gitkeep create mode 100644 power-io/src/main/resources/.gitkeep create mode 100644 power-io/src/test/java/org/nanoboot/powerframework/io/bit/BlobTest.java create mode 100644 power-io/src/test/java/org/nanoboot/powerframework/io/bit/ByteTest.java create mode 100644 power-json/pom.xml create mode 100644 power-json/src/main/java/module-info.java create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByComma.java create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/CommasFinder.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonArray.java (56%) rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java (59%) rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java (74%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonArraySerializable.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonBoolean.java (69%) rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonChar.java (77%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonConstants.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonDouble.java (75%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonException.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonFloat.java (75%) rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonInt.java (75%) rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonLong.java (75%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonObject.java create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectDeserializable.java create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectKeyValue.java create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java (65%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectSerializable.java rename src/main/java/org/nanoboot/powerframework/json/SerializableToJsonObject.java => power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectValidator.java (80%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonParser.java create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrint.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonPrinter.java (71%) rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonString.java (77%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/JsonValue.java rename {src => power-json/src}/main/java/org/nanoboot/powerframework/json/JsonValueType.java (91%) create mode 100644 power-json/src/main/java/org/nanoboot/powerframework/json/package-info.java create mode 100644 power-json/src/main/resources/.gitkeep create mode 100644 power-json/src/test/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByCommaTest.java create mode 100644 power-json/src/test/java/org/nanoboot/powerframework/json/CommasFinderTest.java rename {src => power-json/src}/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java (97%) rename {src => power-json/src}/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java (93%) rename {src => power-json/src}/test/java/org/nanoboot/powerframework/json/JsonValueTest.java (85%) create mode 100644 power-log/pom.xml create mode 100644 power-log/src/main/java/module-info.java create mode 100644 power-log/src/main/java/org/nanoboot/powerframework/log/Level.java create mode 100644 power-log/src/main/java/org/nanoboot/powerframework/log/LogRowCreator.java create mode 100644 power-log/src/main/java/org/nanoboot/powerframework/log/Logger.java create mode 100644 power-log/src/main/java/org/nanoboot/powerframework/log/MethodStartMessageCreator.java create mode 100644 power-log/src/main/java/org/nanoboot/powerframework/log/Target.java create mode 100644 power-log/src/main/resources/.gitkeep create mode 100644 power-log/src/test/java/org/nanoboot/powerframework/log/.gitkeep create mode 100755 power-mail/.gitignore create mode 100755 power-mail/README.md create mode 100644 power-mail/bin/.gitignore create mode 100644 power-mail/bin/backup.sql create mode 100755 power-mail/bin/backupfile.sh create mode 100644 power-mail/bin/mailer.jar create mode 100755 power-mail/bin/mailer.properties.template create mode 100755 power-mail/bin/mailer.sh create mode 100755 power-mail/bin/mailerrv.sh create mode 100644 power-mail/environment-startup.txt create mode 100755 power-mail/pom.xml create mode 100644 power-mail/src/main/java/module-info.java create mode 100644 power-mail/src/main/java/org/nanoboot/powerframework/mail/MailBox.java create mode 100644 power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessage.java create mode 100644 power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessageType.java create mode 100755 power-mail/src/main/java/org/nanoboot/powerframework/mail/Main.java create mode 100644 power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpServer.java create mode 100644 power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpUser.java create mode 100644 power-mail/src/main/resources/.gitkeep create mode 100644 power-mail/src/test/java/org/nanoboot/powerframework/mail/.gitkeep create mode 100644 power-persistence/pom.xml create mode 100644 power-persistence/src/main/java/module-info.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/AttributeType.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/BaseColumns.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityAttribute.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityManager.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityPointer.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntitySchema.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityStorage.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/JavaSqlConvertor.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/MethodInvocation.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/PersistenceException.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/Utils.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Attribute.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/AttributeName.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Entity.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/EntityName.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/ForeignEntity.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/NotNull.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/UUID.java create mode 100644 power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Unmodifiable.java create mode 100644 power-persistence/src/main/resources/.gitkeep create mode 100644 power-persistence/src/test/java/org/nanoboot/powerframework/persistence/.gitkeep create mode 100644 power-random/pom.xml create mode 100644 power-random/src/main/java/module-info.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/RandomException.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceEntry.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/package-info.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/RandomGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/DummyGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactory.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImpl.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessor.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImpl.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGenerator.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/package-info.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/package-info.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/generators/package-info.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomNumberUtils.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomTextUtils.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/internal/package-info.java create mode 100644 power-random/src/main/java/org/nanoboot/powerframework/random/package-info.java create mode 100644 power-random/src/main/resources/.gitkeep create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/RandomExceptionTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGeneratorTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGeneratorTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/generators/RandomGeneratorTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGeneratorTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGeneratorTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImplTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImplTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGeneratorTest.java create mode 100644 power-random/src/test/java/org/nanoboot/powerframework/random/internal/RandomTextUtilsTest.java create mode 100644 power-redmond/pom.xml create mode 100644 power-redmond/src/main/java/module-info.java create mode 100644 power-redmond/src/main/java/org/nanoboot/powerframework/redmond/.gitkeep create mode 100644 power-redmond/src/main/resources/.gitkeep create mode 100644 power-redmond/src/test/java/org/nanoboot/powerframework/redmond/.gitkeep create mode 100644 power-reflection/pom.xml create mode 100644 power-reflection/src/main/java/module-info.java create mode 100644 power-reflection/src/main/java/org/nanoboot/powerframework/reflection/BeanMethod.java create mode 100644 power-reflection/src/main/java/org/nanoboot/powerframework/reflection/ReflectionUtils.java create mode 100644 power-reflection/src/main/resources/.gitkeep create mode 100644 power-reflection/src/test/java/org/nanoboot/powerframework/reflection/ReflectionUtilsTest.java create mode 100644 power-reflection/src/test/java/org/nanoboot/powerframework/reflection/TestClassWithBadConstructorAndMethods.java create mode 100644 power-security/pom.xml create mode 100644 power-security/src/main/java/module-info.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/SecurityException.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/hash/api/HashCalculator.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/AbstractShaHashCalculator.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha1HashCalculator.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha256HashCalculator.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashCalculatorLocator.java create mode 100644 power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashImpl.java create mode 100644 power-security/src/main/resources/.gitkeep create mode 100644 power-security/src/test/java/org/nanoboot/powerframework/security/.gitkeep create mode 100644 power-shark/pom.xml create mode 100644 power-shark/src/main/java/module-info.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/ByteCode.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/Compiler.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/MoleCode.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/expressions/FunctionCall.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/keywords/KeyWords.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigDec.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigNum.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Bool.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Char.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Dec.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Num.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Str.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Add.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/And.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/DecrementByOne.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Divide.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/IncrementByOne.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Multiply.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Not.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Or.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Break.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Continue.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/DoBlock.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Function.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/IfBlock.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Import.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Return.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/StatementParser.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Struct.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/SwitchBlock.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableAssignment.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableDeclaration.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/WhileBlock.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunction.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunctionArgument.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/todo.txt create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/VirtualMachine.java create mode 100644 power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/instructions/.gitkeep create mode 100644 power-shark/src/main/resources/.gitkeep create mode 100644 power-shark/src/test/java/org/nanoboot/powerframework/shark/.gitkeep create mode 100644 power-sound/pom.xml create mode 100644 power-sound/src/main/java/module-info.java create mode 100644 power-sound/src/main/java/org/nanoboot/powerframework/sound/.gitkeep create mode 100644 power-sound/src/main/resources/.gitkeep create mode 100644 power-sound/src/test/java/org/nanoboot/powerframework/sound/.gitkeep create mode 100644 power-sql/pom.xml create mode 100644 power-sql/src/main/java/module-info.java create mode 100644 power-sql/src/main/java/org/nanoboot/powerframework/sql/core/ColumnNameValue.java create mode 100644 power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderBy.java create mode 100644 power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderByType.java create mode 100644 power-sql/src/main/java/org/nanoboot/powerframework/sql/core/SqlStatementCreator.java create mode 100755 power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/AbstractFilter.java create mode 100755 power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlConjunction.java create mode 100755 power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlFilter.java create mode 100755 power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlOperation.java create mode 100644 power-sql/src/main/resources/.gitkeep create mode 100644 power-sql/src/test/java/.gitkeep create mode 100644 power-stat/pom.xml create mode 100644 power-stat/src/main/java/module-info.java create mode 100644 power-stat/src/main/java/org/nanoboot/powerframework/stat/.gitkeep create mode 100644 power-stat/src/main/resources/.gitkeep create mode 100644 power-stat/src/test/java/org/nanoboot/powerframework/stat/.gitkeep create mode 100644 power-svg/pom.xml create mode 100644 power-svg/src/main/java/module-info.java create mode 100644 power-svg/src/main/java/org/nanoboot/powerframework/svg/.gitkeep create mode 100644 power-svg/src/main/resources/.gitkeep create mode 100644 power-svg/src/test/java/org/nanoboot/powerframework/svg/.gitkeep create mode 100644 power-template/.gitkeep create mode 100644 power-template/pom.xml create mode 100644 power-template/src/main/java/module-info.java create mode 100644 power-template/src/main/java/org/nanoboot/powerframework/template/.gitkeep create mode 100644 power-template/src/main/resources/.gitkeep create mode 100644 power-template/src/test/java/org/nanoboot/powerframework/template/.gitkeep create mode 100644 power-text/pom.xml create mode 100644 power-text/src/main/java/module-info.java create mode 100644 power-text/src/main/java/org/nanoboot/powerframework/text/AsciiCharacter.java create mode 100644 power-text/src/main/java/org/nanoboot/powerframework/text/CharacterRange.java create mode 100644 power-text/src/main/java/org/nanoboot/powerframework/text/CharacterType.java create mode 100644 power-text/src/main/java/org/nanoboot/powerframework/text/TextException.java create mode 100644 power-text/src/main/java/org/nanoboot/powerframework/text/package-info.java create mode 100644 power-text/src/main/resources/.gitkeep create mode 100644 power-text/src/test/java/org/nanoboot/powerframework/text/.gitkeep create mode 100644 power-text/src/test/java/org/nanoboot/powerframework/text/AsciiCharacterTest.java create mode 100644 power-text/src/test/java/org/nanoboot/powerframework/text/CharacterRangeTest.java create mode 100644 power-text/src/test/java/org/nanoboot/powerframework/text/TextExceptionTest.java create mode 100644 power-time/pom.xml create mode 100644 power-time/src/main/java/module-info.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/SimpleDateTimeFormatByTimeZone.java rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time}/TimeSource.java (68%) create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/duration/Duration.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/duration/Period.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/duration/SimpleStopWatch.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatch.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatchState.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/module-info.java.txt create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/moment/DateTime.java rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time/moment}/LocalDate.java (52%) create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDateTime.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalTime.java rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time/moment}/TimeZone.java (80%) rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time/moment}/UniversalDateTime.java (50%) rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time/moment}/ZonedDateTime.java (71%) create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/utils/AbstractValidator.java rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time/utils}/DateUnitsValidator.java (50%) create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/utils/LocalSettings.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/utils/RandomDateTimeUnitsGenerator.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/utils/RemainingTimeCalculator.java rename src/main/java/org/nanoboot/powerframework/PowerRuntimeException.java => power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeException.java (75%) create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnit.java create mode 100644 power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitConvertor.java rename {src/main/java/org/nanoboot/powerframework/datetime => power-time/src/main/java/org/nanoboot/powerframework/time/utils}/TimeUnitsValidator.java (51%) create mode 100644 power-time/src/main/resources/.gitkeep create mode 100644 power-time/src/test/java/org/nanoboot/powerframework/time/duration/DurationTest.java create mode 100644 power-time/src/test/java/org/nanoboot/powerframework/time/duration/StopWatchTest.java rename {src/test/java/org/nanoboot/powerframework/datetime => power-time/src/test/java/org/nanoboot/powerframework/time/moment}/DateTimeTest.java (80%) rename {src/test/java/org/nanoboot/powerframework/datetime => power-time/src/test/java/org/nanoboot/powerframework/time/moment}/LocalDateTest.java (83%) create mode 100644 power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTimeTest.java rename {src/test/java/org/nanoboot/powerframework/datetime => power-time/src/test/java/org/nanoboot/powerframework/time/moment}/LocalTimeTest.java (80%) rename {src/test/java/org/nanoboot/powerframework/datetime => power-time/src/test/java/org/nanoboot/powerframework/time/moment}/TimeZoneTest.java (77%) create mode 100644 power-time/src/test/java/org/nanoboot/powerframework/time/moment/UniversalDateTimeTest.java create mode 100644 power-time/src/test/java/org/nanoboot/powerframework/time/moment/ZonedDateTimeTest.java rename {src/test/java/org/nanoboot/powerframework/datetime => power-time/src/test/java/org/nanoboot/powerframework/time/utils}/DateUnitsValidatorTest.java (95%) create mode 100644 power-time/src/test/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidatorTest.java create mode 100644 power-utils/pom.xml create mode 100644 power-utils/src/main/java/module-info.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/CommandReader.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConvention.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConventionConvertor.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/StringTemplate.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/StringUtils.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/UtilsException.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/Done.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/InProgress.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToDo.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToRemove.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/package-info.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/AbstractBuilder.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/Builder.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/package-info.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/collections/ListSplitter.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/compression/.gitkeep create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyNode.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolver.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImpl.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/minitext/.gitkeep create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/package-info.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/MethodInvoker.java create mode 100644 power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/ProxyUtils.java create mode 100644 power-utils/src/main/resources/.gitkeep create mode 100644 power-utils/src/test/java/.gitkeep create mode 100644 power-utils/src/test/java/org/nanoboot/powerframework/utils/CommandReaderTest.java create mode 100644 power-utils/src/test/java/org/nanoboot/powerframework/utils/NamingConventionConvertorTest.java create mode 100644 power-utils/src/test/java/org/nanoboot/powerframework/utils/StringUtilsTest.java create mode 100644 power-utils/src/test/java/org/nanoboot/powerframework/utils/UtilsExceptionTest.java create mode 100644 power-utils/src/test/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImplTest.java create mode 100644 power-view/pom.xml create mode 100644 power-view/src/main/java/module-info.java rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/EnumColour.java (81%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/JavaFXApplication.java (83%) create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/PowerApplication.java rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/Screen.java (91%) rename src/main/java/org/nanoboot/powerframework/simplicity/Simplicity.java => power-view/src/main/java/org/nanoboot/powerframework/view/View.java (73%) create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/ViewException.java rename src/main/java/org/nanoboot/powerframework/simplicity/SimplicityRunnerI.java => power-view/src/main/java/org/nanoboot/powerframework/view/ViewRunner.java (82%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/boxes/AlertBox.java (66%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/boxes/Box.java (68%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/boxes/MessageBox.java (66%) create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/clocks/AnalogClock.java create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/clocks/Clock.java create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/clocks/DigitalClock.java rename {src/main/java/org/nanoboot/powerframework/simplicity/window => power-view/src/main/java/org/nanoboot/powerframework/view/layouts}/CellLayout.java (74%) rename {src/main/java/org/nanoboot/powerframework/simplicity/window => power-view/src/main/java/org/nanoboot/powerframework/view/layouts}/SLayout.java (73%) create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/package-info.java create mode 100644 power-view/src/main/java/org/nanoboot/powerframework/view/svg/.gitkeep rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/ColourVariant.java (85%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/MoveableArea.java (77%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/ResizingGrid.java (78%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/ResizingGridRectangle.java (73%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/TitleBar.java (84%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/TitleIcon.java (75%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/Window.java (82%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/WindowColourSkin.java (91%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/WindowSizeMode.java (88%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/Button.java (75%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/NumericMinusPlus.java (83%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/PasswordField.java (68%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/RadioButton.java (70%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/RadioButtonGroup.java (82%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/SCheckBox.java (71%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/SComboBox.java (72%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/SLabel.java (71%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/TabPane.java (82%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/controls/TextField.java (72%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/titlebuttons/CloseButton.java (73%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/titlebuttons/LineInWindowTitleButton.java (80%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/titlebuttons/MaximizeRestoreButton.java (61%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/titlebuttons/MinimizeButton.java (69%) rename {src/main/java/org/nanoboot/powerframework/simplicity => power-view/src/main/java/org/nanoboot/powerframework/view}/window/titlebuttons/WindowTitleButton.java (81%) create mode 100644 power-view/src/main/resources/.gitkeep create mode 100644 power-view/src/test/java/.gitkeep create mode 100644 power-web/pom.xml create mode 100644 power-web/src/main/java/module-info.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/PowerWebException.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/PrettyPrinter.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/TestMain.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyle.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyles.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelector.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelectors.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/WebElement.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/WebPage.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Action.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Charset.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Class.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Content.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Height.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Href.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/HttpEquiv.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Id.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Method.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Name.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Rel.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Src.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Style.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Template.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Title.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Type.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Value.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Width.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/A.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Body.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Br.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Div.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Form.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/FormMethod.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H1.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H2.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H3.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Head.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HiddenInput.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Hr.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Html.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HtmlElement.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Img.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Input.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/InputType.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Label.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Li.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Link.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Meta.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Ol.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Option.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Select.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Span.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Style.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/SubmitInput.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/TBody.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Table.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/TagTemplate.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Td.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Th.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Title.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Tr.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Ul.java create mode 100644 power-web/src/main/java/org/nanoboot/powerframework/web/javascript/.gitkeep create mode 100644 power-web/src/main/resources/.gitkeep create mode 100644 power-web/src/test/java/org/nanoboot/powerframework/web/.gitkeep create mode 100644 power-wiki/pom.xml create mode 100644 power-wiki/src/main/java/module-info.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/Block.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/BlockList.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/BlockType.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/HtmlTags.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/Macro.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/StringSource.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextFormatter.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextProcessorI.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiException.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiMarks.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiParser.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/convertors/ListConvertor.java create mode 100644 power-wiki/src/main/java/org/nanoboot/powerframework/wiki/macroprocessors/.gitkeep create mode 100644 power-wiki/src/main/resources/.gitkeep create mode 100644 power-wiki/src/test/java/org/nanoboot/powerframework/wiki/.gitkeep create mode 100644 power-xml/pom.xml create mode 100644 power-xml/src/main/java/module-info.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/.gitkeep create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/Attribute.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/Attributes.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/Buildable.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/Constants.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/Element.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/ElementType.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/Elements.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/NoElement.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlComment.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlType.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlTypeI.java create mode 100644 power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlUtils.java create mode 100644 power-xml/src/main/resources/.gitkeep create mode 100644 power-xml/src/test/java/org/nanoboot/powerframework/xml/.gitkeep delete mode 100644 src/main/java/org/nanoboot/powerframework/collections/Dictionary.java delete mode 100644 src/main/java/org/nanoboot/powerframework/collections/DictionaryKeyIterator.java delete mode 100644 src/main/java/org/nanoboot/powerframework/collections/Queue.java delete mode 100644 src/main/java/org/nanoboot/powerframework/collections/Stack.java delete mode 100644 src/main/java/org/nanoboot/powerframework/database/DatabaseConnection.java delete mode 100644 src/main/java/org/nanoboot/powerframework/datetime/DateTime.java delete mode 100644 src/main/java/org/nanoboot/powerframework/datetime/Duration.java delete mode 100644 src/main/java/org/nanoboot/powerframework/datetime/LocalDateTime.java delete mode 100644 src/main/java/org/nanoboot/powerframework/datetime/LocalTime.java delete mode 100644 src/main/java/org/nanoboot/powerframework/datetime/package-info.java delete mode 100644 src/main/java/org/nanoboot/powerframework/json/JsonObject.java delete mode 100644 src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java delete mode 100644 src/main/java/org/nanoboot/powerframework/json/JsonParser.java delete mode 100644 src/main/java/org/nanoboot/powerframework/json/JsonSpecialCharSequences.java delete mode 100644 src/main/java/org/nanoboot/powerframework/json/JsonValue.java delete mode 100644 src/main/java/org/nanoboot/powerframework/package-info.java delete mode 100644 src/main/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGenerator.java delete mode 100644 src/test/java/org/nanoboot/powerframework/collections/DictionaryKeyIteratorTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/collections/DictionaryNodeTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/collections/DictionaryTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/datetime/DurationTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/datetime/LocalDateTimeTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/datetime/TimeUnitsValidatorTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/datetime/UniversalDateTimeTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/datetime/ZonedDateTimeTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGeneratorTest.java delete mode 100644 src/test/java/org/nanoboot/powerframework/pseudorandom/SeedTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d31a2bf --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# Changelog +# 0.1.0 + * ? + diff --git a/README.md b/README.md index 0a849e2..1442a71 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,34 @@ # power-framework - -## Requirements - * Maven - * Java 8 (for example: Amazon Corretto 8 - https://docs.aws.amazon.com/corretto/latest/corretto-8-ug/downloads-list.html) - +## Important notes to read first: + + 1. This is a hobbyist project. + 2. This project is licenced as LGPL 2.1, which also means it is distributed without any warranty. + 3. In case, you find a bug or propose an improvement: + * Raise an issue or participate a new discussion. + +## About + +Power Framework is a Java library. + +It contains several modules: view, collections, json, time, db, persistence, random, reflection, sql, xml and web and others. + +View is an abstraction of JavaFX. Window class may be the most used class of this module and is used as a place for everything user sees. Window class uses custom decorations, system decorations are not used. + +Collections contains full implementation of some collection type like linked list, queue, stack, list, map, set, properties, tree and others. + +Json is used to represent json object and json array as a Java Object. Json files can be parsed to JsonObject instance. Every instance of JsonObject or JsonArray can be printed to minimal or pretty String. + +DB is used to give abstraction for jdbc and SQLite, hides implementation. Database package can be used to store permanent data. + +Persistence is used to dynamically manage SQLite database, create table ddl, insert, update and delete statements are automatically generated from Java classes using reflection. Persistence behaves maybe like the Hibernate library. + +Random is used to generate pseudorandom numbers and is based on linear congruent function and using seeds. + +Time contains some classes used to represent date and time without time zone information, universal date and time, date and time with time zone information. There are also some classes representing durations and period. Time module is partially an abstraction on Java SE time classes, but the interface to use it is a little different. + +Reflection is a abstraction of Java SE reflection classes. + +SQL generates sql Statements. + +Xml is used to generate xml output by Java classes. Web uses xml and creates html pages. diff --git a/pom.xml b/pom.xml index 7aa605e..5fe4ab9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; + License as published by the Free Software Foundation; version 2.1 of the License only. This library is distributed in the hope that it will be useful, @@ -22,52 +22,148 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + + org.nanoboot.essential + nanoboot-parent + 0.1.0-SNAPSHOT + + org.nanoboot.powerframework power-framework - 1.0.0 - jar + 2.0.0-SNAPSHOT + pom Power Framework - A library with many possibilities + + Power Framework is a bundle of Java many purposes libraries + like working with texts, randomness, collections, json format, + time, database, files, desktop graphics and some others. + + + http://robertvokac/products/power-framework + 2016 + + power-core + power-text + power-random + power-utils + power-collections + + power-json + power-time + power-log + power-io + power-web + + power-wiki + power-bean + power-redmond + power-shark + power-sound + + power-stat + power-sql + power-db + power-persistence + power-svg + + power-view + power-xml + power-reflection + power-mail + power-blockchain + + power-security + + - UTF-8 + 2.0.0-SNAPSHOT true - 8 - - - - - - junit - junit - 4.12 - test - - - org.xerial - sqlite-jdbc - 3.39.3.0 - - - + + + Robert Vokac + robertvokac@nanoboot.org + + developer + project manager + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco-maven-plugin.version} + + + + prepare-agent + + + + + report + test + + report + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${checkstyle.skip} + + org.apache.maven.plugins maven-compiler-plugin - ${javase.version} - ${javase.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + + + + junit + junit + ${junit4.version} + test + + + + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + diff --git a/power-ai/pom.xml b/power-ai/pom.xml new file mode 100644 index 0000000..b01ce82 --- /dev/null +++ b/power-ai/pom.xml @@ -0,0 +1,54 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-ai + jar + + Power AI + Artificial intelligence tools for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + + + junit + junit + 4.12 + test + + + + diff --git a/power-ai/src/main/java/module-info.java b/power-ai/src/main/java/module-info.java new file mode 100644 index 0000000..c153b52 --- /dev/null +++ b/power-ai/src/main/java/module-info.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.ai { + +} diff --git a/src/main/java/org/nanoboot/powerframework/utilities/.gitkeep b/power-ai/src/main/java/org/nanoboot/powerframework/ai/.gitkeep similarity index 100% rename from src/main/java/org/nanoboot/powerframework/utilities/.gitkeep rename to power-ai/src/main/java/org/nanoboot/powerframework/ai/.gitkeep diff --git a/src/main/resources/.gitkeep b/power-ai/src/main/resources/.gitkeep similarity index 100% rename from src/main/resources/.gitkeep rename to power-ai/src/main/resources/.gitkeep diff --git a/power-ai/src/test/java/org/nanoboot/powerframework/ai/.gitkeep b/power-ai/src/test/java/org/nanoboot/powerframework/ai/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-bean/pom.xml b/power-bean/pom.xml new file mode 100644 index 0000000..6412e70 --- /dev/null +++ b/power-bean/pom.xml @@ -0,0 +1,54 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-bean + jar + + Power Bean + Dependency functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + + + junit + junit + 4.12 + test + + + + diff --git a/power-bean/src/main/java/module-info.java b/power-bean/src/main/java/module-info.java new file mode 100644 index 0000000..7126f67 --- /dev/null +++ b/power-bean/src/main/java/module-info.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.bean { + +} diff --git a/power-bean/src/main/java/org/nanoboot/powerframework/bean/.gitkeep b/power-bean/src/main/java/org/nanoboot/powerframework/bean/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-bean/src/main/resources/.gitkeep b/power-bean/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-bean/src/test/java/org/nanoboot/powerframework/bean/.gitkeep b/power-bean/src/test/java/org/nanoboot/powerframework/bean/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-blockchain/pom.xml b/power-blockchain/pom.xml new file mode 100644 index 0000000..84f58c1 --- /dev/null +++ b/power-blockchain/pom.xml @@ -0,0 +1,122 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + org.nanoboot.powerframework + power-blockchain + jar + + Power Blockchain + Blockchain library + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + + org.nanoboot.powerframework.blockchain.orig.core.Main + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.nanoboot.powerframework.blockchain.orig.core.Main + + + + + + + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-time + ${power.version} + + + org.nanoboot.powerframework + power-json + ${power.version} + + + org.nanoboot.powerframework + power-random + ${power.version} + + + org.nanoboot.powerframework + power-security + ${power.version} + + + + + junit + junit + 4.12 + test + + + org.projectlombok + lombok + 1.18.10 + compile + + + + diff --git a/power-blockchain/src/main/java/module-info.java b/power-blockchain/src/main/java/module-info.java new file mode 100644 index 0000000..0689fa1 --- /dev/null +++ b/power-blockchain/src/main/java/module-info.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.blockchain { + requires lombok; + requires powerframework.core; + requires powerframework.time; + requires powerframework.json; + requires powerframework.random; + requires powerframework.security; +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/.gitkeep b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockDeserializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockDeserializer.java new file mode 100644 index 0000000..97eee57 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockDeserializer.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.api; + +import org.nanoboot.powerframework.blockchain.core.Block; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockDeserializer { + Block deserialize(String serializedBlock); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockSerializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockSerializer.java new file mode 100644 index 0000000..8a7ba93 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/api/BlockSerializer.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.api; + +import org.nanoboot.powerframework.blockchain.core.Block; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockSerializer { + String serialize(Block block); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/Block.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/Block.java new file mode 100644 index 0000000..8115ecd --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/Block.java @@ -0,0 +1,132 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.core; + +import org.nanoboot.powerframework.blockchain.api.BlockSerializer; +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.json.JsonObjectSerializable; +import org.nanoboot.powerframework.security.hash.api.HashCalculator; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Block implements JsonObjectSerializable { + private static final String BLOCKCHAIN_PROTOCOL = "blockchainProtocol"; + + private static final String HEIGHT = "height"; + + private static final String PREVIOUS_HASH = "previousHash"; + private static final String TIMESTAMP = "timestamp"; + private static final String DIFFICULTY = "difficulty"; + private static final String DATA = "data"; + private static final String NONCE = "nonce"; + + @Getter + private final BlockchainProtocol blockchainProtocol; + + @Getter + private final long height; + @Getter + private final String previousHash; + @Getter + private final String timeStamp; + @Getter + private final String difficultyTarget; + @Getter + private final byte[] data; + + @Getter + private long nonce; + + // + @Getter + private String hash = null; + + //Block Constructor. + public Block(BlockchainProtocol blockchainProtocol, + long height, + String previousHash, + String difficultyTarget, + byte[] data) { + this.blockchainProtocol=blockchainProtocol; + this.height = height; + this.previousHash = previousHash; + this.timeStamp = UniversalDateTime.now().toString(); + this.difficultyTarget = difficultyTarget; + this.data = data; + } + + //Calculate new hash based on blocks contents + public String calculateHash(HashCalculator hashCalculator, BlockSerializer blockSerializer) { + String serializedBlock = blockSerializer.serialize(this); + String calculatedhash = hashCalculator.hash(serializedBlock); + return calculatedhash; + } + + //Increases nonce value until hash target is reached. + public void mineBlock(HashCalculator hashCalculator, BlockSerializer blockSerializer) { + String target = this.difficultyTarget; + + for (long i = 0; i <= Long.MAX_VALUE; i++) { + this.nonce = i; + if (nonce == Integer.MAX_VALUE) { + throw new BlockChainException("Nonce was not found."); + } + if (nonce % 1000000 == 0) { + System.out.println("Nonce # " + nonce); + } + + + + String hash = calculateHash(hashCalculator, blockSerializer); + + if (hashCalculator.compareHexNumbers(hash, this.getDifficultyTarget()) <= 0) { + System.out.println("Found nonce: " + nonce + " A new block was just mined: " + getHash() + "\n" /*+ block.toJsonObject().toPrettyString()*/); + System.out.println("Block Mined!!! : " + hash); + break; + } + } + + } + + @Override + public JsonObject toJsonObject() { + + JsonObject jo = new JsonObject(); + + jo.add(BLOCKCHAIN_PROTOCOL, blockchainProtocol.toJsonObject()); + + jo.add(HEIGHT, height); + + jo.add(PREVIOUS_HASH, previousHash); + jo.add(TIMESTAMP, timeStamp); + jo.add(DIFFICULTY, difficultyTarget); + jo.add(DATA, new String(data)); + jo.add(NONCE, nonce); + + return jo; + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockChainException.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockChainException.java new file mode 100644 index 0000000..0fc92fb --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockChainException.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.core; + +import org.nanoboot.powerframework.core.PowerException; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BlockChainException extends PowerException { + public BlockChainException(String msg) { + super(msg); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngine.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngine.java new file mode 100644 index 0000000..ba4b606 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngine.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.core; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public class BlockchainEngine { + @Getter + private final String protocolName; + private List blockchainEngineVersionList = new ArrayList<>(); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngineVersion.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngineVersion.java new file mode 100644 index 0000000..05ab32d --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainEngineVersion.java @@ -0,0 +1,54 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.core; + +import org.nanoboot.powerframework.blockchain.api.BlockSerializer; +import lombok.AllArgsConstructor; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public class BlockchainEngineVersion { + @Getter + private final String version; + @Getter + private final String hashCalculatorName; + @Getter + private final String targetDifficulty; + @Getter + private final BlockSerializer blockSerializer; + @Getter + private final long validFromBlock; + @Getter + private final long validUntilBlock; + + public String getMayorVersion() { + return version.split(("\\."))[0]; + } + public String getMinorVersion() { + return version.split(("\\."))[1]; + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainProtocol.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainProtocol.java new file mode 100644 index 0000000..48814be --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/core/BlockchainProtocol.java @@ -0,0 +1,56 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.core; + +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.json.JsonObjectSerializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public class BlockchainProtocol implements JsonObjectSerializable { + private static final String PROTOCOL_NAME = "protocolName"; + private static final String PROTOCOL_MAYOR_VERSION = "protocolMayorVersion"; + private static final String PROTOCOL_MINOR_VERSION = "protocolMinorVersion"; + @Getter + private final String protocolName; + @Getter + private final int protocolMayorVersion; + @Getter + private final int protocolMinorVersion; + @Override + public JsonObject toJsonObject() { + + JsonObject jo = new JsonObject(); + + jo.add(PROTOCOL_NAME, protocolName); + jo.add(PROTOCOL_MAYOR_VERSION, protocolMayorVersion); + jo.add(PROTOCOL_MINOR_VERSION, protocolMinorVersion); + + return jo; + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/JsonBlockSerializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/JsonBlockSerializer.java new file mode 100644 index 0000000..23d0a42 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/JsonBlockSerializer.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.impl; + +import org.nanoboot.powerframework.blockchain.api.BlockSerializer; +import org.nanoboot.powerframework.blockchain.core.Block; +import org.nanoboot.powerframework.json.JsonObject; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class JsonBlockSerializer implements BlockSerializer { + + @Override + public String serialize(Block block) { + JsonObject jsonObject = block.toJsonObject(); + return jsonObject.toMinimalString(); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/StringSerializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/StringSerializer.java new file mode 100644 index 0000000..5fe3ae6 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/impl/StringSerializer.java @@ -0,0 +1,45 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.impl; + +import org.nanoboot.powerframework.blockchain.api.BlockSerializer; +import org.nanoboot.powerframework.blockchain.core.Block; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class StringSerializer implements BlockSerializer { + + public static final String SEPARATOR = "::"; + + @Override + public String serialize(Block block) { + return block.getBlockchainProtocol().toString() + SEPARATOR + + block.getHeight() + SEPARATOR + + block.getPreviousHash() + SEPARATOR + + block.getTimeStamp() + SEPARATOR + + block.getDifficultyTarget() + SEPARATOR + + new String(block.getData()) + SEPARATOR + + block.getNonce(); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockData.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockData.java new file mode 100644 index 0000000..f619d87 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockData.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.api; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockData { + String convertToString(); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockDeserializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockDeserializer.java new file mode 100644 index 0000000..3cda061 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockDeserializer.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.api; + +import org.nanoboot.powerframework.blockchain.orig.base.Block; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockDeserializer { + Block deserialize(String serializedBlock); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockMiner.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockMiner.java new file mode 100644 index 0000000..24a1371 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockMiner.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.api; + +import org.nanoboot.powerframework.blockchain.orig.base.Block; +import org.nanoboot.powerframework.blockchain.orig.base.BlockFragment; +import org.nanoboot.powerframework.blockchain.orig.base.BlockType; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockMiner { + Block mine(BlockFragment blockFragment, BlockType blockType); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockSerializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockSerializer.java new file mode 100644 index 0000000..fb9c75f --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockSerializer.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.api; + +import org.nanoboot.powerframework.blockchain.orig.base.Block; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockSerializer { + String serialize(Block block); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockValidator.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockValidator.java new file mode 100644 index 0000000..6eaad05 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/api/BlockValidator.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.api; + +import org.nanoboot.powerframework.blockchain.orig.base.Block; +import org.nanoboot.powerframework.blockchain.orig.base.BlockType; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface BlockValidator { + BlockType getBlockType(); + void validate(Block block); +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/Block.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/Block.java new file mode 100644 index 0000000..0a076ca --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/Block.java @@ -0,0 +1,117 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockData; +import org.nanoboot.powerframework.blockchain.core.BlockChainException; +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.json.JsonObjectSerializable; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Block implements JsonObjectSerializable { + public static final String BLOCK_TYPE_ID = "blockTypeId"; + public static final String BLOCK_HEADER = "blockHeader"; + public static final String BLOCK_DATA = "blockData"; + public static final String NONCE = "nonce"; + + @Getter + private BlockHeader blockHeader; + + @Getter + private BlockData blockData; + + private long nonce; + + @Getter + private String hash; + @Getter + private boolean locked = false; + + @Getter + private BlockType internalBlockType; + + public Block(BlockHeader blockHeader, JsonObject additionBlockHeader, BlockData blockData) { + this.blockHeader = blockHeader; + + this.blockData = blockData; + } + + public void injectBlockType(BlockType blockType) { + this.internalBlockType = blockType; + } + + public String calculateHashTest(long nonce) { + this.nonce = nonce; + String hashedSerializedBlock = internalCalculateHash(); + this.nonce = 0;//todo + return hashedSerializedBlock; + } + + private String internalCalculateHash() { + if (nonce == 0) { + throw new BlockChainException("Nonce cannot be zero."); + } + if (locked) { + throw new BlockChainException("This block is already locked. Cannot set nonce and calculate nonce."); + } + + if (internalBlockType == null) { + throw new BlockChainException("internalBlockType was not injected."); + } + String serializedBlock = this.internalBlockType.getBlockSerializer().serialize(this); + + String hashedSerializedBlock = this.internalBlockType.getHashCalculator().hash(serializedBlock); + + //System.out.println("internalCalculateHash - hash for nonce " + nonce + " = " + hashedSerializedBlock); + return hashedSerializedBlock; + } + + public void lock(long nonce) { + this.nonce = nonce; + String hashedSerializedBlock = internalCalculateHash(); + this.hash = hashedSerializedBlock; + + this.locked = true; + } + + @Override + public JsonObject toJsonObject() { + if (nonce == 0) { + throw new BlockChainException("Nonce cannot be zero, if json object is created from this block instance."); + } + if (internalBlockType == null) { + throw new BlockChainException("internalBlockType was not injected."); + } + JsonObject jo = new JsonObject(); + jo.add(BLOCK_TYPE_ID, internalBlockType.getBlockTypeId()); + jo.add(BLOCK_HEADER, blockHeader.toJsonObject()); + + jo.add(BLOCK_DATA, blockData.convertToString()); + jo.add(NONCE, nonce); + return jo; + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChain.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChain.java new file mode 100644 index 0000000..4c0323e --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChain.java @@ -0,0 +1,100 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import org.nanoboot.powerframework.blockchain.core.BlockChainException; + +import java.util.ArrayList; +import java.util.List; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BlockChain { + private String blockChainEngineName; + private List blocks = new ArrayList<>(); + + public int getTotalHeight() { + return blocks.size() - 1; + } + + public boolean isEmpty() { + return blocks.isEmpty(); + } + + public Block getGenesisBlock() { + if (isEmpty()) { + return null; + } + return getBlock(0); + } + + public Block getLastBlock() { + if (isEmpty()) { + return null; + } + return getBlock(blocks.size() - 1); + } + + public List getLastXBlocks(int xCount) { + List result = new ArrayList<>(); + + if (isEmpty()) { + return result; + } + if (xCount <= blocks.size()) { + for (Block b : blocks) { + result.add(b); + } + return result; + } + for (int i = blocks.size() - xCount; i <= (blocks.size() - 1); i++) { + result.add(blocks.get(i)); + } + return result; + } + + public void addBlock(Block block) { + if (!block.isLocked()) { + throw new BlockChainException("Block is not locked. It cannot be added"); + } + if (blocks.isEmpty() && block.getBlockHeader().getHeight() != 0) { + throw new BlockChainException("New block is a genesis block, but its height is not zero."); + } + Block lastBlock = getLastBlock(); + String previousBlockHash = lastBlock == null ? "0" : lastBlock.getHash(); + + if (!block.getBlockHeader().getPreviousHash().equals(previousBlockHash)) { + throw new BlockChainException("Block previous hash is not equal to the hash of the previous block. It cannot be added to the blockchain."); + } + blocks.add(block); + } + + public Block getBlock(int blockHeight) { + if (blockHeight >= blocks.size()) { + throw new BlockChainException("There is no block with height " + blockHeight); + } + return blocks.get(blockHeight); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChainEngine.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChainEngine.java new file mode 100644 index 0000000..ffe7f3b --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockChainEngine.java @@ -0,0 +1,55 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import org.nanoboot.powerframework.blockchain.core.BlockChainException; +import lombok.AllArgsConstructor; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public abstract class BlockChainEngine { + private String blockChainEngineName; + protected BlockChain blockChain; + protected BlockTypeVersionList blockTypeVersionList; + + public void addData(String data) { + BlockFragment blockFragment = createNewBlockFragment(data); + BlockType blockType = blockTypeVersionList.findBlockType(blockFragment.getBlockHeader().getBlockTypeId()); + if (blockType == null) { + throw new BlockChainException("blockType " + blockFragment.getBlockHeader().getBlockTypeId() + " was not found."); + } + + Block block = blockType.getBlockMiner().mine(blockFragment, blockType); + addBlock(block); + } + + public abstract BlockFragment createNewBlockFragment(String data); + + public void addBlock(Block newBlock) { + blockChain.addBlock(newBlock); + } + +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockFragment.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockFragment.java new file mode 100644 index 0000000..0cedbf0 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockFragment.java @@ -0,0 +1,42 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockData; +import org.nanoboot.powerframework.json.JsonObject; +import lombok.AllArgsConstructor; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public class BlockFragment { + @Getter + private BlockHeader blockHeader; + + @Getter + private BlockData blockData; + +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockHeader.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockHeader.java new file mode 100644 index 0000000..6272d74 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockHeader.java @@ -0,0 +1,60 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.json.JsonObjectSerializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public class BlockHeader implements JsonObjectSerializable { + public static final String BLOCK_TYPE_ID = "blockTypeId"; + public static final String HEIGHT = "height"; + public static final String TIME_STAMP = "timeStamp"; + public static final String PREVIOUS_HASH = "previousHash"; + @Getter + private String blockTypeId; + @Getter + private int height; + @Getter + private long timeStamp; + @Getter + private String previousHash; + @Getter + private String difficulty; + + public JsonObject toJsonObject() { + JsonObject jo = new JsonObject(); + jo.add(BLOCK_TYPE_ID, blockTypeId); + jo.add(HEIGHT, height); + jo.add(TIME_STAMP, timeStamp); + jo.add(PREVIOUS_HASH, previousHash); + return jo; + } + +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockType.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockType.java new file mode 100644 index 0000000..7280eb3 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockType.java @@ -0,0 +1,55 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockDeserializer; +import org.nanoboot.powerframework.blockchain.orig.api.BlockMiner; +import org.nanoboot.powerframework.blockchain.orig.api.BlockSerializer; +import org.nanoboot.powerframework.security.hash.api.HashCalculator; +import lombok.AllArgsConstructor; +import lombok.Getter; +@AllArgsConstructor +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BlockType { + @Getter + private String type; + @Getter + private int mayorVersion; + @Getter + private int minorVersion; + @Getter + private HashCalculator hashCalculator; + @Getter + private BlockSerializer blockSerializer; + @Getter + private BlockDeserializer blockDeserializer; + @Getter + BlockMiner blockMiner; + public String getBlockTypeId() { + return type + ":" + mayorVersion + ":" + minorVersion; + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockTypeVersionList.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockTypeVersionList.java new file mode 100644 index 0000000..ec6b8d8 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/base/BlockTypeVersionList.java @@ -0,0 +1,47 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.base; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BlockTypeVersionList { + private Map blockTypes; + + public BlockTypeVersionList(List blockTypesList) { + blockTypes = new HashMap<>(); + for (BlockType bt : blockTypesList) { + blockTypes.put(bt.getBlockTypeId(), bt); + } + } + + public BlockType findBlockType(String blockTypeId) { + return blockTypes.get(blockTypeId); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Transaction.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Transaction.java new file mode 100644 index 0000000..d794978 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Transaction.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.cash; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Transaction { +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/TransactionValidator.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/TransactionValidator.java new file mode 100644 index 0000000..70e6ccf --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/TransactionValidator.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.cash; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TransactionValidator { +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Wallet.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Wallet.java new file mode 100644 index 0000000..0f09071 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/cash/Wallet.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.cash; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Wallet { +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/core/Main.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/core/Main.java new file mode 100644 index 0000000..d14916c --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/core/Main.java @@ -0,0 +1,48 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.core; + +import org.nanoboot.powerframework.blockchain.orig.base.BlockChain; +import org.nanoboot.powerframework.blockchain.orig.impl.TestCash_BlockChainEngine; +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Main { + public static void main(String[] args) { +// HashCalculator.main(null); +// +// if(true) return; + BlockChain blockChain = new BlockChain(); + TestCash_BlockChainEngine bce = new TestCash_BlockChainEngine(blockChain); + bce.addData("ahoj"); + bce.addData("pavle"); + bce.addData("leo"); + for(int i =0;i<100000000;i++){ + bce.addData(W5RandomGenerator.getStaticInstance().nextText(8)); + } + + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/JsonBlockSerializer.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/JsonBlockSerializer.java new file mode 100644 index 0000000..5e6ae63 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/JsonBlockSerializer.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.impl; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockSerializer; +import org.nanoboot.powerframework.blockchain.orig.base.Block; +import org.nanoboot.powerframework.json.JsonObject; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class JsonBlockSerializer implements BlockSerializer { + + @Override + public String serialize(Block block) { + JsonObject jsonObject = block.toJsonObject(); + //System.out.println(jsonObject.toMinimalString()); + return jsonObject.toMinimalString(); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/SimpleBlockData.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/SimpleBlockData.java new file mode 100644 index 0000000..53b1351 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/SimpleBlockData.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.impl; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockData; +import lombok.AllArgsConstructor; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@AllArgsConstructor +public class SimpleBlockData implements BlockData { + @Getter + private final String string; + @Override + public String convertToString() { + return string; + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_Block.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_Block.java new file mode 100644 index 0000000..2090d02 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_Block.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.impl; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockData; +import org.nanoboot.powerframework.blockchain.orig.base.BlockHeader; +import org.nanoboot.powerframework.blockchain.orig.base.Block; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TestCash_1_0_Block extends Block { + public TestCash_1_0_Block(BlockHeader blockHeader, BlockData blockData) { + super(blockHeader, null, blockData); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockMiner.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockMiner.java new file mode 100644 index 0000000..e0a132d --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockMiner.java @@ -0,0 +1,95 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.impl; + +import org.nanoboot.powerframework.blockchain.orig.api.BlockMiner; +import org.nanoboot.powerframework.blockchain.orig.base.Block; +import org.nanoboot.powerframework.blockchain.orig.base.BlockFragment; +import org.nanoboot.powerframework.blockchain.orig.base.BlockType; +import org.nanoboot.powerframework.blockchain.core.BlockChainException; +import org.nanoboot.powerframework.security.hash.api.HashCalculator; +import org.nanoboot.powerframework.time.duration.Duration; +import org.nanoboot.powerframework.time.duration.StopWatch; +import org.nanoboot.powerframework.time.utils.TimeUnit; + +import java.util.ArrayList; +import java.util.List; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TestCash_1_0_BlockMiner implements BlockMiner { + public static List lastFiveBlockMiningTimesInMilliseconds = new ArrayList<>(); + + @Override + public Block mine(BlockFragment blockFragment, BlockType blockType) { + + TestCash_1_0_Block block = new TestCash_1_0_Block(blockFragment.getBlockHeader(), blockFragment.getBlockData()); + block.injectBlockType(blockType); + + ////System.out.println("Starting mining block # " + block.getBlockHeader().getHeight()); + //System.out.println("Note: One block should be mined in 1 minute, but the last time was " + countOfSecondsToMineLastBlock + " second(s)."); + //System.out.println("Starting mining block # " + block.getBlockHeader().getHeight()); + StopWatch sw = new StopWatch(); + + //System.out.println("start: " + UniversalDateTime.now().toString()); + sw.start(); + + ////System.out.println("Searching hash equal or less than " + block.getBlockHeader().getDifficulty()); + for (long nonce = 1; nonce <= Long.MAX_VALUE; nonce++) { + if (nonce == Integer.MAX_VALUE) { + throw new BlockChainException("Nonce was not found."); + } + if (nonce % 1000000 == 0) { + System.out.println("Nonce # " + nonce); + } + + + HashCalculator hashCalculator = block.getInternalBlockType().getHashCalculator(); + String hash = block.calculateHashTest(nonce); + //System.err.println("hashCalculator.compareHexNumbers("+hash+"+, block.getBlockHeader().getDifficulty()="+block.getBlockHeader().getDifficulty()+")="+hashCalculator.compareHexNumbers(hash, block.getBlockHeader().getDifficulty())); + if (hashCalculator.compareHexNumbers(hash, block.getBlockHeader().getDifficulty()) <= 0) { + + //System.err.println("hashCalculator.compareHexNumbers("+hash+"+, block.getBlockHeader().getDifficulty()="+block.getBlockHeader().getDifficulty()+")="+hashCalculator.compareHexNumbers(hash, block.getBlockHeader().getDifficulty())); + block.lock(nonce); + ////System.out.println("Found nonce: " + nonce + " A new block was just mined: " + block.getHash() + "\n" /*+ block.toJsonObject().toPrettyString()*/); + + break; + } + } + + //System.out.println("end: " + UniversalDateTime.now().toString()); + sw.stop(); + Duration lastDuration = sw.getCurrentDuration(); + if (lastFiveBlockMiningTimesInMilliseconds.size() == 1000) { + lastFiveBlockMiningTimesInMilliseconds.remove(0); + } + lastFiveBlockMiningTimesInMilliseconds.add((int) lastDuration.toTotal(TimeUnit.MILLISECOND)); + //countOfSecondsToMineLastBlock = (int) lastDuration.toTotal(TimeUnit.SECOND); + if (block.getBlockHeader().getHeight() % 100 == 0) + System.out.println("Mining block " + block.getBlockHeader().getHeight() + " + took " + lastDuration.toString() + " ."); + return block; + } + + +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockType.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockType.java new file mode 100644 index 0000000..284f671 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_1_0_BlockType.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.impl; + +import org.nanoboot.powerframework.blockchain.orig.base.BlockType; +import org.nanoboot.powerframework.security.hash.locator.HashCalculatorLocator; +import org.nanoboot.powerframework.security.hash.locator.HashImpl; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TestCash_1_0_BlockType extends BlockType { +private static final String TYPE = "test_cash"; +private static final int MAYOR_VERSION = 1; +private static final int MINOR_VERSION = 0; + public TestCash_1_0_BlockType() { + super(TYPE, MAYOR_VERSION, MINOR_VERSION, HashCalculatorLocator.locate(HashImpl.SHA_256), new JsonBlockSerializer(), null, new TestCash_1_0_BlockMiner()); + } +} diff --git a/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_BlockChainEngine.java b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_BlockChainEngine.java new file mode 100644 index 0000000..5314529 --- /dev/null +++ b/power-blockchain/src/main/java/org/nanoboot/powerframework/blockchain/orig/impl/TestCash_BlockChainEngine.java @@ -0,0 +1,136 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.blockchain.orig.impl; + +import org.nanoboot.powerframework.blockchain.orig.base.*; +import org.nanoboot.powerframework.security.hash.api.HashCalculator; +import org.nanoboot.powerframework.time.duration.Duration; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import org.nanoboot.powerframework.time.utils.TimeUnit; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TestCash_BlockChainEngine extends BlockChainEngine { + + public static final String TEST_CASH = "TestCash"; + public static final int COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK = 10; + //public static final String DEFAULT_DIFFICULTY = "0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + public static final String DEFAULT_DIFFICULTY = "00184f329993e8d38cd0a31969b54367b4fc5af6ed86d827c1343dbf8b66a4a5"; + + public static float DIFFICULTY_PERCENT_CHANGE = (float) 1; + + public TestCash_BlockChainEngine(BlockChain blockChain) { + super(TEST_CASH, blockChain, new BlockTypeVersionList(List.of(new TestCash_1_0_BlockType()))); + } + + @Override + public BlockFragment createNewBlockFragment(String data) { + Block lastBlock = blockChain.getLastBlock(); + int newBlockHeight = lastBlock == null ? 0 : lastBlock.getBlockHeader().getHeight() + 1; + long newTimeStamp = UniversalDateTime.now().toLong(); + String previousBlockHash = lastBlock == null ? "0" : lastBlock.getHash(); + String oldDifficulty = lastBlock == null ? DEFAULT_DIFFICULTY : lastBlock.getBlockHeader().getDifficulty(); + String newDifficulty = oldDifficulty; + + int newDifficultyPeriod = 1000; + if (lastBlock != null && newBlockHeight % newDifficultyPeriod == 0) { + + List lastBlocks = blockChain.getLastXBlocks(newDifficultyPeriod); + int lastBlocksCount = lastBlocks.size(); + Block blockStart = lastBlocks.get(0); + Block blockEnd = lastBlocks.get(lastBlocks.size() - 1); + long moment1 = blockStart.getBlockHeader().getTimeStamp(); + long moment2 = blockEnd.getBlockHeader().getTimeStamp(); + UniversalDateTime udt1 = new UniversalDateTime(moment1); + UniversalDateTime udt2 = new UniversalDateTime(moment2); + Duration duration = new org.nanoboot.powerframework.time.duration.Period(udt1, udt2).getDuration(); + duration.toTotal(TimeUnit.SECOND); + double averageCountOfMillisecondsToMineABlockForTenLastBlocks = (duration.toTotal(TimeUnit.SECOND) / (lastBlocksCount - 1)); + + int countX = 0; + int sum = 0; + for (Integer i : TestCash_1_0_BlockMiner.lastFiveBlockMiningTimesInMilliseconds) { + sum = sum + i; + countX = countX + 1; + } + System.out.println("sumInSeconds="+((double)sum)); + + averageCountOfMillisecondsToMineABlockForTenLastBlocks = ((((double) sum) / ((double) countX)) /*/ 1*/); + System.out.println("averageCountOfMillisecondsToMineABlockForTenLastBlocks=" + averageCountOfMillisecondsToMineABlockForTenLastBlocks); + boolean plus = false; + if(((int)Math.round(averageCountOfMillisecondsToMineABlockForTenLastBlocks))==COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK) { + DIFFICULTY_PERCENT_CHANGE=1f/16; + } else { + if(DIFFICULTY_PERCENT_CHANGE != (float) 1f/1f) { + DIFFICULTY_PERCENT_CHANGE = (float) 1f/1f; + } + } + if (averageCountOfMillisecondsToMineABlockForTenLastBlocks < COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK) { + plus = false; + System.out.println("Difficulty +++ increasing"); + + } + if (averageCountOfMillisecondsToMineABlockForTenLastBlocks > COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK) { + plus = true; + System.out.println("Difficulty --- decreasing"); + } +// if (DIFFICULTY_PERCENT_CHANGE >= 16) { +// DIFFICULTY_PERCENT_CHANGE = 4; +// } + + System.out.println("averageCountOfSecondsToMineABlockForTenLastBlocks=" + averageCountOfMillisecondsToMineABlockForTenLastBlocks); + if (averageCountOfMillisecondsToMineABlockForTenLastBlocks != COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK) { + //DIFFICULTY_PERCENT_CHANGE = DIFFICULTY_PERCENT_CHANGE * 2; + double realDifficultyPercentChange = DIFFICULTY_PERCENT_CHANGE; + double more = averageCountOfMillisecondsToMineABlockForTenLastBlocks > COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK ? averageCountOfMillisecondsToMineABlockForTenLastBlocks : COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK; + double less = averageCountOfMillisecondsToMineABlockForTenLastBlocks < COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK ? averageCountOfMillisecondsToMineABlockForTenLastBlocks : COUNT_OF_MILLISECONDS_TO_MINE_A_BLOCK; + + if ((less / more) < 0.5) { + realDifficultyPercentChange = 50; + } + double change = 1 + ((plus ? 1 : (-1)) * (realDifficultyPercentChange / 100)); +// if((double)(averageCountOfSecondsToMineABlockForTenLastBlocks) / (double)(COUNT_OF_SECONDS_TO_MINE_A_BLOCK)<0.9 || (double)(averageCountOfSecondsToMineABlockForTenLastBlocks) / (double)(COUNT_OF_SECONDS_TO_MINE_A_BLOCK)> 1.1){ +// change = 1 + ((plus ? 1 : (-1)) * (25f / 100)); +// } + System.out.println(" Changing to " + change); + BlockType blockType = blockTypeVersionList.findBlockType("test_cash:1:0"); + HashCalculator hashCalculator = blockType.getHashCalculator(); + String oldDifficultyAsDec = hashCalculator.convertHexStringToDecString(oldDifficulty); + System.out.println("oldDifficultyAsDec=" + oldDifficultyAsDec); + BigInteger bi = new BigDecimal(oldDifficultyAsDec).multiply(new BigDecimal(change)).toBigInteger(); + System.out.println("newDifficultyAsDec=" + bi.toString()); + newDifficulty = hashCalculator.convertDecStringToHexString(bi.toString()); + System.err.println("NEW_DIFFICULTY = " + newDifficulty); + } else { + //DIFFICULTY_PERCENT_CHANGE = DIFFICULTY_PERCENT_CHANGE / 2; + } + } + BlockHeader blockHeader = new BlockHeader("test_cash:1:0", newBlockHeight, newTimeStamp, previousBlockHash, newDifficulty); + return new BlockFragment(blockHeader, new SimpleBlockData(data)); + } +} diff --git a/power-blockchain/src/main/resources/.gitkeep b/power-blockchain/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-blockchain/src/test/java/org/nanoboot/powerframework/blockchain/.gitkeep b/power-blockchain/src/test/java/org/nanoboot/powerframework/blockchain/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-collections/pom.xml b/power-collections/pom.xml new file mode 100644 index 0000000..0534183 --- /dev/null +++ b/power-collections/pom.xml @@ -0,0 +1,73 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-collections + jar + + Power Collections + Collections functionality for the Power library + + + true + + + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-random + ${power.version} + + + org.nanoboot.powerframework + power-utils + ${power.version} + + + org.projectlombok + lombok + + + + + junit + junit + 4.12 + test + + + + diff --git a/power-collections/src/main/java/module-info.java b/power-collections/src/main/java/module-info.java new file mode 100644 index 0000000..b35b49d --- /dev/null +++ b/power-collections/src/main/java/module-info.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +//TODO: collections should have methods returning this + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.collections { + exports org.nanoboot.powerframework.collections; + exports org.nanoboot.powerframework.collections.arrays; + requires powerframework.core; + requires powerframework.random; + requires powerframework.utils; + requires lombok; +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNode.java new file mode 100644 index 0000000..ceb3238 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNode.java @@ -0,0 +1,176 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.collections.internal.AbstractTreeNode; + +/** + * + * @param + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class BinaryTreeNode extends AbstractTreeNode { + /** + * Left node. + */ + @Getter + private BinaryTreeNode left = null; + /** + * Right node. + */ + @Getter + private BinaryTreeNode right = null; + /** + * Type of the node. + * + */ + @Getter + @Setter(AccessLevel.PACKAGE) + private BinaryTreeNodeType type = BinaryTreeNodeType.UNDEFINED; + /** + * + */ + public BinaryTreeNode() { + } + + /** + * + * @param valueIn the value + */ + public BinaryTreeNode(final T valueIn) { + this.setValue(valueIn); + } + + /** + * + * @param valueIn value + * @param leftIn left child + * @param rightIn right child + */ + public BinaryTreeNode( + final T valueIn, + final BinaryTreeNode leftIn, + final BinaryTreeNode rightIn) { + this(valueIn); + this.setLeft(leftIn); + this.setRight(rightIn); + } + + /** + * + * @param valueIn value + * @param typeIn type of node + * @param nodeIn node to add + */ + public BinaryTreeNode( + final T valueIn, + final BinaryTreeNodeType typeIn, + final BinaryTreeNode nodeIn) { + this(valueIn); + this.setNode(typeIn, nodeIn); + } + + + /** + * @param typeIn node type + * @return + */ + public BinaryTreeNode getNode( + final BinaryTreeNodeType typeIn) { + switch (typeIn) { + case LEFT: return getLeft(); + case RIGHT: return getRight(); + default: + String msg = "Unsupported " + + BinaryTreeNode.class.getName() + type; + throw new CollectionException(msg); + } + } + /** + * + * @param node left node to add + */ + public void setLeft(final BinaryTreeNode node) { + setNode(BinaryTreeNodeType.LEFT, node); + } + /** + * + * @param node left node to add + */ + public void setRight(final BinaryTreeNode node) { + setNode(BinaryTreeNodeType.RIGHT, node); + } + /** + * @param typeIn node type + * @param nodeIn node to set + * @return + */ + public void setNode( + final BinaryTreeNodeType typeIn, + final BinaryTreeNode nodeIn) { + switch (typeIn) { + case LEFT: this.left = nodeIn; break; + case RIGHT: this.right = nodeIn; break; + default: + String msg = "Unsupported " + + BinaryTreeNode.class.getName() + type; + throw new CollectionException(msg); + } + nodeIn.setParent(this); + } + /** + * + * @return true, if this node has left node, otherwise false + */ + public boolean hasLeft() { + return hasNode(BinaryTreeNodeType.LEFT); + } + /** + * + * @return true, if this node has right node, otherwise false + */ + public boolean hasRight() { + return hasNode(BinaryTreeNodeType.RIGHT); + } + /** + * @param typeIn node type + * @return + */ + public boolean hasNode( + final BinaryTreeNodeType typeIn) { + BinaryTreeNode node = getNode(typeIn); + return node != null; + } + /** + * @param type node type + * @return true, if this node has right node, otherwise false + */ + public boolean has(final BinaryTreeNodeType type) { + return getRight() != null; + } + + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNodeType.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNodeType.java new file mode 100644 index 0000000..9145f52 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/BinaryTreeNodeType.java @@ -0,0 +1,46 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum BinaryTreeNodeType { + /** + * Undefined node. + */ + UNDEFINED, + /** + * Root node. + */ + ROOT, + /** + * Left node. + */ + LEFT, + /** + * Right node. + */ + RIGHT; +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/CollectionException.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/CollectionException.java new file mode 100644 index 0000000..08c3267 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/CollectionException.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CollectionException extends PowerException { + + /** + * Constructor + * + * @param messageIn message describing this exception + */ + public CollectionException(final String messageIn) { + super(messageIn); + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedList.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedList.java new file mode 100644 index 0000000..f224fc4 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedList.java @@ -0,0 +1,319 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.collections.internal.AbstractLinkedList; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Represents double linked list data structure + * TODO !!! + * + * @param The type of the values stored in this list. + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DoubleLinkedList extends AbstractLinkedList + implements Iterable { +//https://www.javatpoint.com/doubly-linked-list +//https://www.studytonight.com/data-structures/doubly-linked-list +//https://www.geeksforgeeks.org/doubly-linked-list/ +//https://www.tutorialspoint.com/data_structures_algorithms/doubly_linked_list_algorithm.htm + + /** + * The reference to the first node of this list. + */ + @Getter(AccessLevel.PRIVATE) + @Setter(AccessLevel.PRIVATE) + private DoubleLinkedListNode firstNode = null; + /** + * The reference to the last node of this list. + */ + @Getter(AccessLevel.PRIVATE) + @Setter(AccessLevel.PRIVATE) + private DoubleLinkedListNode lastNode = null; + + /** + * Iterator. + * + * @param Node type + */ + private class DoubleLinkedListIterator + implements Iterator { + /** + * Current node. + */ + @Getter(AccessLevel.PRIVATE) + private DoubleLinkedListNode currentNode; + + /** + * @param node start node + */ + DoubleLinkedListIterator(final DoubleLinkedListNode node) { + this.currentNode = new DoubleLinkedListNode<>(null); + this.currentNode.setNext(node); + } + + @Override + public boolean hasNext() { + return currentNode.hasNext(); + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + this.currentNode = currentNode.getNext(); + return this.getCurrentNode().getValue(); + } + } + + /** + * Iterator. Iterates from end to start. + * + * @param Node type + */ + private class ReversDoubleLinkedListIterator + implements Iterator { + /** + * Current node. + */ + @Getter(AccessLevel.PRIVATE) + private DoubleLinkedListNode currentNode; + + /** + * @param lastNodeIn end node + */ + ReversDoubleLinkedListIterator( + final DoubleLinkedListNode lastNodeIn) { + this.currentNode = new DoubleLinkedListNode<>(null); + this.currentNode.setPrevious(lastNodeIn); + } + + @Override + public boolean hasNext() { + return currentNode.hasPrevious(); + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + this.currentNode = currentNode.getPrevious(); + return this.getCurrentNode().getValue(); + } + } + + /** + * @return iterator for this list + */ + @Override + public Iterator iterator() { + return new DoubleLinkedListIterator(this.firstNode); + } + + /** + * @return reverse iterator for this list + */ + public Iterator reverseIterator() { + return new ReversDoubleLinkedListIterator(this.firstNode); + } + + /** + * Deletes all elements of this linked list. + */ + public void clear() { + clearSize(); + firstNode = null; + lastNode = null; + } + + /** + * {@inheritDoc} + */ + @Override + public E addBeforeFirst(final E elementIn) { + DoubleLinkedListNode oldFirstNode = getFirstNode(); + DoubleLinkedListNode newFirstNode = + new DoubleLinkedListNode<>(elementIn); + DoubleLinkedListNode.link(newFirstNode, oldFirstNode); + setFirstNode(newFirstNode); + this.incrementSize(); + return elementIn; + + } + + /** + * {@inheritDoc} + */ + @Override + public E addAfterLast(final E elementIn) { + DoubleLinkedListNode oldLastNode = getLastNode(); + DoubleLinkedListNode newLastNode = + new DoubleLinkedListNode<>(elementIn); + + setLastNode(newLastNode); + + if (isEmpty()) { + setFirstNode(getLastNode()); + } else { + DoubleLinkedListNode.link(oldLastNode, newLastNode); + } + + this.incrementSize(); + + return elementIn; + } + + /** + * {@inheritDoc} + */ + @Override + public E removeFirst() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + DoubleLinkedListNode oldFirstNode = getFirstNode(); + DoubleLinkedListNode newFirstNode = oldFirstNode.getNext(); + E element = oldFirstNode.getValue(); + if (size() == 1) { + clear(); + return element; + } + setFirstNode(newFirstNode); + this.incrementSize(); + + if (this.size() == 1) { + setLastNode(getFirstNode()); + } + newFirstNode.unlinkPrevious(); + return element; + } + + /** + * {@inheritDoc} + */ + @Override + public E removeLast() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + E element = getLastNode().getValue(); + + if (this.size() == 1) { + clear(); + return element; + } + DoubleLinkedListNode beforeLastNode = getLastNode().getPrevious(); + beforeLastNode.unlinkNext(); + setLastNode(beforeLastNode); + this.decrementSize(); + + + return element; + } + + /** + * {@inheritDoc} + */ + @Override + public E getFirst() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return firstNode.getValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public E getLast() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return lastNode.getValue(); + } + + /** + * {@inheritDoc} + */ + @Override + public E remove(final int index) { + DoubleLinkedListNode node = getNodeByIndex(index); + if (node.equals(getFirstNode())) { + return removeFirst(); + } + if (node.equals(getLastNode())) { + return removeLast(); + } + DoubleLinkedListNode beforeNode = node.getPrevious(); + DoubleLinkedListNode.link(beforeNode, node.getNext()); + return node.getValue(); + } + + private DoubleLinkedListNode getNodeByIndex(final int indexIn) { + if (isEmpty()) { + throw new NoSuchElementException(); + } + if (indexIn > (size() - 1)) { + throw new CollectionException( + "Index " + indexIn + " is out of bounds."); + } + int index = 0; + DoubleLinkedListNode node = getFirstNode(); + while (node != null) { + if (index == indexIn) { + return node; + } + node = node.getNext(); + index++; + } + return null; + } + /** + * Returns the element at the specified position in this list. + * + * @param index starting from 1 + * + * @return value + */ + public E get(final int index) { + return getNodeByIndex(index).getValue(); + } + /** + * {@inheritDoc} + */ + @Override + public E set(final int index, final E element) { + getNodeByIndex(index).setValue(element); + return element; + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNode.java new file mode 100644 index 0000000..2b6c003 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNode.java @@ -0,0 +1,166 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.collections.internal.AbstractLinkedListNode; + +/** + * Represents one node of linked list. + * + * It is used to store a value based on the T. + * + * These nodes are linked (forward direction only). + * + * @param The type of the value this node holds + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class DoubleLinkedListNode extends AbstractLinkedListNode { + + /** + * Adds the reference for the node2 to the node1. The node1 will be + * connected to the node2 + * + * @param node1 The node, which field next will be set to node2. + * @param node2 The node, which will be set as the next node of the node1 + */ + static void link(final DoubleLinkedListNode node1, + final DoubleLinkedListNode node2) { + if (node1 != null) { + node1.setNext(node2); + } + if (node2 != null) { + node2.setPrevious(node1); + } + } + /** + * Reference for the previous node. + */ + @Getter + @Setter + private DoubleLinkedListNode previous = null; + + /** + * Reference for the next node. + */ + @Getter + @Setter + private DoubleLinkedListNode next = null; + + /** + * Constructor + * + * Used to create node without key (Key is empty String), used in linked + * list, which does not need keys. + * + * @param valueIn the appropriate field key will be set by this value + */ + DoubleLinkedListNode(final E valueIn) { + this.setValue(valueIn); + } + + /** + * @param type type of the node to get + * @return node by type + */ + public DoubleLinkedListNode getNodeByType( + final DoubleLinkedListNodeReferenceType type) { + if (type.isPrevious()) { + return previous; + } else { + return next; + } + } + + /** + * @param type type of the node to get + * @param node to set + */ + public void setNodeByType( + final DoubleLinkedListNodeReferenceType type, + final DoubleLinkedListNode node) { + if (type.isPrevious()) { + setPrevious(node); + } else { + setNext(node); + } + } + + /** + * Return true if this node has next node, otherwise false. + * + * @return boolean value + */ + boolean hasPrevious() { + return has(DoubleLinkedListNodeReferenceType.PREVIOUS); + } + + /** + * Return true if this node has next node, otherwise false. + * + * @return boolean value + */ + boolean hasNext() { + return has(DoubleLinkedListNodeReferenceType.NEXT); + } + /** + * Return true if this node has node with this type, otherwise false. + * @param type type of the node to get + * @return boolean value + */ + boolean has(final DoubleLinkedListNodeReferenceType type) { + DoubleLinkedListNode node = getNodeByType(type); + return node != null; + } + + /** + * Removes the reference of the next node from this node. + */ + void unlinkAll() { + unlinkPrevious(); + unlinkNext(); + } + + /** + * Removes the reference of the next node from this node. + */ + void unlinkPrevious() { + unlink(DoubleLinkedListNodeReferenceType.PREVIOUS); + } + + /** + * Removes the reference of the next node from this node. + */ + void unlinkNext() { + unlink(DoubleLinkedListNodeReferenceType.NEXT); + } + + /** + * Unlinks node. + * @param type type of the node to unlink + */ + void unlink(final DoubleLinkedListNodeReferenceType type) { + setNodeByType(type, null); + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNodeReferenceType.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNodeReferenceType.java new file mode 100644 index 0000000..69c841f --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/DoubleLinkedListNodeReferenceType.java @@ -0,0 +1,64 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum DoubleLinkedListNodeReferenceType { + /** + * Previous node. + */ + PREVIOUS, + /** + * Next node. + */ + NEXT; + + /** + * Checks the type. + * @return true, if it the previous type, otherwise false. + */ + public boolean isPrevious() { + return this == PREVIOUS; + } + /** + * Checks the type. + * @return true, if it the next type, otherwise false. + */ + public boolean isNext() { + return this == NEXT; + } + /** + * Returns the opposite reference. + * @return opposite reference + */ + public DoubleLinkedListNodeReferenceType opposite() { + if (this.isPrevious()) { + return NEXT; + } else { + return PREVIOUS; + } + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/KeyValue.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/KeyValue.java new file mode 100644 index 0000000..4b05f61 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/KeyValue.java @@ -0,0 +1,71 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.nanoboot.powerframework.utils.StringUtils; + +import java.util.Map; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@AllArgsConstructor +public class KeyValue implements Map.Entry { + /** + * Key used to identify this node, if node with this key is wanted. + */ + @Getter + private String key = StringUtils.EMPTY_STRING; + /** + * The value this node is holding. + */ + @Getter + private V value; + /** + * Setter for key. + * @param k key + * @return the new key + */ + public String setKey(final String k) { + this.key = k; + return this.key; + } + /** + * {@inheritDoc} + */ + @Override + public V setValue(final V v) { + this.value = v; + return this.value; + } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return key + "=" + value; + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerCollection.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerCollection.java new file mode 100644 index 0000000..d1bd11b --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerCollection.java @@ -0,0 +1,215 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import org.nanoboot.powerframework.core.PowerObject; + +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Represents map data structure. Values of type T are mapped to String and + * searched by this String. + * + * @author Robert Vokac + * @since 0.0.0 + * @param the type of items, this map will store. + */ +public class PowerCollection extends PowerObject + implements Collection { + + /** + * Constructor. + *

+ * Constructor description + * + * @param items elements + */ + public PowerCollection(final E... items) { + for (E e : items) { + add(e); + } + } + /** + * List, where are stored items of this map. + */ + private final SingleLinkedList list = new SingleLinkedList<>(); + /** + * {@inheritDoc} + */ + @Override + public int size() { + return list.size(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + /** + * {@inheritDoc} + */ + @Override + public boolean contains(final Object o) { + return list.contains(o); + } + + private class CollectionIterator implements Iterator { + + /** + * Internal list. + */ + private final SingleLinkedList list; + /** + * Current index. + */ + private int currentIndex = 0; + + CollectionIterator(final SingleLinkedList listIn) { + this.list = listIn; + } + @Override + public boolean hasNext() { + return currentIndex < list.size(); + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + E result = list.get(currentIndex); + currentIndex++; + return result; + } + } + /** + * {@inheritDoc} + */ + @Override + public Iterator iterator() { + return new CollectionIterator(this.list); + } + /** + * {@inheritDoc} + */ + @Override + public Object[] toArray() { + return this.list.toArray(); + } + /** + * {@inheritDoc} + */ + @Override + public T[] toArray(final T[] ts) { + return (T[]) this.list.toArray(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean add(final E e) { + return this.list.add(e); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean remove(final Object o) { + return this.list.remove(o); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsAll(final Collection collection) { + for (Object e : collection) { + if (!contains(e)) { + return false; + } + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean addAll(final Collection collection) { + for (E e : collection) { + this.add(e); + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean removeAll(final Collection collection) { + for (Object e: collection) { + collection.remove(e); + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean retainAll(final Collection collection) { + throw new UnsupportedOperationException(); + } + + /** + * {@inheritDoc} + */ + @Override + public void clear() { + this.list.clear(); + } + + /** + * Returns internal list. + * @return internal list + */ + protected SingleLinkedList getInternalList() { + return list; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return list.toString(); + } + protected final boolean throwUnsupportedOperationException() { + throw new UnsupportedOperationException(); + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerList.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerList.java new file mode 100644 index 0000000..7e3ca9a --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerList.java @@ -0,0 +1,193 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerList extends PowerCollection implements List { + /** + * Linked list, where are stored items of this queue. + */ + private final SingleLinkedList list = getInternalList(); + /** + * Constructor. + * + * Constructs an empty list. + */ + public PowerList() { + } + + /** + * Constructor. + * + * Constructor description + * + * @param items elements + */ + public PowerList(final E... items) { + super(items); + } + /** + * {@inheritDoc} + */ + @Override + public boolean addAll( + final int i, final Collection collection) { + return throwUnsupportedOperationException(); + } + /** + * {@inheritDoc} + */ + @Override + public E get(final int i) { + return list.get(i); + } + /** + * {@inheritDoc} + */ + @Override + public E set(final int i, final E e) { + list.set(i, e); + return e; + } + /** + * {@inheritDoc} + */ + @Override + public void add(final int i, final E e) { + throwUnsupportedOperationException(); + } + /** + * {@inheritDoc} + */ + @Override + public E remove(final int i) { + return list.remove(i); + } + /** + * {@inheritDoc} + */ + @Override + public int indexOf(final Object o) { + throwUnsupportedOperationException(); + return 0; + } + /** + * {@inheritDoc} + */ + @Override + public int lastIndexOf(final Object o) { + throwUnsupportedOperationException(); + return 0; + } + + private class PowerListIterator implements ListIterator { + /** + * Internal iterator. + */ + private final Iterator iterator; + + PowerListIterator(final Iterator iteratorIn) { + this.iterator = iteratorIn; + } + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public E next() { + return iterator.next(); + } + + @Override + public boolean hasPrevious() { + throwUnsupportedOperationException(); + return true; + } + + @Override + public E previous() { + throwUnsupportedOperationException(); + return null; + } + + @Override + public int nextIndex() { + throwUnsupportedOperationException(); + return 0; + } + + @Override + public int previousIndex() { + throwUnsupportedOperationException(); + return 0; + } + + @Override + public void remove() { + throwUnsupportedOperationException(); + + } + + @Override + public void set(final E e) { + throwUnsupportedOperationException(); + + } + + @Override + public void add(final E e) { + + } + } + /** + * {@inheritDoc} + */ + @Override + public ListIterator listIterator() { + return new PowerListIterator<>(this.iterator()); + } + /** + * {@inheritDoc} + */ + @Override + public ListIterator listIterator(final int i) { + throwUnsupportedOperationException(); + return null; + } + /** + * {@inheritDoc} + */ + @Override + public List subList(final int i, final int i1) { + throwUnsupportedOperationException(); + return null; + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerMap.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerMap.java new file mode 100644 index 0000000..575d28e --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerMap.java @@ -0,0 +1,266 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import org.nanoboot.powerframework.core.PowerObject; +import org.nanoboot.powerframework.core.exceptions.NotYetImplementedException; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * Represents map data structure. Values of type T are mapped to String and + * searched by this String. + * + * @author Robert Vokac + * @since 0.0.0 + * @param the type of items, this map will store. + */ +public class PowerMap extends PowerObject implements Map { + + /** + * List, where are stored items of this map. + */ + private final SingleLinkedList> list = new SingleLinkedList<>(); + + /** + * {@inheritDoc} + */ + @Override + public int size() { + return list.size(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsKey(final Object o) { + for (KeyValue e : list) { + if (e.getKey().equals(o)) { + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean containsValue(final Object o) { + for (KeyValue e : list) { + if (e.getValue().equals(o)) { + return true; + } + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public T get(final Object o) { + for (KeyValue e : list) { + if (e.getKey().equals(o)) { + return e.getValue(); + } + } + throw new NoSuchElementException("There is no key " + o); + } + + /** + * {@inheritDoc} + */ + @Override + public T put(final String s, final T t) { + this.list.add(new KeyValue(s, t)); + return t; + } + /** + * Puts and return this. + * @param s key + * @param t value + * @return this + */ + public PowerMap putAndReturn(final String s, final T t) { + put(s, t); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public T remove(final Object o) { + for (KeyValue e : list) { + if (e.getKey().equals(o)) { + this.list.remove(e); + return e.getValue(); + } + } + throw new NoSuchElementException(); + } + + /** + * {@inheritDoc} + */ + @Override + public void putAll(final Map map) { + for (Entry entry : map.entrySet()) { + String key = entry.getKey(); + T value = entry.getValue(); + put(key, value); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void clear() { + this.list.clear(); + } + + /** + * {@inheritDoc} + */ + @Override + public Set keySet() { + Set set = new HashSet(); + for (Entry entry : this.entrySet()) { + String key = entry.getKey(); + set.add(key); + } + return set; + } + + /** + * {@inheritDoc} + */ + public List keyList() { + List list2 = new PowerList<>(); + for (KeyValue e : list) { + String key = e.getKey(); + list2.add(key); + } + return list2; + } + /** + * {@inheritDoc} + */ + @Override + public Collection values() { + throw new NotYetImplementedException("Not implemented."); + } + + /** + * {@inheritDoc} + */ + @Override + public Set> entrySet() { + Set> set = new HashSet<>(); + Iterator> iterator = this.list.iterator(); + while (iterator.hasNext()) { + set.add(iterator.next()); + } + return set; + } +//// + /** + * Iterator. + * @return iterator + */ + public Iterator> iterator() { + return new MapIterator(this.list); + } + + private class MapIterator implements Iterator> { + + /** + * Internal list. + */ + private final SingleLinkedList> list; + /** + * Current index. + */ + private int currentIndex = 0; + + MapIterator(final SingleLinkedList> listIn) { + this.list = listIn; + } + @Override + public boolean hasNext() { + return currentIndex < list.size(); + } + + @Override + public KeyValue next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + KeyValue result = list.get(currentIndex); + currentIndex++; + return result; + } + } + + /** + * Updates the dictionary entry with the given key to the given value. + * + * @param keyIn key to search + * @param valueIn value mapped to key will be updated to the valueIn + * + * @return this map + */ + public T replace( + final String keyIn, + final T valueIn) { + this.remove(keyIn); + this.put(keyIn, valueIn); + return valueIn; + } + + @Override + public final String toString() { + StringBuilder sb = new StringBuilder(); + for (KeyValue e: this.list) { + sb.append(e.getKey()).append("=").append(e.getValue()).append("\n"); + } + String result = sb.toString(); + return result.substring(0, result.length() - 1); + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerQueue.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerQueue.java new file mode 100644 index 0000000..6b44167 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerQueue.java @@ -0,0 +1,87 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; +import java.util.Queue; + +/** + * Represents Queue- linear data structure. + * + * @author Robert Vokac + * @since 0.0.0 + * @param object + */ +public class PowerQueue extends PowerCollection implements Queue { + + /** + * Linked list, where are stored items of this queue. + */ + private final SingleLinkedList list = getInternalList(); + /** + * {@inheritDoc} + */ + @Override + public boolean offer(final E e) { + return add(e); + } + + /** + * {@inheritDoc} + */ + @Override + public E remove() { + return list.removeFirst(); + } + + /** + * {@inheritDoc} + */ + @Override + public E poll() { + return list.removeFirst(); + } + + /** + * {@inheritDoc} + */ + @Override + public E element() { + return list.getFirst(); + } + + /** + * {@inheritDoc} + */ + @Override + public E peek() { + return list.getFirst(); + } + + /** + * Adds and returns. + * @param item element to add + * @return this + */ + public PowerQueue addAndReturn(final E item) { + add(item); + return this; + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerSet.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerSet.java new file mode 100644 index 0000000..709f03d --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerSet.java @@ -0,0 +1,144 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import org.nanoboot.powerframework.collections.arrays.ObjectArray; +import org.nanoboot.powerframework.random.generators.RandomGenerator; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * Here goes the description of this class. + *

+ * Set is unordered collection of values and contains no duplicates. + * + * @param element type + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerSet extends PowerCollection implements Set { + /** + * Linked list, where are stored items of this queue. + */ + private final SingleLinkedList list = getInternalList(); + + /** + * Constructor. + *

+ * Constructor description + * + * @param items elements + */ + public PowerSet(final E... items) { + super(items); + } + + /** + * {@inheritDoc} + */ + public boolean add(final E item) { + if (contains(item)) { + String msg = "Can't add item " + item + + ". This object is already stored in this set."; + throw new CollectionException(msg); + } + return this.list.add(item); + } + + /** + * Returns random element of this Set. + * + * @return value + */ + public E getRandom() { + int index = RandomGenerator.getDefaultImplStatic() + .nextInt(1, list.size()); + return list.get(index); + } + + /** + * @return iterator for this list + */ + @Override + public Iterator iterator() { + return new SetIterator(list); + } + + /** + * Iterator implementation. + */ + private class SetIterator implements Iterator { + + /** + * Internal list. + */ + private final SingleLinkedList list; + /** + * Indexes. + */ + private final SingleLinkedList indexes; + + SetIterator(final SingleLinkedList listIn) { + this.list = listIn; + this.indexes = new SingleLinkedList<>(); + + for (int i = 0; i < list.size(); i++) { + indexes.add(i); + } + } + + @Override + public boolean hasNext() { + return !indexes.isEmpty(); + } + + @Override + public E next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + int randomArrayListIndexesListIndex = RandomGenerator + .getDefaultImplStatic().nextInt(0, indexes.size() - 1); + int randomIndex = indexes.get(randomArrayListIndexesListIndex); + E element = list.get(randomIndex); + indexes.remove(randomArrayListIndexesListIndex); + return element; + } + } + + /** + * Creates object array. + * + * @return object array + */ + public final ObjectArray toObjectArray() { + ObjectArray objectArray = new ObjectArray<>(this.size()); + int index = 1; + for (E element : this) { + objectArray.set(element, index++); + } + return objectArray; + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerStack.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerStack.java new file mode 100644 index 0000000..1a62acb --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/PowerStack.java @@ -0,0 +1,68 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +/** + * Represents Stack- linear data structure. + * + * @author Robert Vokac + * @since 0.0.0 + * @param object + */ +public class PowerStack extends PowerCollection implements StackI { + + /** + * Linked list, where are stored items of this queue. + */ + private final SingleLinkedList list = getInternalList(); + /** + * {@inheritDoc} + */ + @Override + public E push(final E item) { + list.addBeforeFirst(item); + return item; + } + + /** + * Pushes and returns. + * @param item element to push + * @return this + */ + public PowerStack pushAndReturn(final E item) { + push(item); + return this; + } + /** + * {@inheritDoc} + */ + @Override + public E pop() { + return list.removeFirst(); + } + /** + * {@inheritDoc} + */ + @Override + public E peek() { + return list.getFirst(); + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/Properties.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/Properties.java new file mode 100644 index 0000000..5a178bd --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/Properties.java @@ -0,0 +1,132 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.Getter; +import org.nanoboot.powerframework.core.PowerObject; +import org.nanoboot.powerframework.utils.annotations.InProgress; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@InProgress +public class Properties extends PowerObject { + /** + * Constant #. + */ + private static final String COMMENT_START_CHARACTER = "#"; + /** + * Constant =. + */ + private static final String EQUAL = "="; + /** + * Constant 0. + */ + private static final int PROPERTYPOSITION = 0; + /** + * Constant 1. + */ + private static final int VALUEPOSITION = 1; + /** + * Map mapping properties and their values. + */ + @Getter + private PowerMap map = new PowerMap<>(); + + /** + * @param propertiesFileTextIn input text + */ + public Properties(final String propertiesFileTextIn) { + String[] rows = propertiesFileTextIn.split("\\r?\\n"); + for (String row : rows) { + if (!row.isEmpty() && !row.startsWith(COMMENT_START_CHARACTER)) { + String[] array = getArrayFromRowIfPossible(row); + String property = array[PROPERTYPOSITION]; + + if (array.length == 2) { + String value = array[VALUEPOSITION]; + map.put(property, value); + } + } + } + } + + /** + * Split row by first "=" occurrence. + * + * @param rowIn row + * @return null, if there is no "=" + */ + private String[] getArrayFromRowIfPossible(final String rowIn) { + return rowIn.split(EQUAL, 2); + } + + /** + * @param propertyIn property + * @return + */ + public String getProperty(final String propertyIn) { + return map.get(propertyIn); + } + + /** + * @param propertyIn property + * @param valueIn value + */ + public void setProperty(final String propertyIn, + final String valueIn) { + map.replace(propertyIn, valueIn); + } + + /** + * @param propertyIn property + * @return true, if the property is present, otherwise false + */ + public boolean hasProperty(final String propertyIn) { + return map.containsKey(propertyIn); + } + /** + * {@inheritDoc} + */ + @Override + public String toString() { + if (this.getMap().isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + + String commaSpace = ", "; + for (String key : this.getMap().keySet()) { + sb + .append(key) + .append(EQUAL) + .append(this.getMap().get(key)) + .append(commaSpace); + } + String result = sb.toString(); + return result.substring(0, result.length() - commaSpace.length()); + } + + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedList.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedList.java new file mode 100644 index 0000000..46bdef3 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedList.java @@ -0,0 +1,442 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.collections.internal.AbstractLinkedList; +import org.nanoboot.powerframework.core.exceptions.NotYetImplementedException; + +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +/** + * Represents linked list data structure. + * + * @param The type of the values stored in this list. + * @author Robert Vokac + * @since 0.0.0 + */ +public class SingleLinkedList extends AbstractLinkedList + implements Collection { + /** + * The reference to the first node of this list. + */ + @Getter(AccessLevel.PRIVATE) + @Setter(AccessLevel.PRIVATE) + private SingleLinkedListNode firstNode = null; + /** + * The reference to the last node of this list. + */ + @Getter(AccessLevel.PRIVATE) + @Setter(AccessLevel.PRIVATE) + private SingleLinkedListNode lastNode = null; + + /** + * Iterator. + * + * @param Node type + */ + private static class SingleLinkedListIterator + implements Iterator { + /** + * Current node. + */ + @Getter(AccessLevel.PRIVATE) + private SingleLinkedListNode currentNode; + + /** + * @param node start node + */ + SingleLinkedListIterator(final SingleLinkedListNode node) { + this.currentNode = new SingleLinkedListNode<>(null); + this.currentNode.setNext(node); + } + + @Override + public boolean hasNext() { + return currentNode.hasNext(); + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + this.currentNode = currentNode.getNext(); + return this.getCurrentNode().getValue(); + } + } + /** + * Constructor + * + * Constructs an empty list. + */ + public SingleLinkedList() { + } + + /** + * Constructor. + * + * Constructor description + * + * @param items elements + */ + public SingleLinkedList(final E... items) { + addAll(items); + } + //// + /** + * Setter for name. + * + * @param items elements + */ + public void addAll(final E... items) { + for (E element : items) { + add(element); + } + } + //// + + /** + * {@inheritDoc} + */ + @Override + public boolean contains(final Object o) { + for (E e : this) { + if (e.hashCode() == o.hashCode()) { + return true; + } + } + return false; + } + /** + * {@inheritDoc} + */ + @Override + public final Iterator iterator() { + return new SingleLinkedListIterator(this.getFirstNode()); + } + /** + * {@inheritDoc} + */ + @Override + public Object[] toArray() { + Object[] array = new Object[this.size()]; + int index = 0; + for (E e : this) { + array[index] = e; + index++; + } + return array; + } + /** + * {@inheritDoc} + */ + @Override + public T1[] toArray(final T1[] t1s) { + throw new NotYetImplementedException("No detail"); + } + /** + * {@inheritDoc} + */ + @Override + public boolean add(final E e) { + this.addAfterLast(e); + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean remove(final Object o) { + int index = 0; + SingleLinkedListNode nodeToRemove; + SingleLinkedListNode beforeNode; + for (E e : this) { + if (e.hashCode() == o.hashCode()) { + remove(index); + return true; + } + index++; + } + return false; + } + /** + * {@inheritDoc} + */ + @Override + public boolean containsAll(final Collection collection) { + if (collection.isEmpty()) { + return true; + } + for (Object e :collection) { + if (!this.contains(e)) { + return false; + } + } + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean addAll(final Collection collection) { + for (E e : collection) { + this.add(e); + } + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean removeAll(final Collection collection) { + for (Object e : collection) { + remove(e); + } + return true; + } + /** + * {@inheritDoc} + */ + @Override + public boolean retainAll(final Collection collection) { + throw new NotYetImplementedException("No detail"); + } + /** + * Clears this list. + * All elements will be removed. + */ + public void clear() { + clearSize(); + firstNode = null; + lastNode = null; + } + //// + /** + * Adds new element before first element. + * + * @param elementIn element + * @return this linked list + */ + public E addBeforeFirst( + final E elementIn) { + SingleLinkedListNode oldRootNode = getFirstNode(); + SingleLinkedListNode newRootNode = + new SingleLinkedListNode<>(elementIn); + SingleLinkedListNode.link(newRootNode, oldRootNode); + setFirstNode(newRootNode); + this.incrementSize(); + if (this.size() == 1) { + setLastNode(getFirstNode()); + } + return elementIn; + } + /** + * Adds new element after last element. + * + * @param elementIn element + * @return this linked list + */ + public E addAfterLast(final E elementIn) { + + SingleLinkedListNode oldLastNode = getLastNode(); + SingleLinkedListNode newNode; + newNode = new SingleLinkedListNode<>(elementIn); + + if (isEmpty()) { + setFirstNode(newNode); + } else { + SingleLinkedListNode.link(oldLastNode, newNode); + } + setLastNode(newNode); + this.incrementSize(); + + return elementIn; + } + + /** + * Removes first element. + * + * @return removed element + */ + public E removeFirst() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + + SingleLinkedListNode oldFirstNode = getFirstNode(); + SingleLinkedListNode newFirstNode = oldFirstNode.getNext(); + E element = oldFirstNode.getValue(); + if (size() == 1) { + clear(); + return element; + } + setFirstNode(newFirstNode); + this.decrementSize(); + + if (this.size() == 1) { + setLastNode(getFirstNode()); + } + return element; + } + + /** + * Removes last element. + * + * @return removed element + */ + public E removeLast() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + E element = getLastNode().getValue(); + + if (this.size() == 1) { + clear(); + } else { + SingleLinkedListNode tempNode = getFirstNode(); + while (tempNode.getNext() != getLastNode()) { + tempNode = tempNode.getNext(); + } + SingleLinkedListNode beforeLastNode = tempNode; + beforeLastNode.unlinkNext(); + setLastNode(beforeLastNode); + this.decrementSize(); + } + + return element; + } + + /** + * @return first element + */ + public E getFirst() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return getFirstNode().getValue(); + } + + /** + * @return last element + */ + public E getLast() { + if (isEmpty()) { + throw new NoSuchElementException(); + } + return getLastNode().getValue(); + } + + /** + * Removes the element at the specified position in this list. + * + * @param index index param + * @return the removed element + */ + public E remove(final int index) { + SingleLinkedListNode node = getNodeByIndex(index); + if (node.equals(getFirstNode())) { + return removeFirst(); + } + if (node.equals(getLastNode())) { + return removeLast(); + } + SingleLinkedListNode beforeNode = getNodeByIndex(index - 1); + beforeNode.setNext(node.getNext()); + decrementSize(); + return node.getValue(); + } + + /** + * Returns the element at the specified position in this list. + * + * @param index starting from 0 + * + * @return value + */ + public E get(final int index) { + return getNodeByIndex(index).getValue(); + } + + private SingleLinkedListNode getNodeByIndex(final int indexIn) { + if (isEmpty()) { + throw new NoSuchElementException(); + } + if (indexIn > (size() - 1)) { + throw new CollectionException( + "Index " + indexIn + " is out of bounds."); + } + int index = 0; + SingleLinkedListNode node = getFirstNode(); + while (node != null) { + if (index == indexIn) { + return node; + } + node = node.getNext(); + index++; + } + return null; + } + + /** + * Replaces the element at the specified position + * in this list with the specified element. + * + * @param index index param + * @param element element param + * @return the new value + */ + public E set(final int index, final E element) { + SingleLinkedListNode node = getNodeByIndex(index); + E originalValue = node.getValue(); + node.setValue(element); + return originalValue; + } + @Override + public final String toString() { + String commaSpace = ", "; + return toString(commaSpace); + } + + /** + * Creates a String representation of this list using the delimiter. + * @param delimiter String delimiter + * @return string representation of the list + */ + public final String toString(final String delimiter) { + if (isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (E e : this) { + sb.append(e); + if (!delimiter.isEmpty()) { + sb.append(delimiter); + } + } + String result = sb.toString(); + result = result.substring(0, result.length() - delimiter.length()); + return result; + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedListNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedListNode.java new file mode 100644 index 0000000..da253cc --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/SingleLinkedListNode.java @@ -0,0 +1,86 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.collections.internal.AbstractLinkedListNode; + +/** + * Represents one node of linked list. + * + * It is used to store a value based on the T. + * + * These nodes are linked (forward direction only). + * + * @author Robert Vokac + * @since 0.0.0 + * @param The type of the value this node holds + */ +class SingleLinkedListNode extends AbstractLinkedListNode { + /** + * Adds the reference for the node2 to the node1. The node1 will be + * connected to the node2 + * + * @param node1 The node, which field next will be set to node2. + * @param node2 The node, which will be set as the next node of the node1 + */ + static void link( + final SingleLinkedListNode node1, + final SingleLinkedListNode node2) { + node1.setNext(node2); + } + + /** + * Reference for the next node. + */ + @Getter + @Setter + private SingleLinkedListNode next = null; + + /** + * Constructor. + * + * Used to create node without key (Key is empty String), used in linked + * list, which does not need keys. + * + * @param valueIn the appropriate field key will be set by this value + */ + SingleLinkedListNode(final E valueIn) { + this.setValue(valueIn); + } + /** + * Return true if this node has next node, otherwise false. + * + * @return boolean value + */ + boolean hasNext() { + return getNext() != null; + } + + /** + * Removes the reference of the next node from this node. + */ + void unlinkNext() { + setNext(null); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/collections/DictionaryNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/StackI.java similarity index 58% rename from src/main/java/org/nanoboot/powerframework/collections/DictionaryNode.java rename to power-collections/src/main/java/org/nanoboot/powerframework/collections/StackI.java index bdb4c73..74ef4ef 100644 --- a/src/main/java/org/nanoboot/powerframework/collections/DictionaryNode.java +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/StackI.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -19,45 +19,36 @@ /////////////////////////////////////////////////////////////////////////////////////////////// package org.nanoboot.powerframework.collections; - /** - * Represents one dictionary entry. + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -class DictionaryNode { +public interface StackI { - private String key; - private T element; - private DictionaryNode next = null; + /** + * Pushes new element. + * @param item element to add + * @return element to add + */ + E push(E item); - DictionaryNode(String key, T element) { - this.key = key; - this.element = element; - } - - T getElement() { - return element; - } - - void setElement(T element) { - this.element = element; - } - - DictionaryNode getNext() { - return next; - } - - void setNext(DictionaryNode next) { - this.next = next; - } - - String getKey() { - return key; - } - - void setKey(String key) { - this.key = key; - } + /** + * Pops element. + * Remove first element. + * @return element to remove + */ + E pop(); + /** + * Returns the top element of this stack without removing this element. + * @return the top element of this stack without removing this element + */ + E peek(); + /** + * Checks, if the stack is empty. + * @return true, if this stack is empty, otherwise false + */ + boolean isEmpty(); } diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/Table.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/Table.java new file mode 100644 index 0000000..45de7bf --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/Table.java @@ -0,0 +1,62 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.core.PowerObject; +import org.nanoboot.powerframework.utils.annotations.ToRemove; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +@ToRemove +public class Table extends PowerObject { + /** + * Name of the table. + */ + @Getter + @Setter + private String name; + /** + * Constructor. + * + * Not meant to be instantiated. + */ + private Table() { + } + + /** + * Constructor. + * + * Constructor description + * + * @param nameIn name + */ + public Table(final String nameIn) { + this.setName(nameIn); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/pseudorandom/Seed.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/Tree.java similarity index 61% rename from src/main/java/org/nanoboot/powerframework/pseudorandom/Seed.java rename to power-collections/src/main/java/org/nanoboot/powerframework/collections/Tree.java index 14f6fe2..e7e611e 100644 --- a/src/main/java/org/nanoboot/powerframework/pseudorandom/Seed.java +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/Tree.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,31 +18,39 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.pseudorandom; +package org.nanoboot.powerframework.collections; + + +import lombok.Getter; /** - * Represents seed. Uses linear congruential function. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @param element type + * + * @author Robert Vokac + * @since 0.0.0 */ -class Seed { +public class Tree { + /** + * Root. + */ + @Getter + private final TreeNode root; - private long currentSeed; - private static final int A = 16807; - private static final int C = 0; - private static final long M = 2147483647; + /** + * Constructor. + */ + public Tree() { + root = new TreeNode<>(); + root.setName("root"); - Seed(long seed) { - this.currentSeed = seed; + } + /** + * Constructor. + * @param rootIn root node + */ + public Tree(final TreeNode rootIn) { + this.root = rootIn; } - long getNextNumber() { - long number = ((A * currentSeed) + C) % M; - this.currentSeed = number; - return number; - } - - void jump() { - getNextNumber(); - } } diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/TreeNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/TreeNode.java new file mode 100644 index 0000000..5e9289a --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/TreeNode.java @@ -0,0 +1,105 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.powerframework.collections.internal.AbstractTreeNode; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + * @param + */ +public final class TreeNode extends AbstractTreeNode { + /** + * Children nodes. + */ + @Getter + @Setter + private PowerList> children = new PowerList<>(); + /** + * + */ + private boolean ableToHaveChildren = true; + + /** + * + */ + public TreeNode() { + } + + /** + * + * @param valueIn the value + */ + public TreeNode(final T valueIn) { + this.setValue(valueIn); + } + + /** + * + * @param valueIn value + * @param childIn child + */ + public TreeNode(final T valueIn, final TreeNode childIn) { + this.setValue(valueIn); + addChild(childIn); + } + + /** + * @param valueIn value + * @param childrenIn children + */ + public TreeNode(final T valueIn, final TreeNode... childrenIn) { + this.setValue(valueIn); + addChildren(childrenIn); + } + + /** + * + * @param childIn child to add + */ + public void addChild(final TreeNode childIn) { + getChildren().add(childIn); + childIn.setParent(this); + } + + /** + * + * @param childrenIn children to add + */ + public void addChildren(final TreeNode... childrenIn) { + for (TreeNode element : childrenIn) { + addChild(element); + } + } + /** + * + * @return true, if this node has some children, otherwise false + */ + public boolean hasChildren() { + return !getChildren().isEmpty(); + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/Array.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/Array.java new file mode 100644 index 0000000..be7fc52 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/Array.java @@ -0,0 +1,1264 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.arrays; + +//ObjectArray>>> array3=new ObjectArray>>>( + +import java.util.*; + +/** + * @param if the ArrayType is not Object, this parameter is ignored. In + * this case use Object as parameter. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Array implements Iterable { + + private static final String SPACEDOT = " ."; + private static final String UNKNOWN_ARRAY_TYPE = "Unknown array type "; + private static final String THE_ARRAY_DIMENSION_COUNT_IS = "The array dimension count is "; + private static final String BUT_SHOULD_1_2_3_OR_4 = ", but should 1, 2, 3 or 4"; + private static final String DOT = "."; + + private static final int CONSTANT_ONE = 1; + + private ArrayType arrayType; + + private int dimensionCount; + private int[] arrayLengths; + + private boolean[] booleanArray1; + private byte[] byteArray1; + private short[] shortArray1; + private int[] intArray1; + private long[] longArray1; + private float[] floatArray1; + private double[] doubleArray1; + private C[] objectArray1; + + private boolean[][] booleanArray2; + private byte[][] byteArray2; + private short[][] shortArray2; + private int[][] intArray2; + private long[][] longArray2; + private float[][] floatArray2; + private double[][] doubleArray2; + private C[][] objectArray2; + + private boolean[][][] booleanArray3; + private byte[][][] byteArray3; + private short[][][] shortArray3; + private int[][][] intArray3; + private long[][][] longArray3; + private float[][][] floatArray3; + private double[][][] doubleArray3; + private C[][][] objectArray3; + + private boolean[][][][] booleanArray4; + private byte[][][][] byteArray4; + private short[][][][] shortArray4; + private int[][][][] intArray4; + private long[][][][] longArray4; + private float[][][][] floatArray4; + private double[][][][] doubleArray4; + private C[][][][] objectArray4; + + /** + * Constructor + *

+ * Creates array. + * + * @param arrayTypeIn the type of this array + * @param arrayLengthsIn 1 to 4, length of the arrays + */ + public Array(ArrayType arrayTypeIn, int... arrayLengthsIn) { + this.arrayLengths = arrayLengthsIn; + this.dimensionCount = arrayLengths.length; + + int array1Length = dimensionCount >= 1 ? this.arrayLengths[0] : 0; + int array2Length = dimensionCount >= 2 ? this.arrayLengths[1] : 0; + int array3Length = dimensionCount >= 3 ? this.arrayLengths[2] : 0; + int array4Length = dimensionCount == 4 ? this.arrayLengths[3] : 0; + + throwRuntimeExceptionIfDimensionOutOfRange(); + this.arrayType = arrayTypeIn; + initArray(array1Length, array2Length, array3Length, array4Length); + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(boolean... values) { + initDynamicInitialization(values.length, ArrayType.BOOLEAN); + this.booleanArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(byte... values) { + initDynamicInitialization(values.length, ArrayType.BYTE); + this.byteArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(short... values) { + initDynamicInitialization(values.length, ArrayType.SHORT); + this.shortArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(int... values) { + initDynamicInitialization(values.length, ArrayType.INT); + this.intArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(long... values) { + initDynamicInitialization(values.length, ArrayType.LONG); + this.longArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(float... values) { + initDynamicInitialization(values.length, ArrayType.FLOAT); + this.floatArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(double... values) { + initDynamicInitialization(values.length, ArrayType.DOUBLE); + this.doubleArray1 = values; + } + + /** + * Constructor + * Creates array dynamically based on the parameters and their count. + * + * @param values values of array + */ + public Array(C... values) { + initDynamicInitialization(values.length, ArrayType.OBJECT); + this.objectArray1 = values; + } + + private void initArray(int array1LengthIn, int array2LengthIn, int array3LengthIn, int array4LengthIn) throws ArrayException { + switch (arrayType) { + case BOOLEAN: + initBooleanArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case BYTE: + initByteArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case SHORT: + initShortArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case INT: + initIntArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case LONG: + initLongArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case FLOAT: + initFloatArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case DOUBLE: + initDoubleArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + case OBJECT: + initObjectArray(array1LengthIn, array2LengthIn, array3LengthIn, array4LengthIn); + break; + default: + throw new ArrayException(UNKNOWN_ARRAY_TYPE + arrayType + + SPACEDOT); + } + } + + private void initBooleanArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + booleanArray1 = new boolean[array1Length]; + return; + case 2: + booleanArray2 = new boolean[array1Length][array2Length]; + return; + case 3: + booleanArray3 = new boolean[array1Length][array2Length][array3Length]; + return; + case 4: + booleanArray4 = new boolean[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initByteArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + byteArray1 = new byte[array1Length]; + return; + case 2: + byteArray2 = new byte[array1Length][array2Length]; + return; + case 3: + byteArray3 = new byte[array1Length][array2Length][array3Length]; + return; + case 4: + byteArray4 = new byte[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initShortArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + shortArray1 = new short[array1Length]; + return; + case 2: + shortArray2 = new short[array1Length][array2Length]; + return; + case 3: + shortArray3 = new short[array1Length][array2Length][array3Length]; + return; + case 4: + shortArray4 = new short[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initIntArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + intArray1 = new int[array1Length]; + return; + case 2: + intArray2 = new int[array1Length][array2Length]; + return; + case 3: + intArray3 = new int[array1Length][array2Length][array3Length]; + return; + case 4: + intArray4 = new int[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + + } + } + + private void initLongArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + longArray1 = new long[array1Length]; + return; + case 2: + longArray2 = new long[array1Length][array2Length]; + return; + case 3: + longArray3 = new long[array1Length][array2Length][array3Length]; + return; + case 4: + longArray4 = new long[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initFloatArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + floatArray1 = new float[array1Length]; + return; + case 2: + floatArray2 = new float[array1Length][array2Length]; + return; + case 3: + floatArray3 = new float[array1Length][array2Length][array3Length]; + return; + case 4: + floatArray4 = new float[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initDoubleArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + doubleArray1 = new double[array1Length]; + return; + case 2: + doubleArray2 = new double[array1Length][array2Length]; + return; + case 3: + doubleArray3 = new double[array1Length][array2Length][array3Length]; + return; + case 4: + doubleArray4 = new double[array1Length][array2Length][array3Length][array4Length]; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initObjectArray(int array1Length, int array2Length, int array3Length, int array4Length) { + switch (dimensionCount) { + case 1: + objectArray1 = (C[]) new Object[array1Length]; + return; + case 2: + objectArray2 = (C[][]) new Object[array1Length][array2Length]; + return; + case 3: + objectArray3 = (C[][][]) new Object[array1Length][array2Length][array3Length]; + return; + case 4: + objectArray4 = (C[][][][]) new Object[array1Length][array2Length][array3Length][array4Length]; + return; + + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initDynamicInitialization(int arrayLength, ArrayType arrayTypeIn) { + this.arrayLengths = new int[]{arrayLength}; + this.dimensionCount = 1; + this.arrayType = arrayTypeIn; + } + + private void throwRuntimeExceptionIfDimensionOutOfRange() { + if (dimensionCount < 0 || dimensionCount > 4) { + throw new ArrayException(THE_ARRAY_DIMENSION_COUNT_IS + + dimensionCount + BUT_SHOULD_1_2_3_OR_4 + DOT); + } + } + + /** + * @return + */ + public ArrayType getArrayType() { + return arrayType; + } + + public int getDimensions() { + return dimensionCount; + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public C getObject(int... index) { + initSettingOrGetting(index, ArrayType.OBJECT); + + switch (index.length) { + case 1: + return this.objectArray1[index[0]]; + case 2: + return this.objectArray2[index[0]][index[1]]; + case 3: + return this.objectArray3[index[0]][index[1]][index[2]]; + case 4: + return this.objectArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return null; + } + } + + /** + * Setter for object. + * + * @param object object to set + * @param index index of the array + */ + public void setObject(C object, int... index) { + initSettingOrGetting(index, ArrayType.OBJECT); + switch (index.length) { + case 1: + this.objectArray1[index[0]] = object; + return; + case 2: + this.objectArray2[index[0]][index[1]] = object; + return; + case 3: + this.objectArray3[index[0]][index[1]][index[2]] = object; + return; + case 4: + this.objectArray4[index[0]][index[1]][index[2]][index[3]] = object; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public boolean getBoolean(int... index) { + initSettingOrGetting(index, ArrayType.OBJECT); + switch (index.length) { + case 1: + return this.booleanArray1[index[0]]; + case 2: + return this.booleanArray2[index[0]][index[1]]; + case 3: + return this.booleanArray3[index[0]][index[1]][index[2]]; + case 4: + return this.booleanArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return false; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setBoolean(boolean value, int... index) { + initSettingOrGetting(index, ArrayType.BOOLEAN); + switch (index.length) { + case 1: + this.booleanArray1[index[0]] = value; + return; + case 2: + this.booleanArray2[index[0]][index[1]] = value; + return; + case 3: + this.booleanArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.booleanArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public byte getByte(int... index) { + initSettingOrGetting(index, ArrayType.BOOLEAN); + switch (index.length) { + case 1: + return this.byteArray1[index[0]]; + case 2: + return this.byteArray2[index[0]][index[1]]; + case 3: + return this.byteArray3[index[0]][index[1]][index[2]]; + case 4: + return this.byteArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return 0; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setByte(byte value, int... index) { + initSettingOrGetting(index, ArrayType.BYTE); + switch (index.length) { + case 1: + this.byteArray1[index[0]] = value; + return; + case 2: + this.byteArray2[index[0]][index[1]] = value; + return; + case 3: + this.byteArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.byteArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public short getShort(int... index) { + initSettingOrGetting(index, ArrayType.SHORT); + switch (index.length) { + case 1: + return this.shortArray1[index[0]]; + case 2: + return this.shortArray2[index[0]][index[1]]; + case 3: + return this.shortArray3[index[0]][index[1]][index[2]]; + case 4: + return this.shortArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return 0; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setShort(short value, int... index) { + initSettingOrGetting(index, ArrayType.SHORT); + switch (index.length) { + case 1: + this.shortArray1[index[0]] = value; + return; + case 2: + this.shortArray2[index[0]][index[1]] = value; + return; + case 3: + this.shortArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.shortArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public int getInt(int... index) { + initSettingOrGetting(index, ArrayType.INT); + switch (index.length) { + case 1: + return this.intArray1[index[0]]; + case 2: + return this.intArray2[index[0]][index[1]]; + case 3: + return this.intArray3[index[0]][index[1]][index[2]]; + case 4: + return this.intArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return 0; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setInt(int value, int... index) { + initSettingOrGetting(index, ArrayType.INT); + switch (index.length) { + case 1: + this.intArray1[index[0]] = value; + return; + case 2: + this.intArray2[index[0]][index[1]] = value; + return; + case 3: + this.intArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.intArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public long getLong(int... index) { + initSettingOrGetting(index, ArrayType.LONG); + switch (index.length) { + case 1: + return this.longArray1[index[0]]; + case 2: + return this.longArray2[index[0]][index[1]]; + case 3: + return this.longArray3[index[0]][index[1]][index[2]]; + case 4: + return this.longArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return 0; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setLong(long value, int... index) { + initSettingOrGetting(index, ArrayType.LONG); + switch (index.length) { + case 1: + this.longArray1[index[0]] = value; + return; + case 2: + this.longArray2[index[0]][index[1]] = value; + return; + case 3: + this.longArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.longArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public float getFloat(int... index) { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT); + initSettingOrGetting(index, ArrayType.FLOAT); + switch (index.length) { + case 1: + return this.floatArray1[index[0]]; + case 2: + return this.floatArray2[index[0]][index[1]]; + case 3: + return this.floatArray3[index[0]][index[1]][index[2]]; + case 4: + return this.floatArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return 0; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setFloat(float value, int... index) { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT); + initSettingOrGetting(index, ArrayType.FLOAT); + switch (index.length) { + case 1: + this.floatArray1[index[0]] = value; + return; + case 2: + this.floatArray2[index[0]][index[1]] = value; + return; + case 3: + this.floatArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.floatArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + /** + * Getter for array value. + * + * @param index index of the array + * @return array value + */ + public double getDouble(int... index) { + initSettingOrGetting(index, ArrayType.DOUBLE); + switch (index.length) { + case 1: + return this.doubleArray1[index[0]]; + case 2: + return this.doubleArray2[index[0]][index[1]]; + case 3: + return this.doubleArray3[index[0]][index[1]][index[2]]; + case 4: + return this.doubleArray4[index[0]][index[1]][index[2]][index[3]]; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + //It should never come here. + return 0; + } + } + + /** + * Setter for value. + * + * @param value value to set + * @param index index of the array + */ + public void setDouble(double value, int... index) { + initSettingOrGetting(index, ArrayType.DOUBLE); + switch (index.length) { + case 1: + this.doubleArray1[index[0]] = value; + return; + case 2: + this.doubleArray2[index[0]][index[1]] = value; + return; + case 3: + this.doubleArray3[index[0]][index[1]][index[2]] = value; + return; + case 4: + this.doubleArray4[index[0]][index[1]][index[2]][index[3]] = value; + return; + default: + throwRuntimeExceptionIfDimensionOutOfRange(); + } + } + + private void initSettingOrGetting(int[] indexIn, ArrayType arrayTypeIn) { + throwExceptionIfOperationIsUnsupported(arrayTypeIn); + throwExceptionIfIndexOutOfRange(indexIn); + convertOkayToJavaIndexArray(indexIn); + } + + private void throwExceptionIfOperationIsUnsupported(ArrayType arrayTypeIn) { + if (arrayTypeIn != this.arrayType) { + throw new ArrayException("This operation is not supported for the array type " + this.arrayType + "."); + } + } + + /** + * @param arrayTypeIn + * @param dimensionCountIn + */ + private void throwExceptionIfOperationIsUnsupported(ArrayType arrayTypeIn, int dimensionCountIn) { + if (arrayTypeIn != this.arrayType) { + throw new ArrayException("This operation is not supported for the array type " + this.arrayType + "."); + } + if (dimensionCountIn != this.dimensionCount) { + throw new ArrayException("This operation is not supported for the dimension count " + dimensionCount + "."); + } + } + + private void throwExceptionIfIndexOutOfRange(int... index) { + int startIndex = CONSTANT_ONE; + int endIndex; + if (index.length != this.getDimensions()) { + throw new ArrayException("Wrong count of indexes. It should be " + this.getDimensions() + ", but is " + index.length + "."); + } + for (int i = 0; i < this.dimensionCount; i++) { + endIndex = this.arrayLengths[i]; + if ((index[i] > endIndex) || (index[i] < startIndex)) { + throw new ArrayException("Index " + index[i] + " is out of range <" + startIndex + ";" + endIndex + "> for dimension " + (i + 1)); + } + } + } + + private void convertOkayToJavaIndexArray(int... index) { + for (int i = 0; i < index.length; i++) { + index[i] = convertOkayToJavaIndex(index[i]); + } + } + + private int convertOkayToJavaIndex(int index) { + return (index - CONSTANT_ONE); + } + + /** + * @return + */ + public int getLength() { + return this.arrayLengths[0]; + } + + /** + * Getter for the length of the array based on the dimension number. + * + * @param dimension 1 or 2 or 3 or 4 + * @return array length of the dimension + */ + public int getLength(int dimension) { + return this.arrayLengths[dimension - 1]; + } + + public boolean[] getBooleanArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN, 1); + return booleanArray1; + } + + public void setBooleanArray1(boolean[] booleanArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN); + this.booleanArray1 = booleanArray1; + } + + public byte[] getByteArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE, 1); + return byteArray1; + } + + public void setByteArray1(byte[] byteArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE); + this.byteArray1 = byteArray1; + } + + public short[] getShortArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT, 1); + return shortArray1; + } + + public void setShortArray1(short[] shortArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT); + this.shortArray1 = shortArray1; + } + + public int[] getIntArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.INT, 1); + return intArray1; + } + + public void setIntArray1(int[] intArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.INT); + this.intArray1 = intArray1; + } + + public long[] getLongArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG, 1); + return longArray1; + } + + public void setLongArray1(long[] longArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG); + this.longArray1 = longArray1; + } + + public float[] getFloatArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT, 1); + return floatArray1; + } + + public void setFloatArray1(float[] floatArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT); + this.floatArray1 = floatArray1; + } + + public double[] getDoubleArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE, 1); + return doubleArray1; + } + + public void setDoubleArray1(double[] doubleArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE); + this.doubleArray1 = doubleArray1; + } + + public C[] getObjectArray1() { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT, 1); + return objectArray1; + } + + public void setObjectArray1(C[] objectArray1) { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT); + this.objectArray1 = objectArray1; + } + + public boolean[][] getBooleanArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN, 2); + return booleanArray2; + } + + public void setBooleanArray2(boolean[][] booleanArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN); + this.booleanArray2 = booleanArray2; + } + + public byte[][] getByteArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE, 2); + return byteArray2; + } + + public void setByteArray2(byte[][] byteArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE); + this.byteArray2 = byteArray2; + } + + public short[][] getShortArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT, 2); + return shortArray2; + } + + public void setShortArray2(short[][] shortArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT); + this.shortArray2 = shortArray2; + } + + public int[][] getIntArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.INT, 2); + return intArray2; + } + + public void setIntArray2(int[][] intArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.INT); + this.intArray2 = intArray2; + } + + public long[][] getLongArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG, 2); + return longArray2; + } + + public void setLongArray2(long[][] longArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG); + this.longArray2 = longArray2; + } + + public float[][] getFloatArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT, 2); + return floatArray2; + } + + public void setFloatArray2(float[][] floatArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT); + this.floatArray2 = floatArray2; + } + + public double[][] getDoubleArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE, 2); + return doubleArray2; + } + + public void setDoubleArray2(double[][] doubleArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT); + this.doubleArray2 = doubleArray2; + } + + public C[][] getObjectArray2() { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT, 2); + return objectArray2; + } + + public void setObjectArray2(C[][] objectArray2) { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT); + this.objectArray2 = objectArray2; + } + + public boolean[][][] getBooleanArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN, 3); + return booleanArray3; + } + + public void setBooleanArray3(boolean[][][] booleanArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN); + this.booleanArray3 = booleanArray3; + } + + public byte[][][] getByteArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE, 3); + return byteArray3; + } + + public void setByteArray3(byte[][][] byteArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE); + this.byteArray3 = byteArray3; + } + + public short[][][] getShortArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT, 3); + return shortArray3; + } + + public void setShortArray3(short[][][] shortArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT); + this.shortArray3 = shortArray3; + } + + public int[][][] getIntArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.INT, 3); + return intArray3; + } + + public void setIntArray3(int[][][] intArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.INT); + this.intArray3 = intArray3; + } + + public long[][][] getLongArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG, 3); + return longArray3; + } + + public void setLongArray3(long[][][] longArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG); + this.longArray3 = longArray3; + } + + public float[][][] getFloatArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT, 3); + return floatArray3; + } + + public void setFloatArray3(float[][][] floatArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT); + this.floatArray3 = floatArray3; + } + + public double[][][] getDoubleArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE, 3); + return doubleArray3; + } + + public void setDoubleArray3(double[][][] doubleArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE); + this.doubleArray3 = doubleArray3; + } + + public C[][][] getObjectArray3() { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT, 4); + return objectArray3; + } + + public void setObjectArray3(C[][][] objectArray3) { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT); + this.objectArray3 = objectArray3; + } + + public boolean[][][][] getBooleanArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN, 4); + return booleanArray4; + } + + public void setBooleanArray4(boolean[][][][] booleanArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.BOOLEAN); + this.booleanArray4 = booleanArray4; + } + + public byte[][][][] getByteArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE, 4); + return byteArray4; + } + + public void setByteArray4(byte[][][][] byteArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.BYTE); + this.byteArray4 = byteArray4; + } + + public short[][][][] getShortArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT, 4); + return shortArray4; + } + + public void setShortArray4(short[][][][] shortArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.SHORT); + this.shortArray4 = shortArray4; + } + + public int[][][][] getIntArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.INT, 4); + return intArray4; + } + + public void setIntArray4(int[][][][] intArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.INT); + this.intArray4 = intArray4; + } + + public long[][][][] getLongArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG, 4); + return longArray4; + } + + public void setLongArray4(long[][][][] longArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.LONG); + this.longArray4 = longArray4; + } + + public float[][][][] getFloatArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT, 4); + return floatArray4; + } + + public void setFloatArray4(float[][][][] floatArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.FLOAT); + this.floatArray4 = floatArray4; + } + + public double[][][][] getDoubleArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE, 4); + return doubleArray4; + } + + public void setDoubleArray4(double[][][][] doubleArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.DOUBLE); + this.doubleArray4 = doubleArray4; + } + + public C[][][][] getObjectArray4() { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT, 4); + return objectArray4; + } + + public void setObjectArray4(C[][][][] objectArray4) { + throwExceptionIfOperationIsUnsupported(ArrayType.OBJECT); + this.objectArray4 = objectArray4; + } + + // @Override +// public Iterator iterator(Array array) { +// +// Iterator iterator; +// switch (this.arrayType) { +// case BOOLEAN: +// return new BooleanArrayIterator(array); +//// case BYTE: +//// return ByteArrayIterator(); +// } +// } +// +// private class BooleanArrayIterator implements Iterator { +// +// private Array array; +// int i = 0; +// +// BooleanArrayIterator(Array arrayIn) { +// this.array = arrayIn; +// } +// +// @Override +// public boolean hasNext() { +// return (i + 1) <= array.getLength(); +// } +// +// public Boolean next() { +// if(!hasNext()) { +// throw new ArrayException("There is no next element."); +// } +// return array.getBoolean(++i); +// } +// } +// +// + @java.lang.Override + public Iterator iterator() { + if (this.dimensionCount != 1) { + throw new ArrayException("For iterating is only supported for one-dimensional arrays."); + } + return new BooleanArrayIterator(this); + } + + class BooleanArrayIterator implements Iterator { + + private Array array; + private int index = 0; + + public BooleanArrayIterator(Array arrayIn) { + this.array = arrayIn; + } + + @Override + public boolean hasNext() { + return (index + 1) <= array.getLength(); + } + + @Override + public Boolean next() { + throwExceptionIfNoNextElement(); + return array.getBoolean(++index); + } + + private void throwExceptionIfNoNextElement() throws ArrayException { + if (!hasNext()) { + throw new ArrayException("There is no next element."); + } + } + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayException.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayException.java new file mode 100644 index 0000000..5e5067a --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayException.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.arrays; + +import org.nanoboot.powerframework.collections.CollectionException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ArrayException extends CollectionException { + + public ArrayException(String message) { + super(message); + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayType.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayType.java new file mode 100644 index 0000000..2d4d1ec --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ArrayType.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.arrays; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum ArrayType { +//TODO CHAR- char array + + BOOLEAN, + BYTE, + CHAR, + SHORT, + INT, + LONG, + FLOAT, + DOUBLE, + OBJECT; + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ByteArray.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ByteArray.java new file mode 100644 index 0000000..f384c89 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ByteArray.java @@ -0,0 +1,67 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.arrays; + +/** + * There will be the choice to select the starting index:0 will be default + * (maybe), but 1 or something else will be possible. + * + * @param + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ByteArray { + + private Array array; + + public ByteArray(int... lengthIn) { + array = new Array(ArrayType.INT, lengthIn); + } + + public ByteArray(byte... values) { + array = new Array(values); + } + + public static ByteArray ofValues(byte... values) { + ByteArray intArray = new ByteArray(values.length); + intArray.array = new Array(values); + return intArray; + } + + public int get(int... index) { + return array.getInt(index); + } + + public void set(int value, + int... index) { + array.setInt(value, index); + } + + /** + * @param dimension 1 or 2 or 3 or 4 + * @return + */ + public int getLength(int dimension) { + return this.array.getLength(dimension); + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/IntArray.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/IntArray.java new file mode 100644 index 0000000..7f85427 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/IntArray.java @@ -0,0 +1,100 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.arrays; + +import java.util.Iterator; + +/** + * There will be the choice to select the starting index:0 will be default + * (maybe), but 1 or something else will be possible. + * + * @param + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class IntArray implements Iterable { + + private Array array; + + public IntArray(int... lengthIn) { + array = new Array(ArrayType.INT, lengthIn); + } + + public static IntArray ofValues(int... values) { + IntArray intArray = new IntArray(values.length); + intArray.array = new Array(values); + return intArray; + } + + public int get(int... index) { + return array.getInt(index); + } + + public void set(int value, + int... index) { + array.setInt(value, index); + } + + /** + * @param dimension 1 or 2 or 3 or 4 + * @return + */ + public int getLength(int dimension) { + return this.array.getLength(dimension); + } + + @java.lang.Override + public Iterator iterator() { + if (array.getDimensions() != 1) { + throw new ArrayException("For iterating is only supported for one-dimensional arrays."); + } + return new IntArrayIterator(array); + } + + class IntArrayIterator implements Iterator { + + private Array array; + private int index = 0; + + public IntArrayIterator(Array arrayIn) { + this.array = arrayIn; + } + + @Override + public boolean hasNext() { + return (index + 1) <= array.getLength(); + } + + @Override + public Integer next() { + throwExceptionIfNoNextElement(); + return array.getInt(++index); + } + + private void throwExceptionIfNoNextElement() throws ArrayException { + if (!hasNext()) { + throw new ArrayException("There is no next element."); + } + } + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ObjectArray.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ObjectArray.java new file mode 100644 index 0000000..6adf437 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/ObjectArray.java @@ -0,0 +1,75 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.arrays; + +/** + * There will be the choice to select the starting index:0 will be default + * (maybe), but 1 or something else will be possible. + * + * @author Robert Vokac + * @since 0.0.0 + * @param + */ +public class ObjectArray { + + private Array array; + + public ObjectArray(int... lengthIn) { + array = new Array(ArrayType.OBJECT, lengthIn); + } + + public static ObjectArray ofValues(C... values) { + ObjectArray objectArray = new ObjectArray<>(values.length); + int index = 1; + for (C element : values) { + objectArray.set(element, index++); + } + return objectArray; + + } +// public ObjectArray(C... values) { +// array = new Array(values); +// } + + public C get(int... index) { + return array.getObject(index); + } + + public void set(C value, + int... index) { + array.setObject(value, index); + } + + /** + * @param dimension 1 or 2 or 3 or 4 + * @return + */ + public int getLength(int dimension) { + return this.array.getLength(dimension); + } + + /** + * @return + */ + public int getLength() { + return this.array.getLength(); + } +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/package-info.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/package-info.java new file mode 100644 index 0000000..9578ec8 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/arrays/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Classes for arrays (index starting from 1, not 0). + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.collections.arrays; diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/buffer/CharBuffer.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/buffer/CharBuffer.java new file mode 100644 index 0000000..f5ddd0f --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/buffer/CharBuffer.java @@ -0,0 +1,64 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.buffer; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class CharBuffer { + + public int size() { + return 0; + } + + public void putAtTheEnd(char ch) { + + } + + public void putAtTheEnd(CharBuffer charBuffer) { + + } +@Deprecated + public void putCurrentCharAtTheEnd(CharBuffer charBuffer) { + + } + + public char get() { + return ' '; + } + + public char get(int position) { + return ' '; + } + + public void move(int move) { + + } + + public String toString() { + return ""; + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/graphs/.gitkeep b/power-collections/src/main/java/org/nanoboot/powerframework/collections/graphs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedList.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedList.java new file mode 100644 index 0000000..5e43c76 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedList.java @@ -0,0 +1,171 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.internal; + +import org.nanoboot.powerframework.collections.arrays.ObjectArray; + +/** + * Represents linked list data structure. + * @param element type + * + * @author Robert Vokac + * @since 0.0.0 + */ +public abstract class AbstractLinkedList implements Iterable { + /** + * Size of this list. + */ + private int size = 0; + + /** + * Returns size of this list. + * @return size of this list + */ + public final int size() { + return this.size; + } + /** + * Checks, if this list is empty. + * @return true, if this list is empty, otherwise false + */ + public boolean isEmpty() { + return this.size() == 0; + } + /** + * Deletes all elements of this linked list. + */ + public abstract void clear(); + /** + * Increments the size of this list by one. + */ + protected void incrementSize() { + ++size; + } + + /** + * Decrements the size of this list by one. + */ + protected void decrementSize() { + --size; + } + + /** + * Sets the size to 0. + */ + protected void clearSize() { + size = 0; + } + /** + * Adds new element before first element. + * + * @param elementIn element + * @return this linked list + */ + public abstract E addBeforeFirst(E elementIn); + + /** + * Adds new element after last element. + * + * @param elementIn element + * @return this linked list + */ + public abstract E addAfterLast(E elementIn); + /** + * Removes first element. + * + * @return removed element + */ + public abstract E removeFirst(); + + /** + * Removes last element. + * + * @return removed element + */ + public abstract E removeLast(); + /** + * @return first element + */ + public abstract E getFirst(); + + /** + * @return last element + */ + public abstract E getLast(); + + /** + * Removes the element at the specified position in this list. + * + * @param index index param + * @return the removed element + */ + public abstract E remove(int index); + + /** + * Returns the element at the specified position in this list. + * + * @param index starting from 1 + * + * @return value + */ + public abstract E get(int index); + + /** + * Replaces the element at the specified position + * in this list with the specified element. + * + * @param index index param + * @param element element param + * @return the new value + */ + public abstract E set(int index, E element); + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + int index = 0; + int lastIndex = this.size() - 1; + for (E element : this) { + stringBuilder.append(element.toString()); + if (index < lastIndex) { + stringBuilder.append(", "); + } + ++index; + } + return stringBuilder.toString(); + } + /** + * Converts this list to an ObjectArray. + * @return ObjectArray + */ + public ObjectArray toObjectArray() { + ObjectArray objectArray = new ObjectArray<>(this.size()); + int index = 1; + for (E element : this) { + objectArray.set(element, index++); + } + return objectArray; + } + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedListNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedListNode.java new file mode 100644 index 0000000..eaceffb --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractLinkedListNode.java @@ -0,0 +1,45 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.internal; + +import lombok.Getter; +import lombok.Setter; + +/** + * Represents one node of linked list. + * + * It is used to store a value based on the T. + * + * These nodes are linked (forward direction only). + * + * @param The type of the value this node holds + * + * @author Robert Vokac + * @since 0.0.0 + */ +public abstract class AbstractLinkedListNode { + /** + * Value. + */ + @Getter + @Setter + private E value; +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractTreeNode.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractTreeNode.java new file mode 100644 index 0000000..b725def --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/AbstractTreeNode.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections.internal; + +import lombok.Getter; +import lombok.Setter; + +/** + * + * @param + * + * @author Robert Vokac + * @since 0.0.0 + */ +public abstract class AbstractTreeNode { + /** + * Parent node. + */ + @Getter + @Setter + private AbstractTreeNode parent = null; + /** + * The value to be hold. + */ + @Getter + @Setter + private T value; + /** + * Name of the node. + */ + @Getter + @Setter + private String name; + +} diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/package-info.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/package-info.java new file mode 100644 index 0000000..68e5a61 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/internal/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Internal classes. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.collections.internal; diff --git a/power-collections/src/main/java/org/nanoboot/powerframework/collections/package-info.java b/power-collections/src/main/java/org/nanoboot/powerframework/collections/package-info.java new file mode 100644 index 0000000..477d484 --- /dev/null +++ b/power-collections/src/main/java/org/nanoboot/powerframework/collections/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Collections used to store instances of classes. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.collections; diff --git a/power-collections/src/main/resources/.gitkeep b/power-collections/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-collections/src/test/java/org/nanoboot/powerframework/collections/PowerMapTest.java b/power-collections/src/test/java/org/nanoboot/powerframework/collections/PowerMapTest.java new file mode 100644 index 0000000..3a9b9a8 --- /dev/null +++ b/power-collections/src/test/java/org/nanoboot/powerframework/collections/PowerMapTest.java @@ -0,0 +1,412 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import java.util.*; + +import static org.junit.Assert.*; + +import org.junit.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class PowerMapTest { + + /** + * + */ + public PowerMapTest() { + } + + /** + * Test of size method, of class map. + */ + @Test + public void testsize() { + //arrange + PowerMap map = new PowerMap<>(); + int expectedValue = 0; + int returnedValue; + //act + returnedValue = map.size(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of size method, of class map. + */ + @Test + public void testsize2() { + //arrange + PowerMap map = new PowerMap<>(); + int expectedValue = 0; + int returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.remove("name"); + map.remove("surname"); + returnedValue = map.size(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of size method, of class map. + */ + @Test + public void testsize3() { + //arrange + PowerMap map = new PowerMap<>(); + int expectedValue = 2; + int returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("surname"); + returnedValue = map.size(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of size method, of class map. + */ + @Test + public void testsize4() { + //arrange + PowerMap map = new PowerMap<>(); + int expectedValue = 1; + int returnedValue; + //act + map.put("surname", "Black"); + returnedValue = map.size(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of isEmpty method, of class map. + */ + @Test + public void testIsEmpty() { + //arrange + PowerMap map = new PowerMap<>(); + boolean returnedValue; + //act + returnedValue = map.isEmpty(); + //assert + assertTrue(returnedValue); + } + + /** + * Test of isEmpty method, of class map. + */ + @Test + public void testIsEmpty2() { + //arrange + PowerMap map = new PowerMap<>(); + boolean returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.remove("name"); + map.remove("surname"); + returnedValue = map.isEmpty(); + //assert + assertTrue(returnedValue); + } + + /** + * Test of isEmpty method, of class map. + */ + @Test + public void testIsEmpty3() { + //arrange + PowerMap map = new PowerMap<>(); + boolean returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("surname"); + returnedValue = map.isEmpty(); + //assert + assertFalse(returnedValue); + } + + /** + * Test of getValue method, of class map. + */ + @Test + public void testIsEmpty4() { + //arrange + PowerMap map = new PowerMap<>(); + boolean returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("name"); + returnedValue = map.isEmpty(); + //assert + assertFalse(returnedValue); + } + + /** + * Test of containsKey method, of class map. + */ + @Test + public void containsKeyKey() { + //arrange + PowerMap map = new PowerMap<>(); + boolean expectedValue = true; + boolean returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + returnedValue = map.containsKey("surname"); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of containsKey method, of class map. + */ + @Test + public void containsKey2() { + //arrange + PowerMap map = new PowerMap<>(); + boolean expectedValue = false; + boolean returnedValue; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + returnedValue = map.containsKey("job"); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of containsKey method, of class map. + */ + @Test + public void containsKey3() { + //arrange + PowerMap map = new PowerMap<>(); + boolean expectedValue = true; + boolean returnedValue; + //act + map.put("name", "John"); + returnedValue = map.containsKey("name"); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of add method, of class map. + */ + @Test + public void testPut() { + //arrange + PowerMap map = new PowerMap<>(); + String expectedString = "Johny"; + String returnedString; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("surname"); + returnedString = map.get("nick"); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of add method, of class map. + */ + @Test + public void testPut2() { + //arrang + PowerMap map = new PowerMap<>(); + String expectedString = "Johny"; + String returnedString; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("name"); + returnedString = map.get("nick"); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of add method, of class map. + */ + @Test + public void testPut3() { + //arrange + PowerMap map = new PowerMap<>(); + String expectedString = "Black"; + String returnedString; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("nick"); + returnedString = map.get("surname"); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of getValue method, of class map. + */ + @Test + public void testGet() { + //arrange + PowerMap map = new PowerMap<>(); + String expectedString = "Black"; + String returnedString; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("name"); + returnedString = map.get("surname"); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of getValue method, of class map. + */ + @Test + public void testGet2() { + //arrange + PowerMap map = new PowerMap<>(); + String expectedString = "Johny"; + String returnedString; + //act + map.put("nick", "Johny"); + returnedString = map.get("nick"); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of updateValue method, of class map. + */ + @Test + public void testReplaceValue() { + //arrange + PowerMap map = new PowerMap<>(); + String expectedString = "Blue"; + String returnedString; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.replace("surname", "Blue"); + returnedString = map.get("surname"); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of remove method, of class map. + */ + @Test + public void testRemove() { + //arrange + boolean isExceptionThrown = false; + PowerMap map = new PowerMap<>(); + String expectedString = "Black"; + String returnedString; + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("surname"); + //act + try { + returnedString = map.get("surname"); + } catch (NoSuchElementException e) { + isExceptionThrown = true; + } + //assert + if (!isExceptionThrown) { + fail("There should be thrown NoSuchElementException"); + } + } + + /** + * Test of getKeyIterator method, of class map. + */ + @Test + public void testIterator() { + //arrange + PowerMap map = new PowerMap<>(); + Iterator> mapIterator; + String expectedString = "Johny"; + String returnedString; + String secondKey; + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + map.remove("surname"); + mapIterator = map.iterator(); + //act + mapIterator.next(); + secondKey = mapIterator.next().getKey(); + returnedString = map.get(secondKey); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of toString method, of class map. + */ + @Test + public void testToString() { + //arrange + PowerMap map = new PowerMap<>(); + String expectedString = "name=John\nsurname=Black\nnick=Johny"; + String returnedString; + //act + map.put("name", "John"); + map.put("surname", "Black"); + map.put("nick", "Johny"); + returnedString = map.toString(); + //assert + assertEquals(expectedString, returnedString); + } + +} diff --git a/power-collections/src/test/java/org/nanoboot/powerframework/collections/PropertiesTest.java b/power-collections/src/test/java/org/nanoboot/powerframework/collections/PropertiesTest.java new file mode 100644 index 0000000..e8f7201 --- /dev/null +++ b/power-collections/src/test/java/org/nanoboot/powerframework/collections/PropertiesTest.java @@ -0,0 +1,120 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import static org.junit.Assert.*; +import org.junit.*; + +import java.util.NoSuchElementException; + +import static org.junit.Assert.assertEquals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PropertiesTest { + private Properties properties; + + @Before + public void setup() { + properties=new Properties(PROPERTIES_FILE_TEXT_IN); + } + public static final String PROPERTIES_FILE_TEXT_IN = "#Fri Jan 17 22:37:45 MYT 2014\n" + + "dbpassword=password\n" + + "database=localhost\n" + + "dbuser=mkyong"; + @Test + public void getProperty() { + //prepare + //execute + //assert + assertEquals(properties.getProperty("dbpassword"), "password"); + assertEquals(properties.getProperty("database"), "localhost"); + assertEquals(properties.getProperty("dbuser"), "mkyong"); + try { + properties.getProperty("abc"); + throw new AssertionError("NoSuchElementException expected, but not thrown."); + } catch (NoSuchElementException e) { + + } + } + + @Test + public void setProperty() { + //prepare + //execute + properties.setProperty("dbpassword", "newPassword"); + //assert + assertEquals(properties.getProperty("dbpassword"), "newPassword"); + assertEquals(properties.getProperty("database"), "localhost"); + assertEquals(properties.getProperty("dbuser"), "mkyong"); + try { + properties.getProperty("abc"); + throw new AssertionError("NoSuchElementException expected, but not thrown."); + } catch (NoSuchElementException e) { + + } + + } + + @Test + public void hasProperty() { + + //prepare + //execute + properties.setProperty("dbpassword", "newPassword"); + //assert + assertTrue(properties.hasProperty("dbpassword")); + assertTrue(properties.hasProperty("database")); + assertTrue(properties.hasProperty("dbuser")); + try { + properties.getProperty("abc"); + throw new AssertionError("NoSuchElementException expected, but not thrown."); + } catch (NoSuchElementException e) { + + } + } + + @Test + public void testToString() { + //prepare + String returned; + //execute + returned = properties.toString(); + //assert + assertTrue(returned.contains("dbpassword=password")); + assertTrue(returned.contains("database=localhost")); + assertTrue(returned.contains("dbuser=mkyong")); + assertTrue(returned.contains(", ")); + } + + @Test + public void getMap() { + PowerMap map = properties.getMap(); + assertNotNull(map); + assertTrue(map.containsKey("dbpassword")); + assertTrue(map.containsKey("database")); + assertTrue(map.containsKey("dbuser")); + } +} diff --git a/src/test/java/org/nanoboot/powerframework/collections/QueueTest.java b/power-collections/src/test/java/org/nanoboot/powerframework/collections/QueueTest.java similarity index 54% rename from src/test/java/org/nanoboot/powerframework/collections/QueueTest.java rename to power-collections/src/test/java/org/nanoboot/powerframework/collections/QueueTest.java index c9ab36c..6f45e23 100644 --- a/src/test/java/org/nanoboot/powerframework/collections/QueueTest.java +++ b/power-collections/src/test/java/org/nanoboot/powerframework/collections/QueueTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -20,14 +20,19 @@ package org.nanoboot.powerframework.collections; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; +import java.util.*; + import static org.junit.Assert.*; +import org.junit.*; + /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class QueueTest { /** @@ -37,102 +42,102 @@ public class QueueTest { } /** - * Test of getCountOfItems method, of class Queue. + * Test of size method, of class Queue. */ @Test - public void testGetCountOfItems() { + public void testsize() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); int expectedCountOfItems = 0; int returnedCountOfItems; //act - returnedCountOfItems = queue.getCountOfItems(); + returnedCountOfItems = queue.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Queue. + * Test of size method, of class Queue. */ @Test - public void testGetCountOfItems2() { + public void testsize2() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); int expectedCountOfItems = 0; int returnedCountOfItems; //act - queue.enqueue("John"); - queue.dequeue(); - returnedCountOfItems = queue.getCountOfItems(); + queue.add("John"); + queue.poll(); + returnedCountOfItems = queue.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Queue. + * Test of size method, of class Queue. */ @Test - public void testGetCountOfItems3() { + public void testsize3() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); int expectedCountOfItems = 0; int returnedCountOfItems; //act - queue.enqueue("John"); - queue.dequeue(); - queue.enqueue("Jack").enqueue("Anne").enqueue("Charlie"); + queue.add("John"); + queue.poll(); + queue.addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie"); - queue.dequeue(); - queue.dequeue(); - queue.dequeue(); - queue.enqueue("Jane"); - queue.dequeue(); - returnedCountOfItems = queue.getCountOfItems(); + queue.poll(); + queue.poll(); + queue.poll(); + queue.add("Jane"); + queue.poll(); + returnedCountOfItems = queue.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Queue. + * Test of size method, of class Queue. */ @Test - public void testGetCountOfItems4() { + public void testsize4() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); int expectedCountOfItems = 1; int returnedCountOfItems; //act - queue.enqueue("John"); - queue.dequeue(); - queue.enqueue("Jack").enqueue("Anne").enqueue("Charlie"); + queue.add("John"); + queue.poll(); + queue.addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie"); - queue.dequeue(); - queue.dequeue(); - queue.enqueue("Jane"); - queue.dequeue(); - returnedCountOfItems = queue.getCountOfItems(); + queue.poll(); + queue.poll(); + queue.add("Jane"); + queue.poll(); + returnedCountOfItems = queue.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Queue. + * Test of size method, of class Queue. */ @Test - public void testGetCountOfItems5() { + public void testsize5() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); int expectedCountOfItems = 3; int returnedCountOfItems; //act - queue.enqueue("John"); - queue.dequeue(); - queue.enqueue("Jack").enqueue("Anne").enqueue("Charlie").enqueue("Susan"); + queue.add("John"); + queue.poll(); + queue.addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie").addAndReturn("Susan"); - queue.dequeue(); - queue.enqueue("Jane"); - queue.dequeue(); - returnedCountOfItems = queue.getCountOfItems(); + queue.poll(); + queue.add("Jane"); + queue.poll(); + returnedCountOfItems = queue.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } @@ -143,7 +148,7 @@ public class QueueTest { @Test public void testIsEmpty() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); boolean expectedValue = true; boolean returnedValue; //act @@ -158,19 +163,19 @@ public class QueueTest { @Test public void testIsEmpty2() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); boolean expectedValue = true; boolean returnedValue; //act - queue.enqueue("John").enqueue("Jack").enqueue("Anne").enqueue("Charlie"); + queue.addAndReturn("John").addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie"); - queue.dequeue(); - queue.dequeue(); - queue.dequeue(); - queue.dequeue(); + queue.poll(); + queue.poll(); + queue.poll(); + queue.poll(); - queue.enqueue("Jane"); - queue.dequeue(); + queue.add("Jane"); + queue.poll(); returnedValue = queue.isEmpty(); //assert assertEquals(expectedValue, returnedValue); @@ -182,18 +187,18 @@ public class QueueTest { @Test public void testIsEmpty3() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); boolean expectedValue = false; boolean returnedValue; //act - queue.enqueue("John").enqueue("Jack").enqueue("Anne").enqueue("Charlie"); + queue.addAndReturn("John").addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie"); - queue.dequeue(); - queue.dequeue(); - queue.dequeue(); + queue.poll(); + queue.poll(); + queue.poll(); - queue.enqueue("Jane"); - queue.dequeue(); + queue.add("Jane"); + queue.poll(); returnedValue = queue.isEmpty(); //assert assertEquals(expectedValue, returnedValue); @@ -205,17 +210,17 @@ public class QueueTest { @Test public void testIsEmpty4() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); boolean expectedValue = false; boolean returnedValue; //act - queue.enqueue("John").enqueue("Jack").enqueue("Anne").enqueue("Charlie"); + queue.addAndReturn("John").addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie"); - queue.dequeue(); - queue.dequeue(); + queue.poll(); + queue.poll(); - queue.enqueue("Jane"); - queue.dequeue(); + queue.add("Jane"); + queue.poll(); returnedValue = queue.isEmpty(); //assert assertEquals(expectedValue, returnedValue); @@ -227,12 +232,12 @@ public class QueueTest { @Test public void testEnqueue() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); String expectedString = "John"; String returnedString; //act - queue.enqueue("John"); - returnedString = queue.dequeue(); + queue.add("John"); + returnedString = queue.poll(); //assert assertEquals(expectedString, returnedString); } @@ -243,12 +248,12 @@ public class QueueTest { @Test public void testDequeue() { //arrange - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); String expectedString = "Alice"; String returnedString; //act - queue.enqueue("Alice").enqueue("Jane"); - returnedString = queue.dequeue(); + queue.addAndReturn("Alice").addAndReturn("Jane"); + returnedString = queue.poll(); //assert assertEquals(expectedString, returnedString); } @@ -257,33 +262,50 @@ public class QueueTest { * Test of dequeue method, of class Queue. */ @Test - public void testDequeue_ThereShouldBeThrownPowerRuntimeException() { + public void testDequeue_ThereShouldBeThrownOkayRuntimeException() { //arrange boolean isExceptionThrown = false; - Queue queue = new Queue<>(); + PowerQueue queue = new PowerQueue<>(); //act try { - queue.dequeue(); - } catch (PowerRuntimeException e) { + queue.poll(); + } catch (NoSuchElementException e) { isExceptionThrown = true; } //assert if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); + fail("There should be thrown OkayRuntimeException"); } } + /** + * Test of peek method, of class Stack. + */ + @Test + public void testClear() { + //arrange + PowerQueue queue = new PowerQueue<>(); + boolean returnedValue; + //act + queue.addAndReturn("John").addAndReturn("Jack").addAndReturn("Anne").addAndReturn("Charlie").addAndReturn("Alice").addAndReturn("Dennis"); + + queue.clear(); + returnedValue = queue.isEmpty(); + //assert + assertTrue(returnedValue); + } + /** * Test of toString method, of class Queue. */ @Test public void testToString() { //arrange - Queue queue = new Queue<>(); - String expectedString = "Alice, Jane, "; + PowerQueue queue = new PowerQueue<>(); + String expectedString = "Alice, Jane"; String returnedString; //act - queue.enqueue("Alice").enqueue("Jane"); + queue.addAndReturn("Alice").addAndReturn("Jane"); returnedString = queue.toString(); //assert assertEquals(expectedString, returnedString); diff --git a/power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListNodeTest.java b/power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListNodeTest.java new file mode 100644 index 0000000..d2765ec --- /dev/null +++ b/power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListNodeTest.java @@ -0,0 +1,164 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import static org.junit.Assert.*; + +import org.junit.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SingleLinkedListNodeTest { + + /** + * Test of link method, of class Node. + */ + @Test + public void link() { + //arrange + SingleLinkedListNode node1 = new SingleLinkedListNode<>("John"); + SingleLinkedListNode node2 = new SingleLinkedListNode<>("Black"); + String expectedString = "Black"; + String returnedString; + //act + SingleLinkedListNode.link(node1, node2); + SingleLinkedListNode returned = node1.getNext(); + returnedString = returned.getValue(); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of getValue method, of class Node. + */ + @Test + public void getValue() { + //arrange + SingleLinkedListNode node = new SingleLinkedListNode<>("John"); + String expectedString = "John"; + String returnedString; + //act + returnedString = node.getValue(); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of setValue method, of class Node. + */ + @Test + public void setValue() { + //arrange + SingleLinkedListNode node = new SingleLinkedListNode<>("John"); + String expectedString = "Jack"; + String returnedString; + //act + node.setValue("Jack"); + returnedString = node.getValue(); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of getNext method, of class Node. + */ + @Test + public void getNext() { + //arrange + SingleLinkedListNode node1 = new SingleLinkedListNode<>("John"); + SingleLinkedListNode node2 = new SingleLinkedListNode<>("Black"); + String expectedString = "Black"; + String returnedString; + //act + node1.setNext(node2); + SingleLinkedListNode returnedmapNode = node1.getNext(); + returnedString = returnedmapNode.getValue(); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of setNext method, of class Node. + */ + @Test + public void setNext() { + //arrange + SingleLinkedListNode node1 = new SingleLinkedListNode<>("John"); + SingleLinkedListNode node2 = new SingleLinkedListNode<>("White"); + String expectedString = "White"; + String returnedString; + //act + node1.setNext(node2); + SingleLinkedListNode returned = node1.getNext(); + returnedString = returned.getValue(); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of hasNext method, of class Node. + */ + @Test + public void hasNext() { + //arrange + SingleLinkedListNode node1 = new SingleLinkedListNode<>("John"); + //act + + //assert + assertFalse(node1.hasNext()); + } + + /** + * Test of hasNext method, of class Node. + */ + @Test + public void hasNext2() { + //arrange + SingleLinkedListNode node1 = new SingleLinkedListNode<>("John"); + SingleLinkedListNode node2 = new SingleLinkedListNode<>("White"); + //act + node1.setNext(node2); + //assert + assertTrue(node1.hasNext()); + } + + /** + * Test of unlinkNext method, of class Node. + */ + @Test + public void unlinkNext() { + //arrange + SingleLinkedListNode node1 = new SingleLinkedListNode<>("John"); + SingleLinkedListNode node2 = new SingleLinkedListNode<>("White"); + //act + assertFalse(node1.hasNext()); + node1.setNext(node2); + assertTrue(node1.hasNext()); + node1.unlinkNext(); + //assert + assertFalse(node1.hasNext()); + } + +} diff --git a/power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListTest.java b/power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListTest.java new file mode 100644 index 0000000..ed59308 --- /dev/null +++ b/power-collections/src/test/java/org/nanoboot/powerframework/collections/SingleLinkedListTest.java @@ -0,0 +1,782 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.collections; + +import java.util.*; + +import static org.junit.Assert.*; + +import org.nanoboot.powerframework.core.exceptions.NotYetImplementedException; +import org.junit.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SingleLinkedListTest { + @Test + public void addAll_EVarArg() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + + //act + linkedList + .addAll("a", "b", "c", "d", "e"); + //assert + assertEquals(5, linkedList.size()); + assertEquals("a, b, c, d, e", linkedList.toString()); + assertEquals("a", linkedList.get(0)); + assertEquals("b", linkedList.get(1)); + assertEquals("c", linkedList.get(2)); + assertEquals("d", linkedList.get(3)); + assertEquals("e", linkedList.get(4)); + } + + @Test + public void contains() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + + //act + linkedList + .addAll("a", "b", "c", "d", "e"); + //assert + assertTrue(linkedList.contains("a")); + assertTrue(linkedList.contains("b")); + assertTrue(linkedList.contains("c")); + assertTrue(linkedList.contains("d")); + assertTrue(linkedList.contains("e")); + assertFalse(linkedList.contains("f")); + } + + @Test + public void iterator() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + StringBuilder sb = new StringBuilder(); + String expected = "12345"; + String returned; + for (int i = 1; i <= 5; i++) { + linkedList.add(String.valueOf(i)); + } + //act + for (String e : linkedList) { + sb.append(e); + } + returned = sb.toString(); + //assert + assertEquals(expected, returned); + } + + @Test + public void toArray_ObjectArray() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + StringBuilder sb = new StringBuilder(); + String expected = "12345"; + String returned; + Object[] array; + for (int i = 1; i <= 5; i++) { + linkedList.add(String.valueOf(i)); + } + //act + array = linkedList.toArray(); + for (Object o : array) { + sb.append(o); + } + returned = sb.toString(); + //assert + assertEquals(5, array.length); + assertEquals(expected, returned); + } + + @Test(expected = NotYetImplementedException.class) + public void toArray_genericArray() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + + for (int i = 1; i <= 5; i++) { + linkedList.add(String.valueOf(i)); + } + //act + linkedList.toArray(new Object[]{}); + //assert + } + + @Test + public void add() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + //assert + linkedList.add("a"); + assertEquals(1, linkedList.size()); + assertEquals("a", linkedList.toString()); + linkedList.add("b"); + assertEquals(2, linkedList.size()); + assertEquals("a, b", linkedList.toString()); + linkedList.add("c"); + assertEquals(3, linkedList.size()); + assertEquals("a, b, c", linkedList.toString()); + } + + @Test + public void remove_Object() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + linkedList.add("a"); + linkedList.add("b"); + linkedList.add("c"); + //assert + //abc + assertEquals(3, linkedList.size()); + linkedList.remove("b"); + //ac + assertEquals(2, linkedList.size()); + assertFalse(linkedList.contains("b")); + linkedList.add("d"); + //acd + assertEquals(3, linkedList.size()); + assertTrue(linkedList.contains("d")); + linkedList.remove("a"); + //cd + assertEquals(2, linkedList.size()); + assertFalse(linkedList.contains("a")); + linkedList.remove("d"); + //c + assertEquals(1, linkedList.size()); + assertFalse(linkedList.contains("d")); + assertTrue(linkedList.contains("c")); + linkedList.remove("c"); + assertEquals(0, linkedList.size()); + assertFalse(linkedList.contains("c")); + // + assertEquals("", linkedList.toString()); + } + + @Test + public void containsAll() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + linkedList.add("a"); + linkedList.add("b"); + linkedList.add("c"); + //assert + assertTrue(linkedList.containsAll(new SingleLinkedList<>("a", "b", "c"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>("b", "c"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>("a", "c"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>("a", "b"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>("a"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>("b"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>("c"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("a", "b", "c", "d"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("b", "c", "d"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("a", "c", "d"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("a", "b", "d"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("a", "d"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("b", "d"))); + assertFalse(linkedList.containsAll(new SingleLinkedList<>("c", "d"))); + assertTrue(linkedList.containsAll(new SingleLinkedList<>())); + } + + @Test + public void testAddAll_collection() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + linkedList.addAll(new SingleLinkedList<>("a", "b", "c")); + //assert + assertEquals(3, linkedList.size()); + assertEquals("a, b, c", linkedList.toString()); + } + + @Test + public void removeAll() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + linkedList.addAll(new SingleLinkedList<>("a", "b", "c")); + linkedList.removeAll(new SingleLinkedList<>("a", "c")); + //assert + assertEquals(1, linkedList.size()); + assertEquals("b", linkedList.toString()); + linkedList.removeAll(new SingleLinkedList<>("b")); + assertEquals(0, linkedList.size()); + assertEquals("", linkedList.toString()); + } + + @Test(expected = NotYetImplementedException.class) + public void retainAll() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + linkedList.addAll(new SingleLinkedList<>("a", "b", "c")); + linkedList.retainAll(new SingleLinkedList<>("a", "c")); + //assert + } + + @Test + public void clear() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + linkedList.addAll(new SingleLinkedList<>("a", "b", "c")); + //assert + assertEquals(3, linkedList.size()); + linkedList.clear(); + assertEquals(0, linkedList.size()); + assertEquals("", linkedList.toString()); + linkedList.add("d"); + assertEquals(1, linkedList.size()); + assertEquals("d", linkedList.toString()); + linkedList.add("e"); + assertEquals(2, linkedList.size()); + assertEquals("d, e", linkedList.toString()); + linkedList.clear(); + assertEquals(0, linkedList.size()); + assertEquals("", linkedList.toString()); + } + + // + @Test + public void addBeforeFirst() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + + //act + + //assert + linkedList.addBeforeFirst("a"); + assertEquals(1, linkedList.size()); + assertEquals("a", linkedList.toString()); + linkedList.addBeforeFirst("b"); + assertEquals(2, linkedList.size()); + assertEquals("b, a", linkedList.toString()); + linkedList.addBeforeFirst("c"); + assertEquals(3, linkedList.size()); + assertEquals("c, b, a", linkedList.toString()); + } + + @Test + public void addAfterLast() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + + //act + + //assert + linkedList.addAfterLast("a"); + assertEquals(1, linkedList.size()); + assertEquals("a", linkedList.toString()); + linkedList.addAfterLast("b"); + assertEquals(2, linkedList.size()); + assertEquals("a, b", linkedList.toString()); + linkedList.addAfterLast("c"); + assertEquals(3, linkedList.size()); + assertEquals("a, b, c", linkedList.toString()); + } + + @Test + public void removeFirst() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + String expectedString = "AnneJohnGeorgeKate"; + String returnedString; + linkedList.addAfterLast("Jack") + ; + linkedList.addAfterLast("Anne") + ; + linkedList.addAfterLast("John") + ; + linkedList.addAfterLast("George") + ; + linkedList.addAfterLast("Kate"); + //act + linkedList.removeFirst(); + StringBuilder stringBuilder = new StringBuilder(); + for (String element : linkedList) { + stringBuilder.append(element); + } + returnedString = stringBuilder.toString(); + //assert + assertEquals(expectedString, returnedString); + linkedList.removeFirst(); + assertEquals(3, linkedList.size()); + assertEquals("John, George, Kate", linkedList.toString()); + } + + @Test + public void removeLast() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + String expectedString = "JackAnneJohnGeorge"; + String returnedString; + linkedList.addAfterLast("Jack") + ; + linkedList.addAfterLast("Anne") + ; + linkedList.addAfterLast("John") + ; + linkedList.addAfterLast("George") + ; + linkedList.addAfterLast("Kate"); + //act + linkedList.removeLast(); + StringBuilder stringBuilder = new StringBuilder(); + for (String element : linkedList) { + stringBuilder.append(element); + } + returnedString = stringBuilder.toString(); + //assert + assertEquals(expectedString, returnedString); + linkedList.removeLast(); + + assertEquals(3, linkedList.size()); + assertEquals("Jack, Anne, John", linkedList.toString()); + } + + @Test + public void getFirst() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + String expectedString = "Jack"; + String returnedString; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + returnedString = linkedList.getFirst(); + //assert + assertEquals(expectedString, returnedString); + linkedList.removeFirst(); + assertEquals("Anne", linkedList.getFirst()); + assertEquals("Anne, John, George, Kate", linkedList.toString()); + } + + @Test + public void getLast() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + String expectedString = "George"; + String returnedString; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.addAfterLast("Mike"); + linkedList.addBeforeFirst("William"); + linkedList.removeFirst(); + linkedList.removeLast(); + linkedList.removeFirst(); + linkedList.addAfterLast("Earl"); + linkedList.removeLast(); + linkedList.removeFirst(); + linkedList.removeLast(); + + returnedString = linkedList.getLast(); + //assert + assertEquals(expectedString, returnedString); + } + + @Test + public void remove_int() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + //assert + linkedList.add("a"); + linkedList.add("b"); + linkedList.add("c"); + //abc + assertEquals(3, linkedList.size()); + linkedList.remove(1); + assertEquals("a, c", linkedList.toString()); + //ac + assertEquals(2, linkedList.size()); + assertFalse(linkedList.contains("b")); + linkedList.add("d"); + assertEquals("a, c, d", linkedList.toString()); + //acd + assertEquals(3, linkedList.size()); + assertTrue(linkedList.contains("d")); + linkedList.remove(0); + //cd + assertEquals(2, linkedList.size()); + assertFalse(linkedList.contains("a")); + linkedList.remove(1); + //c + assertEquals(1, linkedList.size()); + assertFalse(linkedList.contains("d")); + assertTrue(linkedList.contains("c")); + linkedList.remove(0); + assertEquals(0, linkedList.size()); + assertFalse(linkedList.contains("c")); + // + assertEquals("", linkedList.toString()); + } + + @Test + public void get() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + + //assert + assertEquals("Jack", linkedList.get(0)); + assertEquals("Anne", linkedList.get(1)); + assertEquals("John", linkedList.get(2)); + assertEquals("George", linkedList.get(3)); + assertEquals("Kate", linkedList.get(4)); + } + + @Test(expected = NoSuchElementException.class) + public void get2() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + //act + + //assert + assertEquals("Jack", linkedList.get(0)); + + } + + @Test(expected = CollectionException.class) + public void get3() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("Kate"); + //act + linkedList.get(4); + //assert + } + + @Test + public void set() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + linkedList.addAfterLast("a"); + linkedList.addAfterLast("b"); + linkedList.addAfterLast("c"); + linkedList.addAfterLast("d"); + linkedList.addAfterLast("e"); + //act + + //assert + assertEquals("abcde", linkedList.toString("")); + linkedList.set(2, "f"); + assertEquals("abfde", linkedList.toString("")); + linkedList.set(3, "g"); + assertEquals("abfge", linkedList.toString("")); + linkedList.set(0, "h"); + assertEquals("hbfge", linkedList.toString("")); + linkedList.set(3, "i"); + assertEquals("hbfie", linkedList.toString("")); + linkedList.set(1, "j"); + assertEquals("hjfie", linkedList.toString("")); + } + + /** + * Test of toString method, of class LinkedList. + */ + @Test + public void testToString() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + String expectedString = "Jack, Anne, John, George, Kate"; + String returnedString; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + returnedString = linkedList.toString(); + //assert + assertEquals(expectedString, returnedString); + } + + /** + * Test of toString method, of class LinkedList. + */ + @Test + public void testToString_2() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + String expectedString = ""; + String returnedString; + //act + returnedString = linkedList.toString(); + //assert + assertEquals(expectedString, returnedString); + } + + ////// + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_justCreatedInstanceShouldHaveCountZero() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 0; + int returnedCountOfItems; + //act + returnedCountOfItems = linkedList.size(); + //assert + assertEquals(expectedCountOfItems, returnedCountOfItems); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountFive() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 5; + int returnedCountOfItems; + + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + returnedCountOfItems = linkedList.size(); + //assert + assertEquals(expectedCountOfItems, returnedCountOfItems); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountFourAfterFirstRemoved() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 4; + int returnedCountOfItems; + + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.removeFirst(); + returnedCountOfItems = linkedList.size(); + //assert + assertEquals(expectedCountOfItems, returnedCountOfItems); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountThreeAfterTwoFirstRemoved() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 3; + int returnedCountOfItems; + + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.removeFirst(); + linkedList.removeFirst(); + returnedCountOfItems = linkedList.size(); + //assert + assertEquals(expectedCountOfItems, returnedCountOfItems); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountFourAfterLastRemoved() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 4; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.removeLast(); + //assert + assertEquals(expectedCountOfItems, linkedList.size()); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountThreeAfterLastTwoRemoved() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 3; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.removeLast(); + linkedList.removeLast(); + //assert + assertEquals(expectedCountOfItems, linkedList.size()); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountSixAfterAddedBeforeFirst() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 6; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + ; + linkedList.addBeforeFirst("Mike"); + //assert + assertEquals(expectedCountOfItems, linkedList.size()); + } + + /** + * Test of getsize method, of class LinkedList. + */ + @Test + public void size_shouldHaveCountSixAfterAddedAfterLast() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + int expectedCountOfItems = 6; + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.addAfterLast("Mike"); + //assert + assertEquals(expectedCountOfItems, linkedList.size()); + } + + /** + * Test of isEmpty method, of class LinkedList. + */ + @Test + public void isEmpty_justCreatedInstanceShouldBeEmpty() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + boolean returnedValue; + //act + returnedValue = linkedList.isEmpty(); + //assert + assertTrue(returnedValue); + } + + /** + * Test of isEmpty method, of class LinkedList. + */ + @Test + public void isEmpty_linkedListShouldHaveFiveItemsAndShouldNotBeEmpty() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + //assert + assertFalse(linkedList.isEmpty()); + } + + /** + * Test of addBeforeFirst method, of class LinkedList. + */ + @Test + public void isEmpty_countWasFive_fiveItemsWasRemoved_shouldBeEmpty_1() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.removeFirst(); + linkedList.removeLast(); + linkedList.removeLast(); + linkedList.removeFirst(); + linkedList.removeLast(); + //assert + assertTrue(linkedList.isEmpty()); + } + + /** + * Test of addBeforeFirst method, of class LinkedList. + */ + @Test + public void isEmpty_countWasFive_fiveItemsWasRemoved_shouldBeEmpty_2() { + //arrange + SingleLinkedList linkedList = new SingleLinkedList<>(); + linkedList.addAfterLast("Jack"); + linkedList.addAfterLast("Anne"); + linkedList.addAfterLast("John"); + linkedList.addAfterLast("George"); + linkedList.addAfterLast("Kate"); + //act + linkedList.removeFirst(); + linkedList.removeLast(); + linkedList.removeLast(); + linkedList.removeFirst(); + linkedList.removeFirst(); + //assert + assertTrue(linkedList.isEmpty()); + } + +} diff --git a/src/test/java/org/nanoboot/powerframework/collections/StackTest.java b/power-collections/src/test/java/org/nanoboot/powerframework/collections/StackTest.java similarity index 59% rename from src/test/java/org/nanoboot/powerframework/collections/StackTest.java rename to power-collections/src/test/java/org/nanoboot/powerframework/collections/StackTest.java index 827cbf6..65131ca 100644 --- a/src/test/java/org/nanoboot/powerframework/collections/StackTest.java +++ b/power-collections/src/test/java/org/nanoboot/powerframework/collections/StackTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -20,14 +20,18 @@ package org.nanoboot.powerframework.collections; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; +import java.util.*; + import static org.junit.Assert.*; +import org.junit.*; + /** * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class StackTest { /** @@ -37,102 +41,102 @@ public class StackTest { } /** - * Test of getCountOfItems method, of class Stack. + * Test of size method, of class Stack. */ @Test - public void testGetCountOfItems() { + public void testsize() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); int expectedCountOfItems = 0; int returnedCountOfItems; //act - returnedCountOfItems = stack.getCountOfItems(); + returnedCountOfItems = stack.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Stack. + * Test of size method, of class Stack. */ @Test - public void testGetCountOfItems2() { + public void testsize2() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); int expectedCountOfItems = 0; int returnedCountOfItems; //act - stack.push("John"); + stack.pushAndReturn("John"); stack.pop(); - returnedCountOfItems = stack.getCountOfItems(); + returnedCountOfItems = stack.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Stack. + * Test of size method, of class Stack. */ @Test - public void testGetCountOfItems3() { + public void testsize3() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); int expectedCountOfItems = 0; int returnedCountOfItems; //act - stack.push("John"); + stack.pushAndReturn("John"); stack.pop(); - stack.push("Jack").push("Anne").push("Charlie"); + stack.pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie"); stack.pop(); stack.pop(); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); - returnedCountOfItems = stack.getCountOfItems(); + returnedCountOfItems = stack.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Stack. + * Test of size method, of class Stack. */ @Test - public void testGetCountOfItems4() { + public void testsize4() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); int expectedCountOfItems = 1; int returnedCountOfItems; //act - stack.push("John"); + stack.pushAndReturn("John"); stack.pop(); - stack.push("Jack").push("Anne").push("Charlie"); + stack.pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie"); stack.pop(); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); - returnedCountOfItems = stack.getCountOfItems(); + returnedCountOfItems = stack.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } /** - * Test of getCountOfItems method, of class Stack. + * Test of size method, of class Stack. */ @Test - public void testGetCountOfItems5() { + public void testsize5() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); int expectedCountOfItems = 3; int returnedCountOfItems; //act - stack.push("John"); + stack.pushAndReturn("John"); stack.pop(); - stack.push("Jack").push("Anne").push("Charlie").push("Susan"); + stack.pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie").pushAndReturn("Susan"); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); - returnedCountOfItems = stack.getCountOfItems(); + returnedCountOfItems = stack.size(); //assert assertEquals(expectedCountOfItems, returnedCountOfItems); } @@ -143,7 +147,7 @@ public class StackTest { @Test public void testIsEmpty() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); boolean expectedValue = true; boolean returnedValue; //act @@ -158,18 +162,18 @@ public class StackTest { @Test public void testIsEmpty2() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); boolean expectedValue = true; boolean returnedValue; //act - stack.push("John").push("Jack").push("Anne").push("Charlie"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie"); stack.pop(); stack.pop(); stack.pop(); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); returnedValue = stack.isEmpty(); //assert @@ -182,17 +186,17 @@ public class StackTest { @Test public void testIsEmpty3() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); boolean expectedValue = false; boolean returnedValue; //act - stack.push("John").push("Jack").push("Anne").push("Charlie"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie"); stack.pop(); stack.pop(); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); returnedValue = stack.isEmpty(); //assert @@ -205,16 +209,16 @@ public class StackTest { @Test public void testIsEmpty4() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); boolean expectedValue = false; boolean returnedValue; //act - stack.push("John").push("Jack").push("Anne").push("Charlie"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie"); stack.pop(); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); returnedValue = stack.isEmpty(); //assert @@ -225,18 +229,18 @@ public class StackTest { * Test of push method, of class Stack. */ @Test - public void testPush() { + public void testpushAndReturn() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); String expectedString = "Jack"; String returnedString; //act - stack.push("John").push("Jack").push("Anne").push("Charlie"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie"); stack.pop(); stack.pop(); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); returnedString = stack.pop(); //assert @@ -249,32 +253,53 @@ public class StackTest { @Test public void testPop() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); String expectedString = "Dennis"; String returnedString; //act - stack.push("John").push("Jack").push("Anne").push("Charlie").push("Alice").push("Dennis"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie").pushAndReturn("Alice").pushAndReturn("Dennis"); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); returnedString = stack.pop(); //assert assertEquals(expectedString, returnedString); } + /** + * Test of pop method, of class Stack. + */ + @Test + public void testPop2() { + + //arrange + boolean isExceptionThrown = false; + PowerStack stack = new PowerStack<>(); + //act + try { + stack.pop(); + } catch (NoSuchElementException e) { + isExceptionThrown = true; + } + //assert + if (!isExceptionThrown) { + fail("There should be thrown NoSuchElementException"); + } + } + /** * Test of peek method, of class Stack. */ @Test public void testPeek() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); String expectedString = "Dennis"; String returnedString; //act - stack.push("John").push("Jack").push("Anne").push("Charlie").push("Alice").push("Dennis"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie").pushAndReturn("Alice").pushAndReturn("Dennis"); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); returnedString = stack.peek(); //assert @@ -287,38 +312,34 @@ public class StackTest { @Test public void testPeek2() { //arrange - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); int expectedValue = 6; int returnedValue; //act - stack.push("John").push("Jack").push("Anne").push("Charlie").push("Alice").push("Dennis"); + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie").pushAndReturn("Alice").pushAndReturn("Dennis"); - stack.push("Jane"); + stack.pushAndReturn("Jane"); stack.pop(); - returnedValue = stack.getCountOfItems(); + returnedValue = stack.size(); //assert assertEquals(expectedValue, returnedValue); } /** - * Test of pop method, of class Stack. + * Test of peek method, of class Stack. */ @Test - public void testPop2() { - + public void testClear() { //arrange - boolean isExceptionThrown = false; - Stack stack = new Stack<>(); + PowerStack stack = new PowerStack<>(); + boolean returnedValue; //act - try { - stack.pop(); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } + stack.pushAndReturn("John").pushAndReturn("Jack").pushAndReturn("Anne").pushAndReturn("Charlie").pushAndReturn("Alice").pushAndReturn("Dennis"); + + stack.clear(); + returnedValue = stack.isEmpty(); //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); - } + assertTrue(returnedValue); } /** @@ -327,11 +348,11 @@ public class StackTest { @Test public void testToString() { //arrange - Stack stack = new Stack<>(); - String expectedString = "Jane, Alice, "; + PowerStack stack = new PowerStack<>(); + String expectedString = "Jane, Alice"; String returnedString; //act - stack.push("Alice").push("Jane"); + stack.pushAndReturn("Alice").pushAndReturn("Jane"); returnedString = stack.toString(); //assert assertEquals(expectedString, returnedString); diff --git a/power-core/pom.xml b/power-core/pom.xml new file mode 100644 index 0000000..4f2c94d --- /dev/null +++ b/power-core/pom.xml @@ -0,0 +1,57 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-core + jar + + Power Core + Core functionality for the Power library + + + false + + + + + src/main/resources + true + + + + + + + + + org.projectlombok + lombok + + + diff --git a/power-core/src/lombok.config b/power-core/src/lombok.config new file mode 100644 index 0000000..f202d30 --- /dev/null +++ b/power-core/src/lombok.config @@ -0,0 +1,4 @@ +# tells Lombok that this is the root directory and that it shouldn’t search parent directories for more configuration files +config.stopBubbling = true +# tells Lombok to add @lombok.Generated annotation to all generated methods +lombok.addLombokGeneratedAnnotation = true \ No newline at end of file diff --git a/power-core/src/main/java/module-info.java b/power-core/src/main/java/module-info.java new file mode 100644 index 0000000..d82457b --- /dev/null +++ b/power-core/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.core { + requires lombok; + exports org.nanoboot.powerframework.core; + exports org.nanoboot.powerframework.core.exceptions; + exports org.nanoboot.powerframework.core.version; +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/CoreException.java b/power-core/src/main/java/org/nanoboot/powerframework/core/CoreException.java new file mode 100644 index 0000000..47c87ed --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/CoreException.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +/** + * Exception class for classes in core package. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class CoreException extends PowerException { + + /** + * Constructor with message. + * + * @param message message describing the reason, + * why this exception was thrown. + */ + public CoreException(final String message) { + super(message); + } + +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/PowerException.java b/power-core/src/main/java/org/nanoboot/powerframework/core/PowerException.java new file mode 100644 index 0000000..3519951 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/PowerException.java @@ -0,0 +1,55 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +/** + * Exception for Power library. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerException extends RuntimeException { + + /** + * Constructor without message. + */ + public PowerException() { + this("No detail."); + } + + /** + * Constructor with message. + * + * @param message Message describing, what happened + */ + public PowerException(final String message) { + super(message); + } + + /** + * Constructor with exception. + * + * @param exception another exception, which was thrown + */ + public PowerException(final Exception exception) { + this(exception.toString()); + } +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/PowerFramework.java b/power-core/src/main/java/org/nanoboot/powerframework/core/PowerFramework.java new file mode 100644 index 0000000..4897589 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/PowerFramework.java @@ -0,0 +1,75 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +import org.nanoboot.powerframework.core.version.Version; +import org.nanoboot.powerframework.core.version.VersionType; + +/** + * Power is the core class of the Power library. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class PowerFramework { + + /** + * Current mayor number. + */ + private static final int MAJOR_NUMBER = 1; + /** + * Current minor number. + */ + private static final int MINOR_NUMBER = 0; + /** + * Current patch number. + */ + private static final int PATCH_NUMBER = 0; + /** + * Current version of the Power framework. + */ + private static Version version = + new Version( + MAJOR_NUMBER, + MINOR_NUMBER, + PATCH_NUMBER, + VersionType.SNAPSHOT, + 0); + /** + * Returns the version number of Power library. + * + * @return the version number of Power library + */ + public static String getVersion() { + return version.toString(); + } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private PowerFramework() { + //Not meant to be instantiated. + //NOSONAR + } + +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/PowerObject.java b/power-core/src/main/java/org/nanoboot/powerframework/core/PowerObject.java new file mode 100644 index 0000000..5afb534 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/PowerObject.java @@ -0,0 +1,50 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +import lombok.Getter; + +/** + * Base Power object. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerObject { + /** + * Next id. + */ + private static long nextPowerObjectId = 0; + /** + * Id. + */ + @Getter + private final long powerObjectId; + + /** + *Constructor. + */ + public PowerObject() { + this.powerObjectId = nextPowerObjectId; + nextPowerObjectId++; + } + +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedException.java b/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedException.java new file mode 100644 index 0000000..967b0b5 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedException.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.exceptions; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * Exception happening in case, something is called, but not implemented yet. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class NotYetImplementedException extends PowerException { + + /** + * Constructor with message. + * + * @param message message describing the reason, + * why this exception was thrown. + */ + public NotYetImplementedException(final String message) { + super(message); + } + +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodException.java b/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodException.java new file mode 100644 index 0000000..2ba0364 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodException.java @@ -0,0 +1,45 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.exceptions; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * Exception happening in case, something is called, + * but not implemented and not supported now and + * not intended to be supported in future. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class UnsupportedMethodException extends PowerException { + + /** + * Constructor with message. + * + * @param message message describing the reason, + * why this exception was thrown. + */ + public UnsupportedMethodException(final String message) { + super(message); + } + +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/package-info.java b/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/package-info.java new file mode 100644 index 0000000..84a6fce --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/exceptions/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Some common exceptions. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.core.exceptions; diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/package-info.java b/power-core/src/main/java/org/nanoboot/powerframework/core/package-info.java new file mode 100644 index 0000000..c1c7cbb --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/package-info.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Core Power classes. + * + * @author Robert Vokac + * @since 0.0.0 + */ + + +package org.nanoboot.powerframework.core; diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/version/Version.java b/power-core/src/main/java/org/nanoboot/powerframework/core/version/Version.java new file mode 100644 index 0000000..16c4ac5 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/version/Version.java @@ -0,0 +1,341 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.version; +import org.nanoboot.powerframework.core.CoreException; +import lombok.Data; +/* +Examples: + 1.2.0.1 instead of 1.1.2-a1 + 1.2.1.2 instead of 1.1.2-b2 (beta with some bug fixes) + 1.2.2.3 instead of 1.1.2-rc3 (release candidate) + 1.2.3.0 instead of 1.1.2-r (commercial distribution) + 1.2.3.5 instead of 1.1.2-r5 (commercial distribution with many bug fixes) + 1.2.3.5 instead of 1.1.2-SNAPSHOT + */ + +/** + * Version object representing a version of a software. + * @author Robert Vokac + * @since 0.0.0 + */ +@Data +public final class Version implements Comparable { + /** + * Dot "." separator. + */ + public static final String DOT_SEPARATOR = "."; + /** + * Dash "-" separator. + */ + public static final String DASH_SEPARATOR = "-"; + /** + * Internal constant "Version array length must be". + * It is used, if one of the possible exception happens. + */ + private static final String WRONG_ARRAY_LENGTH_EXC_MSG = + "Version array length must be "; + /** + * Constant "VERSION_TYPE_INDEX". + */ + public static final int VERSION_TYPE_INDEX = 3; + /** + * major number. + */ + private int majorNumber; + /** + * minor number. + */ + private int minorNumber; + /** + * patch number. + */ + private int patchNumber; + /** + * Version type. + */ + private VersionType versionType; + + /** + * special number. + * If version type is STANDARD or SNAPSHOT, the special number must be 0. + */ + private int specialNumber; + /** + * Constructor. + */ + public Version() { + //Default constructor to keep the no argument constructor. + this.versionType = VersionType.STANDARD; + } + + /** + * Constructor. + * Version type is STANDARD in this constructor. + * Special number is 0 in this constructor. + * @param majorNumberArg mayor number + * @param minorNumberArg minor number + * @param patchNumberArg patch number + */ + public Version(final int majorNumberArg, + final int minorNumberArg, + final int patchNumberArg) { + this(majorNumberArg, minorNumberArg, + patchNumberArg, VersionType.STANDARD); + } + /** + * Constructor. + * Special number is 0 in this constructor. + * @param majorNumberArg mayor number + * @param minorNumberArg minor number + * @param patchNumberArg patch number + * @param versionTypeArg version type + */ + public Version(final int majorNumberArg, + final int minorNumberArg, + final int patchNumberArg, + final VersionType versionTypeArg) { + this.majorNumber = majorNumberArg; + this.minorNumber = minorNumberArg; + this.patchNumber = patchNumberArg; + this.versionType = versionTypeArg; + this.specialNumber = 0; + } + /** + * Constructor. + * @param majorNumberArg mayor number + * @param minorNumberArg minor number + * @param patchNumberArg patch number + * @param versionTypeArg version type + * @param specialNumberArg special number + */ + public Version(final int majorNumberArg, + final int minorNumberArg, + final int patchNumberArg, + final VersionType versionTypeArg, + final int specialNumberArg) { + this.majorNumber = majorNumberArg; + this.minorNumber = minorNumberArg; + this.patchNumber = patchNumberArg; + this.versionType = versionTypeArg; + this.specialNumber = specialNumberArg; + } + + /** + * Constructor. + * @param versionAsString version as string + */ + public Version(final String versionAsString) { + String normalized = toNormalizedString(versionAsString); + + String[] versionArray = normalized.split("\\" + DOT_SEPARATOR); + final int expectedVersionArrayLength = 5; + if (versionArray.length != expectedVersionArrayLength) { + String msg = WRONG_ARRAY_LENGTH_EXC_MSG + expectedVersionArrayLength + + ", but it is " + versionArray.length; + throw new CoreException(msg); + } + String mayorStr = versionArray[VersionNumberType.MAJOR.getIndex()]; + this.majorNumber = Integer.valueOf(mayorStr); + String minorStr = versionArray[VersionNumberType.MINOR.getIndex()]; + this.minorNumber = Integer.valueOf(minorStr); + String patchStr = versionArray[VersionNumberType.PATCH.getIndex()]; + this.patchNumber = Integer.valueOf(patchStr); + this.versionType = VersionType.of(versionArray[VERSION_TYPE_INDEX]); + String specialStr = versionArray[VersionNumberType.SPECIAL.getIndex()]; + this.specialNumber = Integer.valueOf(specialStr); + checkIsValid(); + } + + /** + * Creates normalized string representation. + * @param versionAsString classic version String + * @return normalized string + */ + private String toNormalizedString(final String versionAsString) { + String normalized = versionAsString; + if (normalized.contains("-")) { //not standard + normalized = normalized.replace(DASH_SEPARATOR, DOT_SEPARATOR); + if (normalized.endsWith(VersionType.SNAPSHOT.getValue())) { + normalized = normalized + 0; + } + } else { + //note: is STANDARD + normalized = normalized + DOT_SEPARATOR + + VersionType.STANDARD.getValue() + + 0; + } + //replace the values + for (VersionType vt : VersionType.values()) { + boolean skipLoop = normalized + .contains(VersionType.STANDARD.getValue()) + && vt != VersionType.STANDARD; + if (skipLoop) { + //continue needed to avoid transforming standard to sta.nda.rd + continue; + } + String value = vt.getValue(); + if (normalized.contains(value)) { + this.versionType = vt; + normalized = normalized.replace(value, value + DOT_SEPARATOR); + } + } + return normalized; + } + + /** + * Creates a String representation of the instance. + * @return version as text + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(majorNumber); + sb.append(DOT_SEPARATOR); + sb.append(minorNumber); + sb.append(DOT_SEPARATOR); + sb.append(patchNumber); + if (getVersionType() != VersionType.STANDARD) { + sb.append(DASH_SEPARATOR); + sb.append(getVersionType().getValue()); + if (getVersionType() != VersionType.SNAPSHOT) { + sb.append(this.getSpecialNumber()); + } + } + return sb.toString(); + } + + /** + * Loads version value. + * @param versionNumberType version sub type + * @return sub version number. + */ + public int getValue(final VersionNumberType versionNumberType) { + switch (versionNumberType) { + case MAJOR: return majorNumber; + case MINOR: return minorNumber; + case PATCH: return patchNumber; + case SPECIAL: return specialNumber; + default: throw new UnsupportedOperationException( + versionNumberType.toString()); + } + } + /** + * Loads version value. + * @param versionNumberType version sub type + * @param value version value + */ + public void setValue(final VersionNumberType versionNumberType, + final int value) { + switch (versionNumberType) { + case MAJOR: this.majorNumber = value; break; + case MINOR: this.minorNumber = value; break; + case PATCH: this.patchNumber = value; break; + case SPECIAL: this.specialNumber = value; break; + default: throw new UnsupportedOperationException( + versionNumberType.toString()); + } + } + + /** + * Increments a sub version. + * @param versionNumberType version sub type to be incremented. + */ + public void increment(final VersionNumberType versionNumberType) { + if (!getVersionType().isStandard()) { + String msg = + "This operation is not supported for version number type " + + versionNumberType; + throw new UnsupportedOperationException(msg); + } + int currentValue = getValue(versionNumberType); + int incrementedValue = currentValue + 1; + setValue(versionNumberType, incrementedValue); + switch (versionNumberType) { + case MAJOR: this.minorNumber = 0; this.patchNumber = 0; break; + case MINOR: this.patchNumber = 0; break; + case PATCH: /*nothing to do*/ break; + default: throw new UnsupportedOperationException( + versionNumberType.toString()); + } + } + /** + * Checks, if the version instance is valid. + * @throws CoreException thrown, if Version instance is not valid. + */ + public void checkIsValid() { + if (!validate()) { + String msg = "Version instance is not valid and cannot be created."; + throw new CoreException(msg); + } + } + /** + * Validates this version instance. + * @return true, if this version instance is valid, otherwise false. + */ + public boolean validate() { + boolean isStandard = this.getVersionType().isStandard(); + boolean isSnapshot = this.getVersionType().isSnapshot(); + if (isStandard || isSnapshot) { + if (specialNumber != 0) { + return false; + } + } else { + if (specialNumber <= 0) { + return false; + } + } + if (majorNumber < 0) { + return false; + } + if (minorNumber < 0) { + return false; + } + if (patchNumber < 0) { //NOSONAR + return false; + } + return true; + } + /** + * Creates exact copy of this version as a new instance. + * @return version instance + */ + public Version getCopy() { + return new Version(toString()); + } + + @Override + public int compareTo(final Version o) { + Version v1 = this; + Version v2 = o; + Integer mayor1 = v1.getMajorNumber(); + Integer mayor2 = v2.getMajorNumber(); + Integer minor1 = v1.getMinorNumber(); + Integer minor2 = v2.getMinorNumber(); + Integer patch1 = v1.getPatchNumber(); + Integer patch2 = v2.getPatchNumber(); + if (mayor1 != mayor2) { + return mayor1.compareTo(mayor2); + } + if (minor1 != minor2) { + return minor1.compareTo(minor2); + } + return patch1.compareTo(patch2); + } +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionNumberType.java b/power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionNumberType.java new file mode 100644 index 0000000..8cb548b --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionNumberType.java @@ -0,0 +1,66 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.version; + +import lombok.Getter; + +/** + * Version subtype. + * @author Robert Vokac + * @since 0.0.0 + */ +public enum VersionNumberType { + /** + * Major version is used for big changes or not backward compatible changes. + */ + MAJOR(0), + /** + * Minor version is used for small changes. + */ + MINOR(1), + /** + * Patch version is used for bug fixed and not for new features. + */ + PATCH(2), + //Note: Index 3 is reserved for version type value. + /** + * Special version is used for some version types. + */ + SPECIAL(4), + /** + * Enumeration only for special purposes. + */ + UNKNOWN(100); + + /** + * Index of the version number type. + */ + @Getter + private final int index; + + /** + * Constructor. + * @param indexArg index of the version number type + */ + VersionNumberType(final int indexArg) { + this.index = indexArg; + } +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionType.java b/power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionType.java new file mode 100644 index 0000000..f5812e1 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/version/VersionType.java @@ -0,0 +1,127 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.version; + +import lombok.Getter; + +/** + * Version type. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum VersionType { + /** + * Snapshot version. + * + * Description: Development version, which may not be stable. + */ + SNAPSHOT("SNAPSHOT"), + /** + * Alpha version. + * + * Description: alpha version. + */ + ALPHA("a"), + /** + * Beta version. + * + * Description: beta version. + */ + BETA("b"), + /** + * Release candidate version. + * + * Description: release candidate version. + */ + RELEASE_CANDIDATE("rc"), + /** + * Standard version. + * + * Description: standard version, which should be stable. + */ + STANDARD("standard"); + + /** + * Value of the version type. + */ + @Getter + private final String value; + + /** + * Constructor. + * @param valueArg of version type. + */ + VersionType(final String valueArg) { + this.value = valueArg; + } + + /** + * Returns version type of value string. + * @param string value as string + * @return version type + */ + public static VersionType of(final String string) { + for (VersionType e : VersionType.values()) { + if (string.equals(e.getValue())) { + return e; + } + } + String msg = "Found no VersionType with value " + string; + throw new UnsupportedOperationException(msg); + } + + /** + * Checks, the version type is SNAPSHOT. + * @return true, it the condition is true, otherwise false + */ + public boolean isSnapshot() { + return this == SNAPSHOT; + } + /** + * Checks, the version type is ALPHA. + * @return true, it the condition is true, otherwise false + */ + public boolean isAlpha() { + return this == ALPHA; + } + /** + * Checks, the version type is BETA. + * @return true, it the condition is true, otherwise false + */ + public boolean isBeta() { + return this == BETA; + } + /** + * Checks, the version type is RELEASE_CANDIDATE. + * @return true, it the condition is true, otherwise false + */ + public boolean isReleaseCandidate() { + return this == RELEASE_CANDIDATE; + } + /** + * Checks, the version type is STANDARD. + * @return true, it the condition is true, otherwise false + */ + public boolean isStandard() { + return this == STANDARD; + } +} diff --git a/power-core/src/main/java/org/nanoboot/powerframework/core/version/package-info.java b/power-core/src/main/java/org/nanoboot/powerframework/core/version/package-info.java new file mode 100644 index 0000000..bc20640 --- /dev/null +++ b/power-core/src/main/java/org/nanoboot/powerframework/core/version/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Version classes. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.core.version; diff --git a/power-core/src/main/resources/.gitkeep b/power-core/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-core/src/main/resources/version.properties b/power-core/src/main/resources/version.properties new file mode 100644 index 0000000..410af8c --- /dev/null +++ b/power-core/src/main/resources/version.properties @@ -0,0 +1 @@ +version = ${project.version} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/CoreExceptionTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/CoreExceptionTest.java new file mode 100644 index 0000000..87e7a14 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/CoreExceptionTest.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CoreExceptionTest { + + @Test + public void constructor_String() { + assertEquals("An error", new CoreException("An error").getMessage()); + } + +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/PowerExceptionTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/PowerExceptionTest.java new file mode 100644 index 0000000..1d0f436 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/PowerExceptionTest.java @@ -0,0 +1,50 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerExceptionTest { + + @Test + public void constructor() { + assertEquals("No detail.", new PowerException().getMessage()); + } + + @Test + public void constructor_String() { + assertEquals("An error", new PowerException("An error").getMessage()); + } + + @Test + public void constructor_Exception() { + RuntimeException e = new RuntimeException("abc"); + assertEquals(e.toString(), new PowerException(e).getMessage()); + } + +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/PowerFrameworkTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/PowerFrameworkTest.java new file mode 100644 index 0000000..311b33c --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/PowerFrameworkTest.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerFrameworkTest { + + @Test + public void getVersion() { + assertNotNull(PowerFramework.getVersion()); + } +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/PowerObjectTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/PowerObjectTest.java new file mode 100644 index 0000000..d021de6 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/PowerObjectTest.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerObjectTest { + + @Test + public void getPowerObjectId() { + assertNotNull(new PowerObject().getPowerObjectId()); + } +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedExceptionTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedExceptionTest.java new file mode 100644 index 0000000..7d47dbf --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/NotYetImplementedExceptionTest.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.exceptions; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class NotYetImplementedExceptionTest { + + @Test + public void constructor_String() { + assertEquals("An error", new NotYetImplementedException("An error").getMessage()); + } + +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodExceptionTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodExceptionTest.java new file mode 100644 index 0000000..6029500 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/exceptions/UnsupportedMethodExceptionTest.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.exceptions; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class UnsupportedMethodExceptionTest { + + @Test + public void constructor_String() { + assertEquals("An error", new UnsupportedMethodException("An error").getMessage()); + } + + +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionNumberTypeTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionNumberTypeTest.java new file mode 100644 index 0000000..5f88c06 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionNumberTypeTest.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.version; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class VersionNumberTypeTest { + @Test + public void constructor() { + assertEquals(0, VersionNumberType.MAJOR.getIndex()); + } + +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTest.java new file mode 100644 index 0000000..0170946 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTest.java @@ -0,0 +1,293 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.version; + +import org.nanoboot.powerframework.core.CoreException; +import org.junit.Ignore; +import org.junit.Test; + +import static org.nanoboot.powerframework.core.version.VersionNumberType.*; +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class VersionTest { + + @Test + public void Version_noArg() { + Version version = new Version(); + assertEquals(0, version.getMajorNumber()); + assertEquals(0, version.getMinorNumber()); + assertEquals(0, version.getPatchNumber()); + assertEquals(VersionType.STANDARD, version.getVersionType()); + assertEquals(0, version.getSpecialNumber()); + } + + @Test + public void Version_int_int_int() { + Version version = new Version(1, 2, 3); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.STANDARD, version.getVersionType()); + assertEquals(0, version.getSpecialNumber()); + } + + @Test + public void Version_int_int_int_versionType() { + Version version = new Version(1, 2, 3, VersionType.SNAPSHOT); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.SNAPSHOT, version.getVersionType()); + assertEquals(0, version.getSpecialNumber()); + } + + @Test + public void Version_int_int_int_versionType_int() { + Version version = new Version(1, 2, 3, VersionType.BETA, 4); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.BETA, version.getVersionType()); + assertEquals(4, version.getSpecialNumber()); + } + + @Test + public void Version_String() { + Version version; + // + version = new Version("1.2.3-SNAPSHOT"); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.SNAPSHOT, version.getVersionType()); + assertEquals(0, version.getSpecialNumber()); + // + version = new Version("1.2.3-a5"); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.ALPHA, version.getVersionType()); + assertEquals(5, version.getSpecialNumber()); + // + version = new Version("1.2.3-b5"); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.BETA, version.getVersionType()); + assertEquals(5, version.getSpecialNumber()); + // + version = new Version("1.2.3-rc5"); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.RELEASE_CANDIDATE, version.getVersionType()); + assertEquals(5, version.getSpecialNumber()); + // + version = new Version("1.2.3"); + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(VersionType.STANDARD, version.getVersionType()); + assertEquals(0, version.getSpecialNumber()); + } + + @Test(expected = CoreException.class) + public void Version_Strin__exc() { + new Version("1.3.4.5"); + } + + @Test + public void testToString() { + Version version; + version = new Version("4.5.6-b7"); + assertEquals(7, version.getSpecialNumber()); + assertEquals("4.5.6-b7", version.toString()); + version = new Version("4.5.6"); + assertEquals("4.5.6", version.toString()); + version = new Version("4.5.6-SNAPSHOT"); + assertEquals("4.5.6-SNAPSHOT", version.toString()); + } + + @Test + public void getValue() { + Version version = new Version(1, 2, 3, VersionType.RELEASE_CANDIDATE, 6); + assertEquals(1, version.getValue(MAJOR)); + assertEquals(2, version.getValue(MINOR)); + assertEquals(3, version.getValue(PATCH)); + assertEquals(6, version.getValue(SPECIAL)); + } + + @Test + public void setValue() { + Version version = new Version(); + version.setValue(MAJOR, 1); + version.setValue(MINOR, 2); + version.setValue(PATCH, 3); + version.setValue(SPECIAL, 6); + // + assertEquals(1, version.getMajorNumber()); + assertEquals(2, version.getMinorNumber()); + assertEquals(3, version.getPatchNumber()); + assertEquals(6, version.getSpecialNumber()); + } + + @Test(expected = UnsupportedOperationException.class) + public void getValue_Exc() { + Version version = new Version(1, 2, 3, VersionType.RELEASE_CANDIDATE, 6); + version.getValue(VersionNumberType.UNKNOWN); + } + + @Test(expected = UnsupportedOperationException.class) + public void setValue_Exc() { + Version version = new Version(); + version.setValue(VersionNumberType.UNKNOWN, 1); + } + + @Test(expected = UnsupportedOperationException.class) + public void increment() { + Version version = new Version(); + version.setVersionType(VersionType.BETA); + version.setSpecialNumber(4); + version.increment(MAJOR); + } + + @Test() + public void increment2() { + Version version; + // + version = new Version(); + version.increment(MAJOR); + assertEquals("1.0.0", version.toString()); + // + version = new Version(); + version.increment(MINOR); + assertEquals("0.1.0", version.toString()); + // + version = new Version(); + version.increment(PATCH); + assertEquals("0.0.1", version.toString()); + } + + @Test(expected = UnsupportedOperationException.class) + public void increment3() { + Version version = new Version(); + version.increment(SPECIAL); + } + + @Test + public void validate() { + assertFalse(new Version(1, 2, 3, VersionType.STANDARD, 1).validate()); + assertFalse(new Version(1, 2, 3, VersionType.SNAPSHOT, 1).validate()); + assertFalse(new Version(1, 2, 3, VersionType.ALPHA, 0).validate()); + assertFalse(new Version(1, 2, 3, VersionType.BETA, 0).validate()); + assertFalse(new Version(1, 2, 3, VersionType.RELEASE_CANDIDATE, 0).validate()); + assertFalse(new Version(1, 2, 3, VersionType.ALPHA, -1).validate()); + assertFalse(new Version(1, 2, 3, VersionType.BETA, -1).validate()); + assertFalse(new Version(1, 2, 3, VersionType.RELEASE_CANDIDATE, -1).validate()); + assertFalse(new Version(-1, 2, 3).validate()); + assertFalse(new Version(1, -2, 3).validate()); + assertFalse(new Version(1, 2, -3).validate()); + assertTrue(new Version(1, 2, 3).validate()); + } + + @Test(expected = CoreException.class) + public void checkIsValid() { + new Version(1, 2, -3, VersionType.STANDARD, 1).checkIsValid(); + } + + @Test + public void getCopy() { + assertEquals("4.5.6-b8", new Version("4.5.6-b8").getCopy().toString()); + } + + /** + * Test of compareTo method, of class Version. + */ + @Test + public void testCompareTo() { + System.out.println("compareTo"); + //prepare + Version v0_0_0 = new Version("0.0.0"); + Version v0_0_1 = new Version("0.0.1"); + Version v0_0_2 = new Version("0.0.2"); + Version v0_1_0 = new Version("0.1.0"); + Version v0_1_1 = new Version("0.1.1"); + Version v0_1_2 = new Version("0.1.2"); + Version v1_0_0 = new Version("1.0.0"); + Version v1_0_1 = new Version("1.0.1"); + Version v1_0_2 = new Version("1.0.2"); + Version v2_0_0 = new Version("2.0.0"); + Version v2_0_1 = new Version("2.0.1"); + Version v2_0_2 = new Version("2.0.2"); + Version[] versions = new Version[]{ + v0_0_0, + v0_0_1, + v0_0_2, + v0_1_0, + v0_1_1, + v0_1_2, + v1_0_0, + v1_0_1, + v1_0_2, + v2_0_0, + v2_0_1, + v2_0_2 + }; + int vmin = 0; + int vmax = versions.length - 1; + //execute + //assert + for (Version v : versions) { + assertEquals(0, v.compareTo(v)); + } + for (int i = vmin; i <= vmax; i++) { + Version current = versions[i]; + Version previous = i == vmin ? null : versions[i - 1]; + Version next = i == vmax ? null : versions[i + 1]; + String msg = String.format( + "current = %s, previous = %s, next = %s", + current.toString(), + (previous == null ? null :previous.toString()), + (next == null ? null :next.toString()) + ); + //System.out.println(msg); + if (previous != null) { + assertEquals("Assertion failed: current > previous : " + msg, 1, current.compareTo(previous)); + } + if (next != null) { + assertEquals("Assertion failed: next > current : " + msg, 1, next.compareTo(current)); + } + // + if (previous != null) { + assertEquals("Assertion failed: previous < current : " + msg, -1, previous.compareTo(current)); + } + if (next != null) { + assertEquals("Assertion failed: current < next : " + msg, -1, current.compareTo(next)); + } + + } + } +} diff --git a/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTypeTest.java b/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTypeTest.java new file mode 100644 index 0000000..8c0f520 --- /dev/null +++ b/power-core/src/test/java/org/nanoboot/powerframework/core/version/VersionTypeTest.java @@ -0,0 +1,91 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.core.version; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class VersionTypeTest { + + @Test + public void of() { + assertEquals(VersionType.SNAPSHOT, VersionType.of("SNAPSHOT")); + assertEquals(VersionType.ALPHA, VersionType.of("a")); + assertEquals(VersionType.BETA, VersionType.of("b")); + assertEquals(VersionType.RELEASE_CANDIDATE, VersionType.of("rc")); + assertEquals(VersionType.STANDARD, VersionType.of("standard")); + } + @Test(expected = UnsupportedOperationException.class) + public void of2() { + VersionType.of("nonsense text"); + } + + @Test + public void isSnapshot() { + assertTrue(VersionType.SNAPSHOT.isSnapshot()); + assertFalse(VersionType.ALPHA.isSnapshot()); + assertFalse(VersionType.BETA.isSnapshot()); + assertFalse(VersionType.RELEASE_CANDIDATE.isSnapshot()); + assertFalse(VersionType.STANDARD.isSnapshot()); + } + + @Test + public void isAlpha() { + assertFalse(VersionType.SNAPSHOT.isAlpha()); + assertTrue(VersionType.ALPHA.isAlpha()); + assertFalse(VersionType.BETA.isAlpha()); + assertFalse(VersionType.RELEASE_CANDIDATE.isAlpha()); + assertFalse(VersionType.STANDARD.isAlpha()); + } + + @Test + public void isBeta() { + assertFalse(VersionType.SNAPSHOT.isBeta()); + assertFalse(VersionType.ALPHA.isBeta()); + assertTrue(VersionType.BETA.isBeta()); + assertFalse(VersionType.RELEASE_CANDIDATE.isBeta()); + assertFalse(VersionType.STANDARD.isBeta()); + } + + @Test + public void isReleaseCandidate() { + assertFalse(VersionType.SNAPSHOT.isReleaseCandidate()); + assertFalse(VersionType.ALPHA.isReleaseCandidate()); + assertFalse(VersionType.BETA.isReleaseCandidate()); + assertTrue(VersionType.RELEASE_CANDIDATE.isReleaseCandidate()); + assertFalse(VersionType.STANDARD.isReleaseCandidate()); + } + + @Test + public void isStandard() { + assertFalse(VersionType.SNAPSHOT.isStandard()); + assertFalse(VersionType.ALPHA.isStandard()); + assertFalse(VersionType.BETA.isStandard()); + assertFalse(VersionType.RELEASE_CANDIDATE.isStandard()); + assertTrue(VersionType.STANDARD.isStandard()); + } +} diff --git a/power-db/pom.xml b/power-db/pom.xml new file mode 100644 index 0000000..a4d88dd --- /dev/null +++ b/power-db/pom.xml @@ -0,0 +1,75 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-db + jar + + Power DB + DB functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-collections + ${power.version} + + + org.nanoboot.powerframework + power-json + ${power.version} + + + org.nanoboot.powerframework + power-time + ${power.version} + + + + + junit + junit + 4.12 + test + + + org.xerial + sqlite-jdbc + 3.28.0 + provided + + + + diff --git a/power-db/src/main/java/module-info.java b/power-db/src/main/java/module-info.java new file mode 100644 index 0000000..4f9a833 --- /dev/null +++ b/power-db/src/main/java/module-info.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.db { + exports org.nanoboot.powerframework.db.manager; + requires powerframework.core; + requires java.sql; + requires powerframework.json; + requires powerframework.time; + requires powerframework.utils; + requires powerframework.collections; +} diff --git a/power-db/src/main/java/org/nanoboot/powerframework/db/engines/AbstractSqlEngine.java b/power-db/src/main/java/org/nanoboot/powerframework/db/engines/AbstractSqlEngine.java new file mode 100644 index 0000000..ce4d141 --- /dev/null +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/engines/AbstractSqlEngine.java @@ -0,0 +1,61 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.db.engines; + +import org.nanoboot.powerframework.core.PowerObject; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class AbstractSqlEngine extends PowerObject { + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private AbstractSqlEngine() { + } + + /** + * Constructor + * + * Constructor description + * + * @param nameIn + */ + public AbstractSqlEngine(String nameIn) { + this.name = nameIn; + } + + + + +} diff --git a/power-db/src/main/java/org/nanoboot/powerframework/db/engines/sqlite/.gitkeep b/power-db/src/main/java/org/nanoboot/powerframework/db/engines/sqlite/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/nanoboot/powerframework/database/SqlCommandQueue.java b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/CommandStore.java similarity index 65% rename from src/main/java/org/nanoboot/powerframework/database/SqlCommandQueue.java rename to power-db/src/main/java/org/nanoboot/powerframework/db/manager/CommandStore.java index e9e3a3d..e7b2963 100644 --- a/src/main/java/org/nanoboot/powerframework/database/SqlCommandQueue.java +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/CommandStore.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,18 +18,30 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import org.nanoboot.powerframework.collections.Queue; +import org.nanoboot.powerframework.collections.PowerQueue; /** * Used to execute more sql commands at once to achieve better performance. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class SqlCommandQueue { +public class CommandStore { - private final Queue queue = new Queue<>(); + private final PowerQueue queue = new PowerQueue<>(); + + public CommandStore() { + + } + + public CommandStore(String sqlCommands) { + String[] commandsArray = sqlCommands.split(";"); + for (String part : commandsArray) { + add(part); + } + } /** * Adds sql command. @@ -37,14 +49,14 @@ public class SqlCommandQueue { * @param command */ public void add(String command) { - this.queue.enqueue(command); + this.queue.add(command); } - String loadNextCommand() { - return this.queue.dequeue(); + String getNextCommand() { + return this.queue.poll(); } - boolean isThereANextCommand() { + boolean hasNextCommand() { return !this.queue.isEmpty(); } diff --git a/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Database.java b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Database.java new file mode 100644 index 0000000..dbada95 --- /dev/null +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Database.java @@ -0,0 +1,515 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.db.manager; + +import java.io.*; +import java.sql.*; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.nanoboot.powerframework.json.JsonArray; +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import static org.nanoboot.powerframework.utils.StringUtils.EMPTY_STRING; + +/** + * Represents connection to a database. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Database { + + private Connection connection = null; + private Statement statement = null; + private final String databaseName; + + private final String jdbcUrl; + + private static final String DOT_SQLITE = ".sqlite"; + + Database(String databaseName) { + this.databaseName = databaseName; + StringBuilder stringBuilder = new StringBuilder().append("jdbc:sqlite:"); + if(!databaseName.equals(EMPTY_STRING)) { + stringBuilder.append(databaseName).append(DOT_SQLITE).toString(); + } + this.jdbcUrl = stringBuilder.toString(); + } + + public UniversalDateTime backup() { + UniversalDateTime universalDateTime = UniversalDateTime.now(); + String dateTimeString = universalDateTime.toString().replace(":", " "); + File databaseFile = new File("." + File.separator + databaseName + DOT_SQLITE); + + File backupDatabaseFile = new File("." + File.separator + databaseFile.getName() + "." + dateTimeString + "." + "sqlitebackup"); + try { + copyFileUsingStream(databaseFile, backupDatabaseFile); + } catch (IOException ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + } + return universalDateTime; + } + + private static void copyFileUsingStream(File source, File dest) throws IOException { + InputStream is = null; + OutputStream os = null; + try { + is = new FileInputStream(source); + os = new FileOutputStream(dest); + byte[] buffer = new byte[1024]; + int length; + while ((length = is.read(buffer)) > 0) { + os.write(buffer, 0, length); + } + } finally { + is.close(); + os.close(); + } + } + + /** + * + * @return name of the database of this database connection + */ + public String getDatabaseName() { + return databaseName; + } + + private void setConnection() { + setConnection(false); + } + + private void setConnection(boolean foreignKeysOn) { + try { + Class.forName("org.sqlite.JDBC"); + connection = DriverManager.getConnection(jdbcUrl); + statement = connection.createStatement(); + if(foreignKeysOn) { + statement.execute("PRAGMA foreign_keys = ON;"); + } + } catch (ClassNotFoundException | SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } + } + + /** + * Executes sql command, which returns no result. + * + * @param command + * + * @return last inserted row id + */ + public int execute(String command) { + int lastInsertedRowId = 0; + setConnection(); + ResultSet resultSet = null; + try { + statement.executeUpdate(command); + resultSet = statement.executeQuery("SELECT last_insert_rowid() AS LASTINSERTEDROWID;"); + resultSet.next(); + lastInsertedRowId = resultSet.getInt(1); + resultSet.close(); + connection.close(); + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } finally { + if(resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + } + } + + } + System.err.println(command); + return lastInsertedRowId; + } + + /** + * Executes sql command, which returns no result. + * + * @param command + * + * @return last inserted row id + */ + public int executeWithForeingKeysOff(String command) { + int lastInsertedRowId = 0; + setConnection(false); + ResultSet resultSet = null; + try { + statement.executeUpdate(command); + resultSet = statement.executeQuery("SELECT last_insert_rowid() AS LASTINSERTEDROWID;"); + resultSet.next(); + lastInsertedRowId = resultSet.getInt(1); + resultSet.close(); + connection.close(); + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } finally { + if(resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + } + } + + } + System.err.println(command); + return lastInsertedRowId; + } + + /** + * Executes sql commands from the command queue. + * + * @param commandQueue + */ + public void executeMoreCommands(CommandStore commandQueue) { + setConnection(); + + try { + connection.setAutoCommit(false); + while (commandQueue.hasNextCommand()) { + String command = commandQueue.getNextCommand(); + System.err.println(command); + statement.executeUpdate(command); + + } + + //No changes has been made in the database yet, so now we will commit + //the changes. + connection.commit(); + } catch (SQLException ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + try { + //An error occured so we rollback the changes. + connection.rollback(); + } catch (SQLException ex1) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex1); + throw new DatabaseOperatingException("Fatal error happened. I was not able to rollback"); + } + } finally { + try { + if(statement != null) { + statement.close(); + connection.close(); + } + } catch (SQLException ex) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + /** + * Executes sql commands from the given String, which is split by ; + * character. + * + * @param commands + */ + public void executeMoreCommands(String commands) { + CommandStore commandQueue = new CommandStore(commands); + + this.executeMoreCommands(commandQueue); + } + + /** + * Executes sql command, which returns result. + * + * @param command + * + * @return + */ + public Table executeAndReturn(String command) { + JsonObject table = new JsonObject(); + + JsonArray columns = new JsonArray(); + JsonArray rows = new JsonArray(); + + table.addString("query", command); + table.addArray("columns", columns); + table.addArray("rows", rows); + + setConnection(); + ResultSet resultSet = null; + try { + resultSet = statement.executeQuery(command); + + ResultSetMetaData rsmd = resultSet.getMetaData(); + int columnCount = rsmd.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String columnName = rsmd.getColumnName(i); + columns.addString(columnName); + } + + while (resultSet.next()) { + JsonArray row = new JsonArray(); + for (int i = 0; i < columns.size(); i++) { + String columnName = columns.getString(i); + String value = resultSet.getString(columnName); + row.addString(value); + } + rows.addArray(row); + } + + connection.close(); + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } finally { + closeConnectionAndResultSet(resultSet); + } + System.err.println(command); + return new Table(table); + } + + public ArrayList executeAndReturnIds(String command, String idColumnName) { + Table table = executeAndReturn(command); + ArrayList list = new ArrayList<>(); + while (table.hasNextRow()) { + table.moveToTheNextRow(); + list.add(table.getString(idColumnName)); + } + + return list; + } + + private void closeConnectionAndResultSet(ResultSet resultSet) { + try { + if(resultSet != null) { + resultSet.close(); + } + if(!connection.isClosed()) { + connection.close(); + } + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } + } + + /** + * Updates value. + * + * @param tableName + * @param id + * @param columnName + * @param newValue + */ + public void updateValue(String tableName, + int id, + String columnName, + String newValue) { + String command + = "UPDATE " + tableName + " SET " + columnName + " = '" + newValue + "' WHERE ID = " + id; + this.execute(command); + System.err.println(command); + } + + /** + * Updates value. + * + * @param tableName + * @param id + * @param columnName + * @param newValue + */ + public void updateValue(String tableName, + int id, + String columnName, + int newValue) { + String command + = "UPDATE " + tableName + " SET " + columnName + " = " + newValue + " WHERE ID = " + id; + this.execute(command); + System.err.println(command); + } + + /** + * + * @param tableName + * @param id + * + * @return row with the given id from the given table as a json object + */ + public JsonObject getRow(String tableName, + int id) { + JsonObject row = new JsonObject(); + + JsonArray columns = new JsonArray(); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("select * from "); + stringBuilder.append(tableName); + stringBuilder.append(" where id="); + stringBuilder.append(id); + + String command = stringBuilder.toString(); + + setConnection(); + ResultSet resultSet = null; + try { + resultSet = statement.executeQuery(command); + System.err.println(command); + ResultSetMetaData rsmd = resultSet.getMetaData(); + int columnCount = rsmd.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String columnName = rsmd.getColumnName(i); + columns.addString(columnName); + } + + if(!resultSet.next()) { + throw new DatabaseOperatingException("There is no row with id " + id + " in table " + tableName); + } + + for (int i = 0; i < columns.size(); i++) { + String columnName = columns.getString(i); + String value = resultSet.getString(columnName); + row.addString(columnName, value); + } + + connection.close(); + } catch (SQLException | PowerException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + throw new IllegalStateException(); + } finally { + + try { + if(resultSet != null) { + resultSet.close(); + } + if(!connection.isClosed()) { + connection.close(); + } + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } + } + return row; + } + + public JsonObject getRow(String tableName, String uidIn) { + + JsonObject row = new JsonObject(); + + JsonArray columns = new JsonArray(); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("select * from "); + stringBuilder.append(tableName); + stringBuilder.append(" where UUID='"); + stringBuilder.append(uidIn); + stringBuilder.append("'"); + + String command = stringBuilder.toString(); + + setConnection(); + ResultSet resultSet = null; + try { + resultSet = statement.executeQuery(command); + System.err.println(command); + ResultSetMetaData rsmd = resultSet.getMetaData(); + int columnCount = rsmd.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + String columnName = rsmd.getColumnName(i); + columns.addString(columnName); + } + + if(!resultSet.next()) { + throw new DatabaseOperatingException("There is no row with uid " + uidIn + " in table " + tableName); + } + + for (int i = 0; i < columns.size(); i++) { + String columnName = columns.getString(i); + String value = resultSet.getString(columnName); + row.addString(columnName, value); + } + + connection.close(); + } catch (SQLException | PowerException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + throw new IllegalStateException(); + } finally { + + try { + if(resultSet != null) { + resultSet.close(); + } + if(!connection.isClosed()) { + connection.close(); + } + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } + } + return row; + } + + /** + * + * @param tableName + * + * @return true, if the table is empty, otherwise false. + */ + public boolean isTableEmpty(String tableName) { + Table resultOfSqlQuery = this.executeAndReturn("SELECT * FROM " + tableName); + return resultOfSqlQuery.isEmpty(); + } + + /** + * + * @param table table name + * @param column column name + * @param whereClause for example: year_of_birth is greater than 1995 + * + * @return String value from a table and first row + */ + public String getString(String table, + String column, + String whereClause) { + String command = "SELECT " + column + " FROM " + table + " WHERE " + whereClause; + String value = null; + + setConnection(); + ResultSet resultSet = null; + try { + resultSet = statement.executeQuery(command); + + if(resultSet.next()) { + value = resultSet.getString(column); + } + connection.close(); + } catch (SQLException e) { + Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); + } finally { + + closeConnectionAndResultSet(resultSet); + + } + System.err.println(command); + return value; + } + + public boolean existTable(String tableName) { + Table table = executeAndReturn("SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "'"); + return !table.isEmpty(); + } + +} diff --git a/power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseException.java b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseException.java new file mode 100644 index 0000000..3fc0af7 --- /dev/null +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseException.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.db.manager; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DatabaseException extends PowerException { + + public DatabaseException(String message) { + super(message); + } + +} diff --git a/power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseOperatingException.java b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseOperatingException.java new file mode 100644 index 0000000..4c693a8 --- /dev/null +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/DatabaseOperatingException.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.db.manager; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DatabaseOperatingException extends PowerException { + + public DatabaseOperatingException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/database/Database.java b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Databases.java similarity index 63% rename from src/main/java/org/nanoboot/powerframework/database/Database.java rename to power-db/src/main/java/org/nanoboot/powerframework/db/manager/Databases.java index 88654ff..97ace5c 100644 --- a/src/main/java/org/nanoboot/powerframework/database/Database.java +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Databases.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,56 +18,44 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.nanoboot.powerframework.PowerRuntimeException; +import java.io.*; +import java.sql.*; +import java.util.logging.*; /** * Manipulates with database. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class Database { +public class Databases { private static final String SQLITEEXTENSION = ".sqlite"; - /** - * Constructor - * - * Not meant to be instantiated. - */ - private Database() { - //Not meant to be instantiated. - } - /** * Creates new database with the given name. * * @param databaseName */ public static void createDatabase(String databaseName) { - if (existsDatabase(databaseName)) { - throw new PowerRuntimeException("A database with the given name already exists."); + if(existsDatabase(databaseName)) { + throw new DatabaseOperatingException("A database with the given name already exists."); } Connection connection = null; try { Class.forName("org.sqlite.JDBC"); connection = DriverManager.getConnection("jdbc:sqlite:" + convertDatabaseNameToFileName(databaseName)); - } catch (Exception e) { - Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, e); - throw new PowerRuntimeException("New database was not created."); + } catch (ClassNotFoundException | SQLException e) { + Logger.getLogger(Databases.class.getName()).log(Level.SEVERE, null, e); + throw new DatabaseOperatingException("New database was not created."); } finally { - if (connection != null) { + if(connection != null) { try { connection.close(); } catch (SQLException ex) { - Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(Databases.class.getName()).log(Level.SEVERE, null, ex); } } } @@ -79,18 +67,19 @@ public class Database { * @param databaseName */ public static void dropDatabase(String databaseName) { - if (!existsDatabase(databaseName)) { - throw new PowerRuntimeException("There is no database with the given name."); + if(!existsDatabase(databaseName)) { + throw new DatabaseOperatingException("There is no database with the given name."); } File file = new File("./" + convertDatabaseNameToFileName(databaseName)); boolean delete = file.delete(); - if (!delete) { - throw new PowerRuntimeException("The database was not dropped."); + if(!delete) { + throw new DatabaseOperatingException("The database was not dropped."); } } /** * @param databaseName + * * @return true, if a database with the name exists, otherwise false. */ public static boolean existsDatabase(String databaseName) { @@ -102,13 +91,14 @@ public class Database { * Creates a database connection for the database with the given name. * * @param databaseName + * * @return database connection to the database with the given name */ - public static DatabaseConnection createDatabaseConnection(String databaseName) { - if ((databaseName != "") && (!existsDatabase(databaseName))) { - throw new PowerRuntimeException("There is no database with the given name."); + public static Database getDatabase(String databaseName) { + if((!"".equals(databaseName)) && (!existsDatabase(databaseName))) { + throw new DatabaseOperatingException("There is no database with the given name."); } - return new DatabaseConnection(databaseName); + return new Database(databaseName); } /** @@ -116,12 +106,21 @@ public class Database { * * @return database connection */ - public static DatabaseConnection createInMemoryDatabaseConnection() { - return createDatabaseConnection(""); + public static Database createInMemoryDatabaseConnection() { + return getDatabase(""); } private static String convertDatabaseNameToFileName(String databaseName) { return databaseName + SQLITEEXTENSION; } + /** + * Constructor + * + * Not meant to be instantiated. + */ + private Databases() { + //Not meant to be instantiated. + } + } diff --git a/src/main/java/org/nanoboot/powerframework/database/ResultOfSqlQuery.java b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Table.java similarity index 80% rename from src/main/java/org/nanoboot/powerframework/database/ResultOfSqlQuery.java rename to power-db/src/main/java/org/nanoboot/powerframework/db/manager/Table.java index 254de5a..d507366 100644 --- a/src/main/java/org/nanoboot/powerframework/database/ResultOfSqlQuery.java +++ b/power-db/src/main/java/org/nanoboot/powerframework/db/manager/Table.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,26 +18,28 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.collections.Dictionary; -import org.nanoboot.powerframework.json.*; +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.json.JsonArray; +import org.nanoboot.powerframework.collections.PowerMap; /** * Represents the result of a sql query. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ -public class ResultOfSqlQuery { +public class Table { private final JsonObject table; private final JsonArray columns; private final JsonArray rows; private int currentRowIndex = -1; - private final Dictionary dictionaryOfColumnNamesIndexes = new Dictionary(); + private final PowerMap dictionaryOfColumnNamesIndexes = new PowerMap(); - ResultOfSqlQuery(JsonObject jsonObject) { + Table(JsonObject jsonObject) { this.table = jsonObject; this.columns = table.getArray("columns"); this.rows = table.getArray("rows"); @@ -45,9 +47,9 @@ public class ResultOfSqlQuery { } private void fillDictionaryOfColumnNamesIndexes() { - for (int i = 0; i < columns.getCountOfItems(); i++) { + for (int i = 0; i < columns.size(); i++) { String currentColumnName = columns.getString(i); - dictionaryOfColumnNamesIndexes.addValue(currentColumnName, i); + dictionaryOfColumnNamesIndexes.put(currentColumnName, i); } } @@ -72,7 +74,7 @@ public class ResultOfSqlQuery { * @return count of rows */ public int getCountOfRows() { - return rows.getCountOfItems(); + return rows.size(); } /** @@ -95,7 +97,7 @@ public class ResultOfSqlQuery { * @return true, if there is a row after the current row, otherwise false. */ public boolean hasNextRow() { - return currentRowIndex + 1 < this.rows.getCountOfItems(); + return currentRowIndex + 1 < this.rows.size(); } /** @@ -106,8 +108,8 @@ public class ResultOfSqlQuery { } private JsonArray getCurrentRow() { - if (currentRowIndex == -1) { - throw new PowerRuntimeException("The position of the current row is before the first row"); + if(currentRowIndex == -1) { + throw new DatabaseOperatingException("The position of the current row is before the first row"); } return rows.getArray(currentRowIndex); } @@ -121,12 +123,13 @@ public class ResultOfSqlQuery { } private int getIndexForTheColumn(String columnName) { - return this.dictionaryOfColumnNamesIndexes.getValue(columnName); + return this.dictionaryOfColumnNamesIndexes.get(columnName); } /** * * @param columnName + * * @return the value of the column of the current row as int */ public int getInt(String columnName) { @@ -137,6 +140,7 @@ public class ResultOfSqlQuery { /** * * @param columnName + * * @return the value of the column of the current row as double */ public double getDouble(String columnName) { @@ -147,6 +151,7 @@ public class ResultOfSqlQuery { /** * * @param columnName + * * @return the value of the column of the current row as String */ public String getString(String columnName) { diff --git a/power-db/src/main/resources/.gitkeep b/power-db/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-db/src/test/java/org/nanoboot/powerframework/db/engines/.gitkeep b/power-db/src/test/java/org/nanoboot/powerframework/db/engines/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/test/java/org/nanoboot/powerframework/database/SqlCommandQueueTest.java b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/CommandStoreTest.java similarity index 75% rename from src/test/java/org/nanoboot/powerframework/database/SqlCommandQueueTest.java rename to power-db/src/test/java/org/nanoboot/powerframework/db/manager/CommandStoreTest.java index 025c0b0..009c47c 100644 --- a/src/test/java/org/nanoboot/powerframework/database/SqlCommandQueueTest.java +++ b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/CommandStoreTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,18 +18,22 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import org.junit.Test; import static org.junit.Assert.*; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class SqlCommandQueueTest { - public SqlCommandQueueTest() { +@Ignore +public class CommandStoreTest { + + public CommandStoreTest() { } /** @@ -38,13 +42,13 @@ public class SqlCommandQueueTest { @Test public void testAdd() { //arrange - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + CommandStore sqlCommandQueue = new CommandStore(); String expectedString = "insert into customers values ('Jack','Black')"; String returnedString; //act sqlCommandQueue.add("insert into customers values ('Jack','Black')"); sqlCommandQueue.add("insert into customers values ('Susan','White')"); - returnedString = sqlCommandQueue.loadNextCommand(); + returnedString = sqlCommandQueue.getNextCommand(); //assert assertEquals(expectedString, returnedString); } @@ -55,14 +59,14 @@ public class SqlCommandQueueTest { @Test public void testLoadNextCommand() { //arrange - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + CommandStore sqlCommandQueue = new CommandStore(); String expectedString = "insert into customers values ('Susan','White')"; String returnedString; //act sqlCommandQueue.add("insert into customers values ('Jack','Black')"); sqlCommandQueue.add("insert into customers values ('Susan','White')"); - sqlCommandQueue.loadNextCommand(); - returnedString = sqlCommandQueue.loadNextCommand(); + sqlCommandQueue.getNextCommand(); + returnedString = sqlCommandQueue.getNextCommand(); //assert assertEquals(expectedString, returnedString); } @@ -73,13 +77,13 @@ public class SqlCommandQueueTest { @Test public void testIsThereANextCommand() { //arrange - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + CommandStore sqlCommandQueue = new CommandStore(); //act sqlCommandQueue.add("insert into customers values ('Jack','Black')"); sqlCommandQueue.add("insert into customers values ('Susan','White')"); - sqlCommandQueue.loadNextCommand(); + sqlCommandQueue.getNextCommand(); //assert - assertTrue(sqlCommandQueue.isThereANextCommand()); + assertTrue(sqlCommandQueue.hasNextCommand()); } /** @@ -88,14 +92,14 @@ public class SqlCommandQueueTest { @Test public void testIsThereANextCommand2() { //arrange - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + CommandStore sqlCommandQueue = new CommandStore(); //act sqlCommandQueue.add("insert into customers values ('Jack','Black')"); sqlCommandQueue.add("insert into customers values ('Susan','White')"); - sqlCommandQueue.loadNextCommand(); - sqlCommandQueue.loadNextCommand(); + sqlCommandQueue.getNextCommand(); + sqlCommandQueue.getNextCommand(); //assert - assertFalse(sqlCommandQueue.isThereANextCommand()); + assertFalse(sqlCommandQueue.hasNextCommand()); } /** @@ -104,8 +108,8 @@ public class SqlCommandQueueTest { @Test public void testToString() { //arrange - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); - String expectedString = "insert into customers values ('Jack','Black'), insert into customers values ('Susan','White'), "; + CommandStore sqlCommandQueue = new CommandStore(); + String expectedString = "insert into customers values ('Jack','Black'), insert into customers values ('Susan','White')"; String returnedString; //act sqlCommandQueue.add("insert into customers values ('Jack','Black')"); diff --git a/src/test/java/org/nanoboot/powerframework/database/DatabaseConnectionTest.java b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/DatabaseConnectionTest.java similarity index 78% rename from src/test/java/org/nanoboot/powerframework/database/DatabaseConnectionTest.java rename to power-db/src/test/java/org/nanoboot/powerframework/db/manager/DatabaseConnectionTest.java index 2864e48..53b2dff 100644 --- a/src/test/java/org/nanoboot/powerframework/database/DatabaseConnectionTest.java +++ b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/DatabaseConnectionTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,38 +18,40 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import java.io.File; import org.nanoboot.powerframework.json.JsonObject; - -import org.nanoboot.powerframework.pseudorandom.PseudoRandomGenerator; -import org.junit.AfterClass; -import org.junit.Test; +import java.io.*; import static org.junit.Assert.*; -import org.junit.BeforeClass; + +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + +@Ignore public class DatabaseConnectionTest { private static final File directory; private static final String directoryName; static { - PseudoRandomGenerator pseudoRandomGenerator = PseudoRandomGenerator.getInstance(); - int randomNumber = pseudoRandomGenerator.getInt(0, 999999); + W5RandomGenerator pseudoW5RandomGenerator = W5RandomGenerator.getStaticInstance(); + int randomNumber = pseudoW5RandomGenerator.nextInt(0, 999999); directoryName = "./temp" + randomNumber + "/"; directory = new File(directoryName); } static public boolean deleteDirectory(File path) { - if (path.exists()) { + if(path.exists()) { File[] files = path.listFiles(); for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { + if(files[i].isDirectory()) { deleteDirectory(files[i]); } else { files[i].delete(); @@ -68,7 +70,7 @@ public class DatabaseConnectionTest { } private String getNextDatabaseName() { - return Integer.toString(PseudoRandomGenerator.getInstance().getInt(0, 1000000)); + return Integer.toString(W5RandomGenerator.getStaticInstance().nextInt(0, 1000000)); } /** @@ -80,8 +82,8 @@ public class DatabaseConnectionTest { String databaseName = directoryName + getNextDatabaseName(); String expectedString = databaseName; String returnedString; - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); //act returnedString = databaseConnection.getDatabaseName(); //assert @@ -95,8 +97,8 @@ public class DatabaseConnectionTest { public void testExecute_String() { //arrange String databaseName = directoryName + getNextDatabaseName(); - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); databaseConnection.execute("create table customers(id integer,name text,surname text,yearofbirth integer)"); //act databaseConnection.execute("insert into customers values(1,'John','Green',1954);"); @@ -111,9 +113,9 @@ public class DatabaseConnectionTest { public void testExecute_SqlCommandQueue() { //arrange String databaseName = directoryName + getNextDatabaseName(); - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); + CommandStore sqlCommandQueue = new CommandStore(); sqlCommandQueue.add("create table customers(id integer,name text,surname text,yearofbirth integer)"); sqlCommandQueue.add("insert into customers values(1,'John','Green',1954);"); sqlCommandQueue.add("insert into customers values(2,'Anne','Blue',1985);"); @@ -132,9 +134,9 @@ public class DatabaseConnectionTest { public void testExecuteAndReturn() { //arrange String databaseName = directoryName + getNextDatabaseName(); - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); + CommandStore sqlCommandQueue = new CommandStore(); sqlCommandQueue.add("create table customers(id integer,name text,surname text,yearofbirth integer)"); sqlCommandQueue.add("insert into customers values(1,'John','Green',1954);"); sqlCommandQueue.add("insert into customers values(2,'Anne','Blue',1985);"); @@ -144,7 +146,7 @@ public class DatabaseConnectionTest { String expectedString = "{\"query\":\"select * from customers\",\"columns\":[\"id\",\"name\",\"surname\",\"yearofbirth\"],\"rows\":[[\"1\",\"John\",\"Green\",\"1954\"],[\"2\",\"Anne\",\"Blue\",\"1985\"],[\"3\",\"Peter\",\"Orange\",\"1990\"]]}"; String returnedString; - ResultOfSqlQuery resultOfSqlQuery; + Table resultOfSqlQuery; //act resultOfSqlQuery = databaseConnection.executeAndReturn(query); returnedString = resultOfSqlQuery.toJsonObject().toMinimalString(); @@ -159,9 +161,9 @@ public class DatabaseConnectionTest { public void testGetRow() { //arrange String databaseName = directoryName + getNextDatabaseName(); - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); + CommandStore sqlCommandQueue = new CommandStore(); sqlCommandQueue.add("create table customers(id integer,name text,surname text,yearofbirth integer)"); sqlCommandQueue.add("insert into customers values(1,'John','Green',1954);"); sqlCommandQueue.add("insert into customers values(2,'Anne','Blue',1985);"); @@ -187,9 +189,9 @@ public class DatabaseConnectionTest { //arrange String databaseName = directoryName + getNextDatabaseName(); boolean returnedValue; - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); + CommandStore sqlCommandQueue = new CommandStore(); sqlCommandQueue.add("create table customers(id integer,name text,surname text,yearofbirth integer)"); databaseConnection.executeMoreCommands(sqlCommandQueue); //act @@ -207,9 +209,9 @@ public class DatabaseConnectionTest { //arrange String databaseName = directoryName + getNextDatabaseName(); boolean returnedValue; - Database.createDatabase(databaseName); - DatabaseConnection databaseConnection = Database.createDatabaseConnection(databaseName); - SqlCommandQueue sqlCommandQueue = new SqlCommandQueue(); + Databases.createDatabase(databaseName); + Database databaseConnection = Databases.getDatabase(databaseName); + CommandStore sqlCommandQueue = new CommandStore(); sqlCommandQueue.add("create table customers(id integer,name text,surname text,yearofbirth integer)"); sqlCommandQueue.add("insert into customers values(1,'John','Green',1954);"); sqlCommandQueue.add("insert into customers values(2,'Anne','Blue',1985);"); diff --git a/src/test/java/org/nanoboot/powerframework/database/DatabaseTest.java b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/DatabaseTest.java similarity index 68% rename from src/test/java/org/nanoboot/powerframework/database/DatabaseTest.java rename to power-db/src/test/java/org/nanoboot/powerframework/db/manager/DatabaseTest.java index 3fef910..8cc7bed 100644 --- a/src/test/java/org/nanoboot/powerframework/database/DatabaseTest.java +++ b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/DatabaseTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,37 +18,38 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import java.io.File; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.pseudorandom.PseudoRandomGenerator; -import org.junit.AfterClass; -import org.junit.Test; +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; +import org.nanoboot.powerframework.core.PowerException; +import java.io.*; import static org.junit.Assert.*; -import org.junit.BeforeClass; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class DatabaseTest { private static final File directory; private static final String directoryName; static { - PseudoRandomGenerator pseudoRandomGenerator = PseudoRandomGenerator.getInstance(); - int randomNumber = pseudoRandomGenerator.getInt(0, 999999); + W5RandomGenerator pseudoW5RandomGenerator = W5RandomGenerator.getStaticInstance(); + int randomNumber = pseudoW5RandomGenerator.nextInt(0, 999999); directoryName = "./temp" + randomNumber + "/"; directory = new File(directoryName); } static public boolean deleteDirectory(File path) { - if (path.exists()) { + if(path.exists()) { File[] files = path.listFiles(); for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { + if(files[i].isDirectory()) { deleteDirectory(files[i]); } else { files[i].delete(); @@ -67,7 +68,7 @@ public class DatabaseTest { } private String getNextDatabaseName() { - return Integer.toString(PseudoRandomGenerator.getInstance().getInt(0, 1000000)); + return Integer.toString(W5RandomGenerator.getStaticInstance().nextInt(0, 1000000)); } /** @@ -78,7 +79,7 @@ public class DatabaseTest { //arrange String databaseName = directoryName + getNextDatabaseName(); //act - Database.createDatabase(databaseName); + Databases.createDatabase(databaseName); //assert assertTrue(new File(databaseName + ".sqlite").exists()); } @@ -92,15 +93,15 @@ public class DatabaseTest { boolean isExceptionThrown = false; String databaseName = directoryName + getNextDatabaseName(); //act - Database.createDatabase(databaseName); + Databases.createDatabase(databaseName); try { - Database.createDatabase(databaseName); - } catch (PowerRuntimeException e) { + Databases.createDatabase(databaseName); + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); + if(!isExceptionThrown) { + fail("There should be thrown OkayRuntimeException"); } } @@ -111,11 +112,11 @@ public class DatabaseTest { public void testDropDatabase() { //arrange String databaseName = directoryName + getNextDatabaseName(); - Database.createDatabase(databaseName); + Databases.createDatabase(databaseName); //act - Database.dropDatabase(databaseName); + Databases.dropDatabase(databaseName); //assert - assertFalse(Database.existsDatabase(databaseName)); + assertFalse(Databases.existsDatabase(databaseName)); } /** @@ -128,13 +129,13 @@ public class DatabaseTest { String databaseName = directoryName + getNextDatabaseName(); //act try { - Database.dropDatabase(databaseName); - } catch (PowerRuntimeException e) { + Databases.dropDatabase(databaseName); + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); + if(!isExceptionThrown) { + fail("There should be thrown OkayRuntimeException"); } } @@ -142,13 +143,13 @@ public class DatabaseTest { * Test of existsDatabaseWithThisName method, of class Database. */ @Test - public void testExistsDatabaseWithThisName() { + public void testExistsDatabase() { //arrange String databaseName = directoryName + getNextDatabaseName(); //act - Database.createDatabase(databaseName); + Databases.createDatabase(databaseName); //assert - assertTrue(Database.existsDatabase(databaseName)); + assertTrue(Databases.existsDatabase(databaseName)); } /** @@ -160,7 +161,7 @@ public class DatabaseTest { String databaseName = directoryName + getNextDatabaseName(); //act //assert - assertFalse(Database.existsDatabase(databaseName)); + assertFalse(Databases.existsDatabase(databaseName)); } /** @@ -172,15 +173,15 @@ public class DatabaseTest { boolean isExceptionThrown = false; String databaseName = directoryName + getNextDatabaseName(); //act - Database.createDatabase(databaseName); + Databases.createDatabase(databaseName); try { - Database.createDatabaseConnection(databaseName); - } catch (PowerRuntimeException e) { + Databases.getDatabase(databaseName); + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { - fail("There should be thrown no PowerRuntimeException"); + if(isExceptionThrown) { + fail("There should be thrown no OkayRuntimeException"); } } @@ -194,13 +195,13 @@ public class DatabaseTest { String databaseName = directoryName + getNextDatabaseName(); //act try { - Database.createDatabaseConnection(databaseName); - } catch (PowerRuntimeException e) { + Databases.getDatabase(databaseName); + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); + if(!isExceptionThrown) { + fail("There should be thrown OkayRuntimeException"); } } diff --git a/src/test/java/org/nanoboot/powerframework/database/ResultOfSqlQueryTest.java b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/TableTest.java similarity index 87% rename from src/test/java/org/nanoboot/powerframework/database/ResultOfSqlQueryTest.java rename to power-db/src/test/java/org/nanoboot/powerframework/db/manager/TableTest.java index 2be8cf6..df49c44 100644 --- a/src/test/java/org/nanoboot/powerframework/database/ResultOfSqlQueryTest.java +++ b/power-db/src/test/java/org/nanoboot/powerframework/db/manager/TableTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,18 +18,21 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.database; +package org.nanoboot.powerframework.db.manager; -import org.nanoboot.powerframework.json.JsonArray; import org.nanoboot.powerframework.json.JsonObject; -import org.junit.Test; +import org.nanoboot.powerframework.json.JsonArray; import static org.junit.Assert.*; +import org.junit.*; /** * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ -public class ResultOfSqlQueryTest { +@Ignore +public class TableTest { private static final String jsonObjectAsString; @@ -59,7 +62,7 @@ public class ResultOfSqlQueryTest { jsonObjectAsString = jsonObject.toMinimalString(); } - public ResultOfSqlQueryTest() { + public TableTest() { } /** @@ -83,7 +86,7 @@ public class ResultOfSqlQueryTest { public void testGetColumnNames() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = "[\"id\",\"name\",\"surname\",\"yearofbirth\"]"; String returnedString; //act @@ -99,7 +102,7 @@ public class ResultOfSqlQueryTest { public void testGetRows() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = "[[\"1\",\"John\",\"Green\",\"1954\"],[\"2\",\"Anne\",\"Blue\",\"1985\"],[\"3\",\"Peter\",\"Orange\",\"1990\"]]"; String returnedString; //act @@ -115,7 +118,7 @@ public class ResultOfSqlQueryTest { public void testGetCountOfRows() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); int expectedValue = 3; int returnedValue; //act @@ -131,7 +134,7 @@ public class ResultOfSqlQueryTest { public void testIsEmpty() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); boolean returnedValue; //act returnedValue = resultOfSqlQuery.isEmpty(); @@ -146,7 +149,7 @@ public class ResultOfSqlQueryTest { public void testResetPosition() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = "[\"1\",\"John\",\"Green\",\"1954\"]"; String returnedString; //act @@ -166,7 +169,7 @@ public class ResultOfSqlQueryTest { public void testHasNextRow() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); boolean returnedValue; //act returnedValue = resultOfSqlQuery.hasNextRow(); @@ -181,7 +184,7 @@ public class ResultOfSqlQueryTest { public void testHasNextRow2() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); resultOfSqlQuery.moveToTheNextRow(); boolean returnedValue; //act @@ -197,7 +200,7 @@ public class ResultOfSqlQueryTest { public void testHasNextRow3() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); resultOfSqlQuery.moveToTheNextRow(); resultOfSqlQuery.moveToTheNextRow(); resultOfSqlQuery.moveToTheNextRow(); @@ -215,7 +218,7 @@ public class ResultOfSqlQueryTest { public void testMoveToTheNextRow() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = "[\"2\",\"Anne\",\"Blue\",\"1985\"]"; String returnedString; //act @@ -233,7 +236,7 @@ public class ResultOfSqlQueryTest { public void testGetInt() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); int expectedValue = 1985; int returnedValue; //act @@ -251,7 +254,7 @@ public class ResultOfSqlQueryTest { public void testGetDouble() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); double expectedValue = 1985d; double returnedValue; //act @@ -269,7 +272,7 @@ public class ResultOfSqlQueryTest { public void testGetString() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = "Anne"; String returnedString; //act @@ -287,7 +290,7 @@ public class ResultOfSqlQueryTest { public void testGetQuery() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = "select * from customers"; String returnedString; //act @@ -303,7 +306,7 @@ public class ResultOfSqlQueryTest { public void testToJsonObject() { //arrange JsonObject jsonObject = new JsonObject(jsonObjectAsString); - ResultOfSqlQuery resultOfSqlQuery = new ResultOfSqlQuery(jsonObject); + Table resultOfSqlQuery = new Table(jsonObject); String expectedString = jsonObjectAsString; String returnedString; //act diff --git a/power-io/pom.xml b/power-io/pom.xml new file mode 100644 index 0000000..e1cbc8c --- /dev/null +++ b/power-io/pom.xml @@ -0,0 +1,68 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-io + jar + + Power IO + IO functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-random + ${power.version} + + + org.nanoboot.powerframework + power-collections + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + junit + junit + 4.12 + test + + + + diff --git a/power-io/src/main/java/module-info.java b/power-io/src/main/java/module-info.java new file mode 100644 index 0000000..a65516b --- /dev/null +++ b/power-io/src/main/java/module-info.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.io { + requires powerframework.core; + requires powerframework.random; + requires powerframework.collections; + requires powerframework.log; + requires java.logging; + requires powerframework.utils; + exports org.nanoboot.powerframework.io.bit.base64; +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/Blob.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/Blob.java new file mode 100644 index 0000000..41dc4f3 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/Blob.java @@ -0,0 +1,228 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit; + +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Blob { + + private final byte[] byteArray; +//TODO will hold byte[], but will have methods to set, update, flip, or read every bit of this blob, for example there will be a request to set the fourt bit of the twentieth byte to true (1) + + /** + * + * @param byteArrayIn + */ + public Blob(byte[] byteArrayIn) { + this.byteArray = byteArrayIn; + } + + public Blob(int countOfBytes) { + this.byteArray = new byte[countOfBytes]; + fillAllByZeroes(); + } + + /** + * + * @param string The required format are only zeroes and ones. Example: "01011101110100011001111" + */ + public Blob(String string) { + this(string.length() / 8); + int bitPosition = 0; + for (char element : string.toCharArray()) { + if(!(element == '1' || element == '0')) { + throw new PowerException("The string must contain only characters 0 or 1. " + "The character " + element + " does not follow this rule."); + } + this.setBits(bitPosition++, new boolean[]{element == '1'}); + + } + } + + public Blob(Blob... blobs) { + int countOfBytes = 0; + for (Blob blob : blobs) { + countOfBytes = +blob.getCountOfBytes(); + } + this.byteArray = new byte[countOfBytes]; + int index = 0; + for (Blob blob : blobs) { + for (int j = 0; j < blob.getCountOfBytes(); j++) { + this.byteArray[index++] = Byte.booleanArrayToByte(blob.getByte(j)); + } + } + + fillAllByZeroes(); + } + + public int getCountOfBytes() { + return this.byteArray.length; + } + + public int getCountOfBits() { + return this.byteArray.length * 8; + } + + public void fillAllByZeroes() { + fillWith(false, 0, this.byteArray.length - 1); + } + + public void fillAllByOnes() { + fillWith(true, 0, this.byteArray.length - 1); + } + + public void fillWith(boolean value, int byteFrom, int byteTo) { + byte booleanArray = Byte.booleanArrayToByte(value, value, value, value, value, value, value, value); + for (int i = byteFrom; i <= byteTo; i++) { + this.byteArray[i] = booleanArray; + } + } + + public void fillRandom() { + fillRandom(0, this.byteArray.length - 1); + + } + + public void fillRandom(int byteFrom, int byteTo) { + boolean[] booleanArray; + W5RandomGenerator pseudoW5RandomGenerator = W5RandomGenerator.getStaticInstance(); + for (int i = byteFrom; i <= byteTo; i++) { + + booleanArray = new boolean[8]; + for (int j = 0; j < 8; j++) { + booleanArray[j] = pseudoW5RandomGenerator.nextBoolean(); + } + + byte byteValue = Byte.booleanArrayToByte(booleanArray);; + this.byteArray[i] = byteValue; + } + + } + + public void flopAll() { + flop(0, this.byteArray.length - 1); + + } + + public void flop(int byteFrom, int byteTo) { + for (int bytePosition = byteFrom; bytePosition <= byteTo; bytePosition++) { + byte byteValue = this.byteArray[bytePosition]; + System.out.println("byteValue=" + byteValue); + boolean[] booleanArray = Byte.byteValueToBooleanArray(byteValue); + booleanArray = flopBooleanArray(booleanArray); + System.out.println("!byteValue=" + byteValue); + byteValue = Byte.booleanArrayToByte(booleanArray); + this.byteArray[bytePosition] = byteValue; + } + + } + + public static boolean[] flopBooleanArray(boolean[] booleanArray) { + for (int i = 0; i < booleanArray.length; i++) { + booleanArray[i] = !booleanArray[i]; + } + return booleanArray; + } + + public boolean[] getByte(int bytePosition) { + return Byte.byteValueToBooleanArray(this.byteArray[bytePosition]); + } + + public void setByte(int bytePosition, boolean[] booleanArray) { + this.byteArray[bytePosition] = Byte.booleanArrayToByte(booleanArray); + } + + public boolean[] getBits(int startBit, int endBit) { + boolean[] booleanArray = new boolean[endBit - startBit + 1]; + int booleanArrayIndex = 0; + int startBitDividedByEight = ((int) (startBit / 8)); + int startByte = startBitDividedByEight - 1; + if(startByte < 0) { + startByte = 0; + } + for (int bytePosition = startByte; booleanArrayIndex < (endBit - startBit + 1); bytePosition++) { + int bitPosition = bytePosition * 8; + byte byteValue = this.byteArray[bytePosition]; + boolean[] booleanArrayOfByte = Byte.byteValueToBooleanArray(byteValue); + for (int j = 0; j < 8; j++) { + boolean booleanValue = booleanArrayOfByte[j]; + + if(bitPosition >= startBit && bitPosition <= endBit) { + booleanArray[booleanArrayIndex++] = booleanValue; + } + bitPosition++; + } + } + return booleanArray; + } + + public void setBits(int startBit, boolean[] bitsToSetArray) { + int endBit = startBit + bitsToSetArray.length - 1; + int booleanArrayIndex = 0; + int startBitDividedByEight = ((int) (startBit / 8)); + int startByte = startBitDividedByEight - 1; + if(startByte < 0) { + startByte = 0; + } + for (int bytePosition = startByte; bytePosition < this.byteArray.length && booleanArrayIndex < bitsToSetArray.length; bytePosition++) { + int bitPosition = bytePosition * 8; + byte byteValue = this.byteArray[bytePosition]; + boolean[] booleanArrayOfByte = Byte.byteValueToBooleanArray(byteValue); + for (int j = 0; j < 8; j++) { + + if(bitPosition >= startBit && bitPosition <= endBit) { + boolean booleanValue = bitsToSetArray[booleanArrayIndex++]; +// System.out.println(booleanValue); + booleanArrayOfByte[j] = booleanValue; + } +// System.out.println(bitPosition); + bitPosition++; + this.byteArray[bytePosition] = Byte.booleanArrayToByte(booleanArrayOfByte); + } + } + } + + public boolean getBit(int bitPosition) { + return getBits(bitPosition, bitPosition)[0]; + } + + public void setBit(int bitPosition, boolean value) { + setBits(bitPosition, new boolean[]{value}); + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + for (byte byteValue : this.byteArray) { + for (boolean booleanValue : Byte.byteValueToBooleanArray(byteValue)) { + stringBuilder.append(booleanValue ? "1" : "0"); + } + } + return stringBuilder.toString(); + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/Byte.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/Byte.java new file mode 100644 index 0000000..cb3c68a --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/Byte.java @@ -0,0 +1,74 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Byte { + + public static byte booleanArrayToByte(boolean... booleanArray) { + final int TWO = 2; + byte byteValue = -128; + int exponent = 0; + for (int i = booleanArray.length - 1; i >= 0; i--) { + int booleanAsInt = booleanArray[i] ? 1 : 0; + byteValue = (byte) (byteValue + (booleanAsInt * Math.pow(TWO, exponent))); + exponent++; + } + return byteValue; + } + + /** + * Convert a byte array to a boolean array. Bit 0 is represented with false, + * Bit 1 is represented with 1 + * + * @param bytes byte[] + * + * @return boolean[] + */ + private static boolean[] byteArrayToBooleanArray(byte[] bytes) { + boolean[] bits = new boolean[bytes.length * 8]; + for (int i = 0; i < bytes.length * 8; i++) { + if(((bytes[i / 8] + 128) & (1 << (7 - (i % 8)))) > 0) { + bits[i] = true; + } + } + return bits; + } + + /** + * Convert a byte array to a boolean array. Bit 0 is represented with false, + * Bit 1 is represented with 1 + * + * @param byteValueIn + * + * @return boolean[] + */ + public static boolean[] byteValueToBooleanArray(byte byteValueIn) { + return byteArrayToBooleanArray(new byte[]{byteValueIn}); + } + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/DigitalInformationUnit.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/DigitalInformationUnit.java new file mode 100644 index 0000000..6668220 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/DigitalInformationUnit.java @@ -0,0 +1,127 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum DigitalInformationUnit { + + /** + * + */ + BIT(null, 1), + + /** + * + */ + BYTE(BIT, 8), + + /** + * + */ + KILOBYTE(BYTE), + + /** + * + */ + MEGABYTE(KILOBYTE), + + /** + * + */ + GIGABYTE(MEGABYTE), + + /** + * + */ + TERABYTE(GIGABYTE), + + /** + * + */ + PETABYTE(TERABYTE), + + /** + * + */ + EXABYTE(PETABYTE); + private static final int CONSTANT1024 = 1024; + private static final int BYTEHASBYTES = 8; + private final long bits; + private final DigitalInformationUnit subordinateUnit; + //TODO + //private final DigitalInformationUnit superiorUnit; + + DigitalInformationUnit(DigitalInformationUnit subordinateUnit, + int bits) { + this.subordinateUnit = subordinateUnit; + this.bits = bits; + } + + DigitalInformationUnit(DigitalInformationUnit subordinateUnit) { + this.subordinateUnit = subordinateUnit; + this.bits = subordinateUnit.getBits() * CONSTANT1024; + } + + /** + * + * @return count of bits of the given unit + */ + public long getBits() { + return bits; + } + + /** + * + * @return count of bytes of the given unit + */ + public long getBytes() { + return bits / BYTEHASBYTES; + } + + /** + * + * @return subordinate unit of this unit. Example KiloByte has subordinate unit Byte. + */ + public DigitalInformationUnit getSubordinateUnit() { + return subordinateUnit; + } + + /** + * + * @param value count of input unit + * @param inputUnit input unit + * @param outputUnit output unit + * + * @return count of output unit + */ + public static long convert(long value, + DigitalInformationUnit inputUnit, + DigitalInformationUnit outputUnit) { + return 0; + //TODO + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/TextCoder.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/TextCoder.java new file mode 100644 index 0000000..7c35ab1 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/TextCoder.java @@ -0,0 +1,291 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit; + +/* + * + * + * tab + * breakline + * upper letter + * unicode one char start + * unicode start + * unicode end + * ! + * " + * # + * $ + * % + * ' + * + * + + * , + * . + * / + * 0 + * 1 + * 2 + * 3 + * 4 + * 5 + * 6 + * 7 + * 8 + * 9 + * : + * < + * = + * ? + * @ + * a + * b + * c + * d + * e + * f + * g + * h + * i + * j + * k + * l + * m + * n + * o + * p + * q + * r + * s + * t + * u + * v + * w + * x + * y + * z + * ~ + * ( + * { + * { + * _ + * Reverse + * +- + * /\ + * () + * [] + * {} + * <> + * |_ + * ~^ + * %& + * :; + * '` + * + * + * tab + * breakline + * upper letter + * unicode one char start + * unicode start + * unicode end + * ! + * " + * # + * $ + * % + * & + * ' + * + * + + * , + * - + * . + * / + * 0 + * 1 + * 2 + * 3 + * 4 + * 5 + * 6 + * 7 + * 8 + * 9 + * : + * ; + * < + * = + * > + * ? + * @ + * \ + * a + * b + * c + * d + * e + * f + * g + * h + * i + * j + * k + * l + * m + * n + * o + * p + * q + * r + * s + * t + * u + * v + * w + * x + * y + * z + * Extension + * ` + * ~ + * ^ + * ( + * ) + * { + * } + * { + * } + * _ + * | + * + * + */ + /* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + + +import org.nanoboot.powerframework.core.exceptions.NotYetImplementedException; +import org.nanoboot.powerframework.core.PowerObject; +import org.nanoboot.powerframework.core.PowerException; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class TextCoder extends PowerObject { + + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + private static final String ALPHABET = "1234567890abcdefghijklmnopqrstuvwxyz!?\"'#$%+*,./:<=@~({{_"; + private static final char[] charArray = ALPHABET.toCharArray(); + + public static Blob encode(String string) { + return null; + } + + public static String decode(Blob blob) { + return null; + } + + private static boolean[] charToBooleanArray(char charIn) { + for (int i = 0; i < charArray.length; i++) { + char value = charArray[i]; + if(value == charIn) { + int intValue = i + 1; + String binaryString = String.format("%60s", Integer.toBinaryString(intValue)); + boolean[] returnValue = new boolean[6]; + for (int j = 0; j < 6; j++) { + returnValue[j] = binaryString.charAt(j) == '1'; + } + return returnValue; + } + } + throw new PowerException("Char " + charIn + " was not found."); + } + +// private static boolean[] booleanArrayToChar(boolean[] booleanArrayIn) { +// for (int i = 0; i < charArray.length; i++) { +// char value = charArray[i]; +// if(value == charIn) { +// int intValue = i + 1; +// String binaryString = String.format("%60s", Integer.toBinaryString(intValue)); +// boolean[] returnValue = new boolean[6]; +// for (int j = 0; j < 6; j++) { +// returnValue[j] = binaryString.charAt(j) == '1'; +// } +// return returnValue; +// } +// } +// throw new DataStoringException("Char " + charIn + " was not found."); +// } + /** + * Constructor + * + * Not meant to be instantiated. + */ + private TextCoder() { + } + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + * / + * private TextCoder() { + * } + * + * /** + * Constructor + * + * Constructor description + * + * @param nameIn + */ + public TextCoder(String nameIn) { + this.name = nameIn; + } + + + @Override + public String toString() { + throw new NotYetImplementedException("toString"); + /** + * LOG.traceStartOfMethod(this, "toString"); + * return NAMEFIELD+"="+name; + */ + } + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Coder.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Coder.java new file mode 100644 index 0000000..88567dd --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Coder.java @@ -0,0 +1,86 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Base64Coder { + + private static Base64Implementation BASE64_IMPLEMENTATION = Base64Implementation.JAVA; + + static { + //setBase64Implementation(Base64Implementation.JAVA); + } + + /** + * + * @param encodedDataIn + * + * @return + */ + public static byte[] decode(String encodedDataIn) { + switch (BASE64_IMPLEMENTATION) { + case OKAY: + return OkayBase64Decoder.decode(encodedDataIn); + case JAVA: + return JavaBase64Coder.decode(encodedDataIn); + default: { + throw new PowerException("Unknown Base64Implementation " + BASE64_IMPLEMENTATION.name() + "."); + } + } + } + + /** + * + * @param byteArrayIn + * + * @return + */ + public static String encode(byte[] byteArrayIn) { + switch (BASE64_IMPLEMENTATION) { + case OKAY: + return OkayBase64Encoder.encode(byteArrayIn); + case JAVA: + return JavaBase64Coder.encode(byteArrayIn); + default: { + throw new PowerException("Unknown Base64Implementation " + BASE64_IMPLEMENTATION.name() + "."); + } + } + + } + + public static Base64Implementation getBase64Implementation() { + return BASE64_IMPLEMENTATION; + } + + public static void setBase64Implementation( + Base64Implementation base64Implementation) { + Base64Coder.BASE64_IMPLEMENTATION = base64Implementation; + } + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Convertor.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Convertor.java new file mode 100644 index 0000000..c984d15 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Convertor.java @@ -0,0 +1,63 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.io.bit.Byte; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class Base64Convertor { + + private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + + static char byteToChar(byte byteValue) { + return ALPHABET[byteValue + 128]; + } + + static boolean[] convertCharToBooleanArray(char charIn) { + byte byteValue = charToByte(charIn); + return Byte.byteValueToBooleanArray(byteValue); + } + + private static byte charToByte(char charIn) { + if(charIn == '=') { + return 0; + } + int index = 0; + for (char element : ALPHABET) { + if(element == charIn) { +// System.out.println(charIn+" converted to "+(index)); + return (byte) (index - 128); + } + index++; + } + + throw new PowerException( + "There is no char: " + charIn); + } + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Implementation.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Implementation.java new file mode 100644 index 0000000..6f11f17 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Implementation.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum Base64Implementation { + + OKAY, + JAVA, + STACKOVERFLOW; +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Padding.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Padding.java new file mode 100644 index 0000000..e3cd0a4 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/Base64Padding.java @@ -0,0 +1,88 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +enum Base64Padding { + + NO(""), + ONEBYTE("=="), + TWOBYTE("="); + + private final String padding; + + Base64Padding(String paddingIn) { + this.padding = paddingIn; + } + + public String getPadding() { + return padding; + } + + static Base64Padding getBase64Padding(byte[] byteArrayIn) { + int byteArrayInLength = byteArrayIn.length; + switch (byteArrayInLength % 3) { + case 0: { + return NO; + } + case 1: { + return ONEBYTE; + } + case 2: { + return TWOBYTE; + } + default: { + throw new PowerException("getPadding method: switch command went to default section. "); + } + } + } + + static Base64Padding getBase64Padding(String encodedData) { + if(org.nanoboot.powerframework.utils.StringUtils.isEmpty(encodedData)) { + return NO; + }; + boolean lastCharIsEqual = encodedData.charAt(encodedData.length() - 1) == '='; + + boolean beforeLastCharIsEqual = encodedData.charAt(encodedData.length() - 1 - 1) == '='; + + if(lastCharIsEqual) { + if(beforeLastCharIsEqual) { + return ONEBYTE; + } else { + return TWOBYTE; + } + } else { + if(beforeLastCharIsEqual) { + throw new PowerException("The last character is not \"=\", but the before last is."); + } else { + return NO; + } + } + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/JavaBase64Coder.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/JavaBase64Coder.java new file mode 100644 index 0000000..20b7cf7 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/JavaBase64Coder.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +import java.util.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class JavaBase64Coder { + + /** + * + * @param encodedDataIn + * + * @return + */ + static byte[] decode(String encodedDataIn) { + return Base64.getDecoder().decode(encodedDataIn); + } + + /** + * + * @param byteArrayIn + * + * @return + */ + static String encode(byte[] byteArrayIn) { + return Base64.getEncoder().encodeToString(byteArrayIn); + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Decoder.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Decoder.java new file mode 100644 index 0000000..21d971c --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Decoder.java @@ -0,0 +1,132 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +import java.util.Arrays; +import org.nanoboot.powerframework.collections.PowerQueue; +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.io.bit.Byte; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class OkayBase64Decoder { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(OkayBase64Decoder.class); + + /** + * + * @param encodedDataIn + * + * @return + */ + public static byte[] decode(String encodedDataIn) { + LOG.traceStartOfMethod(null, "decode", "encodedDataIn", encodedDataIn); + if(encodedDataIn.length() % 4 != 0) { + throw new PowerException("The string length is " + encodedDataIn.length() + ". This length is not divisible four and it must be."); + } + String encodedData = encodedDataIn; + Base64Padding base64Padding = Base64Padding.getBase64Padding(encodedData); + int byteArrayLength = getByteArrayLength(encodedDataIn, base64Padding); + System.out.println("byteArrayLength=" + byteArrayLength); + byte[] byteArray = new byte[byteArrayLength]; + + PowerQueue bitQueue = new PowerQueue<>(); + processChars(byteArray, encodedData, bitQueue); + + return byteArray; + } + + private static int getByteArrayLength(String encodedDataIn, + Base64Padding base64Padding) { + LOG.traceStartOfMethod(null, "getByteArrayLength", "encodedDataIn", encodedDataIn, "base64Padding", base64Padding); + int stringLength = encodedDataIn.length(); + int byteArrayLength = stringLength / 4 * 3; + switch (base64Padding) { + case NO: { + return byteArrayLength; + } + case ONEBYTE: { + return byteArrayLength - 2; + } + case TWOBYTE: { + return byteArrayLength - 1; + } + default: { + throw new PowerException("Unknown Base64Padding " + base64Padding.name() + "."); + } + } + } + + private static void processChars(byte[] byteArray, + String encodedDataIn, + PowerQueue bitQueue) { + LOG.traceStartOfMethod(null, "processChars", "encodedDataIn", encodedDataIn, "bitQueue", bitQueue); + int byteArrayIndex = 0; + for (int i = 0; i < encodedDataIn.length(); i++) { + if(i % 100000 == 0) { + System.out.println(i + "/" + encodedDataIn.length()); + } + char charValue = encodedDataIn.charAt(i); + processChar(charValue, bitQueue); + byteArrayIndex = feedQueue(byteArray, byteArrayIndex, bitQueue); + } + } + + private static void processChar(char charValue, + PowerQueue bitQueue) { + LOG.traceStartOfMethod(null, "processChar", "charValue", charValue, "bitQueue", bitQueue.toString()); +// System.out.println("processChar " + charValue); + +// System.out.println(charValue + " transformed to " + sixBits.toString()); +// System.out.println("sixBits for "+charValue+":" + sixBits.toString()); + boolean[] booleanArray = Base64Convertor.convertCharToBooleanArray(charValue); + for (int j = 2; j < 8; j++) { + boolean element = booleanArray[j]; +// System.out.println("to queue added: " + element); + bitQueue.add(element); + } + } + + private static int feedQueue(byte[] byteArray, + int startByteArrayIndex, + PowerQueue bitQueue) { + LOG.traceStartOfMethod(null, "feedQueue", "byteArray", Arrays.asList(byteArray).toString(), "bitQueue", bitQueue.toString()); + int index = startByteArrayIndex; + while (index < byteArray.length && bitQueue.size() >= 8) { + + boolean[] booleanArray = new boolean[]{bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll()}; +// System.out.println("feeding with "+(byteInstance.getByteValue()+128)); + byteArray[index] = (byte) (Byte.booleanArrayToByte(booleanArray) + 128); + index++; + + } + startByteArrayIndex = index; + return startByteArrayIndex; + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Encoder.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Encoder.java new file mode 100644 index 0000000..41bc5b8 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/OkayBase64Encoder.java @@ -0,0 +1,87 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit.base64; + +import org.nanoboot.powerframework.collections.PowerQueue; +import org.nanoboot.powerframework.io.bit.Byte; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +class OkayBase64Encoder { + + /** + * + * @param byteArrayIn + * + * @return + */ + public static String encode(byte[] byteArrayIn) { + StringBuilder stringBuilder = new StringBuilder(); + Base64Padding base64Padding = Base64Padding.getBase64Padding(byteArrayIn); + + iterateBytes(byteArrayIn, stringBuilder); + stringBuilder.append(base64Padding.getPadding()); + return stringBuilder.toString(); + } + + private static void iterateBytes(byte[] byteArrayIn, + StringBuilder stringBuilder) { + PowerQueue bitQueue = new PowerQueue<>(); + + for (int i = 0; i < byteArrayIn.length; i++) { + processByteToQueue(byteArrayIn[i], bitQueue); + feedQueue(bitQueue, stringBuilder); + + } + if(bitQueue.size() > 0) { + while (bitQueue.size() < 6) { + bitQueue.add(false); + } + feedQueue(bitQueue, stringBuilder); + } + } + + private static void processByteToQueue(byte byteValue, + PowerQueue bitQueue) { + boolean[] booleanArray = Byte.byteValueToBooleanArray(byteValue); + for (boolean element : booleanArray) { + //System.out.print(element ? "1" : "0"); + bitQueue.add(element); + } + } + + private static void feedQueue(PowerQueue bitQueue, + StringBuilder stringBuilder) { + while (bitQueue.size() >= 6) { + + byte byteValue = Byte.booleanArrayToByte(bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll(), bitQueue.poll()); + stringBuilder.append(Base64Convertor.byteToChar(byteValue)); + + } + } + + private OkayBase64Encoder() { + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/package-info.java b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/package-info.java new file mode 100644 index 0000000..fd5bb32 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/bit/base64/package-info.java @@ -0,0 +1,29 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Package with utilities used to convert byte array to base64 string representation and vice versa + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +package org.nanoboot.powerframework.io.bit.base64; diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/BinaryFile.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/BinaryFile.java new file mode 100644 index 0000000..1ce88d8 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/BinaryFile.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BinaryFile { + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/Directory.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/Directory.java new file mode 100644 index 0000000..e1405e5 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/Directory.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Directory { + + /** + * + * @param name directory name Example:MyDocuments + * @param location directory location Example:/John/work/2017 + */ + public Directory(String name, + String location) { + + } +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/Disk.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/Disk.java new file mode 100644 index 0000000..fe42ea6 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/Disk.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Disk { + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/File.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/File.java new file mode 100644 index 0000000..6716eea --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/File.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class File { + + private static final String ROOTFOLDER = "FILESYSTEM"; + String name; + String location; +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileSystem.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileSystem.java new file mode 100644 index 0000000..7f2f2e5 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileSystem.java @@ -0,0 +1,85 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.security.CodeSource; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class FileSystem { + + private static final FileSystem defaultFileSystem = null; + + /** + * + * @param defaultFileSystemArg default file system + */ + public static void setDefaultFileSystem(FileSystem defaultFileSystemArg) { + } + + /** + * + * @param aclass Class instance + * + * @return path to the class file + */ + public static String getJarContainingFolder(Class aclass) { + CodeSource codeSource = aclass.getProtectionDomain().getCodeSource(); + java.io.File jarFile = null; + if(codeSource.getLocation() != null) { + try { + jarFile = new java.io.File(codeSource.getLocation().toURI()); + } catch (URISyntaxException ex) { + Logger.getLogger(FileSystem.class.getName()).log(Level.SEVERE, null, ex); + } + } else { + String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath(); + String jarFilePath = path.substring(path.indexOf(':') + 1, path.indexOf('!')); + try { + jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8"); + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(FileSystem.class.getName()).log(Level.SEVERE, null, ex); + } + jarFile = new java.io.File(jarFilePath); + } + return jarFile.getParentFile().getAbsolutePath(); + } + private final String location; + + /** + * + * @param locationIn path to the root folder of this abstract file system + */ + public FileSystem(String locationIn) { + this.location = locationIn; + } + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileType.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileType.java new file mode 100644 index 0000000..4b22f19 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/FileType.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum FileType { + + /** + * + */ + DIRECTORY, + + /** + * + */ + BYTEARRAY; +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/PowerFileSystem.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/PowerFileSystem.java new file mode 100644 index 0000000..95525a9 --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/PowerFileSystem.java @@ -0,0 +1,66 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +import org.nanoboot.powerframework.core.PowerObject; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class PowerFileSystem extends PowerObject { + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private PowerFileSystem() { + } + + /** + * Constructor + * + * Constructor description + * + * @param nameIn + */ + public PowerFileSystem(String nameIn) { + this.name = nameIn; + } + + + + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/TextFile.java b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/TextFile.java new file mode 100644 index 0000000..f8511ec --- /dev/null +++ b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/TextFile.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.fs; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TextFile { + +} diff --git a/power-io/src/main/java/org/nanoboot/powerframework/io/fs/virtualfilesystem/.gitkeep b/power-io/src/main/java/org/nanoboot/powerframework/io/fs/virtualfilesystem/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-io/src/main/resources/.gitkeep b/power-io/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-io/src/test/java/org/nanoboot/powerframework/io/bit/BlobTest.java b/power-io/src/test/java/org/nanoboot/powerframework/io/bit/BlobTest.java new file mode 100644 index 0000000..641a7de --- /dev/null +++ b/power-io/src/test/java/org/nanoboot/powerframework/io/bit/BlobTest.java @@ -0,0 +1,418 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit; + +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; +import org.junit.*; +import static org.junit.Assert.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BlobTest { + + public BlobTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of fillAllByZeroes method, of class Blob. + */ + @Test + public void testBlobString() { + + //arrange + Blob blob = new Blob(10); + blob.fillRandom(); + Blob blob2; + String expectedString = blob.toString(); + String returnedString; + //act + blob2 = new Blob(expectedString); + returnedString = blob2.toString(); + //assert + System.out.println(expectedString); + System.out.println(returnedString); + assertTrue(expectedString.equals(returnedString)); + } + + /** + * Test of fillAllByZeroes method, of class Blob. + */ + @Test + public void testFillAllByZeroes() { + + //arrange + Blob blob = new Blob(2); + String expectedString = "0000000000000000"; + String returnedString; + //act + returnedString = blob.toString(); + //assert + assertTrue(expectedString.equals(returnedString)); + } + + /** + * Test of fillAllByZeroes method, of class Blob. + */ + @Test + public void testFillAllByZeroes2() { + //arrange + Blob blob = new Blob(2); + blob.fillRandom(); + blob.fillAllByZeroes(); + String expectedString = "0000000000000000"; + String returnedString; + //act + returnedString = blob.toString(); + //assert + assertTrue(expectedString.equals(returnedString)); + } + + /** + * Test of fillAllByOnes method, of class Blob. + */ + @Test + public void testFillAllByOnes() { + //arrange + Blob blob = new Blob(2); + blob.fillAllByOnes(); + String expectedString = "1111111111111111"; + String returnedString; + //act + returnedString = blob.toString(); + //assert + assertTrue(expectedString.equals(returnedString)); + } + + /** + * Test of fillAllByOnes method, of class Blob. + */ + @Test + public void testFillAllByOnes2() { + //arrange + Blob blob = new Blob(2); + blob.fillRandom(); + blob.fillAllByOnes(); + String expectedString = "1111111111111111"; + String returnedString; + //act + returnedString = blob.toString(); + //assert + assertTrue(expectedString.equals(returnedString)); + } + + /** + * Test of fillRandom method, of class Blob. + */ + @Test + public void testFillRandom() { + //arrange + Blob blob = new Blob(2); + blob.fillRandom(); + blob.fillAllByOnes(); + String notExpectedString = "0000000000000000"; + String returnedString; + //act + returnedString = blob.toString(); + //assert + assertFalse(notExpectedString.equals(returnedString)); + } + + /** + * Test of getByte method, of class Blob. + */ + @Test + public void testGetByte() { + //arrange + Blob blob = new Blob(5); + + boolean[] expectedArray = new boolean[]{true, false, false, false, true, true, false, true}; + boolean[] returnedArray; + blob.setByte(2, new boolean[]{true, false, false, false, true, true, false, true}); + //act + + returnedArray = blob.getByte(2); + //assert + assertArrayEquals(expectedArray, returnedArray); + } + + /** + * Test of setByte method, of class Blob. + */ + @Test + public void testSetByte() { + //arrange + Blob blob = new Blob(5); + + String expectedString = "0000000000000000100011010000000000000000"; + String returnedString; + //act + blob.setByte(2, new boolean[]{true, false, false, false, true, true, false, true}); + returnedString = blob.toString(); + //assert + assertTrue(expectedString.equals(returnedString)); + } + + /** + * Test of getBits method, of class Blob. + */ + @Test + public void testGetBits() { + //arrange + Blob blob = new Blob(2); + blob.setByte(0, new boolean[]{true, true, false, true, false, true, true, false}); + blob.setByte(1, new boolean[]{false, true, true, false, false, false, true, false}); + + boolean[] expectedArray = new boolean[]{true, false, false, true, true, false}; + boolean[] returnedArray; + + //act + returnedArray = blob.getBits(6, 11); + //assert + assertArrayEquals(expectedArray, returnedArray); + } + + /** + * Test of getBits method, of class Blob. + */ + @Test + public void testGetBits2() { + //arrange + Blob blob = new Blob(4); + blob.setByte(0, new boolean[]{true, true, false, true, false, true, true, false}); + blob.setByte(1, new boolean[]{false, true, true, false, false, false, true, false}); + blob.setByte(2, new boolean[]{true, false, true, true, false, true, false, false}); + blob.setByte(3, new boolean[]{false, true, false, true, false, true, false, true}); + + boolean[] expectedArray = new boolean[]{false, true, true, false, true, false, false, false, true}; + boolean[] returnedArray; + + //act + returnedArray = blob.getBits(17, 25); + //assert + assertArrayEquals(expectedArray, returnedArray); + } + + /** + * Test of getBits method, of class Blob. + */ + @Test + public void testSetBits() { + //arrange + Blob blob = new Blob(4); + blob.fillAllByZeroes(); + + boolean[] expectedArray = new boolean[]{false, true, true, false, true, false, false, false, true}; + boolean[] returnedArray; + + //act + blob.setBits(17, new boolean[]{false, true, true, false, true, false, false, false, true}); + + returnedArray = blob.getBits(17, 25); + + //assert + assertArrayEquals(expectedArray, returnedArray); + } + + /** + * Test of getBits method, of class Blob. + */ + @Test + public void testSetBits2() { + + W5RandomGenerator pseudoW5RandomGenerator = W5RandomGenerator.getStaticInstance(); + + for (int i = 0; i < 10; i++) { + //System.out.println("Iteration number " + i); + //arrange + Blob blob = new Blob(4); + + boolean[] randomBooleanArray = new boolean[8]; + + for (int j = 0; j < 8; j++) { + randomBooleanArray[j] = pseudoW5RandomGenerator.nextBoolean(); + } + //act + String randomBooleanArrayAsString = new Blob(new byte[]{Byte.booleanArrayToByte(randomBooleanArray)}).toString(); + //System.out.println("Random boolean array is " + randomBooleanArrayAsString); + int startBit = pseudoW5RandomGenerator.nextInt(0, 24); + //System.out.println("Start bit is " + startBit); + blob.setBits(startBit, randomBooleanArray); + //System.out.println("The blob is now: "); + String blobAsString = blob.toString(); + for (int k = 0; k < blobAsString.length(); k++) { + + //System.out.print(blobAsString.charAt(k)); + if((k + 1) % 8 == 0) { + //System.out.println(); + } + } + String blobAsStringSubstring = blobAsString.substring(startBit, startBit + 8); + //System.out.println("blobAsStringSubstring=" + blobAsStringSubstring); + //System.out.println("randomBooleanArrayAsString=" + randomBooleanArrayAsString); + //assert + assertArrayEquals(randomBooleanArrayAsString.toCharArray(), blobAsStringSubstring.toCharArray()); + } + + } + + /** + * Test of toString method, of class Blob. + */ + @Test + public void testToString() { + //arrange + boolean[][] booleanArrays = new boolean[][]{{false, true, true, false, true, false, false, false}, {true, true, false, true, false, true, false, true}}; + Blob blob = new Blob(2); + + String expectedString = "0110100011010101"; + String returnedString; + + //act + blob.setByte(0, booleanArrays[0]); + blob.setByte(1, booleanArrays[1]); + + returnedString = blob.toString(); + + //assert + assertEquals(expectedString, returnedString); + } + +// +// /** +// * Test of flopAll method, of class Blob. +// */ +// @Test +// public void testFlopAll() { +// //arrange +// Blob blob = new Blob(2); +// +// String expectedString = "1111111111111111"; +// String returnedString; +// +// //act +// blob.flopAll(); +// +// returnedString = blob.toString(); +// +// //assert +// assertArrayEquals(expectedString.toCharArray(), returnedString.toCharArray()); +// } +// +// /** +// * Test of flopAll method, of class Blob. +// */ +// @Test +// public void testFlopAll2() { +// //arrange +// Blob blob = new Blob(2); +// +// String expectedString = "0000000000000000"; +// String returnedString; +// +// //act +// blob.fillAllByOnes(); +// blob.flopAll(); +// +// returnedString = blob.toString(); +// +// //assert +// assertArrayEquals(expectedString.toCharArray(), returnedString.toCharArray()); +// } +// +// /** +// * Test of flopAll method, of class Blob. +// */ +// @Test +// public void testFlopAll3() { +// //arrange +// Blob blob = new Blob("0100100101010001"); +// String expectedString = "1011011010101110"; +// String returnedString; +// +// //act +// blob.flopAll(); +// +// returnedString = blob.toString(); +// +// //assert +// assertArrayEquals(expectedString.toCharArray(), returnedString.toCharArray()); +// } + +// /** +// * Test of flop method, of class Blob. +// */ +// @Test +// public void testFlop() { +// //arrange +// Blob blob = new Blob("0100100101010001"); +// String expectedString = "1011011001010001"; +// String returnedString; +// +// //act +// blob.flop(0, 0); +// +// returnedString = blob.toString(); +// System.out.println("###\n" + expectedString + "\n" + returnedString); +// +// //assert +// assertArrayEquals(expectedString.toCharArray(), returnedString.toCharArray()); +// } + /** + * Test of flopBooleanArray method, of class Blob. + */ + @Test + public void testFlopBooleanArray() { + //arrange + + boolean[] booleanArray = new boolean[]{true, true, false, true, false, true, true, false}; + Blob blob = new Blob(Byte.booleanArrayToByte(booleanArray)); + + boolean[] expectedArray = new boolean[]{false, false, true, false, true, false, false, true}; + boolean[] returnedArray; + + //act + returnedArray = Blob.flopBooleanArray(booleanArray); + //assert + assertArrayEquals(expectedArray, returnedArray); + } + +} diff --git a/power-io/src/test/java/org/nanoboot/powerframework/io/bit/ByteTest.java b/power-io/src/test/java/org/nanoboot/powerframework/io/bit/ByteTest.java new file mode 100644 index 0000000..ed74611 --- /dev/null +++ b/power-io/src/test/java/org/nanoboot/powerframework/io/bit/ByteTest.java @@ -0,0 +1,204 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.io.bit; + +import java.util.Arrays; +import org.junit.*; +import static org.junit.Assert.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ByteTest { + + public ByteTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of getByteValue method, of class Byte. + */ + @Test + public void testBooleanArrayToByte() { + //arrange + boolean[] booleanArray = new boolean[]{false, false, false, false, false, false, false, false}; + byte expectedValue = -128; + int returnedValue; + //act + returnedValue = Byte.booleanArrayToByte(booleanArray); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of getByteValue method, of class Byte. + */ + @Test + public void testBooleanArrayToByte2() { + //arrange + boolean[] booleanArray = new boolean[]{false, false, false, false, false, false, false, true}; + byte expectedValue = -127; + int returnedValue; + //act + returnedValue = Byte.booleanArrayToByte(booleanArray); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of getByteValue method, of class Byte. + */ + @Test + public void testBooleanArrayToByte3() { + //arrange + boolean[] booleanArray = new boolean[]{true, true, true, true, true, true, true, true}; + byte expectedValue = 127; + int returnedValue; + //act + returnedValue = Byte.booleanArrayToByte(booleanArray); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray() { + byte byteValue = -128; + boolean[] expectedValue = new boolean[]{false, false, false, false, false, false, false, false}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + System.out.println(Arrays.toString(returnedValue)); + Assert.assertArrayEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray2() { + byte byteValue = -127; + boolean[] expectedValue = new boolean[]{false, false, false, false, false, false, false, true}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + + Assert.assertArrayEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray3() { + byte byteValue = -124; + boolean[] expectedValue = new boolean[]{false, false, false, false, false, true, false, false}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + + Assert.assertArrayEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray4() { + byte byteValue = 0; + boolean[] expectedValue = new boolean[]{true, false, false, false, false, false, false, false}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + + Assert.assertArrayEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray5() { + byte byteValue = 1; + boolean[] expectedValue = new boolean[]{true, false, false, false, false, false, false, true}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + + Assert.assertArrayEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray6() { + byte byteValue = 126; + boolean[] expectedValue = new boolean[]{true, true, true, true, true, true, true, false}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + + Assert.assertArrayEquals(expectedValue, returnedValue); + } + + /** + * Test of getBooleanArray method, of class Byte. + */ + @Test + public void testByteValueToBooleanArray7() { + byte byteValue = (byte) (127); + boolean[] expectedValue = new boolean[]{true, true, true, true, true, true, true, true}; + boolean[] returnedValue; + //act + returnedValue = Byte.byteValueToBooleanArray(byteValue); + //assert + + Assert.assertArrayEquals(expectedValue, returnedValue); + } +} diff --git a/power-json/pom.xml b/power-json/pom.xml new file mode 100644 index 0000000..4528518 --- /dev/null +++ b/power-json/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-json + jar + + Power Json + Json functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-random + ${power.version} + + + org.nanoboot.powerframework + power-utils + ${power.version} + + + org.nanoboot.powerframework + power-collections + ${power.version} + + + + + diff --git a/power-json/src/main/java/module-info.java b/power-json/src/main/java/module-info.java new file mode 100644 index 0000000..6e7368c --- /dev/null +++ b/power-json/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.json { + exports org.nanoboot.powerframework.json; + requires java.logging; + requires powerframework.collections; + requires powerframework.core; +} diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByComma.java b/power-json/src/main/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByComma.java new file mode 100644 index 0000000..b3b5cdf --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByComma.java @@ -0,0 +1,62 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import java.util.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ArrayWithItemsSplitByComma { + + /** + * Returns list of indexes of commas for the given indentation and the given + * String + * + * @param itemsSplitByComma + * @return + */ + static ArrayList getListWithItemsSplitByComma( + String itemsSplitByComma) { + ArrayWithItemsSplitByComma arrayWithItemsSplitByComma = new ArrayWithItemsSplitByComma(itemsSplitByComma); + return arrayWithItemsSplitByComma.arrayList; + } + + private final ArrayList arrayList = new ArrayList<>(); + + private ArrayWithItemsSplitByComma(final String itemsSplitByComma) { + ArrayList listOfCommas = CommasFinder.getListOfIndexesOfCommas(itemsSplitByComma); + int beginIndex = 0; + int endIndex; + for (int element : listOfCommas) { + endIndex = element; + arrayList.add(itemsSplitByComma.substring(beginIndex, endIndex).trim()); + beginIndex = ++endIndex; + } + endIndex = itemsSplitByComma.length(); + arrayList.add(itemsSplitByComma.substring(beginIndex, endIndex).trim()); + } + +} diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/CommasFinder.java b/power-json/src/main/java/org/nanoboot/powerframework/json/CommasFinder.java new file mode 100644 index 0000000..af031ca --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/CommasFinder.java @@ -0,0 +1,92 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import java.util.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class CommasFinder { + + private static boolean nestingWillBeIncreased(char charToCheck) { + return (charToCheck == JsonConstants.OBJECTSTART) || (charToCheck == JsonConstants.ARRAYSTART); + } + + private static boolean nestingWillBeDecreased(char charToCheck) { + return (charToCheck == JsonConstants.OBJECTEND) || (charToCheck == JsonConstants.ARRAYEND); + } + + static ArrayList getListOfIndexesOfCommas(final String string) { + CommasFinder commasFinder = new CommasFinder(string); + return commasFinder.listOfCommas; + } + + private final ArrayList listOfCommas = new ArrayList<>(); + private int nesting = 0; + private char currentChar; + private int charIndex; + private final String string; + + private CommasFinder(final String string) { + this.string = string; + //System.out.println(string); + for (charIndex = 0; charIndex < string.length(); charIndex++) { + updateCurrentChar(); + //System.out.println(string.charAt(charIndex)); + skipStringIfNecessarily(); + + if ((currentChar == JsonConstants.COMMA) && (nesting == 0)) { + //System.out.println("přidání"); + listOfCommas.add(charIndex); + } + if (nestingWillBeIncreased(currentChar)) { + nesting++; + } + if (nestingWillBeDecreased(currentChar)) { + nesting--; + } + + } + } + + private void skipStringIfNecessarily() { + + if ((currentChar == JsonConstants.APOSTROPHE) && (nesting == 0)) { + //System.out.println("skok"); + charIndex++;//NOSONAR + updateCurrentChar(); + while (JsonConstants.APOSTROPHE != currentChar) { + charIndex++;//NOSONAR + updateCurrentChar(); + } + } + } + + private void updateCurrentChar() { + currentChar = string.charAt(charIndex); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonArray.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArray.java similarity index 56% rename from src/main/java/org/nanoboot/powerframework/json/JsonArray.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonArray.java index 93ee6c9..ec7d534 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonArray.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArray.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -21,20 +21,21 @@ package org.nanoboot.powerframework.json; import java.util.ArrayList; -import org.nanoboot.powerframework.PowerRuntimeException; /** * Represents json array. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class JsonArray { +//TODO implement serializable interface private ArrayList arrayList = new ArrayList<>(); /** * Constructor - * + *

* Used to create empty jsonObject. */ public JsonArray() { @@ -43,38 +44,41 @@ public class JsonArray { /** * Constructor - * + *

* From String creates json array. * * @param stringRepresentationOfThisJsonArray */ - public JsonArray(String stringRepresentationOfThisJsonArray) { + public JsonArray(final String stringRepresentationOfThisJsonArray) { JsonArrayParser.parseStringToJsonArray(this, stringRepresentationOfThisJsonArray); } /** - * * @return count of items of this json array. */ - public int getCountOfItems() { + public int size() { return this.arrayList.size(); } /** - * * @return result of this control */ public boolean isEmpty() { return this.arrayList.isEmpty(); } + public void clear() { + this.arrayList.clear(); + } + /** * New value is added- object is converted to the most suitable json value * type and is set as the new value. * * @param object + * @return */ - public void add(Object object) {//NOSONAR + public JsonArray add(Object object) {//NOSONAR if (object == null) { addNull(); } else { @@ -107,31 +111,41 @@ public class JsonArray { addDouble((double) object); break; default: - throw new PowerRuntimeException("I can't add the given object as value."); + throw new JsonException(object.getClass().getName() + " I can't add the given object (" + object.getClass().getName() + ") as value."); } } + return this; + } + + void addJsonValue(JsonValue jsonValue) { + this.arrayList.add(jsonValue); } /** * Adds null. + * + * @return */ - public void addNull() { + public JsonArray addNull() { this.arrayList.add(new JsonValue()); + return this; } /** * Adds json object. * - * @param value + * @param value value to use + * @return */ - public void addObject(JsonObject value) { + public JsonArray addObject(JsonObject value) { this.arrayList.add(new JsonValue(value)); + return this; } /** * Adds json array. * - * @param value + * @param value value to use * @return */ public JsonArray addArray(JsonArray value) {//this @@ -142,79 +156,91 @@ public class JsonArray { /** * Adds boolean. * - * @param value + * @param value value to use + * @return */ - public void addBoolean(boolean value) { - this.arrayList.add(new JsonValue(new JsonBoolean(value))); + public JsonArray addBoolean(boolean value) { + this.arrayList.add(new JsonValue(value)); + return this; } /** * Adds String. * - * @param value + * @param value value to use * @return */ - public JsonArray addString(String value) { - this.arrayList.add(new JsonValue(new JsonString(value))); + public JsonArray addString(final String value) { + this.arrayList.add(new JsonValue(value)); return this; } /** * Adds char. * - * @param value + * @param value value to use + * @return */ - public void addChar(char value) { - this.arrayList.add(new JsonValue(new JsonChar(value))); + public JsonArray addChar(char value) { + this.arrayList.add(new JsonValue(value)); + return this; } /** * Adds int. * - * @param value + * @param value value to use + * @return */ - public void addInt(int value) { - this.arrayList.add(new JsonValue(new JsonInt(value))); + public JsonArray addInt(int value) { + this.arrayList.add(new JsonValue(value)); + return this; } /** * Adds long. * - * @param value + * @param value value to use + * @return */ - public void addLong(long value) { - this.arrayList.add(new JsonValue(new JsonLong(value))); + public JsonArray addLong(long value) { + this.arrayList.add(new JsonValue(value)); + return this; } /** * Adds float. * - * @param value + * @param value value to use + * @return */ - public void addFloat(float value) { - this.arrayList.add(new JsonValue(new JsonFloat(value))); + public JsonArray addFloat(float value) { + this.arrayList.add(new JsonValue(value)); + return this; } /** * Adds double. * - * @param value + * @param value value to use + * @return */ - public void addDouble(double value) { - this.arrayList.add(new JsonValue(new JsonDouble(value))); + public JsonArray addDouble(double value) { + this.arrayList.add(new JsonValue(value)); + return this; } /** - * * @param index * @return json value type of the value at the given index */ public JsonValueType getJsonValueType(int index) { - return this.arrayList.get(index).getJsonValueType(); + return this.arrayList + .get(index) + .getJsonValueType(); } /** - * * @param index * @return JsonObject */ @@ -223,7 +249,6 @@ public class JsonArray { } /** - * * @param index * @return JsonArraz */ @@ -232,155 +257,167 @@ public class JsonArray { } /** - * * @param index * @return boolean */ public boolean getBoolean(int index) { - return this.arrayList.get(index).getJsonBoolean().getBoolean(); + return this.arrayList.get(index).getJsonBoolean(); } /** - * * @param index * @return String */ public String getString(int index) { - return this.arrayList.get(index).getJsonString().getString(); + return this.arrayList.get(index).getJsonString(); } /** - * * @param index * @return char */ public char getChar(int index) { - return this.arrayList.get(index).getJsonChar().getChar(); + return this.arrayList.get(index).getJsonChar(); } /** - * * @param index * @return int */ public int getInt(int index) { - return this.arrayList.get(index).getJsonInt().getInt(); + return this.arrayList.get(index).getJsonInt(); } /** - * * @param index * @return long */ public long getLong(int index) { - return this.arrayList.get(index).getJsonLong().getLong(); + return this.arrayList.get(index).getJsonLong(); } /** - * * @param index * @return float */ public float getFloat(int index) { - return this.arrayList.get(index).getJsonFloat().getFloat(); + return this.arrayList.get(index).getJsonFloat(); } /** - * * @param index * @return double */ public double getDouble(int index) { - return this.arrayList.get(index).getJsonDouble().getDouble(); + return this.arrayList.get(index).getJsonDouble(); } /** - * * @param index to be updated + * @return */ - public void updateNull(int index) { + public JsonArray updateNull(int index) { this.arrayList.set(index, new JsonValue()); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateObject(int index, JsonObject value) { + public JsonArray updateObject(int index, + JsonObject value) { this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateArray(int index, JsonArray value) { + public JsonArray updateArray(int index, + JsonArray value) { this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateBoolean(int index, boolean value) { - this.arrayList.set(index, new JsonValue(new JsonBoolean(value))); + public JsonArray updateBoolean(int index, + boolean value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateString(int index, String value) { - this.arrayList.set(index, new JsonValue(new JsonString(value))); + public JsonArray updateString(int index, + String value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateChar(int index, char value) { - this.arrayList.set(index, new JsonValue(new JsonChar(value))); + public JsonArray updateChar(int index, + char value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateInt(int index, int value) { - this.arrayList.set(index, new JsonValue(new JsonInt(value))); + public JsonArray updateInt(int index, + int value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateLong(int index, long value) { - this.arrayList.set(index, new JsonValue(new JsonLong(value))); + public JsonArray updateLong(int index, + long value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateFloat(int index, float value) { - this.arrayList.set(index, new JsonValue(new JsonFloat(value))); + public JsonArray updateFloat(int index, + float value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** - * * @param index - * @param value to be updated + * @param value value to use to be updated + * @return */ - public void updateDouble(int index, double value) { - this.arrayList.set(index, new JsonValue(new JsonDouble(value))); + public JsonArray updateDouble(int index, + double value) { + this.arrayList.set(index, new JsonValue(value)); + return this; } /** @@ -396,8 +433,25 @@ public class JsonArray { return this.arrayList.get(index); } + boolean isJsonValueType(int index, + JsonValueType jsonValueType) { + return this.getJsonValueType(index) == jsonValueType; + } + + public String toString(JsonPrint jsonPrint) { + switch (jsonPrint) { + case MINIMAL: { + return toMinimalString(); + } + case PRETTY: { + return toPrettyString(); + } + default: + throw new JsonException("Unknown JsonPrint: " + jsonPrint); + } + } + /** - * * @return representation of this json array as minimal String */ public String toMinimalString() { @@ -405,7 +459,6 @@ public class JsonArray { } /** - * * @return representation of this json array as pretty String */ public String toPrettyString() { @@ -413,7 +466,6 @@ public class JsonArray { } /** - * * @return copy of this json array */ public JsonArray getCopy() { diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java similarity index 59% rename from src/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java index 063f0d3..a49ba25 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArrayParser.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -21,68 +21,66 @@ package org.nanoboot.powerframework.json; import java.util.ArrayList; -import org.nanoboot.powerframework.PowerRuntimeException; /** * Is used to create json arrays from Strings. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonArrayParser extends JsonParser { - /** - * Constructor - * - * Not meant to be instantiated. - */ - private JsonArrayParser() { - //Not meant to be instantiated. - } - /** * Parses String to empty json object. * - * @param jsonObject - * @param stringRepresentationOfJsonObject + * @param jsonArray + * @param stringRepresentationOfJsonArray * @return json object from parsed String */ - static JsonArray parseStringToJsonArray(JsonArray jsonArray, String stringRepresentationOfJsonArray) { + static JsonArray parseStringToJsonArray(JsonArray jsonArray, + String stringRepresentationOfJsonArray) { if (!jsonArray.isEmpty()) { - throw new PowerRuntimeException("I can't parse. The json array is not empty."); + throw new JsonException("I can't parse. The json array is not empty."); } String trimmedStringRepresentationOfJsonArray = stringRepresentationOfJsonArray.trim(); if (!isStringJsonArray(trimmedStringRepresentationOfJsonArray)) { - throw new PowerRuntimeException("I can't parse. The trimmed String does not start with [ or does not end with ]"); + throw new JsonException("I can't parse. The trimmed String does not start with [ or does not end with ]: " + trimmedStringRepresentationOfJsonArray); } String collectionsOfValuesOfTheJsonArrayString = deleteTheCharAtTheStartAndTheEnd(trimmedStringRepresentationOfJsonArray); if ("".equals(collectionsOfValuesOfTheJsonArrayString)) { return jsonArray; } + if ("".equals(collectionsOfValuesOfTheJsonArrayString.trim())) { + return jsonArray; + } fillJsonArrayWithParsedValues(jsonArray, collectionsOfValuesOfTheJsonArrayString); return jsonArray; } - private static boolean isStringJsonArray(String trimmedStringRepresentationOfJsonArray) { - return (getFirstCharOfTheString(trimmedStringRepresentationOfJsonArray) == JsonSpecialCharSequences.getArrayLeft()) && (getLastCharOfTheString(trimmedStringRepresentationOfJsonArray) == JsonSpecialCharSequences.getArrayRight()); + private static boolean isStringJsonArray( + String trimmedStringRepresentationOfJsonArray) { + return (getFirstCharOfTheString(trimmedStringRepresentationOfJsonArray) == JsonConstants.ARRAYSTART) && (getLastCharOfTheString(trimmedStringRepresentationOfJsonArray) == JsonConstants.ARRAYEND); } - private static void fillJsonArrayWithParsedValues(JsonArray jsonArray, String collectionsOfValuesOfTheJsonArrayString) { + private static void fillJsonArrayWithParsedValues(JsonArray jsonArray, + String collectionsOfValuesOfTheJsonArrayString) { + ArrayList array = ArrayWithItemsSplitByComma.getListWithItemsSplitByComma(collectionsOfValuesOfTheJsonArrayString); + for (final String element : array) { - ArrayList listOfCommas = getListOfIndexesOfTheStringWhereCharIsCommaAndNestingIsZero(collectionsOfValuesOfTheJsonArrayString); + JsonValue jsonValue = JsonValue.parseStringToJsonValue(element); - int beginIndex; - int indexOfComma = 0; - for (int i = 0; i < listOfCommas.size(); i++) { - beginIndex = ++indexOfComma; - indexOfComma = listOfCommas.get(i); - if (i == 0) { - beginIndex = 0; - } - String fraction = collectionsOfValuesOfTheJsonArrayString.substring(beginIndex, indexOfComma); - Object parsedObject = JsonParser.parseStringToValue(fraction); - jsonArray.add(parsedObject); + jsonArray.addJsonValue(jsonValue); } } + /** + * Constructor + *

+ * Not meant to be instantiated. + */ + private JsonArrayParser() { + //Not meant to be instantiated. + } + } diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java similarity index 74% rename from src/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java index dc15959..1d36b3f 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArrayPrinter.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,21 +23,12 @@ package org.nanoboot.powerframework.json; /** * Used to create String representation of a json array. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonArrayPrinter { /** - * Constructor - * - * Not meant to be instantiated. - */ - private JsonArrayPrinter() { - //Not meant to be instantiated. - } - - /** - * * @return representation of the json array as pretty String */ static String toMinimalString(JsonArray jsonArray) { @@ -45,7 +36,6 @@ class JsonArrayPrinter { } /** - * * @return representation of the json array as pretty String */ static String toPrettyString(JsonArray jsonArray) { @@ -54,34 +44,31 @@ class JsonArrayPrinter { } /** - * * @return representation of the json array as String */ - static String toString(JsonArray jsonArray, boolean printAsPrettyVersion) { + static String toString(JsonArray jsonArray, + boolean printAsPrettyVersion) { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(JsonSpecialCharSequences.getArrayLeft()); + stringBuilder.append(JsonConstants.ARRAYSTART); if (printAsPrettyVersion) { - stringBuilder.append(JsonSpecialCharSequences.getLineBreak()); + stringBuilder.append(JsonConstants.LINEBREAK); } int i = 0; String value; - while (i != jsonArray.getCountOfItems()) { - if (printAsPrettyVersion) { - value = jsonArray.getJsonValue(i).toPrettyString(); - } else { - value = jsonArray.getJsonValue(i).toMinimalString(); - } + while (i != jsonArray.size()) { + + value = printAsPrettyVersion ? jsonArray.getJsonValue(i).toPrettyString() : jsonArray.getJsonValue(i).toMinimalString(); if (printAsPrettyVersion) { if (!((jsonArray.getJsonValue(i).isArray()) || (jsonArray.getJsonValue(i).isObject()))) { - stringBuilder.append(JsonSpecialCharSequences.getTab()); + stringBuilder.append(JsonConstants.TAB); } else { value = JsonPrinter.addTabOnEveryLineStart(value); } } stringBuilder.append(value); - if ((i + 1) != jsonArray.getCountOfItems()) { + if ((i + 1) != jsonArray.size()) { stringBuilder.append(","); } if (printAsPrettyVersion) { @@ -89,10 +76,20 @@ class JsonArrayPrinter { } i++; } - stringBuilder.append(JsonSpecialCharSequences.getArrayRight()); + + stringBuilder.append(JsonConstants.ARRAYEND); return stringBuilder.toString(); } + /** + * Constructor + *

+ * Not meant to be instantiated. + */ + private JsonArrayPrinter() { + //Not meant to be instantiated. + } + } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArraySerializable.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArraySerializable.java new file mode 100644 index 0000000..b3e8f15 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonArraySerializable.java @@ -0,0 +1,45 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface JsonArraySerializable { + + /** + * Creates JsonArray representation of the instance + * of the class implementing this interface. + * + * @return JsonArray representation of the instance + * of the class implementing this interface + */ + JsonArray toJsonArray(); + /** + * Sets this object from a json array. + * @param jsonArray given json array + */ + void fromJsonArray(JsonArray jsonArray); +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonBoolean.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonBoolean.java similarity index 69% rename from src/main/java/org/nanoboot/powerframework/json/JsonBoolean.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonBoolean.java index f0b882f..f3a983e 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonBoolean.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonBoolean.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,26 +23,19 @@ package org.nanoboot.powerframework.json; /** * Represents boolean json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonBoolean { - private final boolean value; - - JsonBoolean(boolean value) { - this.value = value; + static String toString(boolean value) { + return value ? JsonConstants.TRUE : JsonConstants.FALSE; } - boolean getBoolean() { - return this.value; - } - - @Override - public String toString() { - if (getBoolean()) { - return JsonSpecialCharSequences.getTrue(); - } else { - return JsonSpecialCharSequences.getFalse(); - } + /** + * Not meant to be instantiated. + */ + private JsonBoolean() { + //Not meant to be instantiated. } } diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonChar.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonChar.java similarity index 77% rename from src/main/java/org/nanoboot/powerframework/json/JsonChar.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonChar.java index 2b406e2..11247bc 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonChar.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonChar.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,26 +23,23 @@ package org.nanoboot.powerframework.json; /** * Represents char json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonChar { - private final char value; - - JsonChar(char value) { - this.value = value; - } - - char getChar() { - return this.value; - } - - @Override - public String toString() { + static String toString(char value) { StringBuilder sb = new StringBuilder(); sb.append('\"'); - sb.append(Character.toString(getChar())); + sb.append(Character.toString(value)); sb.append('\"'); return sb.toString(); } + + /** + * Not meant to be instantiated. + */ + private JsonChar() { + //Not meant to be instantiated. + } } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonConstants.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonConstants.java new file mode 100644 index 0000000..12e305e --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonConstants.java @@ -0,0 +1,48 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * Used to store char and String constants used to parse or print json objects + * or arrays. + * + * @author Robert Vokac + * @since 0.0.0 + */ +class JsonConstants { + + static final char OBJECTSTART = '{'; + static final char OBJECTEND = '}'; + static final char ARRAYSTART = '['; + static final char ARRAYEND = ']'; + static final char COMMA = ','; + static final char COLON = ':'; + static final char APOSTROPHE = '"'; + static final char LINEBREAK = '\n'; + static final String NULL = "null"; + static final String TRUE = "true"; + static final String FALSE = "false"; + static final String TAB = " "; + static final char SPACE = ' '; + + private JsonConstants() { + } +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonDouble.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonDouble.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/json/JsonDouble.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonDouble.java index 6822cd6..a791a17 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonDouble.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonDouble.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,22 +23,19 @@ package org.nanoboot.powerframework.json; /** * Represents double json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonDouble { - private final double value; - - JsonDouble(double value) { - this.value = value; + static String toString(double value) { + return Double.toString(value); } - double getDouble() { - return this.value; - } - - @Override - public String toString() { - return Double.toString(getDouble()); + /** + * Not meant to be instantiated. + */ + private JsonDouble() { + //Not meant to be instantiated. } } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonException.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonException.java new file mode 100644 index 0000000..05ee387 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonException.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class JsonException extends PowerException { + + /** + * @param message + */ + public JsonException(final String message) { + super(message); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonFloat.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonFloat.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/json/JsonFloat.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonFloat.java index 88be199..8a170e9 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonFloat.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonFloat.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,22 +23,19 @@ package org.nanoboot.powerframework.json; /** * Represents float json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonFloat { - private final float value; - - JsonFloat(float value) { - this.value = value; + static String toString(float value) { + return Float.toString(value); } - float getFloat() { - return this.value; - } - - @Override - public String toString() { - return Float.toString(getFloat()); + /** + * Not meant to be instantiated. + */ + private JsonFloat() { + //Not meant to be instantiated. } } diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonInt.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonInt.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/json/JsonInt.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonInt.java index 58fe21d..fd76fa0 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonInt.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonInt.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,23 +23,20 @@ package org.nanoboot.powerframework.json; /** * Represents int json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonInt { - private final int value; - - JsonInt(int value) { - this.value = value; + static String toString(int value) { + return Integer.toString(value); } - int getInt() { - return this.value; - } - - @Override - public String toString() { - return Integer.toString(getInt()); + /** + * Not meant to be instantiated. + */ + private JsonInt() { + //Not meant to be instantiated. } } diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonLong.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonLong.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/json/JsonLong.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonLong.java index 93fa2ea..2e76f48 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonLong.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonLong.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,22 +23,19 @@ package org.nanoboot.powerframework.json; /** * Represents long json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonLong { - private final long value; - - JsonLong(long value) { - this.value = value; + static String toString(long value) { + return Long.toString(value); } - long getLong() { - return this.value; - } - - @Override - public String toString() { - return Long.toString(getLong()); + /** + * Not meant to be instantiated. + */ + private JsonLong() { + //Not meant to be instantiated. } } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObject.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObject.java new file mode 100644 index 0000000..fd30579 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObject.java @@ -0,0 +1,708 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import org.nanoboot.powerframework.collections.PowerMap; +import org.nanoboot.powerframework.core.PowerObject; + + +import java.util.List; +import java.util.Map; + +/** + * Represents json object of json. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class JsonObject extends PowerObject { + /** + * Constant for Double. + */ + private static final String JAVALANG_DOUBLE = "java.lang.Double"; + /** + * Constant for double. + */ + private static final String JAVALANG_FLOAT = "java.lang.Float"; + /** + * Constant for Long. + */ + private static final String JAVALANG_LONG = "java.lang.Long"; + /** + * Constant for Integer. + */ + private static final String JAVALANG_INTEGER = "java.lang.Integer"; + /** + * Constant for Character. + */ + private static final String JAVALANG_CHARACTER = "java.lang.Character"; + /** + * Constant for String. + */ + private static final String JAVALANG_STRING = "java.lang.String"; + /** + * Constant for Boolean. + */ + private static final String JAVALANG_BOOLEAN = "java.lang.Boolean"; + /** + * Constant for JsonArray. + */ + private static final String POWERJSON_JSON_ARRAY = + "org.nanoboot.powerframework.json.JsonArray"; + /** + * Constant for JsonObject. + */ + private static final String POWERJSON_JSON_OBJECT = + "org.nanoboot.powerframework.json.JsonObject"; + /** + * Internal map. + */ + private final Map map = new PowerMap<>(); + /** + * Json validation schema. + */ + private JsonObject validationByJsonObject = null; + + /** + * Constructor + *

+ * Used to create empty jsonObject. + */ + public JsonObject() { + // Used to create empty jsonObject. + } + + //todo + // +// /** +// * Test of toJsonObject method, of class LinkedList. +// */ +// @Test +// public void testToJsonObject() { +// //arrange +// SingleLinkedList linkedList0 = new SingleLinkedList<>(); +// String expectedString = "{\"firstNode\":{\"key\":\"\",\"element\":\"Jack\",\"next\":{\"key\":\"\",\"element\":\"Anne\",\"next\":{\"key\":\"\",\"element\":\"John\",\"next\":{\"key\":\"\",\"element\":\"George\",\"next\":{\"key\":\"\",\"element\":\"Kate\",\"next\":null}}}}},\"lastNode\":{\"key\":\"\",\"element\":\"Kate\",\"next\":null}}"; +// String returnedString; +// //act +// linkedList0 +// ;linkedList.addAfterLast("Jack") +// ;linkedList.addAfterLast("Anne") +// ;linkedList.addAfterLast("John") +// ;linkedList.addAfterLast("George") +// ;linkedList.addAfterLast("Kate"); +// returnedString = linkedList0.toJsonObject().toMinimalString(); +// //assert +// assertEquals(expectedString, returnedString); +// +// } + + + + /** + * Constructor + *

+ * From String creates json object. + * + * @param textToParse json as text + */ + public JsonObject(final String textToParse) { + JsonObjectParser.parseStringToJsonObject(this, textToParse); + } + + /** + * @param jsonObject json validating schema + */ + public void setValidationJsonObject(final JsonObject jsonObject) { + if (this.validationByJsonObject == null) { + String msg = "The validation json object has been already set."; + throw new JsonException(msg); + } + this.validationByJsonObject = jsonObject; + } + + /** + * @return copy of validating json + */ + public JsonObject getValidationJsonObjectCopy() { + return this.validationByJsonObject.getCopy(); + } + + /** + * @return result of the validation + */ + public boolean validate() { + return false; + } + + /** + * @return count of items(keys and its values) of this json object + */ + public int size() { + return map.size(); + } + + /** + * @return result of this control + */ + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Removes all values of this json object. + */ + public void clear() { + this.map.clear(); + } + + /** + * @param key key to use + * @return result of this control + */ + public boolean hasKey(final String key) { + return this.map.containsKey(key); + } + + /** + * Add to this json object new key, object is converted to the most suitable + * json value type and is set as value of the key. + * + * @param key key to use + * @param object object to use + * @return json object, which was added + */ + public JsonObject add(final String key, + final Object object) { + if (object == null) { + addNull(key); + } else { + switch (object.getClass().getName()) { + case POWERJSON_JSON_OBJECT: + addObject(key, (JsonObject) object); + break; + case POWERJSON_JSON_ARRAY: + addArray(key, (JsonArray) object); + break; + case JAVALANG_BOOLEAN: + addBoolean(key, (boolean) object); + break; + case JAVALANG_STRING: + addString(key, (String) object); + break; + case JAVALANG_CHARACTER: + addChar(key, (char) object); + break; + case JAVALANG_INTEGER: + addInt(key, (int) object); + break; + case JAVALANG_LONG: + addLong(key, (long) object); + break; + case JAVALANG_FLOAT: + addFloat(key, (float) object); + break; + case JAVALANG_DOUBLE: + addDouble(key, (double) object); + break; + default: + String msg = + object.getClass().getName() + + " I can't add the given object as value."; + throw new JsonException(msg); + } + } + return this; + } + + final void addJsonValue(final String key, + final JsonValue jsonValue) { + this.map.put(key, jsonValue); + } + + /** + * Add to this json object new key with null as value. + * + * @param key key to use + * @return this + */ + public JsonObject addNull(final String key) { + this.map.put(key, new JsonValue()); + return this; + } + + /** + * Add to this json object new key with json object as value. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addObject(final String key, + final JsonObject value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * *Add to this json object new key with json array as value. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addArray(final String key, + final JsonArray value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the boolean as the + * value of the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addBoolean(final String key, + final boolean value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the String as the value + * of the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addString(final String key, + final String value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the char as the value + * of the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addChar(final String key, + final char value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the int as the value of + * the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addInt(final String key, + final int value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the long as the value + * of the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addLong(final String key, + final long value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the float as the value + * of the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addFloat(final String key, + final float value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + /** + * Add to this json object new key with the value of the double as the value + * of the key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject addDouble(final String key, + final double value) { + this.map.put(key, new JsonValue(value)); + return this; + } + + public boolean isNull(final String key) { + return getJsonValueType(key) == JsonValueType.NULL; + } + /** + * @param key key to use + * @return value type of the value of the given key + */ + public JsonValueType getJsonValueType(final String key) { + return map.get(key).getJsonValueType(); + } + + final boolean isJsonValueType(final String key, + final JsonValueType jsonValueType) { + return this.getJsonValueType(key) == jsonValueType; + } + + /** + * @param key key to use + * @return object instance converted from the value of the given key + */ + public Object get(final String key) { + return map.get(key).toObject(); + } + + /** + * @param key key to use + * @return json object from the value of the given key + */ + public JsonObject getObject(final String key) { + return this.map.get(key).getJsonObject(); + } + + /** + * @param key key to use + * @return json array from the value of the given key + */ + public JsonArray getArray(final String key) { + return this.map.get(key).getJsonArray(); + } + + /** + * @param key key to use + * @return boolean from the value of the given key + */ + public boolean getBoolean(final String key) { + return this.map.get(key).getJsonBoolean(); + } + + /** + * @param key key to use + * @return String from the value of the given key + */ + public String getString(final String key) { + return this.map.get(key).getJsonString(); + } + + /** + * @param key key to use + * @return char from the value of the given key + */ + public char getChar(final String key) { + return this.map.get(key).getJsonChar(); + } + + /** + * @param key key to use + * @return int from the value of the given key + */ + public int getInt(final String key) { + return this.map.get(key).getJsonInt(); + } + + /** + * @param key key to use + * @return long from the value of the given key + */ + public long getLong(final String key) { + return this.map.get(key).getJsonLong(); + } + + /** + * @param key key to use + * @return float from the value of the given key + */ + public float getFloat(final String key) { + return this.map.get(key).getJsonFloat(); + } + + /** + * @param key key to use + * @return double from the value of the given key + */ + public double getDouble(final String key) { + return this.map.get(key).getJsonDouble(); + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param object object to use + * @return this + */ + public JsonObject update(final String key, + final Object object) { + if (object == null) { + updateNull(key); + } else { + switch (object.getClass().getName()) { + case POWERJSON_JSON_OBJECT: + updateObject(key, (JsonObject) object); + break; + case POWERJSON_JSON_ARRAY: + updateArray(key, (JsonArray) object); + break; + case JAVALANG_BOOLEAN: + updateBoolean(key, (boolean) object); + break; + case JAVALANG_STRING: + updateString(key, (String) object); + break; + case JAVALANG_CHARACTER: + updateChar(key, (char) object); + break; + case JAVALANG_INTEGER: + updateInt(key, (int) object); + break; + case JAVALANG_LONG: + updateLong(key, (long) object); + break; + case JAVALANG_FLOAT: + updateFloat(key, (float) object); + break; + case JAVALANG_DOUBLE: + updateDouble(key, (double) object); + break; + default: + String msg = "I can't add the given object as value."; + throw new JsonException(msg); + } + } + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @return this + */ + public JsonObject updateNull(final String key) { + this.map.replace(key, new JsonValue()); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateObject(final String key, + final JsonObject value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateArray(final String key, + final JsonArray value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateBoolean(final String key, + final boolean value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateString(final String key, + final String value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateChar(final String key, + final char value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateInt(final String key, + final int value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateLong(final String key, + final long value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateFloat(final String key, + final float value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Updates the value of the given key. + * + * @param key key to use + * @param value value to use + * @return this + */ + public JsonObject updateDouble(final String key, + final double value) { + this.map.replace(key, new JsonValue(value)); + return this; + } + + /** + * Removes the key and its value. + * + * @param key key to use + */ + public void removeJsonValue(final String key) { + this.map.remove(key); + } + + /** + * @param jsonPrint object, which text representation will be created + * @return string representation of this json object + */ + public String toString(final JsonPrint jsonPrint) { + switch (jsonPrint) { + case MINIMAL: return toMinimalString(); + case PRETTY: return toPrettyString(); + default: + throw new JsonException("Unknown JsonPrint: " + jsonPrint); + } + } + + /** + * @return String representation of this json object in minimal version + */ + public String toMinimalString() { + return JsonObjectPrinter.toMinimalString(this); + } + + /** + * @return String representation of this json object in pretty toString + * version + */ + public String toPrettyString() { + return JsonObjectPrinter.toPrettyString(this); + } + + /** + * @return copy of this json object + */ + public JsonObject getCopy() { + String stringRepresentationOfThisObject = this.toMinimalString(); + return new JsonObject(stringRepresentationOfThisObject); + } + + /** + * @return key iterator + */ + public List keyList() { + return ((PowerMap) this.map).keyList(); + } + + final JsonValue getJsonValue(final String key) { + return this.map.get(key); + } + + @Override + public final String toString() { + return this.toMinimalString(); + } + +} diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectDeserializable.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectDeserializable.java new file mode 100644 index 0000000..b55c2e8 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectDeserializable.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface JsonObjectDeserializable { + + /** + * Sets this object from a json object. + * @param jsonObject given json object + */ + void fromJsonObject(JsonObject jsonObject); +} diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectKeyValue.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectKeyValue.java new file mode 100644 index 0000000..15320c3 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectKeyValue.java @@ -0,0 +1,84 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class JsonObjectKeyValue { + + private String key; + private String value; + + JsonObjectKeyValue(final String string) { + int colonIndex = findColonIndex(string); + parseKey(string, colonIndex); + parseValue(string, colonIndex); + } + + private void parseKey(final String string, + int colonIndex) { + final int keyStartIndex = 0; + final int keyEndIndex = colonIndex; + key = string.substring(keyStartIndex, keyEndIndex).trim(); + key = cleanKey(key); + } + + private void parseValue(final String string, + int colonIndex) { + final int valueStartIndex = ++colonIndex; + final int valueEndIndex = string.length(); + value = string.substring(valueStartIndex, valueEndIndex).trim(); + } + + private int findColonIndex(final String string) { + int colonIndex; + for (colonIndex = 0; colonIndex < string.length(); colonIndex++) { + char currentChar = string.charAt(colonIndex); + if (currentChar == JsonConstants.COLON) { + return colonIndex; + } + } + throw new JsonException("Colon was not found in " + string); + } + + /** + * Removes the apostrophe from the key. + * + * @param key + * @return + */ + private String cleanKey(final String key) { + return JsonParser.deleteTheCharAtTheStartAndTheEnd(key); + } + + String getKey() { + return key; + } + + String getValue() { + return value; + } +} diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java new file mode 100644 index 0000000..8147ba7 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java @@ -0,0 +1,78 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import java.util.*; + +/** + * Is used to create json objects from strings. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +class JsonObjectParser extends JsonParser { + + /** + * Parses String to empty json object. + * + * @param jsonObject + * @param stringRepresentationOfJsonObject + * @return json object from parsed String + */ + static JsonObject parseStringToJsonObject(JsonObject jsonObject, + String stringRepresentationOfJsonObject) { + if (!jsonObject.isEmpty()) { + throw new JsonException("I can't parse. The json object is not empty."); + } + String trimmedStringRepresentationOfJsonObject = stringRepresentationOfJsonObject.trim(); + if (!isStringJsonObject(trimmedStringRepresentationOfJsonObject)) { + throw new JsonException("I can't parse. The trimmed String does not start with { or does not end with }"); + } + String collectionsOfValuesOfTheJsonObjectString = deleteTheCharAtTheStartAndTheEnd(trimmedStringRepresentationOfJsonObject); + + ArrayList array = ArrayWithItemsSplitByComma.getListWithItemsSplitByComma(collectionsOfValuesOfTheJsonObjectString); + for (final String element : array) { + JsonObjectKeyValue jsonObjectKeyValue = new JsonObjectKeyValue(element); + String key = jsonObjectKeyValue.getKey(); + String value = jsonObjectKeyValue.getValue(); + JsonValue jsonValue = JsonValue.parseStringToJsonValue(value); + //System.out.println("\n\nelement: " + element + "\nkey: " + key + " \nvalue: " + value + " " + jsonValue.getJsonValueType() + " " + jsonValue.toMinimalString()); + + jsonObject.addJsonValue(key, jsonValue); + } + return jsonObject; + } + + private static boolean isStringJsonObject( + String trimmedStringRepresentationOfJsonObject) { + return (getFirstCharOfTheString(trimmedStringRepresentationOfJsonObject) == JsonConstants.OBJECTSTART) && (getLastCharOfTheString(trimmedStringRepresentationOfJsonObject) == JsonConstants.OBJECTEND); + } + + /** + * Constructor + *

+ * Not meant to be instantiated. + */ + private JsonObjectParser() { + //Not meant to be instantiated. + } +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java similarity index 65% rename from src/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java index ca3cfa6..4ebe964 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectPrinter.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -20,27 +20,18 @@ package org.nanoboot.powerframework.json; -import org.nanoboot.powerframework.collections.DictionaryKeyIterator; +import java.util.List; /** * Used to create String representation of a json object. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonObjectPrinter extends JsonPrinter { - /** - * Constructor - * - * Not meant to be instantiated. - */ - private JsonObjectPrinter() { - //Not meant to be instantiated. - } - /** * @param jsonObject - * * @return String representation of this json object in minimal version */ static String toMinimalString(JsonObject jsonObject) { @@ -49,8 +40,8 @@ class JsonObjectPrinter extends JsonPrinter { /** * @param jsonObject - * - * @return String representation of this json object in pretty print version + * @return String representation of this json object in pretty toString + * version */ static String toPrettyString(JsonObject jsonObject) { return toString(jsonObject, true); @@ -59,50 +50,60 @@ class JsonObjectPrinter extends JsonPrinter { /** * @param jsonObject * @param printAsPrettyVersion - * * @return String representation of this json object */ - static String toString(JsonObject jsonObject, boolean printAsPrettyVersion) { - DictionaryKeyIterator keyIterator = jsonObject.getKeyIterator(); + static String toString(JsonObject jsonObject, + boolean printAsPrettyVersion) { + List keyList = jsonObject.keyList(); String value; String key; StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(JsonSpecialCharSequences.getObjectLeft()); + stringBuilder.append(JsonConstants.OBJECTSTART); if (printAsPrettyVersion) { - stringBuilder.append(JsonSpecialCharSequences.getLineBreak()); + stringBuilder.append(JsonConstants.LINEBREAK); } - while (keyIterator.hasNext()) { - key = keyIterator.getNextKey(); - if (printAsPrettyVersion) { - value = jsonObject.getJsonValue(key).toPrettyString(); - } else { - value = jsonObject.getJsonValue(key).toMinimalString(); - } + int setSize = keyList.size(); + int index = 0; + int lastIndex = setSize - 1; + for (String e : keyList){ + key = e; + value = printAsPrettyVersion ? jsonObject.getJsonValue(key).toPrettyString() : jsonObject.getJsonValue(key).toMinimalString(); if (printAsPrettyVersion) { - stringBuilder.append(JsonSpecialCharSequences.getTab()); + stringBuilder.append(JsonConstants.TAB); } - stringBuilder.append(JsonSpecialCharSequences.getApostrophe()); + stringBuilder.append(JsonConstants.APOSTROPHE); stringBuilder.append(key); - stringBuilder.append(JsonSpecialCharSequences.getApostrophe()); - stringBuilder.append(JsonSpecialCharSequences.getColon()); + stringBuilder.append(JsonConstants.APOSTROPHE); + stringBuilder.append(JsonConstants.COLON); if (printAsPrettyVersion && ((jsonObject.getJsonValue(key).isArray()) || (jsonObject.getJsonValue(key).isObject()))) { value = addTabOnEveryLineStartWithoutFirst(value); } stringBuilder.append(value); - if (keyIterator.hasNext()) { + boolean hasNext = index != lastIndex; + if (hasNext) { stringBuilder.append(","); } if (printAsPrettyVersion) { - stringBuilder.append(JsonSpecialCharSequences.getLineBreak()); + stringBuilder.append(JsonConstants.LINEBREAK); } + index++; } - stringBuilder.append(JsonSpecialCharSequences.getObjectRight()); + stringBuilder.append(JsonConstants.OBJECTEND); return stringBuilder.toString(); } + + /** + * Constructor + *

+ * Not meant to be instantiated. + */ + private JsonObjectPrinter() { + //Not meant to be instantiated. + } } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectSerializable.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectSerializable.java new file mode 100644 index 0000000..19680a6 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectSerializable.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface JsonObjectSerializable { + + /** + * Creates JsonObject representation of the instance + * of the class implementing this interface. + * + * @return JsonObject representation of the instance + * of the class implementing this interface + */ + JsonObject toJsonObject(); +} diff --git a/src/main/java/org/nanoboot/powerframework/json/SerializableToJsonObject.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectValidator.java similarity index 80% rename from src/main/java/org/nanoboot/powerframework/json/SerializableToJsonObject.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectValidator.java index 8216581..9fa8016 100644 --- a/src/main/java/org/nanoboot/powerframework/json/SerializableToJsonObject.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonObjectValidator.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -21,10 +21,11 @@ package org.nanoboot.powerframework.json; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public interface SerializableToJsonObject { - public JsonObject toJsonObject(); - public void fromJsonObject(JsonObject jsonObject); +class JsonObjectValidator { + } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonParser.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonParser.java new file mode 100644 index 0000000..eb5293c --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonParser.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * Used to parse String representation of JsonObject or JsonArray to their + * object representation. + * + * @author Robert Vokac + * @since 0.0.0 + */ +class JsonParser { + + static char getFirstCharOfTheString(final String string) { + return string.charAt(0); + } + + static char getLastCharOfTheString(final String string) { + return string.charAt(string.length() - 1); + } + + protected static String deleteTheCharAtTheStartAndTheEnd(final String string) { + return string.substring(1, string.length() - 1); + } + + /** + * Constructor + *

+ * Not meant to be instantiated. + */ + JsonParser() { + //Not meant to be instantiated. + } + +} diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrint.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrint.java new file mode 100644 index 0000000..f511a5a --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrint.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum JsonPrint { + + /** + * + */ + PRETTY, + + /** + * + */ + MINIMAL; +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonPrinter.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrinter.java similarity index 71% rename from src/main/java/org/nanoboot/powerframework/json/JsonPrinter.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrinter.java index 509d913..0e2eae3 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonPrinter.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonPrinter.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,25 +23,27 @@ package org.nanoboot.powerframework.json; /** * Used for JsonObjectPrinter and JsonArrayPrinter to extend. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ class JsonPrinter { + private static final String BREAKTAB = "\n" + JsonConstants.TAB; + + protected static String addTabOnEveryLineStart(final String value) { + return JsonConstants.TAB + addTabOnEveryLineStartWithoutFirst(value); + } + + protected static String addTabOnEveryLineStartWithoutFirst(final String value) { + return value.replace("\n", BREAKTAB); + } + /** * Constructor - * + *

* Not meant to be instantiated. */ JsonPrinter() { //Not meant to be instantiated. } - - static String addTabOnEveryLineStart(String value) { - String result = value.replace("\n", new String("\n" + JsonSpecialCharSequences.getTab())); - return JsonSpecialCharSequences.getTab() + result; - } - - static String addTabOnEveryLineStartWithoutFirst(String value) { - return value.replace("\n", new String("\n" + JsonSpecialCharSequences.getTab())); - } } diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonString.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonString.java similarity index 77% rename from src/main/java/org/nanoboot/powerframework/json/JsonString.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonString.java index 5b8bb2c..5316676 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonString.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonString.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,26 +23,26 @@ package org.nanoboot.powerframework.json; /** * Represents String json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * + * @author Robert Vokac + * @since 0.0.0 */ + class JsonString { - private final String value; - - JsonString(String value) { - this.value = value; - } - - String getString() { - return this.value; - } - - @Override - public String toString() { + static String toString(final String value) { StringBuilder sb = new StringBuilder(); sb.append('\"'); - sb.append(getString()); + sb.append(value); sb.append('\"'); return sb.toString(); } + + /** + * Not meant to be instantiated. + */ + private JsonString() { + //Not meant to be instantiated. + } } diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/JsonValue.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonValue.java new file mode 100644 index 0000000..b37201d --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonValue.java @@ -0,0 +1,364 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; + +import static org.nanoboot.powerframework.json.JsonParser.deleteTheCharAtTheStartAndTheEnd; +import static org.nanoboot.powerframework.json.JsonParser.getFirstCharOfTheString; + +/** + * Represents json value. + * + * @author Robert Vokac + * @since 0.0.0 + */ +class JsonValue { + + static JsonValue parseStringToJsonValue(final String stringToParse) {//NOSONAR + String trimmedStringToParse = stringToParse.trim(); + final char firstChar = getFirstCharOfTheString(trimmedStringToParse); + + if ("null".equals(trimmedStringToParse)) { + return new JsonValue(); + } + if (JsonConstants.OBJECTSTART == firstChar) { + return new JsonValue(new JsonObject(trimmedStringToParse)); + } + if (JsonConstants.ARRAYSTART == firstChar) { + return new JsonValue(new JsonArray(trimmedStringToParse)); + } + if ("true".equals(trimmedStringToParse)) { + return new JsonValue(true); + } + if ("false".equals(trimmedStringToParse)) { + return new JsonValue(false); + } + if (JsonConstants.APOSTROPHE == firstChar) { + return parseStringToStringOrChar(trimmedStringToParse); + } + try { + return parseStringToIntOrLongOrFloatOrDouble(trimmedStringToParse); + } catch (Exception e) { + throw new JsonException("Something went wrong. I am not able to parse: \"" + stringToParse + "\". " + e); + } + + } + + private static JsonValue parseStringToStringOrChar(final String stringToParse) { + String stringWithoutQuotes = deleteTheCharAtTheStartAndTheEnd(stringToParse); + if (stringWithoutQuotes.length() == 1) { + return new JsonValue(stringWithoutQuotes.charAt(0)); + } else { + return new JsonValue(stringWithoutQuotes); + } + } + + private static JsonValue parseStringToIntOrLongOrFloatOrDouble( + String stringToParse) { + String intOrLongPattern = "-?[0-9]*"; + String floatOrDoublePattern = "-?([0-9]*)\\.([0-9]*)"; + + if (Pattern.matches(floatOrDoublePattern, stringToParse)) { + return parseStringToFloatOrDouble(stringToParse); + } + if (Pattern.matches(intOrLongPattern, stringToParse)) { + return parseStringToIntOrLong(stringToParse); + } + throw new JsonException("I am not able to parse the number: \"" + stringToParse + "\"."); + } + + private static JsonValue parseStringToIntOrLong(final String stringToParse) { + try { + return new JsonValue(Integer.parseInt(stringToParse)); + } catch (NumberFormatException e) { + //Logger.getLogger(JsonParser.class.getName()).log(Level.SEVERE, null, e); + try { + return new JsonValue(Long.parseLong(stringToParse)); + } catch (NumberFormatException e2) { + Logger.getLogger(JsonParser.class.getName()).log(Level.SEVERE, null, e2); + throw new JsonException("The number is too long."); + } + } + } + + private static JsonValue parseStringToFloatOrDouble(final String stringToParse) { + int digitsPrecision = 0; + String stringToParseWithoutMinus = stringToParse; + if (stringToParseWithoutMinus.startsWith("-")) { + stringToParseWithoutMinus = stringToParseWithoutMinus.substring(1); + } + for (int i = 0; i < stringToParseWithoutMinus.length(); i++) { + char currentChar = stringToParseWithoutMinus.charAt(i); + if (currentChar == '.') { + digitsPrecision = stringToParseWithoutMinus.length() - 1 - i; + break; + } + } + if (digitsPrecision > 6) { + try { + return new JsonValue(Double.parseDouble(stringToParse)); + } catch (NumberFormatException e) { + //NOSONAR + throw new JsonException("The number is too long."); + } + } else { + return new JsonValue(Float.parseFloat(stringToParse)); + } + } + + private JsonValueType jsonValueType = null; + + private JsonObject jsonObject; + private JsonArray jsonArray; + private boolean jsonBoolean; + private String jsonString; + private char jsonChar; + private int jsonInt; + private long jsonLong; + private float jsonFloat; + private double jsonDouble; + + JsonValue() { + this.jsonValueType = JsonValueType.NULL; + } + + JsonValue(JsonObject jsonObject) { + this.jsonValueType = JsonValueType.OBJECT; + this.jsonObject = jsonObject; + } + + JsonValue(JsonArray jsonArray) { + this.jsonValueType = JsonValueType.ARRAY; + this.jsonArray = jsonArray; + } + + JsonValue(boolean jsonBoolean) { + this.jsonValueType = JsonValueType.BOOLEAN; + this.jsonBoolean = jsonBoolean; + } + + JsonValue(final String jsonString) { + this.jsonValueType = JsonValueType.STRING; + this.jsonString = jsonString; + } + + JsonValue(char jsonLiteral) { + this.jsonValueType = JsonValueType.CHAR; + this.jsonChar = jsonLiteral; + } + + JsonValue(int jsonInt) { + this.jsonValueType = JsonValueType.INT; + this.jsonInt = jsonInt; + } + + JsonValue(long jsonLong) { + this.jsonValueType = JsonValueType.LONG; + this.jsonLong = jsonLong; + } + + JsonValue(float jsonFloat) { + this.jsonValueType = JsonValueType.FLOAT; + this.jsonFloat = jsonFloat; + } + + JsonValue(double jsonDouble) { + this.jsonValueType = JsonValueType.DOUBLE; + this.jsonDouble = jsonDouble; + } + + JsonValueType getJsonValueType() { + return this.jsonValueType; + } + + boolean isJsonValueType(JsonValueType jsonValueType) { + return this.jsonValueType == jsonValueType; + } + + boolean isNull() { + return isJsonValueType(JsonValueType.NULL); + } + + boolean isObject() { + return isJsonValueType(JsonValueType.OBJECT); + } + + boolean isArray() { + return isJsonValueType(JsonValueType.ARRAY); + } + + boolean isBoolean() { + return isJsonValueType(JsonValueType.BOOLEAN); + } + + boolean isString() { + return isJsonValueType(JsonValueType.STRING); + } + + boolean isChar() { + return isJsonValueType(JsonValueType.CHAR); + } + + boolean isInt() { + return isJsonValueType(JsonValueType.INT); + } + + boolean isLong() { + return isJsonValueType(JsonValueType.LONG); + } + + boolean isFloat() { + return isJsonValueType(JsonValueType.FLOAT); + } + + boolean isDouble() { + return isJsonValueType(JsonValueType.DOUBLE); + } + + JsonObject getJsonObject() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.OBJECT); + return this.jsonObject; + } + + JsonArray getJsonArray() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.ARRAY); + return this.jsonArray; + } + + boolean getJsonBoolean() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.BOOLEAN); + return this.jsonBoolean; + } + + String getJsonString() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.STRING); + return this.jsonString; + } + + char getJsonChar() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.CHAR); + return this.jsonChar; + } + + int getJsonInt() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.INT); + return this.jsonInt; + } + + long getJsonLong() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.LONG); + return this.jsonLong; + } + + float getJsonFloat() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.FLOAT); + return this.jsonFloat; + } + + double getJsonDouble() { + throwExceptionIfTypeDoesNotMatch(JsonValueType.DOUBLE); + return this.jsonDouble; + } + + private void throwExceptionIfTypeDoesNotMatch( + JsonValueType wantedJsonValueType) { + if (this.getJsonValueType().equals(wantedJsonValueType)) { + return; + } + throw new JsonException("This JsonValue has no type " + wantedJsonValueType + " The value type is " + this.getJsonValueType().name()); + } + + String toPrettyString() { + return toString(true); + } + + String toMinimalString() { + return toString(false); + } + + String toString(boolean printAsPrettyVersion) {//NOSONAR + switch (this.jsonValueType) { + case NULL: + return JsonConstants.NULL; + case OBJECT: + return printAsPrettyVersion ? this.getJsonObject().toPrettyString() : this.getJsonObject().toMinimalString(); + case ARRAY: + return printAsPrettyVersion ? this.getJsonArray().toPrettyString() : this.getJsonArray().toMinimalString(); + case BOOLEAN: + return JsonBoolean.toString(jsonBoolean); + case STRING: + return JsonString.toString(jsonString); + case CHAR: + return JsonChar.toString(jsonChar); + case INT: + return JsonInt.toString(jsonInt); + case LONG: + return JsonLong.toString(jsonLong); + case FLOAT: + return JsonFloat.toString(jsonFloat); + case DOUBLE: + return JsonDouble.toString(jsonDouble); + default: + throw new IllegalStateException("Enum error."); + } + } + + Object toObject() {//NOSONAR + switch (jsonValueType) { + case NULL: + return null; + + case OBJECT: + return this.getJsonObject(); + + case ARRAY: + return this.getJsonArray(); + + case BOOLEAN: + return this.jsonBoolean; + + case STRING: + return this.jsonString; + + case CHAR: + return this.jsonChar; + + case INT: + return this.jsonInt; + + case LONG: + return this.jsonLong; + + case FLOAT: + return this.jsonFloat; + + case DOUBLE: + return this.jsonDouble; + + default: + throw new IllegalStateException("Enum error."); + } + + } +} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonValueType.java b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonValueType.java similarity index 91% rename from src/main/java/org/nanoboot/powerframework/json/JsonValueType.java rename to power-json/src/main/java/org/nanoboot/powerframework/json/JsonValueType.java index 3f983cf..433eab8 100644 --- a/src/main/java/org/nanoboot/powerframework/json/JsonValueType.java +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/JsonValueType.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -23,7 +23,8 @@ package org.nanoboot.powerframework.json; /** * Represents the type of a json value. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public enum JsonValueType { diff --git a/power-json/src/main/java/org/nanoboot/powerframework/json/package-info.java b/power-json/src/main/java/org/nanoboot/powerframework/json/package-info.java new file mode 100644 index 0000000..2fffa38 --- /dev/null +++ b/power-json/src/main/java/org/nanoboot/powerframework/json/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Json classes. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.json; diff --git a/power-json/src/main/resources/.gitkeep b/power-json/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-json/src/test/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByCommaTest.java b/power-json/src/test/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByCommaTest.java new file mode 100644 index 0000000..8fec2a6 --- /dev/null +++ b/power-json/src/test/java/org/nanoboot/powerframework/json/ArrayWithItemsSplitByCommaTest.java @@ -0,0 +1,66 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import java.util.*; + +import static org.junit.Assert.assertTrue; + +import org.junit.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ArrayWithItemsSplitByCommaTest { + + public ArrayWithItemsSplitByCommaTest() { + } + + /** + * Test of getListWithItemsSplitByComma method, of class + * ArrayWithItemsSplitByComma. + */ + @Test + public void testGetListWithItemsSplitByComma() { + //arrange + String stringToSplit = "\"date of death\":null,\"father\":{\"name\":\"Peter\",\"surname\":\"Black\"},\"mother\":{\"name\":\"Sue\",\"surname\":\"Black\"},\"property\":[null,{\"type\":\"computer\",\"cpu\":\"corei7\",\"ram\":\"16GB\"},[\"8GB memory card\",\"16GB memory card\",\"32GB memory card\",\"128GB memory card\"],true,\"car\",\"y\",42,9987987998798,4.56,1.646659262492],\"is rich\":true,\"name\":\"John\",\"surname\":\"Black\",\"date of birth\":\"1975-09-23\",\"favorit letter\":\"W\",\"year of birth\":1975,\"favorit very long number\":8798799845647987,\"height\":173.5466,\"height- high precision\":173.54666549879545"; + String expectedString = "\"date of death\":null###\"father\":{\"name\":\"Peter\",\"surname\":\"Black\"}###\"mother\":{\"name\":\"Sue\",\"surname\":\"Black\"}###\"property\":[null,{\"type\":\"computer\",\"cpu\":\"corei7\",\"ram\":\"16GB\"},[\"8GB memory card\",\"16GB memory card\",\"32GB memory card\",\"128GB memory card\"],true,\"car\",\"y\",42,9987987998798,4.56,1.646659262492]###\"is rich\":true###\"name\":\"John\"###\"surname\":\"Black\"###\"date of birth\":\"1975-09-23\"###\"favorit letter\":\"W\"###\"year of birth\":1975###\"favorit very long number\":8798799845647987###\"height\":173.5466###\"height- high precision\":173.54666549879545###"; + String returnedString; + StringBuilder stringBuilder = new StringBuilder(); + //act + ArrayList list = ArrayWithItemsSplitByComma.getListWithItemsSplitByComma(stringToSplit); + final String threeHashes = "###"; + for (String element : list) { + stringBuilder.append(element); + stringBuilder.append(threeHashes); + } + + returnedString = stringBuilder.toString(); + //System.out.println("a" + expectedString + "b" + "\n" + "c" + returnedString + "d"); + //assert + assertTrue(expectedString.equals(returnedString)); + } + +} diff --git a/power-json/src/test/java/org/nanoboot/powerframework/json/CommasFinderTest.java b/power-json/src/test/java/org/nanoboot/powerframework/json/CommasFinderTest.java new file mode 100644 index 0000000..443c375 --- /dev/null +++ b/power-json/src/test/java/org/nanoboot/powerframework/json/CommasFinderTest.java @@ -0,0 +1,64 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.json; + +import java.util.*; + +import static org.junit.Assert.assertTrue; + +import org.junit.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CommasFinderTest { + + public CommasFinderTest() { + } + + /** + * Test of getListOfIndexesOfCommas method, of class CommasFinder. + */ + @Test + public void testGetListOfIndexesOfCommas() { + String stringToSplit = "\"date of death\":null,\"father\":{\"name\":\"Peter\",\"surname\":\"Black\"},\"mother\":{\"name\":\"Sue\",\"surname\":\"Black\"},\"property\":[null,{\"type\":\"computer\",\"cpu\":\"corei7\",\"ram\":\"16GB\"},[\"8GB memory card\",\"16GB memory card\",\"32GB memory card\",\"128GB memory card\"],true,\"car\",\"y\",42,9987987998798,4.56,1.646659262492],\"is rich\":true,\"name\":\"John\",\"surname\":\"Black\",\"date of birth\":\"1975-09-23\",\"favorit letter\":\"W\",\"year of birth\":1975,\"favorit very long number\":8798799845647987,\"height\":173.5466,\"height- high precision\":173.54666549879545"; + //arrange + String expectedString = "20,64,106,302,317,331,349,378,399,420,464,482,"; + String returnedString; + StringBuilder stringBuilder = new StringBuilder(); + //act + ArrayList listOfCommas = CommasFinder.getListOfIndexesOfCommas(stringToSplit); + for (int element : listOfCommas) { + stringBuilder.append(element); + stringBuilder.append(JsonConstants.COMMA); + } + + returnedString = stringBuilder.toString(); + //System.out.println("a"+expectedString+"b"+"\n"+"c"+returnedString+"d"); + //assert + assertTrue(expectedString.equals(returnedString)); + } + +} diff --git a/src/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java b/power-json/src/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java similarity index 97% rename from src/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java rename to power-json/src/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java index f20522f..1602db7 100644 --- a/src/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java +++ b/power-json/src/test/java/org/nanoboot/powerframework/json/JsonArrayTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -20,13 +20,18 @@ package org.nanoboot.powerframework.json; -import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class JsonArrayTest { /** @@ -70,7 +75,7 @@ public class JsonArrayTest { jsonArray.addString("calm"); //act - returnedValue = jsonArray.getCountOfItems(); + returnedValue = jsonArray.size(); //assert assertEquals(expectedValue, returnedValue); } @@ -113,7 +118,7 @@ public class JsonArrayTest { } /** - * Test of add method, of class JsonArray. + * Test of addJsonValue method, of class JsonArray. */ @Test public void testAdd() { @@ -684,7 +689,7 @@ public class JsonArrayTest { JsonArray jsonArray = new JsonArray(); jsonArray.addInt(4);//act jsonValue = jsonArray.getJsonValue(0); - returnedValue = jsonValue.getJsonInt().getInt(); + returnedValue = jsonValue.getJsonInt(); //assert assertEquals(expectedValue, returnedValue); } @@ -790,6 +795,7 @@ public class JsonArrayTest { returnedString = propertyCopy.toMinimalString(); //assert boolean result = expectedString.equals(returnedString); + //System.out.println(expectedString +"\n"+ returnedString); assertEquals(expectedString, returnedString); } diff --git a/src/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java b/power-json/src/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java similarity index 93% rename from src/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java rename to power-json/src/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java index bff39e7..e8969c4 100644 --- a/src/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java +++ b/power-json/src/test/java/org/nanoboot/powerframework/json/JsonObjectTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -20,14 +20,16 @@ package org.nanoboot.powerframework.json; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.collections.DictionaryKeyIterator; -import org.junit.Test; +import java.util.*; + import static org.junit.Assert.*; +import org.junit.*; + /** * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class JsonObjectTest { @@ -52,6 +54,7 @@ public class JsonObjectTest { personJohnBlack = new JsonObject(expectedString); returnedString = personJohnBlack.toMinimalString(); //assert + //System.out.println(expectedString+" fff "+returnedString); boolean result = expectedString.equals(returnedString); assertEquals(expectedString, returnedString); } @@ -70,7 +73,7 @@ public class JsonObjectTest { jsonObject.addString("nick", "Johny"); jsonObject.addString("name", "John"); jsonObject.addInt("age", 43); - returnedValue = jsonObject.getCountOfItems(); + returnedValue = jsonObject.size(); //assert assertEquals(expectedValue, returnedValue); } @@ -110,7 +113,7 @@ public class JsonObjectTest { } /** - * Test of containsValueWithKey method, of class JsonObject. + * Test of hasKey method, of class JsonObject. */ @Test public void testContainsValueWithKey() { @@ -123,13 +126,13 @@ public class JsonObjectTest { jsonObject.addString("nick", "Johny"); jsonObject.addString("name", "John"); jsonObject.addInt("age", 43); - returnedValue = jsonObject.containsValueWithKey("nick"); + returnedValue = jsonObject.hasKey("nick"); //assert assertEquals(expectedValue, returnedValue); } /** - * Test of containsValueWithKey method, of class JsonObject. + * Test of hasKey method, of class JsonObject. */ @Test public void testContainsValueWithKey2() { @@ -142,13 +145,13 @@ public class JsonObjectTest { jsonObject.addString("nick", "Johny"); jsonObject.addString("name", "John"); jsonObject.addInt("age", 43); - returnedValue = jsonObject.containsValueWithKey("nationality"); + returnedValue = jsonObject.hasKey("nationality"); //assert assertEquals(expectedValue, returnedValue); } /** - * Test of containsValueWithKey method, of class JsonObject. + * Test of hasKey method, of class JsonObject. */ @Test public void testContainsValueWithKey3() { @@ -158,13 +161,13 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addString("personality", "calm"); - returnedValue = jsonObject.containsValueWithKey("personality"); + returnedValue = jsonObject.hasKey("personality"); //assert assertEquals(expectedValue, returnedValue); } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsNull() { @@ -180,7 +183,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsJsonObject() { @@ -196,7 +199,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsJsonArray() { @@ -212,7 +215,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsBoolean() { @@ -228,7 +231,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsString() { @@ -244,7 +247,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsChar() { @@ -260,7 +263,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsInt() { @@ -276,7 +279,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsLong() {//arrange @@ -291,7 +294,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsFloat() { @@ -307,7 +310,7 @@ public class JsonObjectTest { } /** - * Test of add method, of class JsonObject. + * Test of addJsonValue method, of class JsonObject. */ @Test public void testAdd_ObjectIsDouble() { @@ -333,7 +336,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addNull("nothing"); - returnedValue = jsonObject.containsValueWithKey("nothing"); + returnedValue = jsonObject.hasKey("nothing"); //assert assertEquals(expectedValue, returnedValue); } @@ -349,7 +352,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addObject("object", new JsonObject()); - returnedValue = jsonObject.containsValueWithKey("object"); + returnedValue = jsonObject.hasKey("object"); //assert assertEquals(expectedValue, returnedValue); } @@ -365,7 +368,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addArray("array", new JsonArray()); - returnedValue = jsonObject.containsValueWithKey("array"); + returnedValue = jsonObject.hasKey("array"); //assert assertEquals(expectedValue, returnedValue); } @@ -381,7 +384,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addBoolean("boolean", true); - returnedValue = jsonObject.containsValueWithKey("boolean"); + returnedValue = jsonObject.hasKey("boolean"); //assert assertEquals(expectedValue, returnedValue); } @@ -397,7 +400,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addString("String", "some text"); - returnedValue = jsonObject.containsValueWithKey("String"); + returnedValue = jsonObject.hasKey("String"); //assert assertEquals(expectedValue, returnedValue); } @@ -413,7 +416,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addChar("char", 'a'); - returnedValue = jsonObject.containsValueWithKey("char"); + returnedValue = jsonObject.hasKey("char"); //assert assertEquals(expectedValue, returnedValue); } @@ -429,7 +432,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addInt("int", 2); - returnedValue = jsonObject.containsValueWithKey("int"); + returnedValue = jsonObject.hasKey("int"); //assert assertEquals(expectedValue, returnedValue); } @@ -445,7 +448,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addLong("long", 2l); - returnedValue = jsonObject.containsValueWithKey("long"); + returnedValue = jsonObject.hasKey("long"); //assert assertEquals(expectedValue, returnedValue); } @@ -461,7 +464,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addFloat("float", 2.5f); - returnedValue = jsonObject.containsValueWithKey("float"); + returnedValue = jsonObject.hasKey("float"); //assert assertEquals(expectedValue, returnedValue); } @@ -477,7 +480,7 @@ public class JsonObjectTest { boolean returnedValue; //act jsonObject.addDouble("double", 2.5d); - returnedValue = jsonObject.containsValueWithKey("double"); + returnedValue = jsonObject.hasKey("double"); //assert assertEquals(expectedValue, returnedValue); } @@ -642,6 +645,21 @@ public class JsonObjectTest { assertEquals(expectedValue, returnedValue); } + /** + * Test of isJsonValueType method, of class JsonObject. + */ + @Test + public void testIsJsonValueType() { + //arrange + JsonObject jsonObject = new JsonObject(); + JsonValueType jsonValueType = JsonValueType.DOUBLE; + + //act + jsonObject.addDouble("double", 2.5d); + //assert + assertTrue(jsonObject.isJsonValueType("double", jsonValueType)); + } + /** * Test of get method, of class JsonObject. */ @@ -1010,12 +1028,12 @@ public class JsonObjectTest { jsonObject.removeJsonValue("nick"); try { jsonObject.getString("nick"); - } catch (PowerRuntimeException e) { + } catch (NoSuchElementException e) { isExceptionThrown = true; } //assert if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); + fail("There should be thrown NoSuchElementException"); } } @@ -1163,6 +1181,7 @@ public class JsonObjectTest { personJohnBlackCopy = personJohnBlack.getCopy(); returnedString = personJohnBlackCopy.toMinimalString(); //assert + System.out.println(expectedString + " " + returnedString); boolean result = expectedString.equals(returnedString); assertEquals(expectedString, returnedString); } @@ -1174,7 +1193,7 @@ public class JsonObjectTest { public void testGetKeyIterator() { //arrange JsonObject jsonObject = new JsonObject(); - DictionaryKeyIterator dictionaryKeyIterator; + List list; String expectedString = "name"; String returnedString; //act @@ -1182,31 +1201,10 @@ public class JsonObjectTest { jsonObject.addString("nick", "Johny"); jsonObject.addString("name", "John"); jsonObject.addInt("age", 43); - dictionaryKeyIterator = jsonObject.getKeyIterator(); - dictionaryKeyIterator.getNextKey(); - dictionaryKeyIterator.getNextKey(); - returnedString = dictionaryKeyIterator.getNextKey();; - //assert - assertEquals(expectedString, returnedString); - } + list = jsonObject.keyList(); - /** - * Test of getJsonValue method, of class JsonObject. - */ - @Test - public void testGetJsonValue() { - //arrange - JsonObject jsonObject = new JsonObject(); - DictionaryKeyIterator dictionaryKeyIterator; - String expectedString = "John"; - String returnedString; - //act - jsonObject.addString("personality", "calm"); - jsonObject.addString("nick", "Johny"); - jsonObject.addString("name", "John"); - jsonObject.addInt("age", 43); + returnedString = list.get(2); - returnedString = jsonObject.getJsonValue("name").getJsonString().getString(); //assert assertEquals(expectedString, returnedString); } diff --git a/src/test/java/org/nanoboot/powerframework/json/JsonValueTest.java b/power-json/src/test/java/org/nanoboot/powerframework/json/JsonValueTest.java similarity index 85% rename from src/test/java/org/nanoboot/powerframework/json/JsonValueTest.java rename to power-json/src/test/java/org/nanoboot/powerframework/json/JsonValueTest.java index cd4a4bf..27920b8 100644 --- a/src/test/java/org/nanoboot/powerframework/json/JsonValueTest.java +++ b/power-json/src/test/java/org/nanoboot/powerframework/json/JsonValueTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -20,13 +20,18 @@ package org.nanoboot.powerframework.json; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; -import static org.junit.Assert.*; +import org.nanoboot.powerframework.core.PowerException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class JsonValueTest { @@ -45,9 +50,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.STRING; - JsonString jsonString; + String jsonString; //act - jsonString = new JsonString("hello"); + jsonString = "hello"; jsonValue = new JsonValue(jsonString); expectedValue = jsonValue.getJsonValueType(); //assert @@ -115,9 +120,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.BOOLEAN; - JsonBoolean jsonBoolean; + boolean jsonBoolean; //act - jsonBoolean = new JsonBoolean(true); + jsonBoolean = true; jsonValue = new JsonValue(jsonBoolean); expectedValue = jsonValue.getJsonValueType(); //assert @@ -133,9 +138,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.STRING; - JsonString jsonString; + String jsonString; //act - jsonString = new JsonString("hello"); + jsonString = "hello"; jsonValue = new JsonValue(jsonString); expectedValue = jsonValue.getJsonValueType(); //assert @@ -151,9 +156,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.CHAR; - JsonChar jsonChar; + char jsonChar; //act - jsonChar = new JsonChar('h'); + jsonChar = 'h'; jsonValue = new JsonValue(jsonChar); expectedValue = jsonValue.getJsonValueType(); //assert @@ -169,9 +174,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.INT; - JsonInt jsonInt; + int jsonInt; //act - jsonInt = new JsonInt(549); + jsonInt = 549; jsonValue = new JsonValue(jsonInt); expectedValue = jsonValue.getJsonValueType(); //assert @@ -187,9 +192,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.LONG; - JsonLong jsonLong; + long jsonLong; //act - jsonLong = new JsonLong(4l); + jsonLong = 4l; jsonValue = new JsonValue(jsonLong); expectedValue = jsonValue.getJsonValueType(); //assert @@ -205,9 +210,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.FLOAT; - JsonFloat jsonFloat; + float jsonFloat; //act - jsonFloat = new JsonFloat(8.6f); + jsonFloat = 8.6f; jsonValue = new JsonValue(jsonFloat); expectedValue = jsonValue.getJsonValueType(); //assert @@ -223,9 +228,9 @@ public class JsonValueTest { JsonValue jsonValue; JsonValueType expectedValue; JsonValueType returnedValue = JsonValueType.DOUBLE; - JsonDouble jsonDouble; + double jsonDouble; //act - jsonDouble = new JsonDouble(8.6d); + jsonDouble = 8.6d; jsonValue = new JsonValue(jsonDouble); expectedValue = jsonValue.getJsonValueType(); //assert @@ -239,12 +244,12 @@ public class JsonValueTest { public void testGetJsonObject() { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonObject(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -261,12 +266,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonArray(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -283,12 +288,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonBoolean(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -305,12 +310,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonString(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -327,12 +332,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonChar(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -349,12 +354,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonInt(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -371,12 +376,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonLong(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -393,12 +398,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonFloat(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert @@ -415,12 +420,12 @@ public class JsonValueTest { //arrange boolean isExceptionThrown = false; - JsonString jsonString = new JsonString("hello"); + String jsonString = "hello"; JsonValue jsonValue = new JsonValue(jsonString); //act try { jsonValue.getJsonDouble(); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert diff --git a/power-log/pom.xml b/power-log/pom.xml new file mode 100644 index 0000000..8b02e40 --- /dev/null +++ b/power-log/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-log + jar + + Power Log + Log functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-time + ${power.version} + + + org.nanoboot.powerframework + power-utils + ${power.version} + + + + + junit + junit + 4.12 + test + + + + diff --git a/power-log/src/main/java/module-info.java b/power-log/src/main/java/module-info.java new file mode 100644 index 0000000..b4fd93c --- /dev/null +++ b/power-log/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.log { + exports org.nanoboot.powerframework.log; + requires powerframework.time; + requires powerframework.utils; +} diff --git a/power-log/src/main/java/org/nanoboot/powerframework/log/Level.java b/power-log/src/main/java/org/nanoboot/powerframework/log/Level.java new file mode 100644 index 0000000..819c6ca --- /dev/null +++ b/power-log/src/main/java/org/nanoboot/powerframework/log/Level.java @@ -0,0 +1,106 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.log; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum Level { + + /** + * + */ + OFF(0, "off", "The highest possible rank and is intended to turn off logging."), + + /** + * + */ + FATAL(1, "fatal", "Severe errors that cause premature termination. Expect these to be immediately visible on a status console."), + + /** + * + */ + ERROR(2, "error", "Other runtime errors or unexpected conditions. Expect these to be immediately visible on a status console."), + + /** + * + */ + WARN(3, "warn", "Use of deprecated APIs, poor use of API, 'almost' errors, other runtime situations that are undesirable or unexpected, but not necessarily \"wrong\". Expect these to be immediately visible on a status console."), + + /** + * + */ + INFO(4, "info", "Interesting runtime events (startup/shutdown). Expect these to be immediately visible on a console, so be conservative and keep to a minimum."), + + /** + * + */ + DEBUG(5, "debug", "Detailed information on the flow through the system. Expect these to be written to logs only. Generally speaking, most lines logged by your application should be written as DEBUG."), + + /** + * + */ + TRACE(6, "trace", "Most detailed information. Expect these to be written to logs only. "), + + /** + * + */ + ALL(7, "all", "All possible information will be logged."); + private final int verbiageIndex; + private final String name; + private final String description; + + Level(int verbiageIndex, + String name, + String description) { + this.verbiageIndex = verbiageIndex; + this.name = name; + this.description = description; + } + + /** + * + * @return + */ + public int getVerbiageIndex() { + return verbiageIndex; + } + + /** + * + * @return + */ + public String getDescription() { + return this.description; + } + + /** + * + * @return + */ + public String getName() { + return name; + } +} diff --git a/power-log/src/main/java/org/nanoboot/powerframework/log/LogRowCreator.java b/power-log/src/main/java/org/nanoboot/powerframework/log/LogRowCreator.java new file mode 100644 index 0000000..2073b28 --- /dev/null +++ b/power-log/src/main/java/org/nanoboot/powerframework/log/LogRowCreator.java @@ -0,0 +1,78 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.log; + +import org.nanoboot.powerframework.time.utils.LocalSettings; +import org.nanoboot.powerframework.time.moment.TimeZone; +import org.nanoboot.powerframework.time.moment.ZonedDateTime; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class LogRowCreator { + + private static final String DELIMITER = " "; + private static final String START = "["; + private static final String END = "]"; + private static final String STATIC = "----------STATIC"; + private static final String DASH = "-"; + private static final String NOTOKAYOBJECT = "NOT_OKAY_OBJECT"; + + static String createRow(long rowNumber, + Object object, + Level level, + String className, + String message) { + + if(object instanceof String) { + message = message + DELIMITER + "Warning: The object to log is String."; + } + + int hashCode = object == null ? 0 : object.hashCode(); + String hashCodeAsHexString = Integer.toHexString(hashCode); + + String hash = hashCodeAsHexString; + + TimeZone timeZone = LocalSettings.getLocalTimeZone(); + String time = ZonedDateTime.getCurrentZonedDateTimeForTimeZone(timeZone).toString(); + return org.nanoboot.powerframework.utils.StringUtils.appendObjects( + String.format("%08d", rowNumber), DELIMITER, + START, Thread.currentThread().getName(), END, DELIMITER, + level, DELIMITER, + START, time, " ", timeZone.toString(), END, DELIMITER, + hash, DELIMITER, + className, DELIMITER, + message + ); + + } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private LogRowCreator() { + } +} diff --git a/power-log/src/main/java/org/nanoboot/powerframework/log/Logger.java b/power-log/src/main/java/org/nanoboot/powerframework/log/Logger.java new file mode 100644 index 0000000..1a1516b --- /dev/null +++ b/power-log/src/main/java/org/nanoboot/powerframework/log/Logger.java @@ -0,0 +1,294 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.log; + +import java.io.BufferedWriter; +import java.io.FileWriter; + +/** + * + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Logger { + + private static Level level = Level.OFF; + private static Target target = Target.NOTARGET; + //0 for no limit + private static long maximumLogFileSizeInBytes = 0; + private static boolean logOkayClasses = false; + private static long rowNumber = 0; + + /** + * + * @param classValue + * + * @return + */ + public static Logger getLogger(Class classValue) { + return new Logger(classValue); + } + + /** + * + * @param levelArg + */ + public static void setLevel(Level levelArg) { + level = levelArg; + } + + /** + * + * @return + */ + public static Level getLevel() { + return level; + } + + /** + * + * @param targetArg + */ + public static void setTarget(Target targetArg) { + target = targetArg; + } + + /** + * + * @return + */ + public static Target getTarget() { + return target; + } + + /** + * + * @return + */ + public static long getMaximumLogFileSizeInBytes() { + return maximumLogFileSizeInBytes; + } + +// /** +// * +// * @param digitalInformationUnit +// * @param value +// */ +// public static void setMaximumLogFileSize( +// DigitalInformationUnit digitalInformationUnit, +// long value) { +// maximumLogFileSizeInBytes = digitalInformationUnit.getBytes() * value; +// } + + /** + * + * @return + */ + public static boolean isLogOkayClasses() { + return logOkayClasses; + } + + /** + * + * @param logOkayClasses + */ + public static void setLogOkayClasses(boolean logOkayClasses) { + Logger.logOkayClasses = logOkayClasses; + } + + private static boolean isLevelWanted(Level levelArg) { + if(Logger.getLevel().getVerbiageIndex() == 0) { + return false; + } + return levelArg.getVerbiageIndex() <= Logger.getLevel().getVerbiageIndex(); + } + private final String className; + private final boolean isOkayClass; + + private Logger(Class classValue) { + this.className = classValue.getName(); + isOkayClass = className.startsWith("org.nanoboot.powerframework."); + } + + /** + * + * @param object + * @param message + */ + public void fatal(Object object, + String message) { + log(object, Level.FATAL, message); + } + + /** + * + * @param object + * @param message + */ + public void error(Object object, + String message) { + log(object, Level.ERROR, message); + } + + /** + * + * @param object + * @param message + */ + public void warn(Object object, + String message) { + log(object, Level.WARN, message); + } + + /** + * + * @param object + * @param message + */ + public void info(Object object, + String message) { + log(object, Level.INFO, message); + } + + /** + * + * @param object + * @param message + */ + public void debug(Object object, + String message) { + log(object, Level.DEBUG, message); + } + + /** + * + * @param object + * @param message + */ + public void trace(Object object, + String message) { + log(object, Level.TRACE, message); + } + + /** + * + * @param object + * @param methodName + * @param typeValue + */ + public void traceStartOfMethod(Object object, + String methodName, + Object... typeValue) { + trace(object, MethodStartMessageCreator.createMethodStartMessage(methodName, typeValue)); + } + + /** + * + * @param object + * @param methodName + */ + public void traceStartOfMethod(Object object, + String methodName) { + trace(object, MethodStartMessageCreator.createMethodStartMessage(methodName)); + } + + /** + * + * @param object + * @param level + * @param message + */ + public void log(Object object, + Level level, + String message) { + if((!(isLogOkayClasses())) && this.isOkayClass()) { + return; + } +// if(PseudoRandomGenerator.getGlobalInstance().getInt(0, 3)>1){return;} + if(getTarget() == Target.NOTARGET || !isLevelWanted(level)) { + return; + } + + String row = LogRowCreator.createRow(++rowNumber, object, level, getClassName(), message); + if(target == Target.CONSOLE || target == Target.CONSOLEANDFILES) { + if(level.getVerbiageIndex() <= 2) { + System.err.println(row); + } else { + System.out.println(row); + + } + } + + if(target == Target.FILES || target == Target.CONSOLEANDFILES) { + logStringBuilder.append(row).append("\n"); + final String LOGGINGFILENAME = "log.txt"; + + try (BufferedWriter bw = new BufferedWriter(new FileWriter(LOGGINGFILENAME, true))) { + bw.write(row); + bw.newLine(); + bw.flush(); + } catch (Exception e) { + System.err.println("Can't write next log row to file " + LOGGINGFILENAME); + } + + if(level.getVerbiageIndex() <= 4) { + try (BufferedWriter bw = new BufferedWriter(new FileWriter("info_" + LOGGINGFILENAME, true))) { + bw.write(row); + bw.newLine(); + bw.flush(); + } catch (Exception e) { + System.err.println("Can't write next log row to file " + "info_" + LOGGINGFILENAME); + } + } +// TODO +// write to files + } + } + + private static StringBuilder logStringBuilder = new StringBuilder(); + + public static void saveToFile() { + final String LOGGINGFILENAME = "log.txt"; + try (BufferedWriter bw = new BufferedWriter(new FileWriter(LOGGINGFILENAME, true))) { + bw.write(logStringBuilder.toString()); + logStringBuilder = new StringBuilder(); + bw.newLine(); + bw.flush(); + } catch (Exception e) { + System.err.println("Can't write next log row to file " + LOGGINGFILENAME); + } + } + + private String getClassName() { + return this.className; + } + + /** + * + * @return + */ + public boolean isOkayClass() { + return isOkayClass; + } +} diff --git a/power-log/src/main/java/org/nanoboot/powerframework/log/MethodStartMessageCreator.java b/power-log/src/main/java/org/nanoboot/powerframework/log/MethodStartMessageCreator.java new file mode 100644 index 0000000..c10d178 --- /dev/null +++ b/power-log/src/main/java/org/nanoboot/powerframework/log/MethodStartMessageCreator.java @@ -0,0 +1,83 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.log; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class MethodStartMessageCreator { + + private static final String ARGUMENTSSTART = "("; + private static final String ARGUMENTSEND = ")"; + + private static final Object[] emptyObjectArray = new Object[]{}; + + static String createMethodStartMessage(String methodName) { + return createMethodStartMessage(methodName, emptyObjectArray); + } + + static String createMethodStartMessage(String methodName, + Object... typeValue) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("method ").append(methodName).append(" - start - ").append(ARGUMENTSSTART); + + { + for (int i = 0; i < typeValue.length; i++) { + if(i == typeValue.length) { + break; + } + stringBuilder.append(typeValue[i]); + + i++; + if(i == typeValue.length) { + break; + } + stringBuilder.append("="); + stringBuilder.append(typeValue[i]); + + if((i + 1) != typeValue.length) { + stringBuilder.append(", "); + } else { + break; + } + } + } + + stringBuilder.append(ARGUMENTSEND); + if(typeValue.length % 2 != 0) { + stringBuilder.append(" There is a mismatch: The length of typeValue.length%2!=0;"); + } + return stringBuilder.toString(); + } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private MethodStartMessageCreator() { + } + +} diff --git a/power-log/src/main/java/org/nanoboot/powerframework/log/Target.java b/power-log/src/main/java/org/nanoboot/powerframework/log/Target.java new file mode 100644 index 0000000..3219388 --- /dev/null +++ b/power-log/src/main/java/org/nanoboot/powerframework/log/Target.java @@ -0,0 +1,50 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.log; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum Target { + + /** + * + */ + NOTARGET, + + /** + * + */ + CONSOLE, + + /** + * + */ + FILES, + + /** + * + */ + CONSOLEANDFILES; +} diff --git a/power-log/src/main/resources/.gitkeep b/power-log/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-log/src/test/java/org/nanoboot/powerframework/log/.gitkeep b/power-log/src/test/java/org/nanoboot/powerframework/log/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-mail/.gitignore b/power-mail/.gitignore new file mode 100755 index 0000000..e8f4b88 --- /dev/null +++ b/power-mail/.gitignore @@ -0,0 +1,9 @@ +#files to ignore + +*.metadata/** +*.recommenders/** +*target/** +*build/** +*.idea/** +*.class +*.iml diff --git a/power-mail/README.md b/power-mail/README.md new file mode 100755 index 0000000..dc74e79 --- /dev/null +++ b/power-mail/README.md @@ -0,0 +1,2 @@ +# power-mail +todo: create interfaces and integration with Spring and new mailer-cli standalone module diff --git a/power-mail/bin/.gitignore b/power-mail/bin/.gitignore new file mode 100644 index 0000000..c42cc37 --- /dev/null +++ b/power-mail/bin/.gitignore @@ -0,0 +1,2 @@ +mailer.properties +mailer-conf.properties diff --git a/power-mail/bin/backup.sql b/power-mail/bin/backup.sql new file mode 100644 index 0000000..dacbae8 --- /dev/null +++ b/power-mail/bin/backup.sql @@ -0,0 +1,16 @@ +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd +dsdgfsdgrsd diff --git a/power-mail/bin/backupfile.sh b/power-mail/bin/backupfile.sh new file mode 100755 index 0000000..1c3e0d4 --- /dev/null +++ b/power-mail/bin/backupfile.sh @@ -0,0 +1,12 @@ +fileToBackup=$1 + +if [ -n "$fileToBackup" ]; then + echo "Info: Var fileToBackup was supplied! fileToBackup=$fileToBackup" +else + echo "Fatal: Var fileToBackup was not supplied. Exiting" + exit +fi +echo "Sending backup of file $fileToBackup." + +./mailerrv.sh "Sending backup of file $fileToBackup" "Hello,

I send you the backup file: $fileToBackup.

With regards, Robert Vokac." $fileToBackup +#>> ./mailer.log diff --git a/power-mail/bin/mailer.jar b/power-mail/bin/mailer.jar new file mode 100644 index 0000000000000000000000000000000000000000..4e8bcb3638effc060ad10e3a34354f0a89801d9a GIT binary patch literal 755057 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

I9;Z5{FJgIP(w@!C*!$5-WDbM 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

C^CYKA;oGWzw2ocE^CVe*R0wW= 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�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%0D{?~*VVCPbP9^cPDZ0lj&PNYPv_ z$_>qKjpC_7vy71O$V`<11!t@@$@)!ZTur+!8i2{lBK=jbX$nqO%XOs2x<#hJB(rr% znAo-(3f(7cWhQkCRx8J8D~1B5LENtKb-e4}34!N#ZE9nD#NuopLTnPG^ewXom2I~> zg_KV`3Zf-pmrIy&rXVp7b;FaJNZawe=L}*EE7vzfR5H%P$zB%m z`Z>LuBGV*sHB$(*+?h?3P)W98cL^7q_{0E?BSVZ|f%BC$poe1cT{ z6TT}GF`wfQsy9um3}Z|WP$E+f5@V%$et0P|@N`1>jgs|@LX=Dy@v9hpEYXHBLxf`} zCxlce`K|PNt);RM-Z9STW)b6=G)e~$gwddtaSfu27();QrXWa}uWcYw0Tvj8c2~p# z*Y9>|Qgjk2YSjdP^jktCdv}TRpcN+$eSf)!yM1yeOv|aZK~M*4pEN5U+O2{6+{3l4 zfzgsKG3W=D>St5Z(zb~1Q`PbkLz&bW+u)`}Q8M7}8d6wXRN0QP(1Eu#LC!YQNw+nC=tj`{ zFPL{F1$3c-VtE|#6T%wrt#j%7v~4S6sWJ$@n4eZ5iHl8@r@(R?2ZYafl`RK{N@Dnq?eO3B@Xy7ae`)k6DoQCj**g43XE#w^S`vg2!F%4O z-MMl}r4sx%l}8QL(T=^a+;0Q}L{-n5q$N4UXTiGmPkLE@aNj@t5>jnYVfcCgBaJJNR-bTOtC13rxO`GXNk{g*#YFbQGBWT} z{(r#L^9p6{<_%bKKk7*YIG1;u?}FL<(MekI#teH;IlB3&G

n-}f_Q&HO&`yYCbKp40w^ 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

89;gjyD&6S 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 ZHa0F`pY8?^ns9l7!agvSK4?*v{{t}E`epzC literal 0 HcmV?d00001 diff --git a/power-mail/bin/mailer.properties.template b/power-mail/bin/mailer.properties.template new file mode 100755 index 0000000..316dea4 --- /dev/null +++ b/power-mail/bin/mailer.properties.template @@ -0,0 +1,6 @@ +from=name@gmail.com +serverurl=smtp.gmail.com +serverport=465 +username=name@gmail.com +password=password +ssl=1 diff --git a/power-mail/bin/mailer.sh b/power-mail/bin/mailer.sh new file mode 100755 index 0000000..e703560 --- /dev/null +++ b/power-mail/bin/mailer.sh @@ -0,0 +1,46 @@ +SERVER_CONF=mailer-conf.properties +TO=$1 +SUBJECT=$2 +TEXT=$3 +ATTACHMENT=$4 + +if [ -n "$TO" ]; then + echo "Info: Var TO was supplied! TO=$TO" +else + echo "Fatal: Var TO was not supplied. Exiting" + exit +fi + +if [ -n "$SUBJECT" ]; then + echo "Info: Var SUBJECT was supplied! SUBJECT=$SUBJECT" +else + echo "Fatal: Var SUBJECT was not supplied. Exiting" + exit +fi + +if [ -n "$TEXT" ]; then + echo "Info: Var TEXT was supplied! TEXT=$TEXT" +else + echo "Fatal: Var TEXT was not supplied. Exiting" + exit +fi + +if [ -n "$ATTACHMENT" ]; then + echo "Info: Var ATTACHMENT was supplied! ATTACHMENT=$ATTACHMENT" +else + echo "Info: Var ATTACHMENT was not supplied." +fi + + +export JAVA_HOME=/home/robertvokac/\.jdks/openjdk-16.0.1 + + +$JAVA_HOME/bin/java -jar mailer.jar \ +serverconf=$SERVER_CONF \ +to=$TO \ +"subject=$SUBJECT" \ +"text=$TEXT" \ +attachment=$ATTACHMENT +#>> ./mailer.log + + diff --git a/power-mail/bin/mailerrv.sh b/power-mail/bin/mailerrv.sh new file mode 100755 index 0000000..7cc5586 --- /dev/null +++ b/power-mail/bin/mailerrv.sh @@ -0,0 +1,5 @@ +TO=robertvokac@nanoboot.org + +./mailer.sh $TO "$1" "$2" "$3" + +#>> ./mailer.log diff --git a/power-mail/environment-startup.txt b/power-mail/environment-startup.txt new file mode 100644 index 0000000..e69de29 diff --git a/power-mail/pom.xml b/power-mail/pom.xml new file mode 100755 index 0000000..7907e9f --- /dev/null +++ b/power-mail/pom.xml @@ -0,0 +1,110 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-mail + jar + + Power Mail + Mailing utilities + + + true + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + + org.nanoboot.powerframework.mail.Main + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.nanoboot.powerframework.mail.Main + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${checkstyle.skip} + + + + + + + + + + junit + junit + 4.12 + test + + + com.sun.mail + jakarta.mail + 2.0.1 + + + + + org.projectlombok + lombok + + + diff --git a/power-mail/src/main/java/module-info.java b/power-mail/src/main/java/module-info.java new file mode 100644 index 0000000..fa09e34 --- /dev/null +++ b/power-mail/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.mail { + exports org.nanoboot.powerframework.mail; + requires lombok; + requires jakarta.mail; +} diff --git a/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailBox.java b/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailBox.java new file mode 100644 index 0000000..417b52e --- /dev/null +++ b/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailBox.java @@ -0,0 +1,111 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.mail; + +import jakarta.mail.MessagingException; +import jakarta.mail.Multipart; +import jakarta.mail.PasswordAuthentication; +import jakarta.mail.Session; +import jakarta.mail.Transport; +import lombok.Data; + +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeBodyPart; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeMultipart; +import java.io.File; +import java.io.IOException; +import java.util.Properties; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Data +public class MailBox { + private SmtpServer smtpServer; + public MailBox() { + + } + public MailBox(SmtpServer smtpServer) { + this.smtpServer = smtpServer; + } + /** + * + * @param mailMessage + * @return null, if everything is OK, otherwise the error descriptiopn + */ + public String send (final MailMessage mailMessage, final SmtpUser user) { + + Properties props = new Properties(); + props.put("mail.smtp.host", smtpServer.getServerUrl()); + + props.put("mail.smtp.auth", "true"); + props.put("mail.smtp.port", smtpServer.getServerPort()); + props.put("mail.smtp.ssl.enable", smtpServer.getSsl().equals("1") ? "true" : "false"); + props.put("mail.debug", "true"); + Session session = Session.getDefaultInstance(props, + new jakarta.mail.Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(user.getUserName(), user.getPassword()); + } + }); + + try { + + MimeMessage message = new MimeMessage(session); + message.setFrom(new InternetAddress(smtpServer.getFrom())); + message.setRecipients(jakarta.mail.Message.RecipientType.TO, + InternetAddress.parse(mailMessage.getTo())); + message.setSubject(mailMessage.getSubject(), "utf-8"); + + // if plaint text + // message.setText(target.text); + + Multipart multipart = new MimeMultipart(); + + MimeBodyPart text = new MimeBodyPart(); + // if html text + String type = mailMessage.getMailMessageType() == MailMessageType.TEXT ? "text/plain" : "text/html"; + text.setContent(mailMessage.getText(), type+"; charset=utf-8"); + multipart.addBodyPart(text); + + if(mailMessage.getAttachment() != null && !mailMessage.getAttachment().isEmpty()) { + MimeBodyPart attachment = new MimeBodyPart(); + attachment.attachFile(new File(mailMessage.getAttachment())); + multipart.addBodyPart(attachment); + } + + message.setContent(multipart); + + Transport.send(message); + + System.out.println("Done"); + + } catch (MessagingException | IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + + return null; + } +} diff --git a/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessage.java b/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessage.java new file mode 100644 index 0000000..47144d4 --- /dev/null +++ b/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessage.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.mail; + +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public class MailMessage { + private String to; + private String subject; + private String text; + private String attachment; + private MailMessageType mailMessageType = MailMessageType.TEXT; +} diff --git a/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessageType.java b/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessageType.java new file mode 100644 index 0000000..6e31492 --- /dev/null +++ b/power-mail/src/main/java/org/nanoboot/powerframework/mail/MailMessageType.java @@ -0,0 +1,30 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.mail; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum MailMessageType { + TEXT, HTML; +} diff --git a/power-mail/src/main/java/org/nanoboot/powerframework/mail/Main.java b/power-mail/src/main/java/org/nanoboot/powerframework/mail/Main.java new file mode 100755 index 0000000..b539258 --- /dev/null +++ b/power-mail/src/main/java/org/nanoboot/powerframework/mail/Main.java @@ -0,0 +1,111 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.mail; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Main { + private static class Keys { + + public static final String SERVER_CONF = "serverconf"; + public static final String FROM = "from"; + public static final String SERVER_URL = "serverurl"; + public static final String SERVER_PORT = "serverport"; + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String SSL = "ssl"; + + public static final String TO = "to"; + public static final String SUBJECT = "subject"; + public static final String TEXT = "text"; + public static final String ATTACHMENT = "attachment"; + } + + //https://www.baeldung.com/java-email + + public static void main(String[] args) { + Properties argProps = makePropFromArgs(args); + SmtpServer server = new SmtpServer(); + + server.setFrom(argProps.getProperty(Keys.FROM)); + server.setServerUrl(argProps.getProperty(Keys.SERVER_URL)); + server.setServerPort(argProps.getProperty(Keys.SERVER_PORT)); + SmtpUser user = new SmtpUser(); + user.setUserName(argProps.getProperty(Keys.USERNAME)); + user.setPassword(argProps.getProperty(Keys.PASSWORD)); + server.setSsl(argProps.getProperty(Keys.SSL)); + + MailMessage target = new MailMessage(); + target.setTo(argProps.getProperty(Keys.TO)); + target.setSubject(argProps.getProperty(Keys.SUBJECT)); + target.setText(argProps.getProperty(Keys.TEXT)); + if (argProps.containsKey(Keys.ATTACHMENT)) { + target.setAttachment(argProps.getProperty(Keys.ATTACHMENT)); + } + + MailBox mailBox = new MailBox(server); + mailBox.send(target,user); + } + public static Properties makePropFromArgs(String[] args) { + Properties prop = new Properties(); + for(String arg : args) { + System.out.println(arg); + String[] array = arg.split("="); + if(array.length == 1) { + if (arg.contains(Keys.ATTACHMENT)) { + continue; + } else { + throw new RuntimeException("Parsing key and value for \"" + arg + "\" failed."); + } + } + String key = array[0]; + String value = array[1]; + prop.put(key, value); + } + if (prop.containsKey(Keys.SERVER_CONF)) { + Properties serverConfProp = loadPropFromFile(prop.getProperty(Keys.SERVER_CONF)); + prop.putAll(serverConfProp); + } + return prop; + } + + private static Properties loadPropFromFile(String filePath) { + try (InputStream input = new FileInputStream(filePath)) { + + Properties prop = new Properties(); + + // load a properties file + prop.load(input); + return prop; + } catch (IOException ex) { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage(), ex); + } + } +} diff --git a/power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpServer.java b/power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpServer.java new file mode 100644 index 0000000..e55f12a --- /dev/null +++ b/power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpServer.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.mail; + +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Data +public class SmtpServer { + private String from; + private String serverUrl; + private String serverPort; + private String ssl; + } diff --git a/power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpUser.java b/power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpUser.java new file mode 100644 index 0000000..7dd73ba --- /dev/null +++ b/power-mail/src/main/java/org/nanoboot/powerframework/mail/SmtpUser.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.mail; + +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Data +public class SmtpUser { + private String userName; + private String password; +} diff --git a/power-mail/src/main/resources/.gitkeep b/power-mail/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-mail/src/test/java/org/nanoboot/powerframework/mail/.gitkeep b/power-mail/src/test/java/org/nanoboot/powerframework/mail/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-persistence/pom.xml b/power-persistence/pom.xml new file mode 100644 index 0000000..8133dce --- /dev/null +++ b/power-persistence/pom.xml @@ -0,0 +1,69 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-persistence + jar + + Power Persistence + Persistence functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-db + ${power.version} + + + org.nanoboot.powerframework + power-sql + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + + diff --git a/power-persistence/src/main/java/module-info.java b/power-persistence/src/main/java/module-info.java new file mode 100644 index 0000000..136cfe5 --- /dev/null +++ b/power-persistence/src/main/java/module-info.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + module powerframework.persistence { + requires powerframework.json; + requires powerframework.db; + requires powerframework.log; + requires powerframework.sql; + requires powerframework.utils; + requires powerframework.core; +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/AttributeType.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/AttributeType.java new file mode 100644 index 0000000..10b62ec --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/AttributeType.java @@ -0,0 +1,84 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import org.nanoboot.powerframework.persistence.annotations.ForeignEntity; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum AttributeType { + + ENTITY, + NUMBER, + REAL, + TEXT, + BOOLEAN, + BLOB; + + public static AttributeType getAttributeType(Field field) { + + String canonicalName = EntityAttribute.loadJavaType(field); + switch (canonicalName) { + case "int": + return NUMBER; + case "long": + return NUMBER; + case "byte": + return NUMBER; + case "short": + return NUMBER; + case "float": + return REAL; + case "double": + return REAL; + case "boolean": + return BOOLEAN; + case "java.lang.Integer": + return NUMBER; + case "java.lang.Long": + return NUMBER; + case "java.lang.Byte": + return NUMBER; + case "java.lang.Short": + return NUMBER; + case "java.lang.Float": + return REAL; + case "java.lang.Double": + return REAL; + case "java.lang.Boolean": + return BOOLEAN; + case "java.lang.String": + return TEXT; + } + for (Annotation a : field.getAnnotations()) { + if(a instanceof ForeignEntity) { + return ENTITY; + } + } + throw new PersistenceException(("Cannot get AttributeType from canonicalName " + canonicalName)); + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/BaseColumns.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/BaseColumns.java new file mode 100644 index 0000000..b0d3461 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/BaseColumns.java @@ -0,0 +1,56 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class BaseColumns { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(BaseColumns.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + public BaseColumns() { + } + + public static final String UUID = "UUID"; +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityAttribute.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityAttribute.java new file mode 100644 index 0000000..6fab128 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityAttribute.java @@ -0,0 +1,141 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import org.nanoboot.powerframework.persistence.annotations.Attribute; +import org.nanoboot.powerframework.persistence.annotations.AttributeName; +import org.nanoboot.powerframework.persistence.annotations.ForeignEntity; +import org.nanoboot.powerframework.persistence.annotations.UUID; +import org.nanoboot.powerframework.utils.NamingConvention; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class EntityAttribute { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(EntityAttribute.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + static EntityAttribute create(Field fIn) { + try { + return new EntityAttribute(fIn); + } catch (PersistenceException e) { + //e.printStackTrace(); + System.out.println(fIn.getName() + " failed"); + return null; + } + + } + + private String name; + private AttributeType type; + private Class entity; + private boolean uuid = false; + private String javaName; + private String javaType; + + private EntityAttribute(Field field) { + System.out.println("Processing field " + field.getName()); + boolean isColumn = false; + String columnName = null; + Class foreignEntity = null; + + for (Annotation a : field.getDeclaredAnnotations()) { + System.out.println("Found annotation " + a.annotationType()); + if(a instanceof Attribute) { + isColumn = true; + continue; + } + if(a instanceof AttributeName) { + columnName = ((AttributeName) a).name(); + continue; + } + + if(a instanceof ForeignEntity) { + foreignEntity = ((ForeignEntity) a).clazz(); + continue; + } + if(a instanceof UUID) { + uuid = true; + continue; + } + + } + if(!isColumn) { + throw new PersistenceException("Field " + field.getName() + " in class " + field.getDeclaringClass().getName() + " is not annotated with @Column"); + } + if(columnName == null) { + columnName = org.nanoboot.powerframework.utils.NamingConventionConvertor.convert(field.getName(), NamingConvention.JAVA_FIELD, NamingConvention.DATABASE); + } + name = columnName; + type = AttributeType.getAttributeType(field); + entity = foreignEntity; + javaName = field.getName(); + javaType = loadJavaType(field); + + } + + public String getName() { + return name; + } + + public AttributeType getType() { + return type; + } + + public Class getEntity() { + + return entity; + } + + public boolean isUUID() { + return uuid; + } + + public boolean isForeignEntity() { + return entity != null; + } + + public String getJavaName() { + return javaName; + } + + public String getJavaType() { + return javaType; + } + + static String loadJavaType(Field fieldIn) { + return fieldIn.getType().getCanonicalName(); + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityManager.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityManager.java new file mode 100644 index 0000000..f267012 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityManager.java @@ -0,0 +1,286 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.util.ArrayList; +import org.nanoboot.powerframework.json.JsonObject; +import org.nanoboot.powerframework.sql.core.ColumnNameValue; +import org.nanoboot.powerframework.db.manager.Database; +import org.nanoboot.powerframework.sql.core.SqlStatementCreator; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class EntityManager { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(EntityManager.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + private static final EntityStorage entityStorage = new EntityStorage(); + + /** + * Field description + */ + /** + * Constructor + * + * Not meant to be instantiated. + */ + private EntityManager() { + super(); + } + + private static Database database = null; + + public static void init(Database databaseIn) { + database = databaseIn; + } + + public static Database getDatabase() { + return database; + } + + public static Object load(Class clazz, String uid) { + if(!entityStorage.hasEntity(uid)) { + Object object = loadEntityFromDatabase(clazz, uid); + entityStorage.putEntity(object); + } + return entityStorage.getEntity(uid); + + } + + private static Object loadEntityFromDatabase(Class clazz, String uid) { + System.out.println(clazz + " " + uid); + Object object; + try { + object = clazz.newInstance(); + } catch (InstantiationException ex) { + throw new PersistenceException(ex.getMessage()); + } catch (IllegalAccessException ex) { + throw new PersistenceException(ex.getMessage()); + } + EntitySchema entitySchema = EntitySchema.getSchema(clazz); + JsonObject row = getDatabase().getRow(entitySchema.getName(), uid); + for (EntityAttribute a : entitySchema.getAttributesList()) { + String columnName = a.getName(); + String columnValue = row.getString(columnName); + AttributeType type = a.getType(); + String javaName = a.getJavaName(); + String javaType = a.getJavaType(); + System.out.println("Setting " + object.getClass().getName() + " " + javaName + " " + javaType + " " + columnValue); + setAttribute(object, type, javaName, javaType, columnValue); + + } + return object; + } + + private static void setAttribute(Object object, AttributeType attributeType, String javaName, String javaType, String valueIn) { + switch (javaType) { + + case "int": { + Integer value = Integer.valueOf(valueIn); + MethodInvocation.setInt(object, javaName, value); + } + ; + break; + case "short": { + Short value = Short.valueOf(valueIn); + MethodInvocation.setShort(object, javaName, value); + } + break; + case "byte": { + Byte value = Byte.valueOf(valueIn); + MethodInvocation.setByte(object, javaName, value); + } + break; + case "long": { + Long value = Long.valueOf(valueIn); + MethodInvocation.setLong(object, javaName, value); + } + break; + case "float": { + Float value = Float.valueOf(valueIn); + MethodInvocation.setFloat(object, javaName, value); + } + break; + case "double": { + Double value = Double.valueOf(valueIn); + MethodInvocation.setDouble(object, javaName, value); + } + break; + case "boolean": { + Boolean value = Boolean.valueOf(valueIn); + MethodInvocation.setBoolean(object, javaName, value); + } + case "java.lang.Integer": { + Integer value = Integer.valueOf(valueIn); + MethodInvocation.setInt(object, javaName, value); + } + ; + break; + case "java.lang.Short": { + Short value = Short.valueOf(valueIn); + MethodInvocation.setShort(object, javaName, value); + } + break; + case "java.lang.Byte": { + Byte value = Byte.valueOf(valueIn); + MethodInvocation.setByte(object, javaName, value); + } + break; + case "java.lang.Long": { + Long value = Long.valueOf(valueIn); + MethodInvocation.setLong(object, javaName, value); + } + break; + case "java.lang.Float": { + Float value = Float.valueOf(valueIn); + MethodInvocation.setFloat(object, javaName, value); + } + break; + case "java.lang.Double": { + Double value = Double.valueOf(valueIn); + MethodInvocation.setDouble(object, javaName, value); + } + break; + case "java.lang.Boolean": { + Boolean value = Boolean.valueOf(valueIn); + MethodInvocation.setBoolean(object, javaName, value); + } + case "java.lang.String": { + String value = valueIn; + MethodInvocation.setString(object, javaName, value); + } + break; + + case "org.nanoboot.powerframework.collections.bit.Blob": { +// Integer value = Integer.valueOf(valueIn); +// MethodInvocation.setInt(object, javaName, value); + } + break; + default: { + throw new PersistenceException("Cannot set attribute " + javaName); + } + } + + } + + public static void persist(Object object) { + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + + boolean existTable = getDatabase().existTable(entitySchema.getName()); + System.out.println("Table " + entitySchema.getName() + "exist?=" + existTable); + if(!existTable) { + getDatabase().execute(entitySchema.createSqlCreateStatement()); + } + + boolean insert = !EntityManager.isInDatabase(object); + boolean update = EntityManager.isInDatabase(object); + + if(insert) { + addEntityToDatabase(object, entitySchema); + } + if(update) { + updateEntityInDatabase(object, entitySchema); + } + + } + + private static void addEntityToDatabase(Object object, EntitySchema entitySchema) { + String uuid = Utils.getUUID(); + Utils.setUUIDTo(object, uuid); + String[] valuesIn = new String[entitySchema.getAttributesList().size()]; + int index = 0; + for (EntityAttribute a : entitySchema.getAttributesList()) { + String value = ""; + + value = JavaSqlConvertor.getStringFromJava(object, a); + + valuesIn[index++] = value; + } + + String sqlInsert = SqlStatementCreator.createInsert(entitySchema.getName(), valuesIn); + getDatabase().execute(sqlInsert); + + } + + private static void updateEntityInDatabase(Object object, EntitySchema entitySchema) { + JsonObject row = getDatabase().getRow(entitySchema.getName(), MethodInvocation.getString(object, entitySchema.getIdJavaName())); + ArrayList changedAttributesList = new ArrayList<>(); + for (EntityAttribute a : entitySchema.getAttributesList()) { + String stringValue = row.getString(a.getName()); + if(a.getType() == AttributeType.TEXT) { + stringValue = '\'' + stringValue + '\''; + } + String entityValue = JavaSqlConvertor.getStringFromJava(object, a); + + boolean different = !stringValue.equals(entityValue); + if(different) { + + changedAttributesList.add(a); + } + } + ColumnNameValue[] columnNameValuesArray = new ColumnNameValue[changedAttributesList.size()]; + int index = 0; + for (EntityAttribute a : changedAttributesList) { + ColumnNameValue columnNameValue = new ColumnNameValue(a.getName(), JavaSqlConvertor.getStringFromJava(object, a)); + columnNameValuesArray[index++] = columnNameValue; + } + if(!changedAttributesList.isEmpty()) { + String conditions = entitySchema.getIdJavaName() + "='" + Utils.getUUIDFrom(object) + "'"; + String sqlUpdateStatement = SqlStatementCreator.createUpdate(entitySchema.getName(), conditions, columnNameValuesArray); + getDatabase().execute(sqlUpdateStatement); + } + } + + public static void delete(Object object) { + if(!EntityManager.isInDatabase(object)) { + throw new PersistenceException("Cannot delete object " + object.toString() + "from database. The object is not in the database."); + } + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + + String javaName = entitySchema.getIdJavaName(); + System.out.println("javaName=" + javaName); + + getDatabase().execute("DELETE FROM " + entitySchema.getName() + " WHERE " + entitySchema.getIdName() + "='" + getId(object) + "'"); + entityStorage.deleteEntity(object); + } + + private static String getId(Object object) { + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + return MethodInvocation.getString(object, entitySchema.getIdJavaName()); + } + + public static boolean isInDatabase(Object object) { + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + + return MethodInvocation.getString(object, entitySchema.getIdJavaName()) != null; + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityPointer.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityPointer.java new file mode 100644 index 0000000..3c5097d --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityPointer.java @@ -0,0 +1,61 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class EntityPointer { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(EntityPointer.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private final Class classValue; + + private final String uuid; + + EntityPointer(Class classValueIn, String uuidIn) { + this.classValue = classValueIn; + this.uuid = uuidIn; + } + + public Class getClassValue() { + return classValue; + } + + public String getUUID() { + return uuid; + } + +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntitySchema.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntitySchema.java new file mode 100644 index 0000000..834d8b2 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntitySchema.java @@ -0,0 +1,216 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.nanoboot.powerframework.persistence.annotations.Entity; +import org.nanoboot.powerframework.persistence.annotations.EntityName; +import org.nanoboot.powerframework.utils.NamingConvention; +import org.nanoboot.powerframework.utils.annotations.Done; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class EntitySchema { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(EntitySchema.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + private static final Map map = new HashMap<>(); + + private String name; + private String uuid = null; + private String UUIDJavaName = null; + + private final java.util.ArrayList attributesList = new java.util.ArrayList<>(); + + @Done + public static EntitySchema getSchema(Class clazz) { + + String entityName = getEntityNameFromClass(clazz); + return getSchemaByName(entityName, clazz); + } + + @Done + private static String getEntityNameFromClass(Class clazz) { + String entityName = null; + boolean isEntity = false; + for (Annotation a : clazz.getAnnotations()) { + System.out.println("Found annotation " + a.toString()); + if(a instanceof Entity) { + isEntity = true; + continue; + } + if(a instanceof EntityName) { + entityName = ((EntityName) a).name(); + continue; + } + }; + if(!isEntity) { + throw new PersistenceException("Class " + clazz + " is not annotated with @Entity. Cannot create schema from this class"); + } + if(entityName != null) { + return entityName; + } + entityName = org.nanoboot.powerframework.utils.NamingConventionConvertor.convert(clazz.getName(), NamingConvention.JAVA_FIELD, NamingConvention.DATABASE); + return entityName; + } + + @Done + private static EntitySchema getSchemaByName(String entityName, Class clazz) { + if(!map.containsKey(entityName)) { + map.put(entityName, new EntitySchema(clazz)); + } + return map.get(entityName); + } + + private EntitySchema(Class clazz) { + this.name = getEntityNameFromClass(clazz); + loadAttributesList(clazz); + for (EntityAttribute a : attributesList) { + if(a.isUUID()) { + this.uuid = a.getName(); + this.UUIDJavaName = a.getJavaName(); + } + } + if(uuid == null) { + throw new PersistenceException("Class " + clazz + " has no field annotated with @UUID. Cannot create schema from this class"); + + } + + } + + private void loadAttributesList(Class clazz) { + Field[] fields = clazz.getDeclaredFields(); + System.out.println("class " + clazz + " has " + fields.length); + for (Field f : fields) { + + EntityAttribute attribute = EntityAttribute.create(f); + System.out.println("Attribute for " + f.getName() + " is " + attribute); + if(attribute != null) { + + attributesList.add(attribute); + } + } + System.out.println("attributesList.size()=" + attributesList.size()); + + } + + public String getName() { + return name; + } + + public String getIdName() { + return uuid; + } + + public ArrayList getForeingKeys() { + ArrayList list = new ArrayList<>(); + for (EntityAttribute a : getAttributesList()) { + if(a.isForeignEntity()) { + list.add(a); + } + } + return list; + } + + /** + * Field description + */ + public ArrayList getAttributesList() { + return attributesList; + } + + public String getIdJavaName() { + return UUIDJavaName; + } + + public String createSqlCreateStatement() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("CREATE TABLE "); + stringBuilder.append(this.getName()); + stringBuilder.append("(\n"); + + int aCount = getAttributesList().size(); + int attributeNumber = 0; + for (EntityAttribute a : getAttributesList()) { + attributeNumber++; + stringBuilder.append("\t"); + stringBuilder.append(a.getName()); + stringBuilder.append(" "); + if(a.getType() == AttributeType.ENTITY || a.getType() == AttributeType.BOOLEAN || a.getType() == AttributeType.NUMBER) { + stringBuilder.append("INTEGER"); + } else { + stringBuilder.append(a.getType().name()); + } + if(a.isUUID()) { + stringBuilder.append(" PRIMARY KEY"); + } + if(attributeNumber < aCount) { + stringBuilder.append(", "); + } + + stringBuilder.append("\n"); + } + + ArrayList foreignKeysList = getForeingKeys(); + int foreingKeysCount = foreignKeysList.size(); + if(!getForeingKeys().isEmpty()) { + attributeNumber = 0; + + for (EntityAttribute a : foreignKeysList) { + attributeNumber++; + stringBuilder.append(", \n"); + stringBuilder.append("FOREIGN KEY("); + stringBuilder.append(a.getName()); + stringBuilder.append(") REFERENCES "); + + EntitySchema foreingKeyEntitySchema = EntitySchema.getSchema(a.getEntity()); + stringBuilder.append(foreingKeyEntitySchema.getName()); + stringBuilder.append(" ("); + stringBuilder.append(foreingKeyEntitySchema.getIdName()); + stringBuilder.append(")"); + + if(attributeNumber < foreingKeysCount) { + stringBuilder.append(", "); + } + + stringBuilder.append("\n"); + } + } + stringBuilder.append(");"); + return stringBuilder.toString(); + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityStorage.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityStorage.java new file mode 100644 index 0000000..2022eb6 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/EntityStorage.java @@ -0,0 +1,86 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.util.HashMap; +import java.util.Map; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class EntityStorage { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(EntityStorage.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private static final Map entityMap = new HashMap<>(); + + /** + * Constructor + * + * Constructor description + * + * @param nameIn + */ + public EntityStorage() { + } + + public Object getEntity(String uid) { + + if(entityMap.containsKey(uid)) { + return entityMap.get(uid); + } + return null; + + } + + public boolean hasEntity(String uid) { + return entityMap.containsKey(uid); + } + + public void putEntity(Object object) { + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + String uid = Utils.getUUIDFrom(object); + if(entityMap.containsKey(uid)) { + throw new PersistenceException("Cannot put entity " + entitySchema.getName() + " with uid " + uid + " There is already a entity with the class and uid in the storage."); + } + entityMap.put(uid, object); + + } + + public void deleteEntity(Object object) { + String uid = Utils.getUUIDFrom(object); + entityMap.remove(uid); + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/JavaSqlConvertor.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/JavaSqlConvertor.java new file mode 100644 index 0000000..ac9e7af --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/JavaSqlConvertor.java @@ -0,0 +1,104 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class JavaSqlConvertor { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(JavaSqlConvertor.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private JavaSqlConvertor() { + } + + static String getStringFromJava(Object object, EntityAttribute attribute) { + String value = ""; + if(attribute.getJavaType().equals("int")) { + value = String.valueOf(MethodInvocation.getInt(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("byte")) { + value = String.valueOf(MethodInvocation.getByte(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("short")) { + value = String.valueOf(MethodInvocation.getShort(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("long")) { + value = String.valueOf(MethodInvocation.getLong(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("float")) { + value = String.valueOf(MethodInvocation.getFloat(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("double")) { + value = String.valueOf(MethodInvocation.getDouble(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("boolean")) { + value = MethodInvocation.getBoolean(object, attribute.getJavaName()) ? "1" : "0"; + } + if(attribute.getJavaType().equals("java.lang.Integer")) { + value = String.valueOf(MethodInvocation.getInt(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("java.lang.Byte")) { + value = String.valueOf(MethodInvocation.getByte(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("java.lang.Short")) { + value = String.valueOf(MethodInvocation.getShort(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("java.lang.Long")) { + value = String.valueOf(MethodInvocation.getLong(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("java.lang.Float")) { + value = String.valueOf(MethodInvocation.getFloat(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("java.lang.Double")) { + value = String.valueOf(MethodInvocation.getDouble(object, attribute.getJavaName())); + } + if(attribute.getJavaType().equals("java.lang.Boolean")) { + value = MethodInvocation.getBoolean(object, attribute.getJavaName()) ? "1" : "0"; + } + if(attribute.getJavaType().equals("java.lang.String")) { + value = '\'' + MethodInvocation.getString(object, attribute.getJavaName()) + '\''; + } + return value; + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/MethodInvocation.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/MethodInvocation.java new file mode 100644 index 0000000..0f29a80 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/MethodInvocation.java @@ -0,0 +1,173 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class MethodInvocation { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(MethodInvocation.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + public static void setInt(Object object, String javaName, Integer value) { + set(object, javaName, value, Integer.class); + + } + + public static Integer getInt(Object object, String javaName) { + return (Integer) get(object, javaName); + + } + + public static void setShort(Object object, String javaName, Short value) { + set(object, javaName, value, Short.class); + + } + + public static Short getShort(Object object, String javaName) { + return (Short) get(object, javaName); + + } + + public static void setByte(Object object, String javaName, Byte value) { + set(object, javaName, value, Byte.class); + + } + + public static Byte getByte(Object object, String javaName) { + return (Byte) get(object, javaName); + + } + + public static void setLong(Object object, String javaName, Long value) { + set(object, javaName, value, Long.class); + + } + + public static Long getLong(Object object, String javaName) { + return (Long) get(object, javaName); + + } + + public static void setFloat(Object object, String javaName, Float value) { + set(object, javaName, value, float.class); + + } + + public static Float getFloat(Object object, String javaName) { + return (Float) get(object, javaName); + + } + + public static void setDouble(Object object, String javaName, Double value) { + set(object, javaName, value, double.class); + + } + + public static Double getDouble(Object object, String javaName) { + return (Double) get(object, javaName); + + } + + public static void setBoolean(Object object, String javaName, Boolean value) { + set(object, javaName, value, boolean.class); + + } + + public static Boolean getBoolean(Object object, String javaName) { + return (Boolean) get(object, javaName); + + } + + public static void setString(Object object, String javaName, String value) { + set(object, javaName, value, String.class); + + } + + public static String getString(Object object, String javaName) { + return (String) get(object, javaName); + + } + + private static Object get(Object object, String javaName) { + java.lang.reflect.Method method = getMethod(object, javaName, false); + return invokeMethod(method, object); + + } + + private static void set(Object object, String javaName, Object value, Class type) { + java.lang.reflect.Method method = getMethod(object, javaName, true, type); + invokeMethod(method, object, value); + + } + + private static Object invokeMethod(Method method, Object obj, Object... args) { + + try { + return method.invoke(obj, args); + } catch (IllegalArgumentException e) { + throw new PersistenceException(e.getMessage()); + } catch (IllegalAccessException e) { + throw new PersistenceException(e.getMessage()); + } catch (InvocationTargetException e) { + System.out.println(method.getName() + args.length); + e.printStackTrace(); + throw new PersistenceException(e.getMessage()); + } + + } + + private static Method getMethod(Object object, String javaName, boolean isSet, Class... parameterTypes) { + String getMethodName = isSet ? Utils.createSetMethodName(javaName) : Utils.createGetMethodName(javaName); + java.lang.reflect.Method method; + try { + method = object.getClass().getDeclaredMethod(getMethodName, parameterTypes); + + } catch (SecurityException e) { + throw new PersistenceException(e.getMessage()); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new PersistenceException(e.getMessage()); + } + return method; + } + +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/PersistenceException.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/PersistenceException.java new file mode 100644 index 0000000..7c156ed --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/PersistenceException.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import org.nanoboot.powerframework.core.PowerException; + + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PersistenceException extends PowerException { + + public PersistenceException(String message) { + super(message); + } + +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/Utils.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/Utils.java new file mode 100644 index 0000000..63e6926 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/Utils.java @@ -0,0 +1,118 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence; + +import java.util.UUID; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class Utils { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(Utils.class); + + /** + * Constant description + */ + private static final String SET = "set"; + private static final String GET = "get"; + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private Utils() { + } + + static String createSetMethodName(String javaName) { + return SET + makeFirstLetterUpperCase(javaName); + } + + static String createGetMethodName(String javaName) { + return GET + makeFirstLetterUpperCase(javaName); + } + + private static String makeFirstLetterUpperCase(String string) { + return string.substring(0, 1).toUpperCase() + string.substring(1, string.length()); + } + + static String getUUIDFrom(Object object) { + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + return MethodInvocation.getString(object, entitySchema.getIdJavaName()); + } + + static void setUUIDTo(Object object, String uuid) { + EntitySchema entitySchema = EntitySchema.getSchema(object.getClass()); + MethodInvocation.setString(object, entitySchema.getIdJavaName(), uuid); + } + + public static String getUUID() { +// MessageDigest salt; +// try { +// salt = MessageDigest.getInstance("SHA-256"); +// } catch (NoSuchAlgorithmException ex) { +// Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); +// throw new PersistenceException(ex.getMessage()); +// } +// try { +// salt.update(UUID.randomUUID().toString().getBytes("UTF-8")); +// } catch (UnsupportedEncodingException ex) { +// Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex); +// throw new PersistenceException(ex.getMessage()); +// } +// String digest = hexEncode(salt.digest()); +// return digest; + return UUID.randomUUID().toString(); + } + + /** + * The byte[] returned by MessageDigest does not have a nice + * textual representation, so some form of encoding is usually performed. + * + * This implementation follows the example of David Flanagan's book + * "Java In A Nutshell", and converts a byte array into a String + * of hex characters. + * + * Another popular alternative is to use a "Base64" encoding. + */ + private static String hexEncode(byte[] aInput) { + StringBuilder result = new StringBuilder(); + char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + for (int idx = 0; idx < aInput.length; ++idx) { + byte b = aInput[idx]; + result.append(digits[(b & 0xf0) >> 4]); + result.append(digits[b & 0x0f]); + } + return result.toString(); + } +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Attribute.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Attribute.java new file mode 100644 index 0000000..ba30851 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Attribute.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Inherited +public @interface Attribute { + +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/AttributeName.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/AttributeName.java new file mode 100644 index 0000000..78d8eab --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/AttributeName.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Inherited +public @interface AttributeName { + + String name(); +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Entity.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Entity.java new file mode 100644 index 0000000..6724fa4 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Entity.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface Entity { + + boolean temporary() default false; +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/EntityName.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/EntityName.java new file mode 100644 index 0000000..b43d146 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/EntityName.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface EntityName { + + String name(); +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/ForeignEntity.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/ForeignEntity.java new file mode 100644 index 0000000..ea1b22a --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/ForeignEntity.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ForeignEntity { + + Class clazz(); +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/NotNull.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/NotNull.java new file mode 100644 index 0000000..85103d0 --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/NotNull.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface NotNull { + +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/UUID.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/UUID.java new file mode 100644 index 0000000..984477e --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/UUID.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Inherited +public @interface UUID { + +} diff --git a/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Unmodifiable.java b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Unmodifiable.java new file mode 100644 index 0000000..790079c --- /dev/null +++ b/power-persistence/src/main/java/org/nanoboot/powerframework/persistence/annotations/Unmodifiable.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.persistence.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Unmodifiable { + +} diff --git a/power-persistence/src/main/resources/.gitkeep b/power-persistence/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-persistence/src/test/java/org/nanoboot/powerframework/persistence/.gitkeep b/power-persistence/src/test/java/org/nanoboot/powerframework/persistence/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-random/pom.xml b/power-random/pom.xml new file mode 100644 index 0000000..2da7d87 --- /dev/null +++ b/power-random/pom.xml @@ -0,0 +1,59 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-random + jar + + Power Random + Random functionality for the Power library + + + true + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.projectlombok + lombok + + + org.nanoboot.powerframework + power-text + ${power.version} + compile + + + + diff --git a/power-random/src/main/java/module-info.java b/power-random/src/main/java/module-info.java new file mode 100644 index 0000000..7784023 --- /dev/null +++ b/power-random/src/main/java/module-info.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.random { + exports org.nanoboot.powerframework.random; + exports org.nanoboot.powerframework.random.generators; + exports org.nanoboot.powerframework.random.generators.linearcongruent; + exports org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + exports org.nanoboot.powerframework.random.choicegenerators; + requires powerframework.core; + requires lombok; + requires powerframework.text; +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/RandomException.java b/power-random/src/main/java/org/nanoboot/powerframework/random/RandomException.java new file mode 100644 index 0000000..5b1113d --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/RandomException.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * Exception happening in case, something in random packages failed. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class RandomException extends PowerException { + + /** + * Constructor with message. + * + * @param message message describing the reason, + * why this exception was thrown. + */ + public RandomException(final String message) { + super(message); + } + +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceEntry.java b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceEntry.java new file mode 100644 index 0000000..ca9fb0a --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceEntry.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.choicegenerators; + +import lombok.AllArgsConstructor; +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +@AllArgsConstructor +public class ChoiceEntry { + /** + * Choice entry value - an object. + */ + private final T object; + /** + * Frequency for the object from 0 to 100. + */ + private final int frequency; +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGenerator.java new file mode 100644 index 0000000..4f59bdb --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGenerator.java @@ -0,0 +1,95 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.choicegenerators; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ChoiceGenerator { + /** + * Random for this choice generator. + */ + private final RandomGenerator random; + /** + * Choice entry array, which will be used to generate next ChoiceEntry. + */ + private final ChoiceEntry[] choiceEntries; + /** + * Internal frequency sum int array: + * contains sum of frequencies from frequency of choiceEntries[0] up to the index. + */ + private final int[] frequencySum; + + /** + * Constructor. + * @param randomArg CSRandomGenerator instance for randomness for this choice generator + * @param choiceEntriesArg array of ChoiceEntry instances + */ + public ChoiceGenerator(final RandomGenerator randomArg, final ChoiceEntry... choiceEntriesArg) { + if (choiceEntriesArg.length == 0) { + throw new RandomException("choiceEntries.length == 0"); + } + this.random = randomArg; + this.choiceEntries = choiceEntriesArg; + frequencySum = new int[choiceEntriesArg.length]; + for (int i = 0; i < choiceEntriesArg.length; i++) { + int previousFrequencySum = i == 0 ? 0 : frequencySum[i - 1]; + ChoiceEntry choiceEntry = choiceEntriesArg[i]; + frequencySum[i] = previousFrequencySum + choiceEntry.getFrequency(); + } + } + + /** + * Returns random choice entry using the frequency values of the choice entries. + * + * @return a ChoiceEntry instance- one of the instances in the array passed to the constructor. + * Which instance of ChoiceEntry will be selected depends on the random selected number and + * the frequency values in the ChoiceEntry array. + */ + public ChoiceEntry generate() { + if (this.choiceEntries.length == 1) { + return choiceEntries[0]; + } + int min = 0; + int frequencySumLastIndex = frequencySum.length - 1; + int max = frequencySum[frequencySumLastIndex]; + int randomNumber = random.nextInt(min, max); + ChoiceEntry result = null; + for (int i = 0; i < frequencySum.length; i++) { + int frequencySumItem = frequencySum[i]; + if (randomNumber <= frequencySumItem) { + result = choiceEntries[i]; + break; + } + } + if (result == null) { + throw new RandomException("ChoiceEntry not found."); + } + return result; + + } +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGenerator.java new file mode 100644 index 0000000..e69de77 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGenerator.java @@ -0,0 +1,80 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.choicegenerators; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ProbabilityGenerator { + /** + * Probability minimum, which is 0. + */ + public static final int PROBABILITY_MIN = 0; + /** + * Probability maximum, which is 100. + */ + public static final int PROBABILITY_MAX = 100; + /** + * + */ + private final ChoiceGenerator choiceGenerator; + /** + * Internal flag, which is true, if the probability given in the constructor is 0. + * If alwaysFalse is true, random generator won't be used and false will be always returned. + */ + private final boolean alwaysFalse; + + /** + * Constructor. + * @param random CSRandomGenerator implementation used to generate randomness for this probability generator. + * @param probability Probability- from 0 to 100. + */ + public ProbabilityGenerator(final RandomGenerator random, final int probability) { + if (probability < PROBABILITY_MIN) { + throw new RandomException("Probability is less than minimum: " + probability); + } + if (probability > PROBABILITY_MAX) { + throw new RandomException("Probability is more than maximum: " + probability); + } + alwaysFalse = probability == PROBABILITY_MIN; + ChoiceEntry yes = new ChoiceEntry<>(Boolean.TRUE, probability); + ChoiceEntry no = new ChoiceEntry<>(Boolean.FALSE, PROBABILITY_MAX - probability); + + this.choiceGenerator = new ChoiceGenerator<>(random, yes, no); + } + + /** + * Generates true or false based on the probability. + * + * @return true or false based on the given randomness generator and probability + */ + public boolean generate() { + if (alwaysFalse) { + return false; + } + return this.choiceGenerator.generate().getObject().booleanValue(); + } +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/package-info.java b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/package-info.java new file mode 100644 index 0000000..b9f7dc2 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/choicegenerators/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Color Shapes Engine utils like choice generator and others. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.random.choicegenerators; diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/RandomGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/RandomGenerator.java new file mode 100644 index 0000000..df8634c --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/RandomGenerator.java @@ -0,0 +1,233 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators; + +import org.nanoboot.powerframework.core.exceptions.UnsupportedMethodException; +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; +import org.nanoboot.powerframework.random.internal.RandomNumberUtils; +import org.nanoboot.powerframework.random.internal.RandomTextUtils; +import org.nanoboot.powerframework.text.CharacterType; + +import java.util.ArrayList; +import java.util.List; + +/** + * Random Generator interface with some default methods. + * @author Robert Vokac + * @since 0.0.0 + */ +public interface RandomGenerator { + + /** + * Returns next number. + * + * @return next number + */ + long next(); + + /** + * Skips next number. + */ + default void skip() { + next(); + } + + /** + * Returns current number. + * + * @return current number + */ + default long current() { + String msg = "Current number cannot be returned again."; + throw new UnsupportedMethodException(msg); + } + + /** + * Returns initial number. + * + * @return initial number + */ + default long initialSeed() { + String msg = "Initial number cannot be returned."; + throw new UnsupportedMethodException(msg); + } + + /** + * Returns number of calls of the next() method. + * + * @return initial number + */ + default long numberOfNextCalls() { + String msg = "numberOfNextCalls is not supported."; + throw new UnsupportedMethodException(msg); + } + + /** + * Returns number of calls of the next() method. + * + * @return initial number + */ + default List valuesOfNextCalls() { + String msg = "valuesOfNextCalls is not supported."; + throw new UnsupportedMethodException(msg); + } + + /** + * Returns itself. + * @return itself + */ + RandomGenerator getItself(); + + /** + * Returns next number using the range. + * + * @param from start + * @param to end + * @return next number in the range + */ + default long next(final long from, final long to) { + return RandomNumberUtils.next(getItself(), from, to); + } + + /** + * Returns next number. + * + * @return next number + */ + + default int nextInt() { + return RandomNumberUtils.nextInt(getItself()); + } + + /** + * Return number in the given range. + * + * @param from starting position + * @param to ending position + * @return pseudo random int + */ + default int nextInt(final int from, final int to) { + return RandomNumberUtils.nextInt(getItself(), from, to); + } + + /** + * @return pseudo random boolean + */ + default boolean nextBoolean() { + return RandomNumberUtils.nextBoolean(getItself()); + } + /** + * Returns random character. + * + * @return random character + */ + default char nextChar() { + return RandomTextUtils.nextChar(getItself()); + } + /** + * Returns random character. + * + * @param types type of characters to be used. + * @return random character + */ + default char nextChar(final CharacterType... types) { + return RandomTextUtils.nextChar(getItself(), types); + } + /** + * Returns random text consisting of letters or numbers. + * + * @param length the size of the return String + * @return random text using the given parameters + */ + default String nextText(final int length) { + return RandomTextUtils.nextText(getItself(), length); + } + /** + * Returns random text. + * + * @param length the size of the return String + * @param types character types + * to use for the string to be returned. + * If empty or null: lower and upper + * letters and number only will be used. + * Note: CharacterType.OTHER_NOT_PRINTABLE + * is not supported. + * @return random text using the given parameters + */ + default String nextText(final int length, + final CharacterType... types) { + return RandomTextUtils.nextText(getItself(), length, types); + } + /** + * Returns random element of an array. + * @param elements generic array + * @param type of the array and type to return + * @return random element + */ + default T randomElement(T... elements) { + int to = elements.length - 1; + int randomIndex = nextInt(0, to); + return elements[randomIndex]; + } + default List getRandomItemsFromList(List list, int itemCount) { + if (itemCount > list.size()) { + throw new RandomException("itemCount > list.size()"); + } + List listCopy = new ArrayList<>(); + for (T e : list) { + listCopy.add(e); + } + List result = new ArrayList<>(); + for (int i = 0; i < itemCount; i++) { + int randomListCopyIndex = nextInt(0, listCopy.size() - 1); + T randomItem = listCopy.get(randomListCopyIndex); + listCopy.remove(randomListCopyIndex); + result.add(randomItem); + } + return result; + } + + default T getRandomItemFromList(List list) { + if (list.isEmpty()) { + throw new RandomException("list is empty"); + } + + int randomListCopyIndex = nextInt(0, list.size() - 1); + T randomItem = list.get(randomListCopyIndex); + + return randomItem; + } + /** + * Returns W5RandomGenerator instance. + * @return instance of W5RandomGenerator + */ + static RandomGenerator getDefaultImplStatic() { + return W5RandomGenerator.getStaticInstance(); + } + + /** + * Returns unique string identification of the given random generator type. + * Instances of the same implementation should return same value. + * @return name of the implementation + */ + String getName(); +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGenerator.java new file mode 100644 index 0000000..8066a90 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGenerator.java @@ -0,0 +1,79 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent; + +import org.nanoboot.powerframework.core.exceptions.UnsupportedMethodException; + +/** + * Represents a seed. Uses linear congruential function. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class CPlusPlus11LinearCongruentGenerator + extends LinearCongruentGenerator { + + /** + * multiplier constant. + */ + private static final long MULTIPLIER = 16807; + + /** + * increment constant. + */ + private static final long INCREMENT = 0; + + /** + * modulus constant. + */ + private static final long MODULUS = 2147483647; + + /** + * Constructor. + * + * @param initialSeedParam the number defining the returned numbers + */ + public CPlusPlus11LinearCongruentGenerator( + final long initialSeedParam) { + super(MULTIPLIER, INCREMENT, MODULUS, initialSeedParam); + } + + /** + * Returns current number. + * + * @return current number + */ + @Override + public long current() { + throw new UnsupportedMethodException(""); + } + + /** + * Returns initial seed. + * + * @return initial seed + */ + @Override + public long initialSeed() { + throw new UnsupportedMethodException(""); + } + +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/DummyGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/DummyGenerator.java new file mode 100644 index 0000000..0a5767e --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/DummyGenerator.java @@ -0,0 +1,64 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a seed. Uses linear congruential function. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class DummyGenerator implements RandomGenerator { + private final List nextValues; + private int nextValueIndex = 0; + private final int maxNextValueIndex; + + public DummyGenerator(List nextValues) { + this.nextValues = nextValues; + this.maxNextValueIndex = nextValues.size() - 1; + } + @Override + public long next() { + if(nextValueIndex > maxNextValueIndex) { + throw new RandomException("There is no other value available for next() call."); + } + long next = nextValues.get(nextValueIndex); + nextValueIndex++; + return next; + } + + @Override + public RandomGenerator getItself() { + return this; + } + + @Override + public String getName() { + return this.getClass().getName(); + } +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGenerator.java new file mode 100644 index 0000000..98f0f77 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGenerator.java @@ -0,0 +1,123 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent; + +import lombok.Getter; +import org.nanoboot.powerframework.random.generators.RandomGenerator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a seed. Uses linear congruential function. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class LinearCongruentGenerator implements RandomGenerator { + /** + * number multiplying current seed. + */ + @Getter + private final long multiplier; + + /** + * Number to add to the product. + */ + @Getter + private final long increment; + + /** + * modulus used for the total of the product and increment. + */ + @Getter + private final long modulus; + + /** + * Initial seed. + */ + private final long initialSeed; + + /** + * Current number. + */ + private long current; + + @Getter + private List nextValues = new ArrayList<>(); + + /** + * Constructor. + * + * @param multiplierParam a + * @param incrementParam c + * @param modulusParam m + * @param initialSeedParam the number defining the returned numbers + */ + public LinearCongruentGenerator( + final long multiplierParam, + final long incrementParam, + final long modulusParam, + final long initialSeedParam) { + this.multiplier = multiplierParam; + this.increment = incrementParam; + this.modulus = modulusParam; + this.initialSeed = initialSeedParam; + this.current = this.initialSeed; + } + + @Override + public final long next() { + long pseudoRandomLong = ((multiplier * current) + increment) % modulus; + this.current = pseudoRandomLong; + this.nextValues.add(pseudoRandomLong); + return pseudoRandomLong; + } + + /** + * Returns current number. + * @return current number + */ + @Override + public long current() { + return current; + } + + /** + * Returns initial seed. + * @return initial seed + */ + @Override + public long initialSeed() { + return initialSeed; + } + + @Override + public final RandomGenerator getItself() { + return this; + } + + @Override + public final String getName() { + return this.getClass().getName(); + } + +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactory.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactory.java new file mode 100644 index 0000000..0b6f340 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactory.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; + +/** + * W5 generator factory interface. * + * @author Robert Vokac + * @since 0.0.0 + */ +public interface W5GeneratorsFactory { + /** + * Creates W5 generators. + * @return w5 generators + */ + CPlusPlus11LinearCongruentGenerator[] getSubGenerators(); +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImpl.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImpl.java new file mode 100644 index 0000000..0dedfca --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImpl.java @@ -0,0 +1,161 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import lombok.Getter; +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; + +import java.security.SecureRandom; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +final class W5GeneratorsFactoryImpl implements W5GeneratorsFactory { + + /** + * Plus character. + */ + private static final char PLUS = '+'; + /** + * Asterisk character. + */ + private static final char TIMES = '*'; + /** + *0. + */ + private static final int SEED0_INDEX = 0; + /** + * 1. + */ + private static final int SEED0_START = 1; + /** + * 3. + */ + private static final int SEED0_END = 3; + /** + * 4. + */ + private static final int SEED1_INDEX = 4; + /** + * 5. + */ + private static final int SEED1_START = 5; + /** + * 7. + */ + private static final int SEED1_END = 7; + + /** + * Count of numbers. + */ + private static final int NUMBER_COUNT = 8; + + /** + * w5 generators. + */ + @Getter + private CPlusPlus11LinearCongruentGenerator[] subGenerators; + /** + * Constructor. + */ + W5GeneratorsFactoryImpl() { + SecureRandom random = new SecureRandom(); + long[] randomNumbers = new long[NUMBER_COUNT]; + for (int i = 0; i < NUMBER_COUNT; i++) { + randomNumbers[i] = random.nextLong(); + } + process(randomNumbers); + } + + /** + * Constructor. + * @param numbers input numbers + */ + W5GeneratorsFactoryImpl(final long[] numbers) { + process(numbers); + } + + /** + * Methods processing the input numbers. + * @param randomNumbers random numbers + */ + private void process(final long[] randomNumbers) { + if (randomNumbers == null || randomNumbers.length != NUMBER_COUNT) { + String msg = "Count of numbers must be " + NUMBER_COUNT + "."; + throw new RandomException(msg); + } + long magicNumber = randomNumbers[0]; + CPlusPlus11LinearCongruentGenerator magicGenerator = + new CPlusPlus11LinearCongruentGenerator(magicNumber); + long seed0; + long seed1; + + long number1; + long number2; + long number3; + long number4; + + seed0 = randomNumbers[SEED0_INDEX]; + for (int i = SEED0_START; i <= SEED0_END; i++) { + number1 = seed0; + number2 = randomNumbers[i]; + seed0 = executeRandomPlusOrMultiply( + magicGenerator, number1, number2); + } + + CPlusPlus11LinearCongruentGenerator generator0 = + new CPlusPlus11LinearCongruentGenerator(seed0); + + seed1 = randomNumbers[SEED1_INDEX]; + for (int i = SEED1_START; i <= SEED1_END; i++) { + number3 = seed1; + number4 = randomNumbers[i]; + seed1 = executeRandomPlusOrMultiply( + magicGenerator, number3, number4); + } + CPlusPlus11LinearCongruentGenerator generator1 = + new CPlusPlus11LinearCongruentGenerator(seed1); + this.subGenerators = new CPlusPlus11LinearCongruentGenerator[]{ + magicGenerator, generator0, generator1}; + } + + /** + * Uses total or product of the two given numbers. + * @param rg random number generator + * @param number1 number 1 + * @param number2 number 2 + * @return processes the numbers using the random number generator + */ + private static long executeRandomPlusOrMultiply(final RandomGenerator rg, + final long number1, + final long number2) { + char operation = rg.nextBoolean() ? PLUS : TIMES; + if (operation == PLUS) { + return number1 + number2; + } else { + return number1 * number2; + } + } +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessor.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessor.java new file mode 100644 index 0000000..c57d0a6 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessor.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; +/** + * W5 generator processor interface. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public interface W5GeneratorsProcessor { + /** + * Computes next long using the generators. + * @param generators generators. + * @return next long using the generators + */ + long next(CPlusPlus11LinearCongruentGenerator... generators); +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImpl.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImpl.java new file mode 100644 index 0000000..920d5d0 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImpl.java @@ -0,0 +1,76 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; +/** + * W5 generator processor implementation. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class W5GeneratorsProcessorImpl implements W5GeneratorsProcessor { + + /** + * One million. + */ + private static final int MILLION = 1_000_000_000; + /** + * Expected count of generators. + */ + private static final int EXPECTED_COUNT_OF_GENERATORS = 3; + + @Override + public final long next( + final CPlusPlus11LinearCongruentGenerator... generators) { + if (generators == null) { + throw new RandomException("Generators must not be null."); + } + if (generators.length != EXPECTED_COUNT_OF_GENERATORS) { + String msg = + "Param generators is an array, which has invalid count: " + + generators.length; + throw new RandomException(msg); + } + + long[] numberFractions = new long[2]; + + CPlusPlus11LinearCongruentGenerator g0 = generators[0]; + CPlusPlus11LinearCongruentGenerator g1 = generators[1]; + CPlusPlus11LinearCongruentGenerator g2 = generators[2]; + for (int i = 0; i <= 1; i++) { + if (g0.nextBoolean()) { + g1.skip(); + } else { + g2.skip(); + } + int number1 = g2.nextInt(); + int number2 = g1.nextInt(); + if (g0.nextBoolean()) { + number2 *= (-1); + } + numberFractions[i] = (Math.abs(number1 + number2)) % MILLION; + } + + return (numberFractions[0] * MILLION) + numberFractions[1]; + } +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGenerator.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGenerator.java new file mode 100644 index 0000000..ce87557 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGenerator.java @@ -0,0 +1,112 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; + +/** + * Used to generate pseudo random values. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class W5RandomGenerator implements RandomGenerator { + + /** + * Static instance of the generator. + */ + private static final W5RandomGenerator INSTANCE; + /** + *generators. + */ + private final CPlusPlus11LinearCongruentGenerator[] generators; + + /** + * next() processor. + */ + private final W5GeneratorsProcessor processor; + + /** + * Constructor using random input parameters. + * + */ + public W5RandomGenerator() { + W5GeneratorsFactoryImpl gc = new W5GeneratorsFactoryImpl(); + this.generators = gc.getSubGenerators(); + this.processor = new W5GeneratorsProcessorImpl(); + } + + /** + * Constructor. + * + * @param numbers numbers + */ + @SuppressWarnings("checkstyle:ParameterNumber") + public W5RandomGenerator( + final long... numbers) { + this(new W5GeneratorsFactoryImpl(numbers), + new W5GeneratorsProcessorImpl() + ); + } + + /** + * Constructor. + * + * @param factory a factory + * @param processorIn a processor + */ + @SuppressWarnings("checkstyle:ParameterNumber") + public W5RandomGenerator(final W5GeneratorsFactory factory, + final W5GeneratorsProcessor processorIn) { + this.generators = factory.getSubGenerators(); + this.processor = processorIn; + } + + static { + INSTANCE = new W5RandomGenerator(); + } + + /** + * @return static instance + */ + public static W5RandomGenerator getStaticInstance() { + return INSTANCE; + } + + @Override + public final RandomGenerator getItself() { + return this; + } + + @Override + public final String getName() { + return this.getClass().getName(); + } + + /** + * @return pseudo random long + */ + public long next() { + return processor.next(generators); + } + +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/package-info.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/package-info.java new file mode 100644 index 0000000..aa4997b --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/package-info.java @@ -0,0 +1,26 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * w5 random generator. + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/package-info.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/package-info.java new file mode 100644 index 0000000..d4253e2 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/linearcongruent/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Classes for linear congruent generators. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.random.generators.linearcongruent; diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/generators/package-info.java b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/package-info.java new file mode 100644 index 0000000..01ab557 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/generators/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Generators. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.random.generators; diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomNumberUtils.java b/power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomNumberUtils.java new file mode 100644 index 0000000..6f560ed --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomNumberUtils.java @@ -0,0 +1,97 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.internal; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; + +/** + * Utility for number randomness. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class RandomNumberUtils { + + /** + * Private constructor. + */ + private RandomNumberUtils() { + //Instantiation not needed + } + + /** + * Returns next number using the range. + * @param rg random generator + * @param from start + * @param to end + * @return random number in the range + */ + public static long next( + final RandomGenerator rg, + final long from, + final long to) { + if (from > to) { + throw new RandomException("from is greater than to."); + } + long range = to - from; + long randomLong = rg.next(); + long randomRange = randomLong % (range + 1); + long randomLongInRange; + randomLongInRange = from + randomRange; + + return randomLongInRange; + } + + /** + * Returns next number. + * + * @param rg random generator + * @return next number + */ + public static int nextInt(final RandomGenerator rg) { + return (int) (rg.next() % Integer.MAX_VALUE); + } + + /** + * Return number in the given range. + * + * @param rg random generator + * @param from start position + * @param to end position + * @return pseudo random int + */ + public static int nextInt(final RandomGenerator rg, + final int from, final int to) { + return (int) rg.next(from, to); + } + + /** + * Returns random boolean. + * + * @param rg random generator + * @return pseudo random boolean + */ + public static boolean nextBoolean(final RandomGenerator rg) { + long randomLong = rg.next(0, 1); + return randomLong == 1; + } +} diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomTextUtils.java b/power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomTextUtils.java new file mode 100644 index 0000000..97a2f3f --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/internal/RandomTextUtils.java @@ -0,0 +1,130 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.internal; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.nanoboot.powerframework.text.CharacterRange; +import org.nanoboot.powerframework.text.CharacterType; +/** + * Utility for text randomness. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class RandomTextUtils { + /** + * Private constructor. + */ + private RandomTextUtils() { + //Instantiation not needed + } + /** + * Returns random character. + * + * @param rg random generator to be used + * @return random character + */ + public static char nextChar( + final RandomGenerator rg) { + return nextChar(rg, null); + } + /** + * Returns random character. + * + * @param rg random generator to be used + * @param types type of characters to be used. + * @return random character + */ + public static char nextChar( + final RandomGenerator rg, final CharacterType... types) { + CharacterType[] characterTypes; + if (types == null || types.length == 0) { + characterTypes = new CharacterType[]{ + CharacterType.NUMBER, CharacterType.LOWER_LETTER, + CharacterType.UPPER_LETTER}; + } else { + characterTypes = types; + } + + int charCount = 0; + for (CharacterType type : characterTypes) { + if (type == CharacterType.OTHER_NOT_PRINTABLE) { + String msg = + "CharacterType.OTHER_NOT_PRINTABLE is not supported"; + throw new UnsupportedOperationException(msg); + } + charCount = charCount + CharacterRange.getInstance(type).size(); + } + + int randomPosition = rg.nextInt(1, charCount); + int currentPosition = 0; + + for (CharacterType type : characterTypes) { + char[] array = CharacterRange.getInstance(type).getArray(); + for (char ch : array) { + currentPosition++; + if (currentPosition == randomPosition) { + return ch; + } + } + } + + throw new RandomException("nextChar method failed."); //NOSONAR + } + /** + * Returns random text consisting of letters or numbers. + * + * @param rg random generator to be used + * @param length the size of the return String + * @return random text using the given parameters + */ + public static String nextText( + final RandomGenerator rg, final int length) { + return nextText(rg, length, null); + } + + /** + * Returns random text. + * + * @param rg random generator to be used + * @param length the size of the return String + * @param types character types + * to use for the string to be returned. + * If empty or null: lower and upper + * letters and number only will be used. + * Note: CharacterType.OTHER_NOT_PRINTABLE + * is not supported. + * @return random text using the given parameters + */ + public static String nextText( + final RandomGenerator rg, final int length, + final CharacterType... types) { + + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < length; i++) { + char ch = nextChar(rg, types); + stringBuilder.append(ch); + } + return stringBuilder.toString(); + } +} + diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/internal/package-info.java b/power-random/src/main/java/org/nanoboot/powerframework/random/internal/package-info.java new file mode 100644 index 0000000..3e9bc70 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/internal/package-info.java @@ -0,0 +1,26 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Internal classes. + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.random.internal; diff --git a/power-random/src/main/java/org/nanoboot/powerframework/random/package-info.java b/power-random/src/main/java/org/nanoboot/powerframework/random/package-info.java new file mode 100644 index 0000000..b29fd05 --- /dev/null +++ b/power-random/src/main/java/org/nanoboot/powerframework/random/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Classes used to generated some randomness. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.random; diff --git a/power-random/src/main/resources/.gitkeep b/power-random/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/RandomExceptionTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/RandomExceptionTest.java new file mode 100644 index 0000000..9ff3fef --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/RandomExceptionTest.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class RandomExceptionTest { + @Test + public void constructor_String() { + assertEquals("An error", new RandomException("An error").getMessage()); + } + +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGeneratorTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGeneratorTest.java new file mode 100644 index 0000000..7e680fa --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ChoiceGeneratorTest.java @@ -0,0 +1,222 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.choicegenerators; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ChoiceGeneratorTest { + private RandomGenerator random; + + @Before + public void setup() { + random = RandomGenerator.getDefaultImplStatic(); + } + + @Test(expected = RandomException.class) + public void constructor_generator_choiceEntries_choiceEntriesMustNotBeEmptyAndIsEmpty() { + //prepare + assertNotNull(new ChoiceGenerator(random)); + //execute + //assert + } + + @Test() + public void constructor_generator_choiceEntries_choiceEntriesMustNotBeEmptyAndIsNotEmpty() { + //prepare + + assertNotNull(new ChoiceGenerator(random, new ChoiceEntry<>("a", 50))); + //execute + //assert + } + + @Test() + public void constructor_generator_choiceEntries_choiceEntriesMustNotBeEmptyAndIsNotEmpty2() { + //prepare + + assertNotNull(new ChoiceGenerator(random, new ChoiceEntry<>("a", 50), new ChoiceEntry<>("b", 75))); + //execute + //assert + } + + @Test + public void generate_hasOnlyOneEntry() { + //prepare + + ChoiceGenerator choiceGenerator = new ChoiceGenerator(random, new ChoiceEntry<>("a", 50)); + //execute + + //assert + assertEquals("a", choiceGenerator.generate().getObject()); + } + + @Test + public void generate_hasTwoEntries() { + //prepare + + ChoiceGenerator choiceGenerator = new ChoiceGenerator(random, new ChoiceEntry<>("a", 50), new ChoiceEntry<>("b", 75)); + //execute + Object generatedString = choiceGenerator.generate().getObject(); + assertTrue("a".equals(generatedString) || "b".equals(generatedString)); + //assert + } + + @Test + public void generate_mockedCheck() { +// //prepare + class ARandomGeneratorImpl implements RandomGenerator { + private int[] intArray = new int[]{0, 24, 25, 26, 60, 74, 75, 76, 149, 150}; + private int nextIndex = 0; + private boolean fromToChecked = false; + + @Override + public long next() { + return 0; + } + + public int nextInt(int from, int to) { + if (!fromToChecked) { + assertEquals(0, from); + assertEquals(150, to); + fromToChecked = true; + } + if (nextIndex >= intArray.length) { + fail("next index is " + nextIndex + ", but the intArray has length " + intArray.length); + } + int result = intArray[nextIndex]; + ++nextIndex; + return result; + } + + @Override + public RandomGenerator getItself() { + return this; + } + + @Override + public String getName() { + return "choiceRandomGenerator"; + } + } + RandomGenerator randomArg = new ARandomGeneratorImpl(); + ChoiceEntry green = new ChoiceEntry<>("green", 25);//0-25 + ChoiceEntry orange = new ChoiceEntry<>("orange", 50);//26-75 + ChoiceEntry red = new ChoiceEntry<>("red", 75);//76/150 + + ChoiceGenerator choiceGenerator = new ChoiceGenerator(randomArg, green, orange, red); +// //execute +// //assert + assertTrue("green".equals(choiceGenerator.generate().getObject())); + assertTrue("green".equals(choiceGenerator.generate().getObject())); + assertTrue("green".equals(choiceGenerator.generate().getObject())); + assertTrue("orange".equals(choiceGenerator.generate().getObject())); + assertTrue("orange".equals(choiceGenerator.generate().getObject())); + assertTrue("orange".equals(choiceGenerator.generate().getObject())); + assertTrue("orange".equals(choiceGenerator.generate().getObject())); + assertTrue("red".equals(choiceGenerator.generate().getObject())); + assertTrue("red".equals(choiceGenerator.generate().getObject())); + assertTrue("red".equals(choiceGenerator.generate().getObject())); + } + @Test(expected = RandomException.class) + public void generate_entryNotFound() { +// //prepare + class ARandomGeneratorImpl implements RandomGenerator { + @Override + public long next() { + return 0; + } + + public int nextInt(int from, int to) { + return to + 1; + } + + @Override + public RandomGenerator getItself() { + return this; + } + + @Override + public String getName() { + return "choiceRandomGenerator"; + } + } + RandomGenerator randomArg = new ARandomGeneratorImpl(); + ChoiceEntry green = new ChoiceEntry<>("green", 25);//0-25 + ChoiceEntry orange = new ChoiceEntry<>("orange", 50);//26-75 + ChoiceEntry red = new ChoiceEntry<>("red", 75);//76/150 + + ChoiceGenerator choiceGenerator = new ChoiceGenerator(randomArg, green, orange, red); +// //execute + choiceGenerator.generate().getObject(); +// //assert + } +// @Test +// public void generate() { +// //todo +// +// //prepare +// ChoiceEntry colored = new ChoiceEntry<>("colored", 80); +// ChoiceEntry joker = new ChoiceEntry<>("joker", 10); +// ChoiceEntry automaticBomb = new ChoiceEntry<>("automaticBomb", 15); +// ChoiceEntry manualBomb = new ChoiceEntry<>("manualBomb", 40); +// +// //execute +// +// int coloredCount = 0; +// int jokerCount = 0; +// int automaticBombCount = 0; +// int manualBombCount = 0; +// ChoiceGenerator choiceGenerator = new ChoiceGenerator<>(random, colored, joker, automaticBomb, manualBomb); +// +// int multi = 10000; +// for (int i = 0; i < 145 * multi; i++) { +// //System.out.println(choiceGenerator.generate().getName()); +// switch (choiceGenerator.generate().getObject()) { +// case "colored": +// coloredCount++; +// break; +// case "joker": +// jokerCount++; +// break; +// case "automaticBomb": +// automaticBombCount++; +// break; +// case "manualBomb": +// manualBombCount++; +// break; +// } +// } +// System.out.println("colored=80 joker=10 automaticBomb=15 manualBomb=40"); +// System.out.println(coloredCount / multi + " " + jokerCount / multi + " " + automaticBombCount / multi + " " + manualBombCount / multi); +// //assert +// assertTrue(true); +// } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGeneratorTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGeneratorTest.java new file mode 100644 index 0000000..883480b --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/choicegenerators/ProbabilityGeneratorTest.java @@ -0,0 +1,153 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.choicegenerators; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ProbabilityGeneratorTest { + private RandomGenerator randomGenerator; + + @Before + public void setup() { + randomGenerator = RandomGenerator.getDefaultImplStatic(); + } + + @Test(expected = RandomException.class) + public void constructor_probabilityIsLessThanMinimum() { + new ProbabilityGenerator(randomGenerator, -1); + } + @Test(expected = RandomException.class) + public void constructor_probabilityIsMoreThanMinimum() { + new ProbabilityGenerator(randomGenerator, 101); + } + @Test(expected = Test.None.class) + public void constructor_probabilityIsOK0() { + new ProbabilityGenerator(randomGenerator, 0); + } + @Test(expected = Test.None.class) + public void constructor_probabilityIsOK1() { + new ProbabilityGenerator(randomGenerator, 1); + } + @Test(expected = Test.None.class) + public void constructor_probabilityIsOK99() { + new ProbabilityGenerator(randomGenerator, 99); + } + @Test(expected = Test.None.class) + public void constructor_probabilityIsOK60() { + new ProbabilityGenerator(randomGenerator, 60); + } + @Test(expected = Test.None.class) + public void constructor_probabilityIsOK100() { + new ProbabilityGenerator(randomGenerator, 100); + } + + @Test + public void generate_alwaysFalse() { + assertEquals(false, new ProbabilityGenerator(randomGenerator, 0).generate()); + } @Test + public void generate_alwaysTrue() { + assertEquals(true, new ProbabilityGenerator(randomGenerator, 100).generate()); + } + @Test + public void generate_NotAlwaysFalse() { + boolean trueGenerated = false; + boolean falseGenerated = false; + for(int i = 0; i<100; i++) { + boolean result = new ProbabilityGenerator(randomGenerator, 40).generate(); + if(result) { + trueGenerated = true; + } else { + falseGenerated = true; + } + if(trueGenerated && falseGenerated) { + //no need for next loop + break; + } + } + assertTrue(trueGenerated && falseGenerated); + } + + + @Test + public void generate_mockedCheck() { +// //prepare + class ARandomGeneratorImpl implements RandomGenerator { + private int[] intArray = new int[]{0, 24, 25, 26, 60, 74, 75, 76, 99, 100}; + private int nextIndex = 0; + private boolean fromToChecked = false; + + @Override + public long next() { + return 0; + } + + public int nextInt(int from, int to) { + if (!fromToChecked) { + assertEquals(0, from); + assertEquals(100, to); + fromToChecked = true; + } + if (nextIndex >= intArray.length) { + fail("next index is " + nextIndex + ", but the intArray has length " + intArray.length); + } + int result = intArray[nextIndex]; + ++nextIndex; + return result; + } + + @Override + public RandomGenerator getItself() { + return this; + } + + @Override + public String getName() { + return "choiceRandomGenerator"; + } + } + RandomGenerator randomArg = new ARandomGeneratorImpl(); + + ProbabilityGenerator choiceGenerator = new ProbabilityGenerator(randomArg, 40); +// //execute +// //assert + + assertTrue(choiceGenerator.generate()); + assertTrue(choiceGenerator.generate()); + assertTrue(choiceGenerator.generate()); + assertTrue(choiceGenerator.generate()); + assertFalse(choiceGenerator.generate()); + assertFalse(choiceGenerator.generate()); + assertFalse(choiceGenerator.generate()); + assertFalse(choiceGenerator.generate()); + assertFalse(choiceGenerator.generate()); + assertFalse(choiceGenerator.generate()); + } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/generators/RandomGeneratorTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/RandomGeneratorTest.java new file mode 100644 index 0000000..a10bd2c --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/RandomGeneratorTest.java @@ -0,0 +1,1379 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators; + +import org.nanoboot.powerframework.core.exceptions.UnsupportedMethodException; +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; +import org.nanoboot.powerframework.text.CharacterType; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class RandomGeneratorTest { + + private RandomGenerator randomGenerator; + + @Before + public void setUp() { + this.randomGenerator = new RandomGenerator() { + private int currentIndex = 0; + @Override + public long next() { + long toReturn = randomNumbers[currentIndex]; + currentIndex++; + if(currentIndex > (randomNumbers.length - 1)) { + currentIndex = 0; + for(int i = 0; i < randomNumbers.length; i++) { + randomNumbers[i] = RandomGenerator.getDefaultImplStatic().next(); + } + } + return toReturn; + } + + @Override + public RandomGenerator getItself() { + return this; + } + + @Override + public String getName() { + return "testGenerator"; + } + }; + } + + @Test + public void next() { + //setup + //execute + //assert + for (int i = 0; i < 10; i++) { + long randomLong = randomGenerator.next(); + assertEquals(randomNumbers[i], randomLong); + } + } + + @Test + public void skip() { + randomGenerator.skip(); + randomGenerator.skip(); + randomGenerator.skip(); + assertEquals(630129986537696031l, randomGenerator.next()); + } + + @Test(expected = UnsupportedMethodException.class) + public void current() { + randomGenerator.current(); + } + + @Test(expected = UnsupportedMethodException.class) + public void initialSeed() { + randomGenerator.initialSeed(); + } + @Test(expected = UnsupportedMethodException.class) + public void numberOfNextCalls() { + randomGenerator.numberOfNextCalls(); + } + @Test + public void getItself() { + assertEquals(this.randomGenerator.hashCode(), randomGenerator.getItself().hashCode()); + } + + @Test + public void getNext_interval() { + long min = Integer.MAX_VALUE; + long max = Integer.MIN_VALUE; + long from = 36; + long to = 418; + for(int i = 0; i < 9999; i++) { + long randomLong = randomGenerator.next(from, to); + if(randomLong < from) { + String msg = "Random number is " + randomLong +", but it should be at least " + from; + throw new AssertionError(msg); + } + if(randomLong > to) { + String msg = "Random number is " + randomLong +", but it should be at most " + to; + throw new AssertionError(msg); + } + if(randomLong < min) { + min = randomLong; + } + if(randomLong > max) { + max = randomLong; + } + } + + assertEquals(from, min); + assertEquals(to, max); + + } + + @Test(expected = RandomException.class) + public void getNext_interval_exception() { + randomGenerator.next(10, 5); + } + + @Test + public void nextInt() { + assertEquals(randomNumbers[0] % Integer.MAX_VALUE, randomGenerator.nextInt()); + } + @Test + public void nextInt_interval() { + int from = 31; + int to = 43; + assertEquals(from + (randomNumbers[0] % (to - from + 1)), randomGenerator.nextInt(from, to)); + } + @Test + public void nextBoolean() { + int from = 0; + int to = 1; + boolean expected = from + (randomNumbers[0] % (to - from + 1)) == 1; + boolean returned = randomGenerator.nextInt(from, to) == 1; + assertEquals(expected, returned); + } + @Test + public void nextChar_types_numbers() { + for(int i = 0; i < 10000; i++) { + char ch = randomGenerator.nextChar(CharacterType.NUMBER); + assertTrue(Character.isDigit(ch)); + } + } + @Test + public void nextChar_types_lower() { + for(int i = 0; i < 1000; i++) { + char ch = randomGenerator.nextChar(CharacterType.LOWER_LETTER); + assertTrue(Character.isLowerCase(ch)); + } + } + @Test + public void nextChar_types_upper() { + for(int i = 0; i < 1000; i++) { + char ch = randomGenerator.nextChar(CharacterType.UPPER_LETTER); + assertTrue(Character.isUpperCase((ch))); + } + } + @Test + public void nextChar_types_otherPrintable() { + for(int i = 0; i < 1000; i++) { + char ch = randomGenerator.nextChar(CharacterType.OTHER_PRINTABLE); + assertFalse(Character.isWhitespace(ch)); + } + } + + @Test(expected = UnsupportedOperationException.class) + public void nextChar_types_notPrintable() { + randomGenerator.nextChar(CharacterType.OTHER_NOT_PRINTABLE); + } + + @Test + public void nextChar_types_null() { + for(int i = 0; i < 1000; i++) { + char ch = randomGenerator.nextChar(null); + boolean digit = Character.isDigit((ch)); + boolean upper = Character.isLowerCase((ch)); + boolean lower = Character.isUpperCase((ch)); + assertTrue(digit || upper || lower); + } + } + @Test + public void nextChar() { + for(int i = 0; i < 1000; i++) { + char ch = randomGenerator.nextChar(); + boolean digit = Character.isDigit((ch)); + boolean upper = Character.isLowerCase((ch)); + boolean lower = Character.isUpperCase((ch)); + assertTrue(digit || upper || lower); + } + } + @Test + public void nextText() { + String returned = randomGenerator.nextText(100); + assertEquals(100, returned.length()); + + for(char ch : returned.toCharArray()) { + boolean digit = Character.isDigit((ch)); + boolean upper = Character.isLowerCase((ch)); + boolean lower = Character.isUpperCase((ch)); + assertTrue(digit || upper || lower); + } + } + @Test + public void nextText_types_numbers() { + String returned = randomGenerator.nextText(100, CharacterType.NUMBER); + assertEquals(100, returned.length()); + for(char ch : returned.toCharArray()) { + assertTrue(Character.isDigit(ch)); + } + } + @Test + public void nextText_types_lower() { + String returned = randomGenerator.nextText(100, CharacterType.LOWER_LETTER); + for(char ch : returned.toCharArray()) { + assertTrue(Character.isLowerCase(ch)); + } + } + @Test + public void nextText_types_upper() { + String returned = randomGenerator.nextText(100, CharacterType.UPPER_LETTER); + for(char ch : returned.toCharArray()) { + assertTrue(Character.isUpperCase((ch))); + } + } + @Test + public void nextText_types_otherPrintable() { + String returned = randomGenerator.nextText(100, CharacterType.OTHER_PRINTABLE); + for(char ch : returned.toCharArray()) { + assertFalse(Character.isWhitespace(ch)); + } + } + @Test + public void randomElement() { + int[] array = new int[] {5, 4, 9, 6, 7, 2, 5, 4, 3, 4}; + + int from = 0; + int to = array.length - 1; + + int expectedIndex = (int) (from + (randomNumbers[0] % (to - from + 1))); + + int expected = array[expectedIndex]; + int returned = randomGenerator.randomElement(5, 4, 9, 6, 7, 2, 5, 4, 3, 4); + assertEquals(expected, returned); + } + @Test + public void getDefaultImplStatic() { + assertEquals(W5RandomGenerator.class, RandomGenerator.getDefaultImplStatic().getClass()); + + } + @Test + public void getName() { + assertEquals("testGenerator", randomGenerator.getName()); + } + + private final long[] randomNumbers = new long[]{ + 989766495916971073l, + + 752993031226338159l, + 208354589825897774l, + 630129986537696031l, + 122750107603623909l, + 87213201598134595l, + 732467883029815946l, + 751898065858841694l, + 579435717923219006l, + 313749987799630863l, + 884714377553716529l, + + 965051149136722169l, + 421787665199259631l, + 657038602346525671l, + 644714380109667537l, + 922906928077404901l, + 126313368451040874l, + 432338839333393149l, + 964607090671253533l, + 232964735789415443l, + 980665142167025862l, + + 469480217825462263l, + 899326816885015702l, + 875906247414770612l, + 419271813568148348l, + 955628780979616049l, + 964851394856633044l, + 920402918873167315l, + 44542537047619878l, + 287326444325502099l, + 794814281028802127l, + + 859177155807759723l, + 620591375117177024l, + 589187555016189839l, + 791188474180923574l, + 73454149626876152l, + 142674074411581083l, + 585073587365940420l, + 797609949662655103l, + 175124149742874202l, + 62869744120989896l, + + 551110293305242845l, + 127931539523886339l, + 920703134552677363l, + 732981382349612211l, + 62732588721496394l, + 44561050006996382l, + 119194178707933536l, + 978123130429376315l, + 862942328036352295l, + 57296861210520041l, + + 182897743270630415l, + 13207875902886200l, + 552533674022145482l, + 488462941904442l, + 863787304545250572l, + 413189539957215648l, + 229359591670445984l, + 804030022526807608l, + 596524207037097032l, + 934443234016356922l, + + 76899063002059964l, + 658148485712861578l, + 598631015449229747l, + 393367604407414191l, + 926192250542061452l, + 674530714803093099l, + 35980063030147176l, + 30954039774891937l, + 833583092170077764l, + 587471530888374861l, + + 910416218581766388l, + 89142545784819968l, + 151420602460129151l, + 271087393304205269l, + 290597398727472261l, + 27766748062900907l, + 446097133117871237l, + 191672387717785454l, + 797842155411794101l, + 69321366131136411l, + + 196344047914946886l, + 226534298261372486l, + 490733667486015817l, + 773800494736883628l, + 780878109429919665l, + 515093295699804077l, + 357085444986459223l, + 851849805620623387l, + 867722507013561571l, + 358088420691515641l, + + 924912656888885760l, + 791137295807713442l, + 692109859097581060l, + 595235990482238397l, + 909911716524758764l, + 724164923777388510l, + 586273377500475847l, + 686482600666828362l, + 122259762435890876l, + 566175710915777957l, + + 824013986198676042l, + 245061253612931712l, + 167220601921039098l, + 434074374001348226l, + 668858174281724461l, + 453804170192441776l, + 859959205173779472l, + 853636563417799200l, + 479051589857657035l, + 557683456529024680l, + + 296261642099843803l, + 165139612823205352l, + 155787048574294110l, + 143595911615173500l, + 673657014621949249l, + 906076400428015241l, + 513670209912993763l, + 967088312580862643l, + 7774131720357429l, + 630028985223713495l, + + 25673252210732419l, + 144773850559041528l, + 439733456225171722l, + 858180869123858142l, + 211394276775897243l, + 408958963895371321l, + 423472822369839857l, + 232250260713347003l, + 180706716595929038l, + 98596496887866469l, + + 875678307360992371l, + 437677508049887441l, + 125170452011422203l, + 538873642230562466l, + 245197558852455185l, + 932439585603976220l, + 855639307352288859l, + 954348029862438234l, + 414712671173750006l, + 115793895418238465l, + + 729484834132583888l, + 640350420376446233l, + 818925474623589460l, + 364705040323764220l, + 967195943649962411l, + 303126878372263790l, + 360410707087981191l, + 387292627370779711l, + 700601266013880678l, + 356883926601879126l, + + 22583787254966927l, + 986671573053499222l, + 998723929588817991l, + 771416126519180332l, + 474486512646652781l, + 478980122430145054l, + 207722595782621257l, + 79453748112027572l, + 527397308782140854l, + 585044216263462538l, + + 125397053030499187l, + 366348072275664491l, + 77735524260232115l, + 495683911214898558l, + 589156015838720909l, + 467920113868761777l, + 162071785283760169l, + 231818370419047340l, + 64307278747146290l, + 47784451860387975l, + + 980055089222892624l, + 764895420560925155l, + 507748042124615833l, + 187837301351429921l, + 161726553994583475l, + 151422489191956904l, + 995805250100891082l, + 805765551492075924l, + 779377962936816736l, + 714449863347865272l, + + 204015610543644036l, + 800804416286176830l, + 646873902118250214l, + 940547022409709067l, + 355335675726436202l, + 326830247048130605l, + 343704151019838190l, + 656205611304404762l, + 877236490577055500l, + 446537683901693422l, + + 451209390817813316l, + 11157320132649709l, + 140467946119304817l, + 625342666087475024l, + 342673456876050403l, + 315569879245239626l, + 207968007467613588l, + 977052991039833138l, + 277741169924035053l, + 469100868042333879l, + + 210908198788613658l, + 854488919399758838l, + 3288187261221639l, + 494117930374517280l, + 731270158063398126l, + 848080613499701383l, + 358143826050226673l, + 485357819668739357l, + 994980436445591452l, + 76293103128952918l, + + 778136068861694776l, + 670025736323147161l, + 352721274969489950l, + 485187894208110493l, + 702706773816545161l, + 44707306458740608l, + 944417111189439331l, + 894057190523044627l, + 30682149482009118l, + 76878633081476039l, + + 553790321773052068l, + 314230667439537839l, + 177236046084452338l, + 122014325466816562l, + 161909702213081218l, + 591811608817332520l, + 217450796035684001l, + 735138186156364486l, + 681433260907839992l, + 418486890410244753l, + + 680797495071076289l, + 747074640063267196l, + 970128954640424935l, + 749293492114586858l, + 11728511685421992l, + 262723921643718347l, + 52511438356285514l, + 906980307982728909l, + 714879316279668660l, + 221738484375496833l, + + 623442200780086407l, + 251366198355718391l, + 369497919802436634l, + 20566205275807771l, + 122283743988898264l, + 815446371346272803l, + 316726822909350586l, + 790134832122644904l, + 501226775853693784l, + 1337249705074813l, + + 453262610930759038l, + 646409148301283422l, + 115579604842016905l, + 33123012565546311l, + 978401269339561507l, + 44559377343909176l, + 19514897145295274l, + 147732651075503554l, + 62477757530514553l, + 260280421539621771l, + + 324238700214102842l, + 647134533413426639l, + 667861750635862171l, + 420689767461447978l, + 772352145109448446l, + 796179608438897262l, + 775193349127889400l, + 941347947779866031l, + 584282451615184212l, + 941377827111057142l, + + 96189303582019295l, + 116554265264888383l, + 64574525242522589l, + 107193428552434739l, + 245510251765329105l, + 166731170493188357l, + 809949044924133275l, + 758446436914795159l, + 703043770138182890l, + 954111788081599515l, + + 136859390487133799l, + 229398128019805757l, + 651047768724581987l, + 623470636016241482l, + 442548529015475022l, + 728985363468126656l, + 601534825724343989l, + 598462429001189524l, + 14767637168520017l, + 110164501031113217l, + + 2267313487106505l, + 602846630066870040l, + 942742593948916153l, + 257204231220552883l, + 41928825432205789l, + 776312071726565063l, + 684333501541382594l, + 63285132045891152l, + 522617064506888728l, + 399087258085430322l, + + 369335162042873576l, + 957670343495191416l, + 894002800673663108l, + 741978997518334019l, + 128424383495722946l, + 57080626670556024l, + 485987359155298593l, + 720571698380414156l, + 316090628021588845l, + 721320013932672383l, + + 616724893214386955l, + 107069018902912492l, + 335684669220671881l, + 439953298090264365l, + 668766344826342757l, + 574744557050893533l, + 837492715859226581l, + 939289420759255103l, + 98903495101419241l, + 441715606911262548l, + + 711796137250653774l, + 934294998305577754l, + 197739857572958523l, + 961031575986889814l, + 330389633371653429l, + 199423454318381389l, + 992806915531521002l, + 752430128263180102l, + 762067171884748509l, + 868397567289449078l, + + 978131695000691716l, + 832128538091881692l, + 332557797779603829l, + 394456793413733508l, + 180261204826305843l, + 376912355571214015l, + 699324587358673569l, + 23664544583454006l, + 327974511279267901l, + 120073261092787575l, + + 563426405452397018l, + 539285614539978334l, + 785159842287844887l, + 835395581519794346l, + 304538904528755810l, + 355722924067394933l, + 872021767601702295l, + 567818208391267105l, + 58356714335016452l, + 189908048834163l, + + 343501795801836652l, + 488363327236059203l, + 740530667847012558l, + 242398605490351338l, + 662829190349084673l, + 387176771976134318l, + 535572586279439811l, + 226785219604563426l, + 883971137296029526l, + 463867511805352267l, + + 225406583424538674l, + 767143254638275960l, + 627578036627621188l, + 25194585179292536l, + 159276033783105316l, + 533166587231767915l, + 195503830999903877l, + 143548530694574858l, + 586403308472695038l, + 251461295483424073l, + + 778235211474807028l, + 974511127821538962l, + 234351427339669293l, + 674903609403754570l, + 269821646330066486l, + 10514582197647671l, + 310058695603171887l, + 692680666938759459l, + 219702762257174799l, + 394327857010791187l, + + 104120696002956785l, + 932035253132951222l, + 705303760596228724l, + 168109021472592056l, + 908473434800454594l, + 633342640675753663l, + 196262077066269791l, + 130870864471689386l, + 269052619107011939l, + 945989485807845083l, + + 167108829297904344l, + 512431642627242657l, + 53724341864043852l, + 558641630923859339l, + 556959743803390749l, + 631425063603427402l, + 259979605773105171l, + 429845634788551705l, + 244769122315885960l, + 68536687575157864l, + + 688477984888810823l, + 733667124080264275l, + 881307008976788145l, + 85557557143709570l, + 547241936295049024l, + 608170667337476859l, + 58957920476606510l, + 966060963172955950l, + 867800335117402924l, + 67375619265528809l, + + 190969923528632347l, + 425149549991394157l, + 538334572515114711l, + 708307525017999452l, + 25983085084983815l, + 672261026943582858l, + 219667292242148547l, + 121957383179923845l, + 77600241275319820l, + 216862167739468905l, + + 606810218542445629l, + 943507623528873810l, + 969116817300440475l, + 12294116326297464l, + 6701016055162488l, + 624148164468923139l, + 78300069444424190l, + 19339949012001435l, + 165626331279732152l, + 535298529150864448l, + + 342297987067286266l, + 76712730862205265l, + 677273670705782858l, + 365940154344684371l, + 869554945670002296l, + 143520586808279523l, + 50570344277958922l, + 516182849234970511l, + 841581438239588733l, + 411495218013677191l, + + 672042442089442583l, + 388189082933141721l, + 532413363660096075l, + 245694872166351121l, + 173457735056327844l, + 55738952212441330l, + 685288240200814731l, + 473032558397903901l, + 943476816171477314l, + 672789553202097285l, + + 805925063742429491l, + 124678068431134300l, + 13921407309531118l, + 830591085998177448l, + 677885221100759302l, + 11585222315953622l, + 394914761078378599l, + 909884684182383685l, + 563688113563876970l, + 42694141238573193l, + + 419578667557172439l, + 147566640180796541l, + 346803738847761056l, + 378264395597132729l, + 930271350665310527l, + 437581192162885448l, + 299930128325228815l, + 240538700114345918l, + 259199844081041850l, + 874083841019950255l, + + 72260965305822261l, + 368038336038653535l, + 714122594498963544l, + 967513072020571246l, + 484984100291969771l, + 9452592082712525l, + 131894126687948613l, + 816971684689577237l, + 719491956090110547l, + 184818342461202456l, + + 789755232122159266l, + 8086343656007639l, + 26699760340096952l, + 781284894742592836l, + 25114915695064791l, + 685759569040742267l, + 226989427089149728l, + 520659265356096853l, + 526051806884389203l, + 781488870876163849l, + + 645865087449340773l, + 809989057949122731l, + 991235493762324907l, + 404707747203463395l, + 217109962102321421l, + 925147721894965627l, + 245797411148608332l, + 37234179444654375l, + 949620603085483027l, + 461465260728668501l, + + 188139378599779749l, + 943884429997790515l, + 554924935592323568l, + 155486103337003356l, + 98429650840068725l, + 744643263103143420l, + 217347355647296224l, + 34408212331573531l, + 987662457879222179l, + 557453354831676008l, + + 552194949301514231l, + 498679200317988091l, + 96173410445840903l, + 470259390124137059l, + 918846869428290795l, + 527541280515626944l, + 60266896027091098l, + 803321185229952136l, + 673869040626721885l, + 938647849874098059l, + + 230922827820056946l, + 112461300772429907l, + 879634712004775205l, + 598816372145594026l, + 24781318238269431l, + 799861815797916440l, + 549153933444765585l, + 877992147843679864l, + 651571788003265307l, + 442367527434582550l, + + 178372288197305720l, + 826839327598528358l, + 98774413195253460l, + 816432291769633027l, + 647962124566255034l, + 559374089603489176l, + 544605736920583258l, + 817024743564487677l, + 529396216145379263l, + 967712267561680183l, + + 504376644759607435l, + 446026341255411979l, + 695828899771876248l, + 835953376807091163l, + 26855908735118584l, + 238447183576881932l, + 993827408015672199l, + 833930996349911951l, + 173076358439417285l, + 657629865761042316l, + + 895867636891618365l, + 168944231763094742l, + 781190513685739063l, + 623214154683127617l, + 70075004308400680l, + 18443229148102777l, + 116932247227716414l, + 256057517353843325l, + 968929032552610408l, + 207014180855464275l, + + 816936789295741802l, + 882995528260035433l, + 926023904722708169l, + 412566385816249322l, + 525718689734642016l, + 46920823614039094l, + 721803959992601933l, + 898168692225347300l, + 934485935477344407l, + 575677109964718533l, + + 831409923501333949l, + 227533115045760681l, + 290666692630857576l, + 738134833093141619l, + 490488525842458863l, + 746816333196754644l, + 566021160371491180l, + 708616607887178478l, + 128659096747965617l, + 970839065344320588l, + + 566062071670423991l, + 584278724241763662l, + 32552672364919489l, + 37866008535922086l, + 472450513414112684l, + 696409119018293313l, + 115075911937425774l, + 424621772752312046l, + 511569662923999567l, + 92880606000027127l, + + 670098169072435269l, + 558056450072881022l, + 933378835959842396l, + 976604733923728806l, + 130322919640592354l, + 580712134609707403l, + 709037719269642214l, + 662262438038865940l, + 470453514500829867l, + 207366963580530330l, + + 793214185522905948l, + 51852989050826915l, + 808587861629563903l, + 432136681955100363l, + 186653579520578302l, + 282860108445159829l, + 445767399365275146l, + 907762598905806393l, + 193073464810090860l, + 360915499408439905l, + + 437807875937094684l, + 342704281471250858l, + 772853776000997108l, + 910808026239666144l, + 750773510093713546l, + 294650426417174248l, + 239395454575084931l, + 988245372995882576l, + 116788160781815856l, + 260427803867176874l, + + 160765275244852731l, + 457421767272628860l, + 954387940750518382l, + 663009953334137662l, + 635210353908427372l, + 202191859706540593l, + 730592613929605495l, + 560114800359292146l, + 118680166891048312l, + 37945444124052740l, + + 82561837702781039l, + 670968171275271971l, + 249762040649479013l, + 426742960251642201l, + 140131797903050209l, + 185585888977431133l, + 802883946492614673l, + 375966331892328518l, + 678515968858488398l, + 980554004646091626l, + + 271282266915421027l, + 713566381108325971l, + 195484642496969703l, + 937837809451789980l, + 116587593283362818l, + 12326068884729358l, + 311248065455402864l, + 268537300065713148l, + 830395257050669915l, + 517717524945941475l, + + 594706781477047517l, + 683514718104875033l, + 71811944144373759l, + 549184158793550316l, + 743962980344436770l, + 342815229646475244l, + 91820024504045781l, + 942183429383424182l, + 634567154658953208l, + 880813552161194772l, + + 937450136245659108l, + 359216376088709535l, + 86868034556739793l, + 278428450887175865l, + 548644880526995838l, + 468965562244484588l, + 853471036651405927l, + 8707407169342708l, + 749597355229463749l, + 824330701508242834l, + + 333814657130019606l, + 979058204952438795l, + 462673809227471775l, + 536914299306206417l, + 971285548245198442l, + 784544499996793098l, + 121899926051377836l, + 500200468001370135l, + 863713040769516555l, + 149374448127027320l, + + 195968112763074517l, + 875555620594003339l, + 87922904524696016l, + 6167146666167473l, + 750019279660004038l, + 793059668144961967l, + 313591420157104300l, + 291353638706672805l, + 34005427496032037l, + 404306311566585712l, + + 982104925320434595l, + 621802565491163415l, + 380546341802334942l, + 282624560308059338l, + 332765931735475715l, + 54875760860716960l, + 184820261436826411l, + 298338878388543994l, + 74076826076886381l, + 49573770474794851l, + + 973395222473939314l, + 64651430740271251l, + 929010958483401561l, + 37911712122731241l, + 632987115622895492l, + 782598739454753832l, + 64661505976924920l, + 789897433985290804l, + 27464097941226613l, + 123510101443062121l, + + 33498761022578628l, + 468710335459633953l, + 438430699110659170l, + 850870972391715098l, + 339812322380229534l, + 523007559257421888l, + 263416253899555937l, + 132523463308547710l, + 24838429221983195l, + 300869548000262289l, + + 343418926622874467l, + 30181716442445862l, + 529364455337554114l, + 292068669069465220l, + 64769173797843942l, + 249469622904871477l, + 234469028566604888l, + 735530319785919659l, + 917242500339529288l, + 616037710995254445l, + + 749129146363729104l, + 778125197706617057l, + 508374702704627684l, + 72638011840510682l, + 484654969086851340l, + 950681819081366290l, + 405552770893024111l, + 120788073807664024l, + 240225181610043759l, + 756173519263400684l, + + 13886814190793329l, + 431811651361404368l, + 785644429323050469l, + 265083669668502313l, + 733468396640565119l, + 372535991695630142l, + 24818311402075021l, + 521896835131504122l, + 392125133711207535l, + 193359056782367881l, + + 56285603302444520l, + 226057805358921359l, + 643195421142563932l, + 104039098798909983l, + 626861113096363266l, + 84979886179949074l, + 486561880501439802l, + 619593458713206099l, + 225357170894458053l, + 35456814333125993l, + + 721058429053269174l, + 307576443080026683l, + 476143167247863238l, + 659345640009293086l, + 985001803816353351l, + 38729588081549534l, + 813458085650668800l, + 570847499633521267l, + 660108714578144950l, + 661225024935217344l, + + 42748541343135302l, + 542409368779631480l, + 528124190371792375l, + 713468453464772935l, + 484088995075370541l, + 981866214702501659l, + 666616968432354481l, + 915366435818397300l, + 874789585783968537l, + 370682054020070752l, + + 62400492067982047l, + 499850828608660586l, + 937308826652753434l, + 128558027742649386l, + 515758774554168845l, + 418916546792152877l, + 117458158181369773l, + 49562168386073568l, + 807699418958763493l, + 742145797937476656l, + + 658882936116031548l, + 204462546453824419l, + 902445336976128875l, + 92692847289431172l, + 704173225059386342l, + 66639290013818113l, + 410809876283803885l, + 35952706968093473l, + 759178465001909493l, + 704067752087811350l, + + 986846122776679407l, + 688733536926677107l, + 856981725890032261l, + 988531073663474807l, + 713944308475162539l, + 118847362753841156l, + 732154169724665416l, + 19005988695596513l, + 832967922377006760l, + 973672108375451327l, + + 725363671507632935l, + 718391433167648827l, + 352442795126799491l, + 784366612685799127l, + 903475113629207005l, + 687344358628029044l, + 931153086939207082l, + 104622912997824952l, + 82734710816696367l, + 442945641213286735l, + + 466668555176155455l, + 323463885452719651l, + 188346511024345667l, + 766367939017272210l, + 965557189722432799l, + 230021363393593477l, + 929823950768692802l, + 252119831032411121l, + 8663957261501470l, + 113678441668172265l, + + 346067535048822494l, + 611852318957245790l, + 143506956345691962l, + 298077130751139726l, + 30362893522113816l, + 584809401672606297l, + 970507405565942077l, + 651371758660525390l, + 621096534538655650l, + 913256556326717871l, + + 648137154880192988l, + 225633300626096742l, + 566328830294529543l, + 224653110464048130l, + 934793514428492485l, + 368669206081879487l, + 492047566736472873l, + 55677597207791273l, + 511090860495737174l, + 805179231181087093l, + + 579465450607118895l, + 943178320920110013l, + 444370234898293122l, + 85402155273287473l, + 362296626894728546l, + 904433285064260477l, + 190330319436502780l, + 59222297912696625l, + 408990860335567709l, + 589474956992376535l, + + 612081053822594602l, + 273841370377697349l, + 272219993018871562l, + 790440816539391295l, + 181577768978858005l, + 239045710732833793l, + 427305914448398239l, + 810713867022076074l, + 422004697986874870l, + 61779602162057360l, + + 980850466579786024l, + 897408269714821783l, + 619814398120106912l, + 210645472288950922l, + 588031623554562447l, + 577816781653286458l, + 597096829305673645l, + 303263549224049320l, + 156355604966014545l, + 999940201019640042l, + + 545864139992129854l, + 349017325128116083l, + 312747275210422873l, + 769921140030237021l, + 583681481462832740l, + 876665826353151013l, + 958730437530779530l, + 388741443686872468l, + 549591630978958697l, + 443407922528477935l, + + 82305770875576464l, + 302021456870308996l, + 116477878113900295l, + 856679918251291335l, + 974226342944969019l, + 694139457609844063l, + 726774949030800224l, + 86877842882273743l, + 23661131870341092l, + 519961257582540181l, + + 124870722812351703l, + 297797906052041293l, + 529300884305730318l, + 743823006938836829l, + 693356820954784852l, + 70200457779735722l, + 557950436116202181l, + 178048064580575228l, + 745694808225018793l, + 505492689124300290l, + + 40688677867063716l, + 906029319339783317l, + 723220762979849441l, + 800464128881487142l, + 16347017065781833l, + 569886286729488306l, + 325425109670718805l, + 799442369608504858l, + 517422685398994930l, + 483902362458877314l, + + 343944156351081038l, + 263401490344217325l, + 891805550054649417l, + 549964066230638103l, + 114442932252102499l, + 640299083036361103l, + 341716062024968086l, + 680156879554562369l, + 33197732406536887l, + 662573057092916456l, + + 23166250889366276l, + 439588424130385671l, + 976147149098943410l, + 966634459881083697l, + 955059511573997874l, + 602113383584625957l, + 873746183951302433l, + 106714649853262351l, + 266085001547779077l, + 602087418558089717l, + + 771162091195456127l, + 998022611394638150l, + 578861073290344770l, + 13953259172769202l, + 263059390252436849l, + 713849611657917124l, + 278753817441368442l, + 209565289634712522l, + 86628925891496630l, + 498675700983612899l, + + 352975355046283550l, + 807496683264729873l, + 757414973431593798l, + 624901866090760637l, + 431198654617222493l, + 223908778956608211l, + 992095795763587040l, + 371430120032038210l, + 895172486004081377l, + 512169660024349480l, + + 767660901924081084l, + 7567310010434317l, + 493691704503907170l, + 651819017168740877l, + 419256610638853952l, + 476464930284074251l, + 250867234483595881l, + 96309592020475526l, + 167816615939027947l, + 964084605323017643l, + + 78696641868548689l, + 619677965603222936l, + 867538832840647115l, + 708534737809458263l, + 528951692596349161l, + 410702275077305522l, + 98861683128847623l, + 685470552066531037l, + 102158622587431874l, + 892742832708342987l, + + 276250292240003760l, + 239000555803703746l, + 41085552660210325l, + 104036952726091280l, + 35294919829298821l, + 642288598713607316l, + 655668230261877292l, + 256750121560967030l, + 51978151194127888l, + 168586225957102212l, + + 721423574237200365l, + 591127759846196563l, + 160139061303914939l, + 85049184808387624l, + 448955483195415375l, + 828466296971252038l, + 16440113349605274l, + 287422461146256705l, + 695577615454841932l + }; +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGeneratorTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGeneratorTest.java new file mode 100644 index 0000000..e2544c8 --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/CPlusPlus11LinearCongruentGeneratorTest.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent; + +import org.nanoboot.powerframework.core.exceptions.UnsupportedMethodException; +import org.junit.Before; +import org.junit.Test; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CPlusPlus11LinearCongruentGeneratorTest { + /** + * initial seed. + */ + private static final long INITIAL_SEED = 100000; + + private CPlusPlus11LinearCongruentGenerator g; + @Before + public void setup() { + g = new CPlusPlus11LinearCongruentGenerator(INITIAL_SEED); + } + @Test(expected = UnsupportedMethodException.class) + public void current() { + g.current(); + } + + @Test(expected = UnsupportedMethodException.class) + public void initialSeed() { + g.initialSeed(); + } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGeneratorTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGeneratorTest.java new file mode 100644 index 0000000..f2f0d37 --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/LinearCongruentGeneratorTest.java @@ -0,0 +1,103 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent; + +import org.junit.Before; +import org.junit.Test; + +import java.util.stream.IntStream; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class LinearCongruentGeneratorTest { + + /** + * multiplier constant. + */ + private static final long MULTIPLIER = 16807; + + /** + * increment constant. + */ + private static final long INCREMENT = 0; + + /** + * modulus constant. + */ + private static final long MODULUS = 2147483647; + /** + * initial seed. + */ + private static final long INITIAL_SEED = 100000; + + private LinearCongruentGenerator g; + @Before + public void setup() { + g = new LinearCongruentGenerator(MULTIPLIER, INCREMENT, MODULUS, INITIAL_SEED); + } + @Test + public void next() { + assertEquals(((MULTIPLIER * INITIAL_SEED) + INCREMENT) % MODULUS, g.next()); + } + + @Test + public void current() { + g.next(); + assertEquals(((MULTIPLIER * INITIAL_SEED) + INCREMENT) % MODULUS, g.current()); + } + + @Test + public void initialSeed() { + IntStream.range(0, 100).forEach(i -> g.next()); + assertEquals(INITIAL_SEED, g.initialSeed()); + } + + @Test + public void getItself() { + assertEquals(g, g.getItself()); + } + + @Test + public void getName() { + assertEquals(g.getClass().getName(), g.getName()); + } + + @Test + public void getMultiplier() { + assertEquals(MULTIPLIER, g.getMultiplier()); + } + + @Test + public void getIncrement() { + assertEquals(INCREMENT, g.getIncrement()); + } + + @Test + public void getModulus() { + assertEquals(MODULUS, g.getModulus()); + } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImplTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImplTest.java new file mode 100644 index 0000000..793d8fb --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsFactoryImplTest.java @@ -0,0 +1,59 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; +import org.junit.Test; + +import static junit.framework.TestCase.assertEquals; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class W5GeneratorsFactoryImplTest { + + private W5GeneratorsFactoryImpl g; + + @Test(expected = RandomException.class) + public void constructor2() { + new W5GeneratorsFactoryImpl(null); + } + @Test(expected = RandomException.class) + public void constructor3() { + new W5GeneratorsFactoryImpl(new long[] {1,2,3,4,5,6,7}); + } + + @Test + public void getSubGenerators() { + W5GeneratorsFactoryImpl w5GeneratorsFactory = new W5GeneratorsFactoryImpl(new long[] {1l,2l,3l,4l,5l,6l,7l,8l}); + CPlusPlus11LinearCongruentGenerator[] array = w5GeneratorsFactory.getSubGenerators(); + StringBuilder sb = new StringBuilder(); + for(CPlusPlus11LinearCongruentGenerator e : array) { + sb.append(e.nextInt(0,9)).append(","); + sb.append(e.nextInt(0,9)).append(","); + sb.append(e.nextInt(0,9)).append(","); + } + assertEquals("4,8,3,0,3,1,0,0,7,", sb.toString()); + } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImplTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImplTest.java new file mode 100644 index 0000000..1757ee9 --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5GeneratorsProcessorImplTest.java @@ -0,0 +1,51 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.nanoboot.powerframework.random.RandomException; +import org.nanoboot.powerframework.random.generators.linearcongruent.CPlusPlus11LinearCongruentGenerator; +import org.junit.Before; +import org.junit.Test; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class W5GeneratorsProcessorImplTest { + + private W5GeneratorsProcessorImpl p; + @Before + public void setup() { + p = new W5GeneratorsProcessorImpl(); + } + @Test(expected = RandomException.class) + public void next() { + p.next(null); + } + @Test(expected = RandomException.class) + public void next2() { + p.next( + new CPlusPlus11LinearCongruentGenerator(20), + new CPlusPlus11LinearCongruentGenerator(30) + ); + } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGeneratorTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGeneratorTest.java new file mode 100644 index 0000000..cf85e4c --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/generators/linearcongruent/combined/w5/W5RandomGeneratorTest.java @@ -0,0 +1,59 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class W5RandomGeneratorTest { + + W5RandomGenerator g; + @Before + public void setup() { + g = new W5RandomGenerator(); + } + @Test + public void getStaticInstance() { + assertNotNull(W5RandomGenerator.getStaticInstance()); + } + + @Test + public void getItself() { + assertEquals(g, g.getItself()); + } + + @Test + public void getName() { + assertEquals(g.getClass().getName(), g.getName()); + } + + @Test + public void next() { + assertNotNull(g.next()); + } +} diff --git a/power-random/src/test/java/org/nanoboot/powerframework/random/internal/RandomTextUtilsTest.java b/power-random/src/test/java/org/nanoboot/powerframework/random/internal/RandomTextUtilsTest.java new file mode 100644 index 0000000..7096879 --- /dev/null +++ b/power-random/src/test/java/org/nanoboot/powerframework/random/internal/RandomTextUtilsTest.java @@ -0,0 +1,49 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.random.internal; + +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.nanoboot.powerframework.text.CharacterType; +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class RandomTextUtilsTest { + + @Test + public void nextChar() { + RandomGenerator rg = RandomGenerator.getDefaultImplStatic(); + char ch = RandomTextUtils.nextChar(rg, null); + assertTrue(Character.isDigit(ch) || Character.isUpperCase(ch) || Character.isLowerCase(ch)); + ch = RandomTextUtils.nextChar(rg, new CharacterType[] {}); + assertTrue(Character.isDigit(ch) || Character.isUpperCase(ch) || Character.isLowerCase(ch)); + ch = RandomTextUtils.nextChar(rg, CharacterType.LOWER_LETTER); + assertTrue(Character.isLowerCase(ch)); + ch = RandomTextUtils.nextChar(rg, CharacterType.LOWER_LETTER, CharacterType.NUMBER); + assertTrue(Character.isDigit(ch) || Character.isLowerCase(ch)); + + } +} diff --git a/power-redmond/pom.xml b/power-redmond/pom.xml new file mode 100644 index 0000000..b874caf --- /dev/null +++ b/power-redmond/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-redmond + jar + + Power Redmond + Redmond for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + diff --git a/power-redmond/src/main/java/module-info.java b/power-redmond/src/main/java/module-info.java new file mode 100644 index 0000000..f99825e --- /dev/null +++ b/power-redmond/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.template { + requires powerframework.core; + requires powerframework.log; + requires powerframework.utils; +} diff --git a/power-redmond/src/main/java/org/nanoboot/powerframework/redmond/.gitkeep b/power-redmond/src/main/java/org/nanoboot/powerframework/redmond/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-redmond/src/main/resources/.gitkeep b/power-redmond/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-redmond/src/test/java/org/nanoboot/powerframework/redmond/.gitkeep b/power-redmond/src/test/java/org/nanoboot/powerframework/redmond/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-reflection/pom.xml b/power-reflection/pom.xml new file mode 100644 index 0000000..70eceae --- /dev/null +++ b/power-reflection/pom.xml @@ -0,0 +1,57 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-reflection + jar + + Power Reflection + Reflection functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + + junit + junit + 4.12 + test + + + org.projectlombok + lombok + + + + diff --git a/power-reflection/src/main/java/module-info.java b/power-reflection/src/main/java/module-info.java new file mode 100644 index 0000000..77ace08 --- /dev/null +++ b/power-reflection/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.reflection { + requires lombok; + requires powerframework.core; + exports org.nanoboot.powerframework.reflection; +} diff --git a/power-reflection/src/main/java/org/nanoboot/powerframework/reflection/BeanMethod.java b/power-reflection/src/main/java/org/nanoboot/powerframework/reflection/BeanMethod.java new file mode 100644 index 0000000..e6a4f35 --- /dev/null +++ b/power-reflection/src/main/java/org/nanoboot/powerframework/reflection/BeanMethod.java @@ -0,0 +1,51 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.reflection; + +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum BeanMethod { + /** + * Getter - get prefix. + */ + GETTER("get"), + /** + * Setter - set prefix. + */ + + SETTER("set"); + + /** + * Bean method prefix. + */ + @Getter + private final String prefix; + + BeanMethod(final String prefixIn) { + this.prefix = prefixIn; + } +} diff --git a/power-reflection/src/main/java/org/nanoboot/powerframework/reflection/ReflectionUtils.java b/power-reflection/src/main/java/org/nanoboot/powerframework/reflection/ReflectionUtils.java new file mode 100644 index 0000000..88e116b --- /dev/null +++ b/power-reflection/src/main/java/org/nanoboot/powerframework/reflection/ReflectionUtils.java @@ -0,0 +1,211 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.reflection; + +import org.nanoboot.powerframework.core.PowerException; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class ReflectionUtils { + /** + * Constructor. + */ + private ReflectionUtils() { + //Not needed to be instantiated. + } + + /** + * @param classFullName class full name + * @return Class instance with the given name + * @throws PowerException, if there is found no such class + */ + public static Class getClassForName(final String classFullName) { + Class clazz = null; + try { + clazz = Class.forName(classFullName); + } catch (ClassNotFoundException e) { + throw new PowerException(e); + } + return clazz; + } + /** + * @param clazz Class instance + * @param parameterTypes parameter types + * + * @return Constructor instance with the given parameter types + * @throws PowerException, if there is found no such class + */ + public static Constructor getConstructor( + final Class clazz, final Class... parameterTypes) { + Constructor constructor; + try { + constructor = clazz.getConstructor(parameterTypes); + } catch (NoSuchMethodException e) { + StringBuilder sb = new StringBuilder(); + for (Class c :parameterTypes) { + sb.append(c.getName()); + sb.append(", "); + } + String msg = "Class " + clazz + + " has no constructor with parameters \"" + + sb.toString() + "\" " + e.toString(); + throw new PowerException(msg); + } + + return constructor; + } + + /** + * @param constructor constructor + * @param parameters parameters + * + * @return Object instance for the given constructor + * @throws PowerException, if instantiation failed + */ + public static Object newInstance( + final Constructor constructor, + final Object... parameters) { + Object o; + try { + o = constructor.newInstance(parameters); + } catch (InstantiationException + | IllegalAccessException | InvocationTargetException e) { + throw new PowerException(e); + } + return o; + + } + /** + * @param forClass class + * @param methodName method name + * @param parameterTypes parameter types + * + * @return Constructor instance with the given parameter types + * @throws PowerException, if there is found no such method + */ + public static Method getMethod( + final Class forClass, + final String methodName, + final Class... parameterTypes) { + Method method; + try { + method = forClass.getMethod(methodName, parameterTypes); + } catch (NoSuchMethodException e) { + throw new PowerException(e); + } + + return method; + } + + /** + * Invokes a method. + * @param method method + * @param o object + * @param args arguments + * @return Return object, if there is one + */ + public static Object invokeMethod( + final Method method, + final Object o, + final Object... args) { + try { + return method.invoke(o, args); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new PowerException(e); + } + + } + + /** + * @param beanName bean name + * @return getter name + */ + public static String getGetterMethodName(final String beanName) { + return getBeanMethodName(beanName, BeanMethod.GETTER); + } + /** + * @param beanName bean name + * @return setter name + */ + public static String getSetterMethodName(final String beanName) { + return getBeanMethodName(beanName, BeanMethod.SETTER); + } + + /** + * @param beanName bean name + * @param beanMethod bean method + * @return bean method name + */ + private static String getBeanMethodName( + final String beanName, + final BeanMethod beanMethod) { + return beanMethod.getPrefix() + + makeFirstLetterUpperCase(beanName); + } + + /** + * Makes the first letter upper case. + * @param string input string + * @return modified string + */ + private static String makeFirstLetterUpperCase(final String string) { + return string.substring(0, 1) + .toUpperCase() + string.substring(1, string.length()); + } + + /** + * Invoke setter of a object for a bean. + * + * @param object object + * @param beanName bean name + * @param bean bean + */ + public static void setBean( + final Object object, final String beanName, final Object bean) { + Method method = getMethod( + object.getClass(), + getSetterMethodName(beanName), + bean.getClass()); + invokeMethod(method, object, bean); + } + /** + * Invoke getter of a object for a bean. + * + * @param object object + * @param beanName bean name + * @return bean + */ + public static Object getBean( + final Object object, + final String beanName) { + Method method = getMethod( + object.getClass(), getGetterMethodName(beanName)); + return invokeMethod(method, object); + } +} diff --git a/power-reflection/src/main/resources/.gitkeep b/power-reflection/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-reflection/src/test/java/org/nanoboot/powerframework/reflection/ReflectionUtilsTest.java b/power-reflection/src/test/java/org/nanoboot/powerframework/reflection/ReflectionUtilsTest.java new file mode 100644 index 0000000..fff5b72 --- /dev/null +++ b/power-reflection/src/test/java/org/nanoboot/powerframework/reflection/ReflectionUtilsTest.java @@ -0,0 +1,131 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.reflection; + +import org.nanoboot.powerframework.core.PowerException; +import org.junit.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import static org.junit.Assert.assertEquals; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ReflectionUtilsTest { + + @Test(expected = PowerException.class) + public void getClassForName() { + //prepare + //execute + ReflectionUtils.getClassForName("abc.Def"); + //verify + } + + @Test(expected = PowerException.class) + public void getConstructor() { + //prepare + //execute + ReflectionUtils.getConstructor(Integer.class, Boolean.class); + //verify + } + + @Test(expected = PowerException.class) + public void newInstance() { + //prepare + + //execute + Constructor constructor; + try { + constructor = TestClassWithBadConstructorAndMethods.class.getConstructor(); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + ReflectionUtils.newInstance(constructor); + //verify + } + + @Test(expected = PowerException.class) + public void getMethod() { + //prepare + //execute + ReflectionUtils.getMethod(Integer.class, "abc"); + //assert + } + + @Test(expected = PowerException.class) + public void invokeMethod() { + //prepare + TestClassWithBadConstructorAndMethods testClassWithBadConstructorAndMethods = + new TestClassWithBadConstructorAndMethods(true); + //execute + Method method = ReflectionUtils.getMethod( + TestClassWithBadConstructorAndMethods.class, + "throwIllegalAccessException"); + ReflectionUtils.invokeMethod(method, testClassWithBadConstructorAndMethods); + //assert + } + + @Test + public void getGetterMethodName() { + //prepare + //execute + //assert + assertEquals("getMyName", ReflectionUtils.getGetterMethodName("myName")); + } + + @Test + public void getSetterMethodName() { + //prepare + //execute + //assert + assertEquals("setMyName", ReflectionUtils.getSetterMethodName("myName")); + } + + @Test + public void setBean() { + //prepare + TestClassWithBadConstructorAndMethods testClassWithBadConstructorAndMethods = + new TestClassWithBadConstructorAndMethods(true); + //execute + //assert + ReflectionUtils. + setBean(testClassWithBadConstructorAndMethods, "name", "testName"); + String returned = testClassWithBadConstructorAndMethods.getName(); + assertEquals("testName", returned); + } + + @Test + public void getBean() { + //prepare + TestClassWithBadConstructorAndMethods testClassWithBadConstructorAndMethods = + new TestClassWithBadConstructorAndMethods(true); + testClassWithBadConstructorAndMethods.setName("testName"); + //execute + //assert + Object returned = ReflectionUtils. + getBean(testClassWithBadConstructorAndMethods, "name"); + assertEquals("testName",returned); + } +} diff --git a/power-reflection/src/test/java/org/nanoboot/powerframework/reflection/TestClassWithBadConstructorAndMethods.java b/power-reflection/src/test/java/org/nanoboot/powerframework/reflection/TestClassWithBadConstructorAndMethods.java new file mode 100644 index 0000000..d7d8deb --- /dev/null +++ b/power-reflection/src/test/java/org/nanoboot/powerframework/reflection/TestClassWithBadConstructorAndMethods.java @@ -0,0 +1,46 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.reflection; + +import lombok.Getter; +import lombok.Setter; + +/** + * Testing class with bad constructor throwing a RuntimeException. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TestClassWithBadConstructorAndMethods { + @Getter + @Setter + private String name; + + public TestClassWithBadConstructorAndMethods() { + throw new RuntimeException("test exception"); + } + //OK constructor + public TestClassWithBadConstructorAndMethods(boolean booleanForOkConstructor) { + } + public void throwIllegalAccessException() throws IllegalAccessException { + throw new IllegalAccessException("test IllegalAccessException"); + } +} diff --git a/power-security/pom.xml b/power-security/pom.xml new file mode 100644 index 0000000..2c0901c --- /dev/null +++ b/power-security/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-security + jar + + Power Security + security + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + + + org.projectlombok + lombok + + + diff --git a/power-security/src/main/java/module-info.java b/power-security/src/main/java/module-info.java new file mode 100644 index 0000000..50f96f8 --- /dev/null +++ b/power-security/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.security { + exports org.nanoboot.powerframework.security.hash.api; + exports org.nanoboot.powerframework.security.hash.locator; + requires lombok; + requires powerframework.core; +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/SecurityException.java b/power-security/src/main/java/org/nanoboot/powerframework/security/SecurityException.java new file mode 100644 index 0000000..1fb2d89 --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/SecurityException.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security; + +import org.nanoboot.powerframework.core.PowerException; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SecurityException extends PowerException { + public SecurityException(String msg) { + super(msg); + } +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/hash/api/HashCalculator.java b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/api/HashCalculator.java new file mode 100644 index 0000000..0d38fb8 --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/api/HashCalculator.java @@ -0,0 +1,114 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security.hash.api; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface HashCalculator { + String UTF_8 = "UTF-8"; + + String hash(byte[] dataToHash); + + default String hash(String dataToHash) { + byte[] byteArray = new byte[0]; + try { + byteArray = dataToHash.getBytes(UTF_8); + } catch (UnsupportedEncodingException e) { + throw new SecurityException(e.getMessage()); + } + return hash(byteArray); + } + + String getName(); + int getLength(); + + default String convertHexStringToDecString(String hex) { + return new BigInteger(hex, 16).toString(); + } + + default String convertDecStringToHexString(String dec) { + String str = convertDecStringToBigInteger(dec).toString(16); + ; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < (getLength() - str.length()); i++) { + sb.append("0"); + } + sb.append(str); + return sb.toString(); + } + + default BigInteger convertDecStringToBigInteger(String dec) { + return new BigInteger(dec, 10); + } + + default String convertBigIntegerToDecString(BigInteger bi) { + return bi.toString(10); + } + + /** + * @param hex1 + * @param hex2 + * @return if 0, then hex1=hex2. if -1, then hex1hex2. + */ + default int compareHexNumbers(String hex1, String hex2) { + int result = hex1.compareTo(hex2); + if (result == 0) { + return 0; + } + if (result < 0) { + return -1; + } else { + return 1; + } + } + + public static void main(String[] args) { + System.out.println("convertHexToDec(F)=" + new BigInteger("F", 16).toString()); + System.out.println("convertDecToHex(15)=" + new BigInteger("15", 10).toString(16)); + HashCalculator hc = new HashCalculator() { + @Override + public String hash(byte[] dataToHash) { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public int getLength() { + return 0; + } + }; + System.out.println("compareHexNumbers(c,c)=" + hc.compareHexNumbers("c", "c")); + System.out.println("compareHexNumbers(c,e)=" + hc.compareHexNumbers("c", "e")); + System.out.println("compareHexNumbers(e,c)=" + hc.compareHexNumbers("e", "c")); + } +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/AbstractShaHashCalculator.java b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/AbstractShaHashCalculator.java new file mode 100644 index 0000000..f3e7f49 --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/AbstractShaHashCalculator.java @@ -0,0 +1,59 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security.hash.impl; + +import org.nanoboot.powerframework.security.hash.api.HashCalculator; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public abstract class AbstractShaHashCalculator implements HashCalculator { + + @Override + public String hash(byte[] dataToHash) { + MessageDigest digest = null; + byte[] bytes = null; + try { + digest = MessageDigest.getInstance(getName()); + digest.reset(); + bytes = digest.digest(dataToHash); + } catch (NoSuchAlgorithmException ex) { + throw new SecurityException(ex.getMessage()); + } + StringBuffer buffer = new StringBuffer(); + for (byte b : bytes) { + buffer.append(String.format("%02x", b)); + } +// if (Math.random() < 0.1) +// try { +// Thread.sleep(3); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + return buffer.toString(); + } +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha1HashCalculator.java b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha1HashCalculator.java new file mode 100644 index 0000000..1ecfa0a --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha1HashCalculator.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security.hash.impl; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class Sha1HashCalculator extends AbstractShaHashCalculator { + + public static final String SHA_1 = "SHA-1"; + + @Override + public String getName() { + return SHA_1; + } + + @Override + public int getLength() { + return 40; + } +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha256HashCalculator.java b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha256HashCalculator.java new file mode 100644 index 0000000..f202d4c --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/impl/Sha256HashCalculator.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security.hash.impl; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class Sha256HashCalculator extends AbstractShaHashCalculator { + + public static final String SHA_256 = "SHA-256"; + + @Override + public String getName() { + return SHA_256; + } + + @Override + public int getLength() { + return 64; + } +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashCalculatorLocator.java b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashCalculatorLocator.java new file mode 100644 index 0000000..f79b84c --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashCalculatorLocator.java @@ -0,0 +1,66 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security.hash.locator; + +import org.nanoboot.powerframework.security.hash.api.HashCalculator; +import org.nanoboot.powerframework.security.hash.impl.Sha256HashCalculator; + +import java.util.HashMap; +import java.util.Map; +import org.nanoboot.powerframework.security.hash.impl.Sha1HashCalculator; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class HashCalculatorLocator { + + private static final Map map = new HashMap<>(); + + public static HashCalculator locate(String hashImplname) { + return locate(HashImpl.valueOf(hashImplname)); + } + + public static HashCalculator locate(HashImpl hashImpl) { + String name = hashImpl.getName(); + if (!map.containsKey(name)) { + switch (name) { + case "SHA-1": + map.put(name, new Sha1HashCalculator()); + break; + case "SHA-256": + map.put(name, new Sha256HashCalculator()); + break; + default: { + //nothing to do + } + } + } + HashCalculator hashCalculator = map.get(name); + if (hashCalculator == null) { + String msg = "HashCalculator with name " + name + " was not found."; + throw new SecurityException(msg); + } + return hashCalculator; + } +} diff --git a/power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashImpl.java b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashImpl.java new file mode 100644 index 0000000..3af0b2c --- /dev/null +++ b/power-security/src/main/java/org/nanoboot/powerframework/security/hash/locator/HashImpl.java @@ -0,0 +1,42 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.security.hash.locator; + +import lombok.Getter; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum HashImpl { + SHA_1("SHA-1"), + SHA_256("SHA-256"); + + HashImpl(String nameIn) { + this.name = nameIn; + } + @Getter + private final String name; + +} diff --git a/power-security/src/main/resources/.gitkeep b/power-security/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-security/src/test/java/org/nanoboot/powerframework/security/.gitkeep b/power-security/src/test/java/org/nanoboot/powerframework/security/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-shark/pom.xml b/power-shark/pom.xml new file mode 100644 index 0000000..4b7471b --- /dev/null +++ b/power-shark/pom.xml @@ -0,0 +1,52 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-shark + jar + + Power Shark + Shark programming language + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.projectlombok + ${lombok.version} + lombok + provided + + + + diff --git a/power-shark/src/main/java/module-info.java b/power-shark/src/main/java/module-info.java new file mode 100644 index 0000000..b2f639e --- /dev/null +++ b/power-shark/src/main/java/module-info.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +//TODO: collections should have methods returning this + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.shark { + requires powerframework.core; + requires lombok; +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/ByteCode.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/ByteCode.java new file mode 100644 index 0000000..c9152cc --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/ByteCode.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.compiler; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ByteCode { + + private final byte[] byteArray = new byte[1024]; +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/Compiler.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/Compiler.java new file mode 100644 index 0000000..effc11c --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/compiler/Compiler.java @@ -0,0 +1,42 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.compiler; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Compiler { + /* + * ByteCode byteCode = Compiler.compile("//some code"); + * + * MoleCode moleCode= new MoleCode(); + * + * Function functionMultiplyAndAddOne= new Function("multiplyAndAddOne", "num", new VariableDeclaration("arg1","num"), new VariableDeclaration("arg2","num")); + * functionMultiplyAndAddOne.addStatement(new Return(new IncrementByOne(new Multiply(arg1,arg2)))); + * moleCode.addStatement(functionMultiplyAndAddOne); + * mole.addFunctionCall("multiplyAndAddOne",4, 6); + * ByteCode byteCode2 = Compiler.compile(moleCode); + */ +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/MoleCode.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/MoleCode.java new file mode 100644 index 0000000..f960d4e --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/MoleCode.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class MoleCode { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/expressions/FunctionCall.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/expressions/FunctionCall.java new file mode 100644 index 0000000..8a901ef --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/expressions/FunctionCall.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.expressions; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class FunctionCall { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/keywords/KeyWords.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/keywords/KeyWords.java new file mode 100644 index 0000000..05c471a --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/keywords/KeyWords.java @@ -0,0 +1,169 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.keywords; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum KeyWords { + + /** + * + */ + IMPORT("import"), + + /** + * + */ + NUM("num"), + + /** + * + */ + BIGNUM("bignum"), + + /** + * + */ + DEC("dec"), + + /** + * + */ + BIGDEC("bigdec"), + + /** + * + */ + CHAR("char"), + + /** + * + */ + BOOL("bool"), + + /** + * + */ + FUN("fun"), + + /** + * + */ + ENDFUN("endfun"), + + /** + * + */ + STRUCT("struct"), + + /** + * + */ + ENDSTRUCT("endstruct"), + + /** + * + */ + FIN("fin"), + + /** + * + */ + IF("if"), + + /** + * + */ + THEN("then"), + + /** + * + */ + ELSE("else"), + + /** + * + */ + DO("do"), + + /** + * + */ + ENDDO("enddo"), + + /** + * + */ + SWITCH("switch"), + + /** + * + */ + CASE("case"), + + /** + * + */ + DEFAULT("default"), + + /** + * + */ + BREAK("break"), + + /** + * + */ + CONTINUE("continue"), + + /** + * + */ + GOTO("goto"), + + /** + * + */ + LABEL("label"), + + /** + * + */ + RETURN("return"); + private final String value; + + KeyWords(String value) { + this.value = value; + } + + /** + * + * @return + */ + public String getValue() { + return value; + } +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigDec.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigDec.java new file mode 100644 index 0000000..ba6399d --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigDec.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BigDec { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigNum.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigNum.java new file mode 100644 index 0000000..df9b966 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/BigNum.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class BigNum { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Bool.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Bool.java new file mode 100644 index 0000000..26441f6 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Bool.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Bool { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Char.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Char.java new file mode 100644 index 0000000..c120315 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Char.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Char { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Dec.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Dec.java new file mode 100644 index 0000000..952721e --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Dec.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Dec { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Num.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Num.java new file mode 100644 index 0000000..b2b29a9 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Num.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Num { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Str.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Str.java new file mode 100644 index 0000000..a83f3aa --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/literals/Str.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.literals; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Str { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Add.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Add.java new file mode 100644 index 0000000..66ffd7a --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Add.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Add { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/And.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/And.java new file mode 100644 index 0000000..5b63fef --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/And.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class And { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/DecrementByOne.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/DecrementByOne.java new file mode 100644 index 0000000..31f9d91 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/DecrementByOne.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DecrementByOne { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Divide.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Divide.java new file mode 100644 index 0000000..eec8e74 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Divide.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Divide { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/IncrementByOne.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/IncrementByOne.java new file mode 100644 index 0000000..d20cc9c --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/IncrementByOne.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class IncrementByOne { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Multiply.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Multiply.java new file mode 100644 index 0000000..9693cb1 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Multiply.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Multiply { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Not.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Not.java new file mode 100644 index 0000000..2385af8 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Not.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Not { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Or.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Or.java new file mode 100644 index 0000000..5ff3a01 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/operators/Or.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.operators; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Or { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Break.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Break.java new file mode 100644 index 0000000..ea689e3 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Break.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Break { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Continue.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Continue.java new file mode 100644 index 0000000..ffb22fa --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Continue.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Continue { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/DoBlock.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/DoBlock.java new file mode 100644 index 0000000..0123a3d --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/DoBlock.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DoBlock { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Function.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Function.java new file mode 100644 index 0000000..1f03fd1 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Function.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +import java.util.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Function { + + private String returnType; + private String name; + private ArrayList arguments = null; +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/IfBlock.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/IfBlock.java new file mode 100644 index 0000000..19d3975 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/IfBlock.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class IfBlock { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Import.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Import.java new file mode 100644 index 0000000..372e2b3 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Import.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Import { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Return.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Return.java new file mode 100644 index 0000000..62bd14d --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Return.java @@ -0,0 +1,30 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Return { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/StatementParser.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/StatementParser.java new file mode 100644 index 0000000..1f7d446 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/StatementParser.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class StatementParser { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Struct.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Struct.java new file mode 100644 index 0000000..635c057 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/Struct.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Struct { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/SwitchBlock.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/SwitchBlock.java new file mode 100644 index 0000000..9c505c5 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/SwitchBlock.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SwitchBlock { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableAssignment.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableAssignment.java new file mode 100644 index 0000000..758287c --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableAssignment.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class VariableAssignment { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableDeclaration.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableDeclaration.java new file mode 100644 index 0000000..5bc88f4 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/VariableDeclaration.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class VariableDeclaration { + + private String type; + private String name; +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/WhileBlock.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/WhileBlock.java new file mode 100644 index 0000000..eaa8167 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/statements/WhileBlock.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.statements; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class WhileBlock { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunction.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunction.java new file mode 100644 index 0000000..0aac312 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunction.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.syntax; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SharkFunction { + private String name; + + private String body; +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunctionArgument.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunctionArgument.java new file mode 100644 index 0000000..54e393c --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/language/syntax/SharkFunctionArgument.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.language.syntax; + +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Data +public class SharkFunctionArgument { + private String name; + private String type; +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/todo.txt b/power-shark/src/main/java/org/nanoboot/powerframework/shark/todo.txt new file mode 100644 index 0000000..db7fb2a --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/todo.txt @@ -0,0 +1 @@ + //num bignum dec bigdec bool str enum list map set queue stack diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/VirtualMachine.java b/power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/VirtualMachine.java new file mode 100644 index 0000000..959e004 --- /dev/null +++ b/power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/VirtualMachine.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.shark.virtualmachine; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class VirtualMachine { + +} diff --git a/power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/instructions/.gitkeep b/power-shark/src/main/java/org/nanoboot/powerframework/shark/virtualmachine/instructions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-shark/src/main/resources/.gitkeep b/power-shark/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-shark/src/test/java/org/nanoboot/powerframework/shark/.gitkeep b/power-shark/src/test/java/org/nanoboot/powerframework/shark/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-sound/pom.xml b/power-sound/pom.xml new file mode 100644 index 0000000..0820bda --- /dev/null +++ b/power-sound/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-sound + jar + + Power Sound + Sound for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + diff --git a/power-sound/src/main/java/module-info.java b/power-sound/src/main/java/module-info.java new file mode 100644 index 0000000..3b72ce0 --- /dev/null +++ b/power-sound/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + module powerframework.template { + requires powerframework.core; + requires powerframework.log; + requires powerframework.utils; +} diff --git a/power-sound/src/main/java/org/nanoboot/powerframework/sound/.gitkeep b/power-sound/src/main/java/org/nanoboot/powerframework/sound/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-sound/src/main/resources/.gitkeep b/power-sound/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-sound/src/test/java/org/nanoboot/powerframework/sound/.gitkeep b/power-sound/src/test/java/org/nanoboot/powerframework/sound/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-sql/pom.xml b/power-sql/pom.xml new file mode 100644 index 0000000..528c4f4 --- /dev/null +++ b/power-sql/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-sql + jar + + Power SQL + SQL functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-json + ${power.version} + + + + org.projectlombok + lombok + + + + + junit + junit + 4.12 + test + + + + diff --git a/power-sql/src/main/java/module-info.java b/power-sql/src/main/java/module-info.java new file mode 100644 index 0000000..d392fc6 --- /dev/null +++ b/power-sql/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.sql { + exports org.nanoboot.powerframework.sql.core; + exports org.nanoboot.powerframework.sql.filter; + requires lombok; + requires powerframework.json; +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/ColumnNameValue.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/ColumnNameValue.java new file mode 100644 index 0000000..de60c80 --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/ColumnNameValue.java @@ -0,0 +1,57 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.core; + +import lombok.Getter; +import lombok.Setter; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ColumnNameValue { + + /** + * Field description + */ + @Getter + @Setter + private String name; + /** + * Field description + */ + @Getter + @Setter + private String value; + + public ColumnNameValue(String nameIn, String valueIn) { + this.name = nameIn; + this.value = valueIn; + } + + + + public String toString() { + return name + '=' + value; + } +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderBy.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderBy.java new file mode 100644 index 0000000..8d84c6d --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderBy.java @@ -0,0 +1,57 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.core; + +import org.nanoboot.powerframework.json.JsonObject; +import lombok.Getter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class OrderBy { + @Getter + private final String property; + @Getter + private final OrderByType orderByType; + + public OrderBy(JsonObject jo) { + this.property = jo.getString("property"); + this.orderByType = OrderByType.valueOf(jo.getString("orderByType")); + } + + public OrderBy(String property, OrderByType orderByType) { + this.property = property; + this.orderByType = orderByType; + } + + public OrderBy(String property) { + this(property, OrderByType.DEFAULT); + } + + public JsonObject toJsonObject() { + JsonObject jo = new JsonObject(); + jo.addString("property", property); + jo.addString("orderByType", orderByType.name()); + return jo; + } +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderByType.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderByType.java new file mode 100644 index 0000000..82aca54 --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/OrderByType.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.core; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum OrderByType { + ASC, DESC; + public static final OrderByType DEFAULT=OrderByType.ASC; +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/SqlStatementCreator.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/SqlStatementCreator.java new file mode 100644 index 0000000..401af3f --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/core/SqlStatementCreator.java @@ -0,0 +1,130 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.core; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class SqlStatementCreator { + + /** + * Constant description + */ + private static final String SELECT_ALL_FROM = "SELECT * FROM "; + private static final String SELECT_UUID_FROM = "SELECT UUID FROM "; + private static final String INSERT_INTO_TEMPLATE = "INSERT INTO %s VALUES (%s);"; + private static final String UPDATE_TEMPLATE = "UPDATE %s SET "; + private static final String WHERE = "WHERE"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private SqlStatementCreator() { + } + + /** + * Setter for name. + * + * @param nameIn + */ + public static String createSelect(String tableName, String conditions) { + String sql = SELECT_ALL_FROM + tableName + (conditions != null ? (" WHERE " + conditions) : ""); + //System.out.println(sql); + return sql; + } + + /** + * Setter for name. + * + * @param nameIn + */ + public static String createSelectUuids(String tableName, String conditions) { + String sql = SELECT_UUID_FROM + tableName + (conditions != null ? (" WHERE " + conditions) : ""); + //System.out.println(sql); + return sql; + } + + /** + * Setter for name. + * + * @param nameIn + */ + public static String createInsert(String tableName, String... valuesIn) { + String valuesAsString; + StringBuilder stringBuilder = new StringBuilder(); + int valuesInMaxIndex = valuesIn.length - 1; + + for (int i = 0; i <= valuesInMaxIndex; i++) { + String e = valuesIn[i]; + stringBuilder.append(e); + if(i < valuesInMaxIndex) { + stringBuilder.append(',').append(' '); + } + + } + valuesAsString = stringBuilder.toString(); + String sql = String.format(INSERT_INTO_TEMPLATE, tableName, valuesAsString); + //System.out.println(sql); + return sql; + } + + /** + * Setter for name. + * + * @param nameIn + */ + public static String createUpdate(String tableName, String conditions, ColumnNameValue... columnNameValues) { + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(String.format(UPDATE_TEMPLATE, tableName)); + int columnNameValuesStringMaxIndex = columnNameValues.length - 1; + + for (int i = 0; i <= columnNameValuesStringMaxIndex; i++) { + String e = columnNameValues[i].toString(); + stringBuilder.append(e); + if(i < columnNameValuesStringMaxIndex) { + stringBuilder.append(',').append(' '); + } + + } + if(conditions != null) { + stringBuilder.append(' '); + stringBuilder.append(WHERE); + stringBuilder.append(' '); + stringBuilder.append(conditions); + } + String sql = stringBuilder.toString(); + //System.out.println(sql); + return sql; + } + +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/AbstractFilter.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/AbstractFilter.java new file mode 100755 index 0000000..74cf3d6 --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/AbstractFilter.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.filter; + +/** + * AbstractFilter Class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public abstract class AbstractFilter { + protected String result; + + @Override + public String toString() { + return this.getResult(); + } + + public String getResult() { + return this.result; + } +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlConjunction.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlConjunction.java new file mode 100755 index 0000000..0c27545 --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlConjunction.java @@ -0,0 +1,69 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.filter; + +/** + * SqlConjunction Class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SqlConjunction extends AbstractFilter { + + public static final String AND = "AND"; + public static final String OR = "OR"; + + public SqlConjunction(final String conjunction, final Object... object) { + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append('('); + int operationCount = object.length; + if (operationCount == 0) { + this.result = ""; + return; + } + if (operationCount == 1) { + this.result = object.toString(); + return; + } + int index = 0; + final int maxIndex = object.length - 1; + for (Object o : object) { + stringBuilder.append(o); + + if (index++ != maxIndex) { + stringBuilder.append(' '); + stringBuilder.append(conjunction); + stringBuilder.append(' '); + } + } + stringBuilder.append(')'); + this.result = stringBuilder.toString(); + + } + + public SqlConjunction(final String raw) { + + this.result = raw; + + } + +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlFilter.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlFilter.java new file mode 100755 index 0000000..344d8fd --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlFilter.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.filter; + +/** + * SqlFilter Class. + *

+ * Used to generate the WHERE part of a SQL statement. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SqlFilter extends AbstractFilter { + + public SqlFilter(final SqlConjunction sqlConjunction) { + this.result = sqlConjunction.toString(); + System.out.println("SqlFilter generated WHERE part:\n\t" + this.result); + } + + public SqlFilter(final SqlOperation sqlOperation) { + this.result = sqlOperation.toString(); + System.out.println("SqlFilter generated WHERE part:\n\t" + this.result); + } + +} diff --git a/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlOperation.java b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlOperation.java new file mode 100755 index 0000000..5df54d4 --- /dev/null +++ b/power-sql/src/main/java/org/nanoboot/powerframework/sql/filter/SqlOperation.java @@ -0,0 +1,92 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.sql.filter; + +/** + * SqlOperation Class. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SqlOperation extends AbstractFilter { + public static final String EQUAL = "="; + public static final String GREATER_OR_EQUAL = ">="; + public static final String GREATER = ">"; + public static final String LESS_OR_EQUAL = "<="; + public static final String LESS = "<"; + + private static final String IN = " IN "; + private static final String NOT_IN = " NOT IN "; + + public static SqlOperation createNotInSqlOperation(final String what, final Object[] where) { + return createInSqlOperation(what, where, true); + } + + public static SqlOperation createInSqlOperation(final String what, final Object[] where) { + return createInSqlOperation(what, where, false); + } + + private static SqlOperation createInSqlOperation(final String what, final Object[] where, final boolean not) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("("); + stringBuilder.append(what); + stringBuilder.append(not ? NOT_IN : IN); + stringBuilder.append("("); + int index = 0; + int maxIndex = where.length - 1; + for (Object e : where) { + stringBuilder.append(e); + if (index != maxIndex) { + stringBuilder.append(", "); + } + + index++; + } + stringBuilder.append("))"); + SqlOperation sqlOperation = new SqlOperation(); + sqlOperation.result = stringBuilder.toString(); + return sqlOperation; + } + + private SqlOperation() { + + } + + public SqlOperation(final String operation, final Object object1, final Object object2) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append('('); + stringBuilder.append(object1); + stringBuilder.append(' '); + stringBuilder.append(operation); + stringBuilder.append(' '); + stringBuilder.append(object2); + stringBuilder.append(')'); + this.result = stringBuilder.toString(); + } + + public SqlOperation(final String raw) { + this.result = raw; + } + + public static String quote(final String string) { + return '\'' + string + '\''; + } +} diff --git a/power-sql/src/main/resources/.gitkeep b/power-sql/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-sql/src/test/java/.gitkeep b/power-sql/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-stat/pom.xml b/power-stat/pom.xml new file mode 100644 index 0000000..8c05969 --- /dev/null +++ b/power-stat/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-stat + jar + + Power Stat + Stat for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + diff --git a/power-stat/src/main/java/module-info.java b/power-stat/src/main/java/module-info.java new file mode 100644 index 0000000..3001755 --- /dev/null +++ b/power-stat/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.template { + requires powerframework.core; + requires powerframework.log; + requires powerframework.utils; +} diff --git a/power-stat/src/main/java/org/nanoboot/powerframework/stat/.gitkeep b/power-stat/src/main/java/org/nanoboot/powerframework/stat/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-stat/src/main/resources/.gitkeep b/power-stat/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-stat/src/test/java/org/nanoboot/powerframework/stat/.gitkeep b/power-stat/src/test/java/org/nanoboot/powerframework/stat/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-svg/pom.xml b/power-svg/pom.xml new file mode 100644 index 0000000..3035f65 --- /dev/null +++ b/power-svg/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-svg + jar + + Power SVG + SVG for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + diff --git a/power-svg/src/main/java/module-info.java b/power-svg/src/main/java/module-info.java new file mode 100644 index 0000000..f99825e --- /dev/null +++ b/power-svg/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.template { + requires powerframework.core; + requires powerframework.log; + requires powerframework.utils; +} diff --git a/power-svg/src/main/java/org/nanoboot/powerframework/svg/.gitkeep b/power-svg/src/main/java/org/nanoboot/powerframework/svg/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-svg/src/main/resources/.gitkeep b/power-svg/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-svg/src/test/java/org/nanoboot/powerframework/svg/.gitkeep b/power-svg/src/test/java/org/nanoboot/powerframework/svg/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-template/.gitkeep b/power-template/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-template/pom.xml b/power-template/pom.xml new file mode 100644 index 0000000..2e1b6f2 --- /dev/null +++ b/power-template/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-template + jar + + Power Template + Template for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + diff --git a/power-template/src/main/java/module-info.java b/power-template/src/main/java/module-info.java new file mode 100644 index 0000000..f99825e --- /dev/null +++ b/power-template/src/main/java/module-info.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.template { + requires powerframework.core; + requires powerframework.log; + requires powerframework.utils; +} diff --git a/power-template/src/main/java/org/nanoboot/powerframework/template/.gitkeep b/power-template/src/main/java/org/nanoboot/powerframework/template/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-template/src/main/resources/.gitkeep b/power-template/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-template/src/test/java/org/nanoboot/powerframework/template/.gitkeep b/power-template/src/test/java/org/nanoboot/powerframework/template/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-text/pom.xml b/power-text/pom.xml new file mode 100644 index 0000000..8317b5c --- /dev/null +++ b/power-text/pom.xml @@ -0,0 +1,54 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-text + jar + + Power Text + Text functionality for the Power library + + + false + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + + org.projectlombok + lombok + + + + diff --git a/power-text/src/main/java/module-info.java b/power-text/src/main/java/module-info.java new file mode 100644 index 0000000..4d52fc9 --- /dev/null +++ b/power-text/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.text { + exports org.nanoboot.powerframework.text; + requires powerframework.core; + requires lombok; +} diff --git a/power-text/src/main/java/org/nanoboot/powerframework/text/AsciiCharacter.java b/power-text/src/main/java/org/nanoboot/powerframework/text/AsciiCharacter.java new file mode 100644 index 0000000..ba35461 --- /dev/null +++ b/power-text/src/main/java/org/nanoboot/powerframework/text/AsciiCharacter.java @@ -0,0 +1,623 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +import lombok.Getter; + +/** + * Enumeration for Ascii characters. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum AsciiCharacter { + /** + * Constant for ascii character constant ' '. + */ + SPACE(32, "space", CharacterType.OTHER_NOT_PRINTABLE), + /** + * Constant for ascii character constant '!'. + */ + EXCLAMATION_MARK(33, "exclamation mark", CharacterType.OTHER_PRINTABLE, + '?'), + /** + * Constant for ascii character constant '"'. + */ + QUOTATION_MARK(34, "quotation mark", + CharacterType.OTHER_PRINTABLE, + '\''), + /** + * Constant for ascii character constant '#'. + */ + NUMBER_SIGN(35, "number sign", CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '$'. + */ + DOLLAR_SIGN(36, "dollar sign", CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '%'. + */ + PERCENT_SIGN(37, "percent sign", CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '&'. + */ + AMPERSAND(38, "ampersand", CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '''. + */ + APOSTROPHE(39, "apostrophe", CharacterType.OTHER_PRINTABLE, + '"'), + /** + * Constant for ascii character constant '('. + */ + ROUND_BRACKET_START(40, "round bracket start", + CharacterType.OTHER_PRINTABLE, + ')'), + /** + * Constant for ascii character constant ')'. + */ + ROUND_BRACKET_END(41, "round bracket end", + CharacterType.OTHER_PRINTABLE, + '('), + /** + * Constant for ascii character constant '*'. + */ + ASTERISK(42, "asterisk", + CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '+'. + */ + PLUS_SIGN(43, "plus sign", + CharacterType.OTHER_PRINTABLE, + '-'), + /** + * Constant for ascii character constant ','. + */ + COMMA(44, "comma", + CharacterType.OTHER_PRINTABLE, + '.'), + /** + * Constant for ascii character constant '-'. + */ + MINUS_SIGN(45, "minus sign", + CharacterType.OTHER_PRINTABLE, + '+'), + /** + * Constant for ascii character constant '.'. + */ + FULL_STOP(46, "full stop", + CharacterType.OTHER_PRINTABLE, + ','), + /** + * Constant for ascii character constant '/'. + */ + SLASH(47, "slash", + CharacterType.OTHER_PRINTABLE, + '\\'), + /** + * Constant for ascii character constant '0'. + */ + ZERO(48, "zero", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '1'. + */ + ONE(49, "one", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '2'. + */ + TWO(50, "two", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '3'. + */ + THREE(51, "three", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '4'. + */ + FOUR(52, "four", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '5'. + */ + FIVE(53, "five", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '6'. + */ + SIX(54, "six", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '7'. + */ + SEVEN(55, "seven", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '8'. + */ + EIGHT(56, "eight", + CharacterType.NUMBER), + /** + * Constant for ascii character constant '9'. + */ + NINE(57, "nine", + CharacterType.NUMBER), + /** + * Constant for ascii character constant ':'. + */ + COLON(58, "colon", + CharacterType.OTHER_PRINTABLE, + ';'), + /** + * Constant for ascii character constant ';'. + */ + SEMICOLON(59, "semicolon", + CharacterType.OTHER_PRINTABLE, + ':'), + /** + * Constant for ascii character constant '<'. + */ + LESS_THAN_SIGN(60, "less than sign", + CharacterType.OTHER_PRINTABLE, + '>'), + /** + * Constant for ascii character constant '='. + */ + EQUALS_SIGN(61, "equals sign", + CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '>'. + */ + GREATER_THAN_SIGN(62, "greater than sign", + CharacterType.OTHER_PRINTABLE, + '<'), + /** + * Constant for ascii character constant '?'. + */ + QUESTION_MARK(63, "question mark", + CharacterType.OTHER_PRINTABLE, + '!'), + /** + * Constant for ascii character constant '@'. + */ + AT_SIGN(64, "at sign", + CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant 'A'. + */ + A_UPPER(65, "a upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'B'. + */ + B_UPPER(66, "b upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'C'. + */ + C_UPPER(67, "c upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'D'. + */ + D_UPPER(68, "d upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'E'. + */ + E_UPPER(69, "e upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'F'. + */ + F_UPPER(70, "f upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'G'. + */ + G_UPPER(71, "g upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'H'. + */ + H_UPPER(72, "h upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'I'. + */ + I_UPPER(73, "i upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'J'. + */ + J_UPPER(74, "j upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'K'. + */ + K_UPPER(75, "k upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'L'. + */ + L_UPPER(76, "l upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'M'. + */ + M_UPPER(77, "m upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'N'. + */ + N_UPPER(78, "n upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'O'. + */ + O_UPPER(79, "o upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'P'. + */ + P_UPPER(80, "p upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'Q'. + */ + Q_UPPER(81, "q upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'R'. + */ + R_UPPER(82, "r upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'S'. + */ + S_UPPER(83, "s upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'T'. + */ + T_UPPER(84, "t upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'U'. + */ + U_UPPER(85, "u upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'V'. + */ + V_UPPER(86, "v upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'W'. + */ + W_UPPER(87, "w upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'X'. + */ + X_UPPER(88, "x upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'Y'. + */ + Y_UPPER(89, "y upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant 'Z'. + */ + Z_UPPER(90, "z upper", + CharacterType.UPPER_LETTER), + /** + * Constant for ascii character constant '['. + */ + SQUARE_BRACKET_START(91, + "square bracket start", + CharacterType.OTHER_PRINTABLE, + ']'), + /** + * Constant for ascii character constant '\'. + */ + BACKSLASH(92, "backslash", + CharacterType.OTHER_PRINTABLE, + '/'), + /** + * Constant for ascii character constant ']'. + */ + SQUARE_BRACKET_END(93, "square bracket end", + CharacterType.OTHER_PRINTABLE, + '['), + /** + * Constant for ascii character constant '^'. + */ + CARET(94, "caret", + CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant '_'. + */ + UNDERSCORE(95, "underscore", + CharacterType.OTHER_PRINTABLE, + '|'), + /** + * Constant for ascii character constant '`'. + */ + GRAVE_ACCENT(96, "grave accent", + CharacterType.OTHER_PRINTABLE), + /** + * Constant for ascii character constant 'a'. + */ + A_LOWER(97, "a lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'b'. + */ + B_LOWER(98, "b lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'c'. + */ + C_LOWER(99, "c lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'd'. + */ + D_LOWER(100, "d lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'e'. + */ + E_LOWER(101, "e lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'f'. + */ + F_LOWER(102, "f lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'g'. + */ + G_LOWER(103, "g lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'h'. + */ + H_LOWER(104, "h lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'i'. + */ + I_LOWER(105, "i lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'j'. + */ + J_LOWER(106, "j lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'k'. + */ + K_LOWER(107, "k lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'l'. + */ + L_LOWER(108, "l lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'm'. + */ + M_LOWER(109, "m lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'n'. + */ + N_LOWER(110, "n lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'o'. + */ + O_LOWER(111, "o lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'p'. + */ + P_LOWER(112, "p lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'q'. + */ + Q_LOWER(113, "q lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'r'. + */ + R_LOWER(114, "r lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 's'. + */ + S_LOWER(115, "s lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 't'. + */ + T_LOWER(116, "t lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'u'. + */ + U_LOWER(117, "u lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'v'. + */ + V_LOWER(118, "v lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'w'. + */ + W_LOWER(119, "w lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'x'. + */ + X_LOWER(120, "x lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'y'. + */ + Y_LOWER(121, "y lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant 'z'. + */ + Z_LOWER(122, "z lower", + CharacterType.LOWER_LETTER), + /** + * Constant for ascii character constant '{'. + */ + CURLY_BRACKET_START(123, + "curly bracket start", + CharacterType.OTHER_PRINTABLE, + '}'), + /** + * Constant for ascii character constant '|'. + */ + VERTICAL_BAR(124, "vertical bar", + CharacterType.OTHER_PRINTABLE, + '_'), + /** + * Constant for ascii character constant '}'. + */ + CURLY_BRACKET_END(125, "curly bracket end", + CharacterType.OTHER_PRINTABLE, + '{'); + /** + * The position of the character. + */ + @Getter + private final int asciiPosition; + + /** + * The character. + */ + @Getter + private final Character character; + /** + * Description of the character. + */ + @Getter + private final String description; + + /** + * Character type. + */ + @Getter + private final CharacterType characterType; + + /** + * Opposite character. + */ + @Getter + private final Character oppositeCharacter; + + /** + * Constructor. + * + * @param asciiPositionIn position in ascii + * @param descriptionIn description of the character + * @param characterTypeIn character type + * asciiCharacter + * @param oppositeCharIn opposite ascii character + */ + AsciiCharacter(final int asciiPositionIn, final String descriptionIn, + final CharacterType characterTypeIn, + final Character oppositeCharIn) { + this.asciiPosition = asciiPositionIn; + this.description = descriptionIn; + this.character = (char) asciiPositionIn; + this.characterType = characterTypeIn; + + if (oppositeCharIn == null) { + if (this.characterType == CharacterType.UPPER_LETTER) { + this.oppositeCharacter = Character.toLowerCase(character); + } else if (this.characterType == CharacterType.LOWER_LETTER) { + this.oppositeCharacter = Character.toUpperCase(character); + } else { + this.oppositeCharacter = null; + } + } else { + this.oppositeCharacter = oppositeCharIn; + } + } + + /** + * Constructor. + * + * @param asciiPositionIn position in ascii + * @param descriptionIn name of the character + * @param characterTypeIn character type + * asciiCharacter + */ + AsciiCharacter(final int asciiPositionIn, final String descriptionIn, + final CharacterType characterTypeIn) { + this(asciiPositionIn, descriptionIn, characterTypeIn, null); + } + + /** + * Returns character. + * + * @return character + */ + public char toChar() { + return getCharacter(); + } + /** + * Returns string. + * + * @return string + */ + public String asString() { + return String.valueOf(toChar()); + } + + /** + * Returns AsciiCharacter based on the ch parameter, if possible, + * otherwise returns null. + * + * @param ch input character + * @return AsciiCharacter, if possible, otherwise null + */ + public static AsciiCharacter ofCharacter(final char ch) { + for (AsciiCharacter ac : AsciiCharacter.values()) { + if (ac.getCharacter() == ch) { + return ac; + } + } + return null; + } +} diff --git a/power-text/src/main/java/org/nanoboot/powerframework/text/CharacterRange.java b/power-text/src/main/java/org/nanoboot/powerframework/text/CharacterRange.java new file mode 100644 index 0000000..bdca8c5 --- /dev/null +++ b/power-text/src/main/java/org/nanoboot/powerframework/text/CharacterRange.java @@ -0,0 +1,186 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +import lombok.Getter; + +import java.util.Arrays; + +/** + * Representing ascii characters of a type. + * + * @author Robert Vokac + * @since 0.0.0 + */ +@Getter +public final class CharacterRange { + /** + * Ascii starting position for number characters. + */ + private static final int NUMERIC_CHARS_FROM = 48; + /** + * Ascii ending position for number characters. + */ + private static final int NUMERIC_CHARS_TO = 57; + /** + * Ascii starting position for lower letter characters. + */ + private static final int LOWER_LETTERS_CHARS_FROM = 97; + /** + * Ascii ending position for lower letter characters. + */ + private static final int LOWER_LETTERS_CHARS_TO = 122; + /** + * Ascii starting position for upper letter characters. + */ + private static final int UPPER_LETTERS_CHARS_FROM = 65; + /** + * Ascii ending position for upper letter characters. + */ + private static final int UPPER_LETTERS_CHARS_TO = 90; + /** + * Ascii starting position for printable characters. + */ + private static final int PRINTABLE_ASCII_CHARS_FROM = 33; + /** + * Ascii ending position for printable characters. + */ + private static final int PRINTABLE_ASCII_CHARS_TO = 126; + + /** + * Range for numbers. + */ + public static final CharacterRange NUMBERS; + /** + * Range for lower letters. + */ + public static final CharacterRange LOWER_LETTERS; + /** + * Range for upper letters. + */ + public static final CharacterRange UPPER_LETTERS; + /** + * Range for printable characters. + */ + public static final CharacterRange PRINTABLE_CHARACTERS_LETTERS; + + /** + * Character type. + */ + private final CharacterType type; + + /** + * Ascii starting position. + */ + private final int asciiFrom; + + /** + * Ascii ending position. + */ + private final int asciiTo; + + /** + * Char array of the character of this type. + */ + private final char[] array; + + static { + NUMBERS = new CharacterRange( + CharacterType.NUMBER, NUMERIC_CHARS_FROM, NUMERIC_CHARS_TO + ); + LOWER_LETTERS = new CharacterRange( + CharacterType.LOWER_LETTER, + LOWER_LETTERS_CHARS_FROM, LOWER_LETTERS_CHARS_TO + ); + UPPER_LETTERS = new CharacterRange( + CharacterType.UPPER_LETTER, + UPPER_LETTERS_CHARS_FROM, UPPER_LETTERS_CHARS_TO + ); + PRINTABLE_CHARACTERS_LETTERS = new CharacterRange( + CharacterType.OTHER_PRINTABLE, + PRINTABLE_ASCII_CHARS_FROM, PRINTABLE_ASCII_CHARS_TO + ); + } + + /** + * Returns instance of CharacterRange + * based on the given type. + * + * @param type type of the character range to return + * Note: printable characters + * are not supported. + * @return CharacterRange instance + */ + public static CharacterRange getInstance( + final CharacterType type) { + switch (type) { + case NUMBER: return NUMBERS; + case LOWER_LETTER: return LOWER_LETTERS; + case UPPER_LETTER: return UPPER_LETTERS; + case OTHER_PRINTABLE: return PRINTABLE_CHARACTERS_LETTERS; + default: + String msg = "Type " + type + " is not supported."; + throw new TextException(msg); + } + } + + /** + * Constructor. + * @param characterType type of the character range to return + * * Note: printable characters + * * are not supported. + * @param asciiFromParam starting position + * @param asciiToParam ending position + */ + private CharacterRange(final CharacterType characterType, + final int asciiFromParam, final int asciiToParam) { + boolean numbersAreInRange = asciiFromParam <= asciiToParam; + if (!numbersAreInRange) { + String msg = "asciiFromParam must be less or equal to asciiToParam"; + throw new TextException(msg); + } + this.type = characterType; + this.asciiFrom = asciiFromParam; + this.asciiTo = asciiToParam; + this.array = new char[this.size()]; + int index = 0; + for (int i = asciiFrom; i <= asciiTo; i++) { + char ch = (char) i; + array[index++] = ch; + } + } + + /** + * Returns size of the range. + * @return size of the characters in the range + */ + public int size() { + return asciiTo - asciiFrom + 1; + } + + /** + * Returns the character array. + * @return array + */ + public char[] getArray() { + return Arrays.copyOf(this.array, this.array.length); + } +} diff --git a/power-text/src/main/java/org/nanoboot/powerframework/text/CharacterType.java b/power-text/src/main/java/org/nanoboot/powerframework/text/CharacterType.java new file mode 100644 index 0000000..a0d057c --- /dev/null +++ b/power-text/src/main/java/org/nanoboot/powerframework/text/CharacterType.java @@ -0,0 +1,54 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +/** + * Enumeration for character types. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum CharacterType { + /** + * 0-9. + */ + NUMBER, + + /** + * a-z. + */ + LOWER_LETTER, + + /** + * A-Z. + */ + UPPER_LETTER, + + /** + * For example: !@#$%^&*()~?. + */ + OTHER_PRINTABLE, + + /** + * For example: spaces, tabs. + */ + OTHER_NOT_PRINTABLE; +} diff --git a/power-text/src/main/java/org/nanoboot/powerframework/text/TextException.java b/power-text/src/main/java/org/nanoboot/powerframework/text/TextException.java new file mode 100644 index 0000000..732eebb --- /dev/null +++ b/power-text/src/main/java/org/nanoboot/powerframework/text/TextException.java @@ -0,0 +1,44 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * Exception happening in case, something in random packages failed. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TextException extends PowerException { + + /** + * Constructor with message. + * + * @param message message describing the reason, + * why this exception was thrown. + */ + public TextException(final String message) { + super(message); + } + +} diff --git a/power-text/src/main/java/org/nanoboot/powerframework/text/package-info.java b/power-text/src/main/java/org/nanoboot/powerframework/text/package-info.java new file mode 100644 index 0000000..819de4e --- /dev/null +++ b/power-text/src/main/java/org/nanoboot/powerframework/text/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Classes used to operate with texts. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.text; diff --git a/power-text/src/main/resources/.gitkeep b/power-text/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-text/src/test/java/org/nanoboot/powerframework/text/.gitkeep b/power-text/src/test/java/org/nanoboot/powerframework/text/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-text/src/test/java/org/nanoboot/powerframework/text/AsciiCharacterTest.java b/power-text/src/test/java/org/nanoboot/powerframework/text/AsciiCharacterTest.java new file mode 100644 index 0000000..9f30a22 --- /dev/null +++ b/power-text/src/test/java/org/nanoboot/powerframework/text/AsciiCharacterTest.java @@ -0,0 +1,103 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class AsciiCharacterTest { + + @Test + public void toChar() { + for (AsciiCharacter e : AsciiCharacter.values()) { + char ch = e.toChar(); + AsciiCharacter ac = AsciiCharacter.ofCharacter(ch); + assertEquals(ch, ac.toChar()); + } + } + + @Test + public void ofCharacter() { + assertEquals(AsciiCharacter.CARET, AsciiCharacter.ofCharacter('^')); + assertEquals(null, AsciiCharacter.ofCharacter('‣')); + } + + @Test + public void getAsciiPosition() { + int position = 100; + char ch = (char) position; + assertEquals(position, AsciiCharacter.ofCharacter(ch).getAsciiPosition()); + } + + @Test + public void getCharacter() { + char ch = '3'; + AsciiCharacter ac = AsciiCharacter.ofCharacter(ch); + assertEquals(ch, ac.toChar()); + } + + @Test + public void getDescription() { + for (AsciiCharacter e : AsciiCharacter.values()) { + assertNotNull(e.getDescription()); + assertFalse(e.getDescription().isEmpty()); + } + } + + @Test + public void getCharacterType() { + assertEquals(CharacterType.NUMBER, AsciiCharacter.ofCharacter('5').getCharacterType()); + assertEquals(CharacterType.LOWER_LETTER, AsciiCharacter.ofCharacter('g').getCharacterType()); + assertEquals(CharacterType.UPPER_LETTER, AsciiCharacter.ofCharacter('M').getCharacterType()); + assertEquals(CharacterType.OTHER_NOT_PRINTABLE, AsciiCharacter.ofCharacter(' ').getCharacterType()); + assertEquals(CharacterType.OTHER_PRINTABLE, AsciiCharacter.ofCharacter('*').getCharacterType()); + } + + @Test + public void getOppositeCharacter() { + for (AsciiCharacter ac : AsciiCharacter.values()) { + if (ac.getOppositeCharacter() != null) { + Character character = ac.getCharacter(); + Character oppositeCharacter = ac.getOppositeCharacter(); + Character expected = character; + Character returned = AsciiCharacter.ofCharacter(oppositeCharacter).getOppositeCharacter(); + assertEquals(expected, returned); + } + } + assertEquals(AsciiCharacter.ROUND_BRACKET_START.getCharacter(), + AsciiCharacter.ROUND_BRACKET_END.getOppositeCharacter()); + } + + @Test + public void asString() { + String expected = "3"; + AsciiCharacter ac = AsciiCharacter.ofCharacter('3'); + assertEquals(expected, ac.asString()); + } + +} diff --git a/power-text/src/test/java/org/nanoboot/powerframework/text/CharacterRangeTest.java b/power-text/src/test/java/org/nanoboot/powerframework/text/CharacterRangeTest.java new file mode 100644 index 0000000..b214d57 --- /dev/null +++ b/power-text/src/test/java/org/nanoboot/powerframework/text/CharacterRangeTest.java @@ -0,0 +1,150 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +import org.junit.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CharacterRangeTest { + + @Test(expected = AssertionError.class) + public void constructor() { + Constructor constructor= (Constructor) CharacterRange.class.getDeclaredConstructors()[0]; + constructor.setAccessible(true); + try { + CharacterRange obj = constructor.newInstance(CharacterType.OTHER_PRINTABLE, 10, 5); + } catch (InstantiationException e) { + e.printStackTrace(); + throw new AssertionError("UnexpectedException: " + e); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new AssertionError("UnexpectedException: " + e); + } catch (InvocationTargetException e) { + e.printStackTrace(); + throw new AssertionError("UnexpectedException: " + e); + } + } + + @Test + public void constructor2() { + Constructor constructor= (Constructor) CharacterRange.class.getDeclaredConstructors()[0]; + constructor.setAccessible(true); + try { + CharacterRange obj = constructor.newInstance(CharacterType.OTHER_PRINTABLE, 10, 15); + } catch (InstantiationException e) { + e.printStackTrace(); + throw new AssertionError("UnexpectedException: " + e); + } catch (IllegalAccessException e) { + e.printStackTrace(); + throw new AssertionError("UnexpectedException: " + e); + } catch (InvocationTargetException e) { + e.printStackTrace(); + throw new AssertionError("UnexpectedException: " + e); + } + assertTrue("passed", true); + } + @Test + public void getInstance() { + assertEquals(CharacterRange.NUMBERS, + CharacterRange.getInstance(CharacterType.NUMBER)); + assertEquals(CharacterRange.LOWER_LETTERS, + CharacterRange.getInstance(CharacterType.LOWER_LETTER)); + assertEquals(CharacterRange.UPPER_LETTERS, + CharacterRange.getInstance(CharacterType.UPPER_LETTER)); + assertEquals(CharacterRange.PRINTABLE_CHARACTERS_LETTERS, + CharacterRange.getInstance(CharacterType.OTHER_PRINTABLE)); + + try { + CharacterRange.getInstance(CharacterType.OTHER_NOT_PRINTABLE); + String msg = + "Exception TextException expected, because the following type is not supported: " + + CharacterType.OTHER_NOT_PRINTABLE; + throw new AssertionError(msg); + } catch (TextException e) { + //passed + } + } + + @Test + public void size() { + int expected = CharacterRange.NUMBERS.getAsciiTo() - CharacterRange.NUMBERS.getAsciiFrom() + 1; + int returned = CharacterRange.NUMBERS.size(); + assertEquals(expected, returned); + } + + @Test + public void getArray_numbers() { + char[] expected = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + char[] returned = CharacterRange.NUMBERS.getArray(); + + assertArrayEquals(expected, returned); + } + @Test + public void getArray_lowerLetters() { + char[] expected = new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + char[] returned = CharacterRange.UPPER_LETTERS.getArray(); + + assertArrayEquals(expected, returned); + } + @Test + public void getArray_upperLetters() { + char[] expected = new char[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; + char[] returned = CharacterRange.LOWER_LETTERS.getArray(); + + assertArrayEquals(expected, returned); + } + @Test + public void getArray_printableCharacters() { + char[] expected = new char[] {'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'}; + char[] returned = CharacterRange.PRINTABLE_CHARACTERS_LETTERS.getArray(); + + assertArrayEquals(expected, returned); + } + + @Test + public void getType() { + assertEquals(CharacterType.NUMBER, CharacterRange.NUMBERS.getType()); + assertEquals(CharacterType.LOWER_LETTER, CharacterRange.LOWER_LETTERS.getType()); + assertEquals(CharacterType.UPPER_LETTER, CharacterRange.UPPER_LETTERS.getType()); + assertEquals(CharacterType.OTHER_PRINTABLE, CharacterRange.PRINTABLE_CHARACTERS_LETTERS.getType()); + } + + @Test + public void getAsciiFrom() { + assertEquals(48, CharacterRange.NUMBERS.getAsciiFrom()); + } + + @Test + public void getAsciiTo() { + assertEquals(57, CharacterRange.NUMBERS.getAsciiTo()); + } + +} diff --git a/power-text/src/test/java/org/nanoboot/powerframework/text/TextExceptionTest.java b/power-text/src/test/java/org/nanoboot/powerframework/text/TextExceptionTest.java new file mode 100644 index 0000000..407b2e7 --- /dev/null +++ b/power-text/src/test/java/org/nanoboot/powerframework/text/TextExceptionTest.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.text; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TextExceptionTest { + + @Test + public void constructor_String() { + assertEquals("An error", new TextException("An error").getMessage()); + } + +} diff --git a/power-time/pom.xml b/power-time/pom.xml new file mode 100644 index 0000000..b652c73 --- /dev/null +++ b/power-time/pom.xml @@ -0,0 +1,84 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-time + jar + + Power Time + Time functionality for the Power library + + + true + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + ${checkstyle.skip} + + + + + + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-random + ${power.version} + + + org.nanoboot.powerframework + power-utils + ${power.version} + + + + + org.projectlombok + lombok + + + junit + junit + 4.12 + test + + + + diff --git a/power-time/src/main/java/module-info.java b/power-time/src/main/java/module-info.java new file mode 100644 index 0000000..1bcaa4d --- /dev/null +++ b/power-time/src/main/java/module-info.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.time { + exports org.nanoboot.powerframework.time.duration; + exports org.nanoboot.powerframework.time.moment; + exports org.nanoboot.powerframework.time.utils; + requires powerframework.random; + requires powerframework.utils; + requires powerframework.core; + requires lombok; +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/SimpleDateTimeFormatByTimeZone.java b/power-time/src/main/java/org/nanoboot/powerframework/time/SimpleDateTimeFormatByTimeZone.java new file mode 100644 index 0000000..243490d --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/SimpleDateTimeFormatByTimeZone.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time; + +import java.text.*; +import org.nanoboot.powerframework.time.moment.TimeZone; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +class SimpleDateTimeFormatByTimeZone extends SimpleDateFormat { + + /** + * + * @param timeZone + * @param formatText + */ + SimpleDateTimeFormatByTimeZone(TimeZone timeZone, + String formatText) { + super(formatText); + setTimeZone(java.util.TimeZone.getTimeZone(timeZone.toString())); + } +} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/TimeSource.java b/power-time/src/main/java/org/nanoboot/powerframework/time/TimeSource.java similarity index 68% rename from src/main/java/org/nanoboot/powerframework/datetime/TimeSource.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/TimeSource.java index 9992e1c..22e0317 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/TimeSource.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/TimeSource.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,28 +18,40 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time; -import java.text.DateFormat; -import java.util.Calendar; -import java.util.Date; +import java.text.*; +import java.util.*; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import org.nanoboot.powerframework.time.moment.TimeZone; /** * Is used to get current universal date and time. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ -class TimeSource { +public class TimeSource { - private static final org.nanoboot.powerframework.datetime.TimeZone universalTimeZone = new org.nanoboot.powerframework.datetime.TimeZone("GMT"); + private static final TimeZone universalTimeZone = new TimeZone("GMT"); - private static final DateFormat yearFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "yyyy"); - private static final DateFormat monthFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "MM"); - private static final DateFormat dayFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "dd"); - private static final DateFormat hourFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "HH"); - private static final DateFormat minuteFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "mm"); - private static final DateFormat secondFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "ss"); - private static final DateFormat millisecondFormat = new DateTime.SimpleDateTimeFormatByTimeZone(universalTimeZone, "S"); + private static final DateFormat yearFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "yyyy"); + private static final DateFormat monthFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "MM"); + private static final DateFormat dayFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "dd"); + private static final DateFormat hourFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "HH"); + private static final DateFormat minuteFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "mm"); + private static final DateFormat secondFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "ss"); + private static final DateFormat millisecondFormat = new SimpleDateTimeFormatByTimeZone(universalTimeZone, "S"); + + /** + * + * @return current universal date time + */ + public static UniversalDateTime getCurrentUniversalDateTimeInstance() { + TimeSource timeSource = new TimeSource(); + return timeSource.getCurrentUniversalDateTime(); + } /** * Represents source for current universal date time. @@ -57,15 +69,6 @@ class TimeSource { this.universalDateTime = this.buildCurrentUniversalDateTime(); } - /** - * - * @return current universal date time - */ - public static UniversalDateTime getCurrentUniversalDateTimeInstance() { - TimeSource timeSource = new TimeSource(); - return timeSource.getCurrentUniversalDateTime(); - } - /** * * @return Date instance for current universal date and time @@ -98,7 +101,7 @@ class TimeSource { * * @return current universal date time */ - UniversalDateTime getCurrentUniversalDateTime() { + private UniversalDateTime getCurrentUniversalDateTime() { return this.universalDateTime; } } diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/duration/Duration.java b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/Duration.java new file mode 100644 index 0000000..a5af6fe --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/Duration.java @@ -0,0 +1,429 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; + +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.nanoboot.powerframework.time.utils.TimeException; +import org.nanoboot.powerframework.time.utils.TimeUnit; +import org.nanoboot.powerframework.time.utils.TimeUnitConvertor; +import org.nanoboot.powerframework.time.utils.TimeUnitsValidator; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import org.nanoboot.powerframework.time.moment.ZonedDateTime; +import org.nanoboot.powerframework.utils.StringUtils; + +/** + * Is used to do arithmetics with Date and Time. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class Duration { + + private static final Duration zeroDuration = new Duration(0); + + private static final String PLUS = "+"; + private static final String MINUS = "-"; + private static final String COLON = ":"; + + /** + * + * @return Duration instance + */ + public static Duration getZeroDuration() { + return zeroDuration; + } + + /** + * + * @return random duration + */ + public static Duration createRandomDuration() { + Duration duration; + RandomGenerator pseudoRandomNumberGenerator = RandomGenerator.getDefaultImplStatic(); + long days = pseudoRandomNumberGenerator.nextInt(0, 6000); + int hours = pseudoRandomNumberGenerator.nextInt(0, 23); + int minutes = pseudoRandomNumberGenerator.nextInt(0, 59); + int seconds = pseudoRandomNumberGenerator.nextInt(0, 59); + int milliseconds = pseudoRandomNumberGenerator.nextInt(0, 999); + duration = new Duration(days, hours, minutes, seconds, milliseconds); + return duration; + } + + /** + * + * @param value value of count of the unit + * @param timeUnit TimeUnit instance + * + * @return an instance of Duration class with the given count of days + */ + public static Duration of(long value, TimeUnit timeUnit) { + return new Duration(convertToMilliseconds(value, timeUnit)); + } + + /** + * Converts the value (timeUnit) to count of milliseconds. + * + * @param value value of count of the unit + * @param timeUnit TimeUnit instance for the value + * + * @return count of milliseconds of the count of the timeUnits + */ + private static long convertToMilliseconds(long value, TimeUnit timeUnit) { + return value * getMillisecondsPerTimeUnit(timeUnit); + } + + /** + * + * @param timeUnit TimeUnit instance + * + * @return count of milliseconds of one timeUnit + */ + private static int getMillisecondsPerTimeUnit(TimeUnit timeUnit) { + return (int) TimeUnitConvertor.convert(1, timeUnit, TimeUnit.MILLISECOND); + + } + + /** + * + * @param universalDateTime UniversalDateTime instance + * @param duration Duration instance to add to the time + * + * @return add to universalDateTime duration and return result + */ + public static UniversalDateTime fromUniversalDateTimePlusDurationCreateNewUniversalDateTime(UniversalDateTime universalDateTime, Duration duration) { + return addToUniversalDateTimeDuration(universalDateTime, duration, true); + } + + /** + * + * @param universalDateTime UniversalDateTime instance + * @param duration Duration instance to remove from the time + * + * @return subtract from universalDateTime duration and return result + */ + public static UniversalDateTime fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime( + UniversalDateTime universalDateTime, + Duration duration) { + return addToUniversalDateTimeDuration(universalDateTime, duration, false); + } + + private static UniversalDateTime addToUniversalDateTimeDuration( + UniversalDateTime universalDateTime, + Duration duration, + boolean trueForAddingFalseForSubtracting) { + java.time.LocalDateTime javaLocalDateTime = universalDateTime.removeUniversalTimeZone().toJavaLocalDateTime(); + java.time.Duration javaDuration = duration.toJavaDuration(); + java.time.LocalDateTime newJavaLocalDateTime; + if(trueForAddingFalseForSubtracting) { + newJavaLocalDateTime = javaLocalDateTime.plus(javaDuration); + } else { + newJavaLocalDateTime = javaLocalDateTime.minus(javaDuration); + } + + int year = newJavaLocalDateTime.getYear(); + int day = newJavaLocalDateTime.getDayOfMonth(); + int month = newJavaLocalDateTime.getMonth().getValue(); + int hour = newJavaLocalDateTime.getHour(); + int minute = newJavaLocalDateTime.getMinute(); + int second = newJavaLocalDateTime.getSecond(); + final int nanosecondspermillisecond; + nanosecondspermillisecond = 1000000; + int millisecond = newJavaLocalDateTime.getNano() / nanosecondspermillisecond; + + return new UniversalDateTime(year, month, day, hour, minute, second, millisecond); + } + + /** + * + * @param zonedDateTime ZonedDateTime instance + * @param duration Duration instance to add to the time + * + * @return add to zonedDateTime duration and return result + */ + public static ZonedDateTime fromZonedDateTimePlusDurationCreateNewZonedDateTime(ZonedDateTime zonedDateTime, Duration duration) { + return addToZonedDateTimeDuration(zonedDateTime, duration, true); + } + + /** + * + * @param zonedDateTime ZonedDateTime instance + * @param duration Duration instance to remove from the time + * + * @return subtract from zonedDateTime duration and return result + */ + public static ZonedDateTime fromZonedDateTimeMinusDurationCreateNewZonedDateTime( + ZonedDateTime zonedDateTime, + Duration duration) { + return addToZonedDateTimeDuration(zonedDateTime, duration, false); + } + + private static ZonedDateTime addToZonedDateTimeDuration( + ZonedDateTime zonedDateTime, + Duration duration, + boolean trueForAddingFalseForSubtracting) { + UniversalDateTime universalDateTime = zonedDateTime.toUniversalDateTime(); + UniversalDateTime newUniversalDateTime; + if(trueForAddingFalseForSubtracting) { + newUniversalDateTime = fromUniversalDateTimePlusDurationCreateNewUniversalDateTime(universalDateTime, duration); + } else { + newUniversalDateTime = fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime(universalDateTime, duration); + } + + return newUniversalDateTime.convertToZonedDateTimeWithUniversalTimeZone().toZonedDateTime(zonedDateTime.getTimeZone()); + } + + private final long countOfTotalMilliseconds; + private final int days; + private final int hours; + private final int minutes; + private final int seconds; + private final int milliseconds; + private final boolean positive; + + /** + * Constructor + * + * Creates new Duration with duration 0 milliseconds. + * + */ + public Duration() { + this(0); + } + + /** + * Constructor + * + * Creates new Duration from count of milliseconds. + * + * @param countOfMilliseconds milliseconds representing the new Duration + */ + public Duration(long countOfMilliseconds) { + + positive = countOfMilliseconds >= 0; + + this.countOfTotalMilliseconds = Math.abs(countOfMilliseconds); + this.days = (int) Math.floor(this.toTotal(TimeUnit.DAY)); + this.hours = (int) Math.floor(this.toTotal(TimeUnit.HOUR) - TimeUnitConvertor.convert(days, TimeUnit.DAY, TimeUnit.HOUR)); + this.minutes = (int) (Math.floor(this.toTotal(TimeUnit.MINUTE)) - TimeUnitConvertor.convert(days, TimeUnit.DAY, TimeUnit.MINUTE) - TimeUnitConvertor.convert(hours, TimeUnit.HOUR, TimeUnit.MINUTE)); + this.seconds = (int) Math.floor(this.toTotal(TimeUnit.SECOND) - TimeUnitConvertor.convert(days, TimeUnit.DAY, TimeUnit.SECOND) - TimeUnitConvertor.convert(hours, TimeUnit.HOUR, TimeUnit.SECOND) - TimeUnitConvertor.convert(minutes, TimeUnit.MINUTE, TimeUnit.SECOND)); + this.milliseconds = (int) (this.toTotal(TimeUnit.MILLISECOND) - TimeUnitConvertor.convert(days, TimeUnit.DAY, TimeUnit.MILLISECOND) - TimeUnitConvertor.convert(hours, TimeUnit.HOUR, TimeUnit.MILLISECOND) - TimeUnitConvertor.convert(minutes, TimeUnit.MINUTE, TimeUnit.MILLISECOND) - TimeUnitConvertor.convert(seconds, TimeUnit.SECOND, TimeUnit.MILLISECOND)); + + } + + /** + * Constructor + * + * Creates new Duration from the given values. + * + * @param days value + * @param hours value + * @param minutes value + * @param seconds value + * @param milliseconds value + */ + public Duration(long days, int hours, int minutes, int seconds, int milliseconds) { + this(true, days, hours, minutes, seconds, milliseconds); + } + + /** + * Constructor + * + * Creates new Duration from the given values. + * + * @param positive true, if this duration is greater than 0, otherwise false + * @param days value + * @param hours value + * @param minutes value + * @param seconds value + * @param milliseconds value + */ + public Duration(boolean positive, long days, int hours, int minutes, int seconds, int milliseconds) { + this( + (positive ? 1 : (-1)) + * (convertToMilliseconds(days, TimeUnit.DAY) + + convertToMilliseconds(hours, TimeUnit.HOUR) + + convertToMilliseconds(minutes, TimeUnit.MINUTE) + + convertToMilliseconds(seconds, TimeUnit.SECOND) + + milliseconds) + ); + TimeUnitsValidator.validate(hours, minutes, seconds, milliseconds); + } + + /** + * Constructor + * + * Creates new Duration from the String. + * + * @param string representing the new Duration + */ + public Duration(String string) { + String[] splitString = string.split("\\:+"); + if(splitString.length != 5) { + throw new TimeException("Input String has wrong format."); + } + try { + this.days = Integer.parseInt(splitString[0]); + this.hours = Integer.parseInt(splitString[1]); + this.minutes = Integer.parseInt(splitString[2]); + this.seconds = Integer.parseInt(splitString[3]); + this.milliseconds = Integer.parseInt(splitString[4]); + this.countOfTotalMilliseconds = convertToMilliseconds(days, TimeUnit.DAY) + + convertToMilliseconds(hours, TimeUnit.HOUR) + + convertToMilliseconds(minutes, TimeUnit.MINUTE) + + convertToMilliseconds(seconds, TimeUnit.SECOND) + + milliseconds; + this.positive = string.charAt(0) != '-'; + } catch (NumberFormatException e) {//NOSONAR + throw new TimeException("Input String has wrong format."); + } + TimeUnitsValidator.validate(hours, minutes, seconds, milliseconds); + } + + /** + * + * @param timeUnit TimeUnit instance + * + * @return value + */ + public long get(TimeUnit timeUnit) { + switch (timeUnit) { + case DAY: + return this.days; + case HOUR: + return this.hours; + case MINUTE: + return this.minutes; + case SECOND: + return this.seconds; + case MILLISECOND: + return this.milliseconds; + default: + throw new UnsupportedOperationException(); + } + } + + /** + * + * @return result of this control + */ + public boolean isPositive() { + return this.positive; + } + + /** + * + * @return new Duration instance created from negated this object + */ + public Duration negated() { + return new Duration((int) this.toTotal(TimeUnit.MILLISECOND) * (-1)); + } + + /** + * + * @return new Duration instance created from this object, if this object is + * negative, returned Duration is not negative + */ + public Duration abs() { + long absCountOfTotalMilliseconds; + absCountOfTotalMilliseconds = this.countOfTotalMilliseconds >= 0 ? countOfTotalMilliseconds : (countOfTotalMilliseconds * (-1)); + return new Duration(absCountOfTotalMilliseconds); + } + + /** + * + * @param durationToAdd Duration instance to add + * + * @return new Duration by adding the two Duration instance together + */ + public Duration plus(Duration durationToAdd) { + return plus((long) durationToAdd.toTotal(TimeUnit.MILLISECOND), TimeUnit.MILLISECOND); + } + + /** + * + * @param value value + * @param timeUnit TimeUnit instance + * + * @return new Duration instance + */ + public Duration plus(long value, TimeUnit timeUnit) { + return new Duration((int) this.toTotal(TimeUnit.MILLISECOND) + convertToMilliseconds(value, timeUnit)); + } + + /** + * + * @param durationToSubtract Duration instance + * + * @return from this object plus the given durationToAdd new Duration + */ + public Duration minus(Duration durationToSubtract) { + //TODO A bug is probably here. + return minus((long) durationToSubtract.toTotal(TimeUnit.MILLISECOND), TimeUnit.MILLISECOND); + } + + /** + * + * @param value value + * @param timeUnit TimeUnit instance + * + * @return new Duration instance + */ + public Duration minus(long value, + TimeUnit timeUnit) { + return new Duration((int) this.toTotal(TimeUnit.MILLISECOND) - convertToMilliseconds(value, timeUnit)); + } + + /** + * + * @param timeUnit DAY,HOUR,MINUTE,SECOND, MILLISECOND + * + * @return number of the timeUnit representing this duration + */ + public double toTotal(TimeUnit timeUnit) { + int divisor = 0; + divisor = getMillisecondsPerTimeUnit(timeUnit); + return countOfTotalMilliseconds / divisor; + + } + + /** + * + * @return java.time.duration representation of this object + */ + java.time.Duration toJavaDuration() { + java.time.Duration javaDuration = java.time.Duration.ofMillis((int) this.toTotal(TimeUnit.MILLISECOND)); + return this.isPositive() ? javaDuration : javaDuration.negated(); + } + + @Override + public String toString() { + return StringUtils.appendObjects(this.isPositive() ? PLUS : MINUS, + get(TimeUnit.DAY), + COLON, + get(TimeUnit.HOUR), + COLON, + get(TimeUnit.MINUTE), + COLON, + get(TimeUnit.SECOND), + COLON, + get(TimeUnit.MILLISECOND)); + } +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/duration/Period.java b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/Period.java new file mode 100644 index 0000000..f2a9116 --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/Period.java @@ -0,0 +1,182 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; + +import org.nanoboot.powerframework.time.moment.LocalDateTime; +import org.nanoboot.powerframework.time.utils.TimeException; +import org.nanoboot.powerframework.time.utils.TimeUnit; +import org.nanoboot.powerframework.time.moment.UniversalDateTime; +import org.nanoboot.powerframework.time.moment.ZonedDateTime; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Period { + + private static Duration getDuration(UniversalDateTime startUniversalDateTime, + UniversalDateTime endUniversalDateTime) { + java.time.LocalDateTime javaStartLocalDateTime = startUniversalDateTime.removeUniversalTimeZone().toJavaLocalDateTime(); + java.time.LocalDateTime javaEndLocalDateTime = endUniversalDateTime.removeUniversalTimeZone().toJavaLocalDateTime(); + java.time.Duration javaDuration = java.time.Duration.between(javaStartLocalDateTime, javaEndLocalDateTime); + return new Duration(javaDuration.toMillis()); + } + + private final UniversalDateTime startUniversalDateTime; + private final UniversalDateTime endUniversalDateTime; + private final ZonedDateTime startZonedDateTime; + private final ZonedDateTime endZonedDateTime; + private final Duration duration; + + /** + * + * @param startUniversalDateTime UniversalDateTime instance + * @param endUniversalDateTime UniversalDateTime instance + */ + public Period(UniversalDateTime startUniversalDateTime, + UniversalDateTime endUniversalDateTime) { + this.startUniversalDateTime = startUniversalDateTime; + this.endUniversalDateTime = endUniversalDateTime; + this.startZonedDateTime = null; + this.endZonedDateTime = null; + this.duration = getDuration(startUniversalDateTime, endUniversalDateTime); + } + + /** + * + * @param startZonedDateTime + * @param endZonedDateTime + */ + public Period(ZonedDateTime startZonedDateTime, + ZonedDateTime endZonedDateTime) { + this.startUniversalDateTime = null; + this.endUniversalDateTime = null; + this.startZonedDateTime = startZonedDateTime; + this.endZonedDateTime = endZonedDateTime; + this.duration = getDuration(startZonedDateTime.toUniversalDateTime(), endZonedDateTime.toUniversalDateTime()); + } + + /** + * + * @param startUniversalDateTime UniversalDateTime instance + * @param plusDuration Duration to add + */ + public Period(UniversalDateTime startUniversalDateTime, + Duration plusDuration) { + this.startUniversalDateTime = startUniversalDateTime; + + java.time.LocalDateTime javaStartLocalDateTime = startUniversalDateTime.removeUniversalTimeZone().toJavaLocalDateTime(); + this.endUniversalDateTime = new UniversalDateTime(LocalDateTime.toPowerLocalDateTime(javaStartLocalDateTime.plusNanos((long) plusDuration.toTotal(TimeUnit.MILLISECOND) * 1000000))); + + this.startZonedDateTime = null; + this.endZonedDateTime = null; + + this.duration = getDuration(startUniversalDateTime, endUniversalDateTime); + } + + /** + * + * @param startZonedDateTime ZonedDateTime instance + * @param plusDuration Duration instance to add + */ + public Period(ZonedDateTime startZonedDateTime, + Duration plusDuration) { + this.startUniversalDateTime = null; + this.endUniversalDateTime = null; + + this.startZonedDateTime = startZonedDateTime; + + java.time.LocalDateTime javaStartLocalDateTime = startUniversalDateTime.removeUniversalTimeZone().toJavaLocalDateTime(); + this.endZonedDateTime = new UniversalDateTime(LocalDateTime.toPowerLocalDateTime(javaStartLocalDateTime.plusNanos((long) plusDuration.toTotal(TimeUnit.MILLISECOND) * 1000000))).convertToZonedDateTimeWithUniversalTimeZone(); + + this.duration = getDuration(startZonedDateTime.toUniversalDateTime(), endZonedDateTime.toUniversalDateTime()); + } + + /** + * + * @return Duration instance counted of this period + */ + public Duration getDuration() { + return duration; + } + + /** + * + * @return true, if this period uses universalDateTime, otherwise false + */ + public boolean usesUniversalTime() { + return startUniversalDateTime != null; + } + + /** + * + * @return true, if this period uses zonedDateTime, otherwise false + */ + public boolean usesZonedTime() { + return startZonedDateTime != null; + } + + /** + * + * @return UniversalDateTime instance + */ + public UniversalDateTime getStartUniversalDateTime() { + if(startUniversalDateTime == null) { + throw new TimeException("This period has no start universal date time."); + } + return startUniversalDateTime; + } + + /** + * + * @return UniversalDateTime instance + */ + public UniversalDateTime getEndUniversalDateTime() { + if(endUniversalDateTime == null) { + throw new TimeException("This period has no start universal date time."); + } + return endUniversalDateTime; + } + + /** + * + * @return ZonedDateTime instance + */ + public ZonedDateTime getStartZonedDateTime() { + if(startZonedDateTime == null) { + new TimeException("This period has no start universal date time."); + } + return startZonedDateTime; + } + + /** + * + * @return ZonedDateTime instance + */ + public ZonedDateTime getEndZonedDateTime() { + if(endZonedDateTime == null) { + new TimeException("This period has no start universal date time."); + } + return endZonedDateTime; + } +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/duration/SimpleStopWatch.java b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/SimpleStopWatch.java new file mode 100644 index 0000000..16d914e --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/SimpleStopWatch.java @@ -0,0 +1,141 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; +//TODO: Simple stop watch- Power- if running multiple times- there is an error - it is thrown - StopWatch was already started- to be fixed + +import org.nanoboot.powerframework.time.utils.TimeException; + + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class SimpleStopWatch { + + final static long MILLISECONDHASNANOSECONDS = 1000000; + final static long SECONDHASMILLISECONDS = 1000; + final static long MINUTEHASSECONDS = 60; + final static long MINUTEHASMILLISECONDS = MINUTEHASSECONDS * SECONDHASMILLISECONDS; + + private long timeStart; + private long timeEnd; + + private long totalNanoseconds; + + private long totalMilliseconds; + private long runningTimeInMinutes; + private long runningTimeInSeconds; + private long runningTimeInMilliseconds; + + private boolean started = false; + private boolean stopped = false; + + public SimpleStopWatch() { + + } + + public void start() { + if(this.started) { + throw new TimeException("The stop watch was already started."); + } + this.timeStart = System.nanoTime(); + this.started = true; + } + + public void stop() { + if(!this.started) { + throw new TimeException("The stop watch was not started."); + } + + if(this.stopped) { + throw new TimeException("The stop watch was already stopped."); + } + + this.timeEnd = System.nanoTime(); + this.stopped = true; + this.computeTime(); + } + + private void computeTime() { + + this.throwExceptionIfWasNotStopped(); + + this.totalNanoseconds = this.timeEnd - this.timeStart; + this.totalMilliseconds = this.totalNanoseconds / MILLISECONDHASNANOSECONDS; + + long remainingMilliseconds = this.totalMilliseconds; + + this.runningTimeInMinutes = remainingMilliseconds / MINUTEHASMILLISECONDS; + remainingMilliseconds = remainingMilliseconds - (this.runningTimeInMinutes * MINUTEHASMILLISECONDS); + + this.runningTimeInSeconds = remainingMilliseconds / SECONDHASMILLISECONDS; + remainingMilliseconds = remainingMilliseconds - (this.runningTimeInSeconds * SECONDHASMILLISECONDS); + + this.runningTimeInMilliseconds = remainingMilliseconds; + + } + + public boolean isStarted() { + return this.started; + } + + public boolean isStopped() { + return this.stopped; + } + + public long getTotalNanoseconds() { + this.throwExceptionIfWasNotStopped(); + return this.totalNanoseconds; + } + + public long getTotalMilliseconds() { + this.throwExceptionIfWasNotStopped(); + return this.totalMilliseconds; + } + + public long getRunningTimeInMinutes() { + this.throwExceptionIfWasNotStopped(); + return this.runningTimeInMinutes; + } + + public long getRunningTimeInSeconds() { + this.throwExceptionIfWasNotStopped(); + return this.runningTimeInSeconds; + } + + public long getRunningTimeInMilliseconds() { + this.throwExceptionIfWasNotStopped(); + return this.runningTimeInMilliseconds; + } + + public String createMessage() { + this.throwExceptionIfWasNotStopped(); + return "The running time was " + this.runningTimeInMinutes + " minutes, " + this.runningTimeInSeconds + " seconds and " + this.runningTimeInMilliseconds + " milliseconds (" + this.totalNanoseconds + " nanoseconds in total)."; + } + + private void throwExceptionIfWasNotStopped() { + if(!this.stopped) { + throw new TimeException("The stop watch was not stopped."); + } + } + +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatch.java b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatch.java new file mode 100644 index 0000000..f20f452 --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatch.java @@ -0,0 +1,128 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; + +import org.nanoboot.powerframework.time.utils.TimeException; +import org.nanoboot.powerframework.time.utils.TimeUnit; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class StopWatch { + + private static final int NANOSECONDHASMILlISECONDS = 1000000; + + private static long convertNanosecondsToMilliSeconds(long nanoseconds) { + return nanoseconds / NANOSECONDHASMILlISECONDS; + } + private Duration currentDuration = Duration.getZeroDuration(); + private StopWatchState stopWatchState = StopWatchState.CLEAR; + + private long startFlag = 0; + private long endFlag = 0; + + /** + * + * @return + */ + public StopWatchState getStopWatchState() { + return this.stopWatchState; + } + + /** + * + */ + public void clear() { + this.stopWatchState = StopWatchState.CLEAR; + this.currentDuration = Duration.getZeroDuration(); + } + + /** + * + */ + public void start() { + if(this.stopWatchState == StopWatchState.RUNNING) { + return; + } + startFlag = this.getCurrentFlagInNanoseconds(); + stopWatchState = StopWatchState.RUNNING; + } + + /** + * + */ + public void stop() { + if(this.stopWatchState == StopWatchState.RUNNING) { + endFlag = this.getCurrentFlagInNanoseconds(); + this.currentDuration = this.currentDuration.plus(getElapsedTimeInMillisecondsFromFlags(), TimeUnit.MILLISECOND); + startFlag = 0; + endFlag = 0; + this.stopWatchState = StopWatchState.STOPPED; + } + } + + private long getElapsedTimeInMillisecondsFromFlags() { + return StopWatch.convertNanosecondsToMilliSeconds(endFlag - startFlag); + } + + /** + * + * @return + */ + public Duration getCurrentDuration() { + if(this.stopWatchState == StopWatchState.RUNNING) { + throw new TimeException("Can't get the duration, becuae the StopWatch is running. Stop StopWatch before getting duration"); + } + + return this.currentDuration; + } + + private long getCurrentFlagInNanoseconds() { + return System.nanoTime(); + } + + /** + * + * @return + */ + public boolean isClear() { + return this.stopWatchState == StopWatchState.CLEAR; + } + + /** + * + * @return + */ + public boolean isRunning() { + return this.stopWatchState == StopWatchState.RUNNING; + } + + /** + * + * @return + */ + public boolean isStopped() { + return this.stopWatchState == StopWatchState.STOPPED; + } +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatchState.java b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatchState.java new file mode 100644 index 0000000..840fbf2 --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/duration/StopWatchState.java @@ -0,0 +1,45 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum StopWatchState { + + /** + * + */ + CLEAR, + + /** + * + */ + RUNNING, + + /** + * + */ + STOPPED; +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/module-info.java.txt b/power-time/src/main/java/org/nanoboot/powerframework/time/module-info.java.txt new file mode 100644 index 0000000..e316d2c --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/module-info.java.txt @@ -0,0 +1,7 @@ +module powerframework.datetime { +requires powerframework.json; +requires powerframework.pseudorandom; +exports powerframework.datetime.elapsed; +exports powerframework.datetime.moment; +exports powerframework.datetime.utilities; +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/moment/DateTime.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/DateTime.java new file mode 100644 index 0000000..913193d --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/DateTime.java @@ -0,0 +1,261 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.moment; + +import org.nanoboot.powerframework.time.utils.TimeException; + +/** + * This class represents date and time and is immutable. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public abstract class DateTime implements Comparable { + + private final LocalDate date; + private final LocalTime time; + + /** + * Constructor + *

+ * Sets all values. + * + * @param localDate Represents a date. + * @param localTime Represents a time. + */ + DateTime(LocalDate localDate, + LocalTime localTime) { + this.date = localDate; + this.time = localTime; + } + + /** + * Constructor + *

+ * Sets all values. + * + * @param year Represents a year. + * @param month Represents a month. + * @param day Represents a day. + * @param hour24Format Represents an hour. + * @param minute Represents a minute + * @param second Represents a second. + * @param millisecond Represents a millisecond. + */ + DateTime(int year, + int month, + int day, + int hour24Format, + int minute, + int second, + int millisecond) { + this.date = new LocalDate(year, month, day); + this.time = new LocalTime(hour24Format, minute, second, millisecond); + } + + /** + * Constructor + *

+ * Sets all values from another object. + * + * @param dateTimeIn instance of a object extending the DateTime class, which values of this object will be set from + */ + protected DateTime(DateTime dateTimeIn) { + int year = dateTimeIn.getYear(); + int month = dateTimeIn.getMonth(); + int day = dateTimeIn.getDay(); + date = new LocalDate(year, month, day); + + int hour24Format = dateTimeIn.getHour(); + int minute = dateTimeIn.getMinute(); + int second = dateTimeIn.getSecond(); + int millisecond = dateTimeIn.getMillisecond(); + time = new LocalTime(hour24Format, minute, second, millisecond); + } + + /** + * Constructor + *

+ * Sets all values from String + * + * @param dateTimeInString This String has following format: 2016-12-31 + * 24:45:14:453 yyyy-MM-dd HH:mm:ss:SSS + */ + public DateTime(String dateTimeInString) { + String[] array=dateTimeInString.split(" "); + if(array.length!= 2){ + throw new TimeException("Wrong Date Time format: " + dateTimeInString); + } + date = new LocalDate(array[0]); + + time = new LocalTime(array[1]); + } + /** + * Constructor + *

+ * Sets all values from String + * + * @param dateTimeInString This String has following format: 2016-12-31 + * 24:45:14:453 yyyy-MM-dd HH:mm:ss:SSS + */ + public DateTime(long dateTimeAsLong) { + String str = String.valueOf(dateTimeAsLong); + + if(str.length()!= 17){ + throw new TimeException("Wrong Date Time format: " + dateTimeAsLong); + } + String year = str.substring(0,4); + String month = str.substring(4,6); + String day = str.substring(6,8); + String hour = str.substring(8,10); + String minute = str.substring(10,12); + String second = str.substring(12,14); + String millisecond = str.substring(14,17); + + int yearInt = Integer.valueOf(year); + int monthInt = Integer.valueOf(month); + int dayInt = Integer.valueOf(day); + int hourInt = Integer.valueOf(hour); + int minuteInt = Integer.valueOf(minute); + int secondInt = Integer.valueOf(second); + int millisecondInt = Integer.valueOf(millisecond); + + date = new LocalDate(yearInt, monthInt, dayInt); + + time = new LocalTime(hourInt, minuteInt, secondInt, millisecondInt); + } + + /** + * @return year + */ + public int getYear() { + return this.date.getYear(); + } + + /** + * @return month + */ + public int getMonth() { + return this.date.getMonth(); + } + + /** + * @return day + */ + public int getDay() { + return this.date.getDay(); + } + + /** + * @return hour + */ + public int getHour() { + return this.time.getHour(); + } + + /** + * @return minute + */ + public int getMinute() { + return this.time.getMinute(); + } + + /** + * @return second + */ + public int getSecond() { + return this.time.getSecond(); + } + + /** + * @return millisecond + */ + public int getMillisecond() { + return this.time.getMillisecond(); + } + /** + * @return date + */ + public LocalDate getDate() { + return this.date; + } + + /** + * @return time + */ + public LocalTime getTime() { + return this.time; + } + + @Override + public String toString() { + StringBuilder stringBuffer = new StringBuilder(); + stringBuffer.append(this.date.toString()); + stringBuffer.append(" "); + stringBuffer.append(this.time.toString()); + + return stringBuffer.toString(); + } + + public long toLong() { + StringBuilder sb = new StringBuilder(); + sb.append(getYear()); + + if (getMonth() < 10) { + sb.append("0"); + } + sb.append(getMonth()); + + if (getDay() < 10) { + sb.append("0"); + } + sb.append(getDay()); + + if (getHour() < 10) { + sb.append("0"); + } + sb.append(getHour()); + + if (getMinute() < 10) { + sb.append("0"); + } + sb.append(getMinute()); + + if (getSecond() < 10) { + sb.append("0"); + } + sb.append(getSecond()); + + if (getMillisecond() < 100) { + sb.append("0"); + } + if (getMillisecond() < 10) { + sb.append("0"); + } + sb.append(getMillisecond()); + + return Long.valueOf(sb.toString()); + } + + public int compareTo(DateTime otherDateTime) { + return Long.valueOf(toLong()).compareTo(Long.valueOf(otherDateTime.toLong())); + } +} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/LocalDate.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDate.java similarity index 52% rename from src/main/java/org/nanoboot/powerframework/datetime/LocalDate.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDate.java index 02fdd47..e304580 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/LocalDate.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDate.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,16 +18,63 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.time.moment; -import org.nanoboot.powerframework.PowerRuntimeException; +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.time.utils.DateUnitsValidator; +import org.nanoboot.powerframework.time.utils.TimeException; +import org.nanoboot.powerframework.utils.StringUtils; /** * Represents Date without time zone information. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokáč e-mail: robertvokac@nanoboot.org */ -public final class LocalDate { +public final class LocalDate { + + private static final String DASH = "-"; + public static final int LOCAL_DATE_AS_STRING_LENGTH = 10; + + /** + * + * @param s with format yyyy-MM-dd + */ + public LocalDate(String s) { + if (s == null) { + throw new TimeException("Local date as string is null."); + } + if (s.length() != LOCAL_DATE_AS_STRING_LENGTH) { + throw new TimeException("Local date length is " + s.length() + ", but length 10 is expected."); + } + int year = Integer.parseInt(s.substring(0, 4)); + int month = Integer.parseInt(s.substring(5, 7)); + int day = Integer.parseInt(s.substring(8, 10)); + + DateUnitsValidator.validate(year, month, day); + this.year = year; + this.month = month; + this.day = day; + } + + /** + * Checks if year is leap. A year is leap if this year is divided by 4 and + * there remainder 0. In other words this year is divisible by 4. + * + * @param year value + * + * @return true if the year is leap, otherwise false. + */ + public static boolean isYearLeap(int year) { + return (year % 4) == 0; + } + + private final int year; private final int month; @@ -39,55 +86,17 @@ public final class LocalDate { * @param year Year of this date. * @param month Month of this date. * @param day Day of this date. - * @exception PowerRuntimeException if parameters are invalid or have wrong + * + * @throws PowerException if parameters are invalid or have wrong * combination. */ public LocalDate(int year, int month, int day) { - LocalDate.checkInputValuesForDateAndIfThereIsAnInvalidOneThrowException(year, month, day); + DateUnitsValidator.validate(year, month, day); this.year = year; this.month = month; this.day = day; } - /** - * Checks input data for date. - * - * @param year - * @param month - * @param day - * @exception PowerRuntimeException if input data for date are invalid or - * have wrong combination.
- * This will throw PowerRuntimeException: - * {@code new LocalDateTime(2015,2,29)}
- * This will throw PowerRuntimeException: - * {@code new LocalDateTime(2013,6,31)}
- * This will not throw PowerRuntimeException: - * {@code new LocalDateTime(2013,6,30)}
- */ - private static void checkInputValuesForDateAndIfThereIsAnInvalidOneThrowException(int year, int month, int day) { - if (!DateUnitsValidator.isMonthValid(month)) { - throw new PowerRuntimeException("Month is not valid."); - } - if (!DateUnitsValidator.isDayValid(day)) { - throw new PowerRuntimeException("Day is not valid."); - } - if (!DateUnitsValidator.hasDateValidCombination(year, month, day)) { - throw new PowerRuntimeException("Date has not valid combination."); - - } - } - - /** - * Checks if year is leap. A year is leap if this year is divided by 4 and - * there remainder 0. In other words this year is divisible by 4. - * - * @param year - * @return true if the year is leap, otherwise false. - */ - public static boolean isYearLeap(int year) { - return (year % 4) == 0; - } - /** * * @return year of this date. @@ -114,19 +123,8 @@ public final class LocalDate { @Override public String toString() { - StringBuilder stringBuilder; - stringBuilder = new StringBuilder(); - stringBuilder.append(this.getYear()); - stringBuilder.append("-"); - if (month < 10) { - stringBuilder.append("0"); - } - stringBuilder.append(this.getMonth()); - stringBuilder.append("-"); - if (day < 10) { - stringBuilder.append("0"); - } - stringBuilder.append(this.getDay()); - return stringBuilder.toString(); + return StringUtils.appendObjects(getYear(), DASH, month < 10 ? "0" : "", getMonth(), DASH, day < 10 ? "0" : "", getDay()); } + + } diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDateTime.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDateTime.java new file mode 100644 index 0000000..7955138 --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalDateTime.java @@ -0,0 +1,167 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.moment; + +import java.time.format.DateTimeFormatter; + +/** + * This class stores date time without time zone information. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class LocalDateTime extends DateTime { + + /** + * + * @param universalDateTime UniversalDateTime instance + * + * @return LocalDateTime instance + */ + public static LocalDateTime removeUniversalTimeZone(UniversalDateTime universalDateTime) { + return new LocalDateTime(universalDateTime); + } + + /** + * + * @param zonedDateTime ZonedDateTime instance + * + * @return LocalDateTime instance + */ + public static LocalDateTime removeTimeZone(ZonedDateTime zonedDateTime) { + return new LocalDateTime(zonedDateTime); + } + + /** + * + * + * @param ldt java.time.LocalDateTime instance + * + * @return a java.time.LocalDateTime instance from this object + */ + public static LocalDateTime toPowerLocalDateTime(java.time.LocalDateTime ldt) { + return new LocalDateTime(ldt.getYear(), ldt.getDayOfMonth(), ldt.getDayOfMonth(), ldt.getHour(), ldt.getMinute(), ldt.getSecond(), ldt.getSecond()); + } + + /** + * Constructor + * + * Creates new LocalDateTime from String. + * + * @param dateTimeInString string representing the new LocalDateTime + */ + public LocalDateTime(final String dateTimeInString) { + super(dateTimeInString); + } + + /** + * Constructor + * + * Creates new LocalDateTime with these parameters. + * + * @param date date + * @param time time + */ + public LocalDateTime(final LocalDate date, final LocalTime time) { + super(date.getYear(), date.getMonth(), date.getDay(), + time.getHour(), time.getMinute(), time.getSecond(), + time.getMillisecond()); + } + /** + * Constructor + * + * Creates new LocalDateTime with these parameters. + * + * @param year value + * @param month value + * @param day value + * @param hour24Format value + * @param minute value + * @param second value + * @param millisecond value + */ + public LocalDateTime(int year, + int month, + int day, + int hour24Format, + int minute, + int second, + int millisecond) { + super(year, month, day, hour24Format, minute, second, millisecond); + } + + /** + * Constructor + * + * Creates new LocalDateTime from UniversalDateTime. + * + * @param universalDateTime UniversalDateTime instance + */ + private LocalDateTime(UniversalDateTime universalDateTime) { + super(universalDateTime); + } + + /** + * Constructor + * + * Creates new LocalDateTime from ZonedDateTime. The time zone information + * is lost. + * + * @param zonedDateTime ZonedDateTime instance + */ + private LocalDateTime(ZonedDateTime zonedDateTime) { + super(zonedDateTime); + } + + /** + * Adds the universal time zone information to this local date time and + * return new instance. + * + * @return a UniversalDateTime instance from this object. + */ + public UniversalDateTime addUniversalTimeZoneInformation() { + return UniversalDateTime.addUniversalTimeZoneInformation(this); + } + + /** + * Adds the time zone information to this local date time and return new + * instance. + * + * @param timeZone time zone of new created ZonedDateTime + * + * @return a ZonedDateTime instance from this object + */ + public ZonedDateTime addTimeZone(TimeZone timeZone) { + return ZonedDateTime.joinLocalDateTimeAndTimeZone(this, timeZone); + } + + /** + * + * + * @return a java.time.LocalDateTime instance from this object + */ + public java.time.LocalDateTime toJavaLocalDateTime() { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"); + String stringRepresentationOfThisObject = this.toString(); + return java.time.LocalDateTime.parse(stringRepresentationOfThisObject, dateTimeFormatter); + } + +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalTime.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalTime.java new file mode 100644 index 0000000..d2255ba --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/LocalTime.java @@ -0,0 +1,138 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.moment; + +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.time.utils.TimeException; +import org.nanoboot.powerframework.time.utils.TimeUnitsValidator; +import lombok.Getter; + +/** + * Represents Time without date and time zone information. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class LocalTime { + + private static final String COLON = ":"; + public static final int LOCAL_TIME_AS_STRING_LENGTH = 12; + + @Getter + private final int hour; + @Getter + private final int minute; + @Getter + private final int second; + @Getter + private final int millisecond; + + /** + * Constructor. + * Millisecond is automatically set to 0. + * + * @param hour hour value + * @param minute minute value + * @param second second value + * + * @throws PowerException if parameters are invalid. + */ + public LocalTime(int hour, + int minute, + int second) { + this(hour, minute, second, 0); + } + /** + * Constructor + * + * @param hour hour value + * @param minute minute value + * @param second second value + * @param millisecond millisecond value + * + * @throws PowerException if parameters are invalid. + */ + public LocalTime(int hour, + int minute, + int second, + int millisecond) { + TimeUnitsValidator.validate(hour, minute, second, millisecond); + this.hour = hour; + this.minute = minute; + this.second = second; + this.millisecond = millisecond; + } + + /** + * + * @param s with format HH:mm:ss:SSS + */ + public LocalTime(String s) { + if (s == null) { + throw new TimeException("Local time as string is null."); + } + if (s.length() != LOCAL_TIME_AS_STRING_LENGTH) { + throw new TimeException("Local time length is " + s.length() + ", but length 12 is expected."); + } + int hour = Integer.parseInt(s.substring(0, 2)); + int minute = Integer.parseInt(s.substring(3, 5)); + int second = Integer.parseInt(s.substring(6, 8)); + int millisecond = Integer.parseInt(s.substring(9, 12)); + TimeUnitsValidator.validate(hour, minute, second, millisecond); + this.hour = hour; + this.minute = minute; + this.second = second; + this.millisecond = millisecond; + } + + /* + * Converts this time to format HH:MM:SS::MIS + */ + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + + if(hour < 10) { + stringBuilder.append("0"); + } + stringBuilder.append(this.getHour()); + stringBuilder.append(COLON); + if(minute < 10) { + stringBuilder.append("0"); + } + stringBuilder.append(this.getMinute()); + stringBuilder.append(COLON); + if(second < 10) { + stringBuilder.append("0"); + } + stringBuilder.append(this.getSecond()); + stringBuilder.append(COLON); + if(millisecond < 10) { + stringBuilder.append("00"); + } else if(millisecond < 100) { + stringBuilder.append("0"); + } + stringBuilder.append(this.getMillisecond()); + return stringBuilder.toString(); + } + + +} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/TimeZone.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/TimeZone.java similarity index 80% rename from src/main/java/org/nanoboot/powerframework/datetime/TimeZone.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/moment/TimeZone.java index cbf4cf2..194cfb2 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/TimeZone.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/TimeZone.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,39 +18,23 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import org.nanoboot.powerframework.PowerRuntimeException; +import java.time.*; +import java.util.*; +import org.nanoboot.powerframework.time.utils.TimeException; /** * Represents time zone. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ public class TimeZone { private static final ArrayList listOfTimeZones = new ArrayList<>(ZoneId.getAvailableZoneIds()); - private final String timeZoneID; - - /** - * Constructor - * - * Only time zone with valid timeZoneID can be created. - * - * @param timeZoneID - */ - public TimeZone(String timeZoneID) { - if (!TimeZone.isTimeZoneIDValid(timeZoneID)) { - throw new PowerRuntimeException("There is no time zone id with the name " + timeZoneID + "."); - } - this.timeZoneID = timeZoneID; - } - static { Collections.sort(listOfTimeZones); } @@ -60,17 +44,33 @@ public class TimeZone { * @return list of all available time zone IDs */ public static List getListOfTimeZoneIDs() { - return listOfTimeZones; + return Collections.unmodifiableList(listOfTimeZones); } /** * * @param timeZoneID + * * @return true if the timeZoneID is valid (available), otherwise false. */ public static boolean isTimeZoneIDValid(String timeZoneID) { return listOfTimeZones.contains(timeZoneID); } + private final String timeZoneID; + + /** + * Constructor + * + * Only time zone with valid timeZoneID can be created. + * + * @param timeZoneID + */ + public TimeZone(String timeZoneID) { + if(!TimeZone.isTimeZoneIDValid(timeZoneID)) { + throw new TimeException("There is no time zone id with the name " + timeZoneID + "."); + } + this.timeZoneID = timeZoneID; + } /** * diff --git a/src/main/java/org/nanoboot/powerframework/datetime/UniversalDateTime.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/UniversalDateTime.java similarity index 50% rename from src/main/java/org/nanoboot/powerframework/datetime/UniversalDateTime.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/moment/UniversalDateTime.java index a9985a9..f026a20 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/UniversalDateTime.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/UniversalDateTime.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,17 +18,57 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; -import org.nanoboot.powerframework.pseudorandom.PseudoRandomGenerator; +import org.nanoboot.powerframework.random.generators.RandomGenerator; +import org.nanoboot.powerframework.time.TimeSource; +import org.nanoboot.powerframework.time.utils.DateUnitsValidator; +import org.nanoboot.powerframework.time.duration.Duration; +import org.nanoboot.powerframework.time.duration.Period; /** * This class stores universal date time. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public final class UniversalDateTime extends DateTime { + static UniversalDateTime addUniversalTimeZoneInformation( + LocalDateTime localDateTime) { + return new UniversalDateTime(localDateTime); + } + + /** + * + * @return current universal date time + */ + public static UniversalDateTime now() { + return TimeSource.getCurrentUniversalDateTimeInstance(); + } + + /** + * + * @return random universal date time + */ + public static UniversalDateTime random() { + UniversalDateTime universalDateTime; + int maxPossibleYear = UniversalDateTime.now().getYear(); + RandomGenerator randomGenerator = RandomGenerator.getDefaultImplStatic(); + int randomYear = randomGenerator.nextInt(1900, maxPossibleYear); + int randomMonth = randomGenerator.nextInt(1, 12); + int randomDay = randomGenerator.nextInt(1, 31); + int randomHour = randomGenerator.nextInt(0, 23); + int randomMinute = randomGenerator.nextInt(0, 59); + int randomSecond = randomGenerator.nextInt(0, 59); + int randomMillisecond = randomGenerator.nextInt(0, 999); + if(!DateUnitsValidator.hasDateValidCombination(randomYear, randomMonth, randomDay)) { + randomDay -= randomGenerator.nextInt(3, 20); + } + universalDateTime = new UniversalDateTime(randomYear, randomMonth, randomDay, randomHour, randomMinute, randomSecond, randomMillisecond); + return universalDateTime; + } + /** * Constructor * @@ -53,7 +93,13 @@ public final class UniversalDateTime extends DateTime { * @param second * @param millisecond */ - public UniversalDateTime(int year, int month, int day, int hour24Format, int minute, int second, int millisecond) { + public UniversalDateTime(int year, + int month, + int day, + int hour24Format, + int minute, + int second, + int millisecond) { super(year, month, day, hour24Format, minute, second, millisecond); } @@ -64,7 +110,7 @@ public final class UniversalDateTime extends DateTime { * * @param zonedDateTime */ - public UniversalDateTime(ZonedDateTime zonedDateTime) { + private UniversalDateTime(ZonedDateTime zonedDateTime) { super(zonedDateTime.toUniversalDateTime()); } @@ -78,54 +124,46 @@ public final class UniversalDateTime extends DateTime { public UniversalDateTime(LocalDateTime localDateTime) { super(localDateTime); } - /** + * Constructor * - * @return current universal date time + * Creates new UniversalDateTime from long. + * + * @param udtAsLong */ - public static UniversalDateTime getCurrentUniversalDateTime() { - return TimeSource.getCurrentUniversalDateTimeInstance(); + public UniversalDateTime(long udtAsLong) { + super(udtAsLong); + } + + UniversalDateTime updateDateAndTimeToUniversalTimeZone( + ZonedDateTime zonedDateTime) { + return new UniversalDateTime(zonedDateTime); } /** * - * @return random universal date time + * @param duration + * + * @return */ - public static UniversalDateTime getRandomUniversalDateTime() { - UniversalDateTime universalDateTime; - - int maxPossibleYear = UniversalDateTime.getCurrentUniversalDateTime().getYear(); - - int randomYear = PseudoRandomGenerator.getInstance().getInt(1900, maxPossibleYear); - int randomMonth = PseudoRandomGenerator.getInstance().getInt(1, 12); - int randomDay = PseudoRandomGenerator.getInstance().getInt(1, 31); - - int randomHour = PseudoRandomGenerator.getInstance().getInt(0, 23); - int randomMinute = PseudoRandomGenerator.getInstance().getInt(0, 59); - int randomSecond = PseudoRandomGenerator.getInstance().getInt(0, 59); - int randomMillisecond = PseudoRandomGenerator.getInstance().getInt(0, 999); - - if (!DateUnitsValidator.hasDateValidCombination(randomYear, randomMonth, randomDay)) { - randomDay = randomDay - PseudoRandomGenerator.getInstance().getInt(3, 20); - } - - universalDateTime = new UniversalDateTime(randomYear, randomMonth, randomDay, randomHour, randomMinute, randomSecond, randomMillisecond); - - return universalDateTime; + public UniversalDateTime plusDuration(Duration duration) { + return new Period(this, duration).getEndUniversalDateTime(); } /** - * @return a ZonedDateTime instance from this object + * + * @return */ - public ZonedDateTime toZonedDateTime() { - return new ZonedDateTime(this); + public ZonedDateTime convertToZonedDateTimeWithUniversalTimeZone() { + return ZonedDateTime.updateDateAndTimeToUniversalDateTime(this); } /** - * @return a LocalDateTime instance from this object without universal date - * time information. + * + * @return */ - public LocalDateTime toLocalDateTime() { - return new LocalDateTime(this); + public LocalDateTime removeUniversalTimeZone() { + return LocalDateTime.removeUniversalTimeZone(this); } + } diff --git a/src/main/java/org/nanoboot/powerframework/datetime/ZonedDateTime.java b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/ZonedDateTime.java similarity index 71% rename from src/main/java/org/nanoboot/powerframework/datetime/ZonedDateTime.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/moment/ZonedDateTime.java index e83366a..2c183d6 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/ZonedDateTime.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/moment/ZonedDateTime.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,20 +18,70 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; import java.time.ZoneId; -import java.time.format.DateTimeFormatter; +import java.time.format.*; +import org.nanoboot.powerframework.time.duration.Duration; +import org.nanoboot.powerframework.time.duration.Period; /** * Represents date and time with time zone information. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public final class ZonedDateTime extends DateTime { private static final String DATETIMEFORMAT = "yyyy-MM-dd HH:mm:ss:SSS"; private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIMEFORMAT); + + /** + * + * @param timeZone + * + * @return + */ + public static ZonedDateTime getCurrentZonedDateTimeForTimeZone( + TimeZone timeZone) { + UniversalDateTime udt = UniversalDateTime.now(); + return udt.convertToZonedDateTimeWithUniversalTimeZone().toZonedDateTime(timeZone); + } + + static ZonedDateTime updateDateAndTimeToUniversalDateTime( + UniversalDateTime universalDateTime) { + return new ZonedDateTime(universalDateTime); + } + + static ZonedDateTime joinLocalDateTimeAndTimeZone( + LocalDateTime localDateTime, + TimeZone toTimeZone) { + return new ZonedDateTime(localDateTime, toTimeZone); + } + + /** + * + * @param dateTimeInString + * @param oldTimeZone + * @param newTimeZone + * + * @return String representation from the given String, but old time zone is + * changed to new time zone. + */ + static String convertDateTimeFromOneTimeZoneToAnother( + String dateTimeInString, + TimeZone oldTimeZone, + TimeZone newTimeZone) { + + java.time.LocalDateTime localDateTime = java.time.LocalDateTime.parse(dateTimeInString, dateTimeFormatter); + + ZoneId oldZoneID = ZoneId.of(oldTimeZone.getTimeZoneID()); + java.time.ZonedDateTime oldZonedDateTime = localDateTime.atZone(oldZoneID); + + ZoneId newZoneId = ZoneId.of(newTimeZone.getTimeZoneID()); + java.time.ZonedDateTime newZonedDateTime = oldZonedDateTime.withZoneSameInstant(newZoneId); + return dateTimeFormatter.format(newZonedDateTime); + } /** * Instance of class UniversalDateTime for this ZonedDateTime. */ @@ -45,10 +95,10 @@ public final class ZonedDateTime extends DateTime { * * @param universalDateTime */ - public ZonedDateTime(UniversalDateTime universalDateTime) { + private ZonedDateTime(UniversalDateTime universalDateTime) { super(universalDateTime); - TimeZone timeZoneForUniversalTime = new org.nanoboot.powerframework.datetime.TimeZone("UTC"); + TimeZone timeZoneForUniversalTime = new TimeZone("UTC"); this.timeZone = timeZoneForUniversalTime; this.universalDateTime = universalDateTime; @@ -62,12 +112,13 @@ public final class ZonedDateTime extends DateTime { * @param localDateTime * @param toTimeZone */ - public ZonedDateTime(LocalDateTime localDateTime, org.nanoboot.powerframework.datetime.TimeZone toTimeZone) { + private ZonedDateTime(LocalDateTime localDateTime, + TimeZone toTimeZone) { super(localDateTime.getYear(), localDateTime.getMonth(), localDateTime.getDay(), localDateTime.getHour(), localDateTime.getMinute(), localDateTime.getSecond(), localDateTime.getMillisecond()); String stringRepresentationOfLocalDateTime = localDateTime.toString(); - TimeZone timeZoneForUniversalTime = new org.nanoboot.powerframework.datetime.TimeZone("UTC"); - String stringRepresentationOfZonedDateTimeWithUniversalTimeZone = org.nanoboot.powerframework.datetime.ZonedDateTime.convertDateTimeFromOneTimeZoneToAnother( + TimeZone timeZoneForUniversalTime = new TimeZone("UTC"); + String stringRepresentationOfZonedDateTimeWithUniversalTimeZone = ZonedDateTime.convertDateTimeFromOneTimeZoneToAnother( stringRepresentationOfLocalDateTime, toTimeZone, timeZoneForUniversalTime @@ -86,34 +137,14 @@ public final class ZonedDateTime extends DateTime { * @param zonedDateTime * @param newTimeZone */ - public ZonedDateTime(ZonedDateTime zonedDateTime, org.nanoboot.powerframework.datetime.TimeZone newTimeZone) { + public ZonedDateTime(ZonedDateTime zonedDateTime, + TimeZone newTimeZone) { super(ZonedDateTime.convertDateTimeFromOneTimeZoneToAnother(zonedDateTime.toString(), zonedDateTime.timeZone, newTimeZone)); this.universalDateTime = zonedDateTime.toUniversalDateTime(); this.timeZone = newTimeZone; } - /** - * - * @param dateTimeInString - * @param oldTimeZone - * @param newTimeZone - * - * @return String representation from the given String, but old time zone is - * changed to new time zone. - */ - static String convertDateTimeFromOneTimeZoneToAnother(String dateTimeInString, org.nanoboot.powerframework.datetime.TimeZone oldTimeZone, org.nanoboot.powerframework.datetime.TimeZone newTimeZone) { - - java.time.LocalDateTime localDateTime = java.time.LocalDateTime.parse(dateTimeInString, dateTimeFormatter); - - ZoneId oldZoneID = ZoneId.of(oldTimeZone.getTimeZoneID()); - java.time.ZonedDateTime oldZonedDateTime = localDateTime.atZone(oldZoneID); - - ZoneId newZoneId = ZoneId.of(newTimeZone.getTimeZoneID()); - java.time.ZonedDateTime newZonedDateTime = oldZonedDateTime.withZoneSameInstant(newZoneId); - return dateTimeFormatter.format(newZonedDateTime); - } - /** * * @return time zone of this ZonedDateTime @@ -122,6 +153,16 @@ public final class ZonedDateTime extends DateTime { return timeZone; } + /** + * + * @param duration + * + * @return + */ + public ZonedDateTime plusDuration(Duration duration) { + return new Period(this, duration).getEndZonedDateTime(); + } + /** * * @return a UniversalDateTime instance from this object @@ -135,16 +176,17 @@ public final class ZonedDateTime extends DateTime { * @return a LocalDateTime instance from this object */ public LocalDateTime toLocalDateTime() { - return new LocalDateTime(this); + return LocalDateTime.removeTimeZone(this); } /** * * @param newTimeZone + * * @return a ZonedDateTime instance from this object with the given new time * zone. */ - public ZonedDateTime toZonedDateTime(org.nanoboot.powerframework.datetime.TimeZone newTimeZone) { + public ZonedDateTime toZonedDateTime(TimeZone newTimeZone) { return new ZonedDateTime(this, newTimeZone); } diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/utils/AbstractValidator.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/AbstractValidator.java new file mode 100644 index 0000000..b7771be --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/AbstractValidator.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public abstract class AbstractValidator { + + static boolean isInBound(TimeUnit timeUnit, + int value) { + return (value >= timeUnit.getLowerBound()) && (value <= timeUnit.getHigherBound()); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/DateUnitsValidator.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/DateUnitsValidator.java similarity index 50% rename from src/main/java/org/nanoboot/powerframework/datetime/DateUnitsValidator.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/utils/DateUnitsValidator.java index 2f941d6..6efbc8e 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/DateUnitsValidator.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/DateUnitsValidator.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,17 +18,19 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.utils; import java.util.ArrayList; -import org.nanoboot.powerframework.PowerRuntimeException; +import org.nanoboot.powerframework.core.PowerException; +import org.nanoboot.powerframework.time.moment.LocalDate; /** * Validates date units. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -class DateUnitsValidator { +public class DateUnitsValidator extends AbstractValidator { private static final int MONTHLOWERBOUND = 1; private static final int MONTHHIGHERBOUND = 12; @@ -36,96 +38,136 @@ class DateUnitsValidator { private static final int DAYHIGHERBOUND = 31; private static final int MAXIMUMDAYFORFEBRUARYANDLEAPYEAR = 29; private static final int MAXIMUMDAYFORFEBRUARYANDNOTLEAPYEAR = 28; + private static final ArrayList LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31 = new ArrayList<>(); - /** - * Constructor + static { + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(1); + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(3); + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(5); + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(7); + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(8); + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(10); + LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.add(12); + } + + + /* + * Checks input data for date. * - * Not meant to be instantiated. + * @param year + * @param month + * @param day + * @exception PowerRuntimeException if input data for date are invalid or + * have wrong combination.
+ * This will throw PowerRuntimeException: + * {@code new LocalDateTime(2015,2,29)}
+ * This will throw PowerRuntimeException: + * {@code new LocalDateTime(2013,6,31)}
+ * This will not throw PowerRuntimeException: + * {@code new LocalDateTime(2013,6,30)}
*/ - private DateUnitsValidator() { + /** + * + * @param year year value + * @param month month value + * @param day day value + */ + public static void validate(int year, + int month, + int day) { + if(!DateUnitsValidator.isMonthValid(month)) { + throw new TimeException("Month " + month + " is not valid."); + } + if(!DateUnitsValidator.isDayValid(day)) { + throw new TimeException("Day " + day + " is not valid."); + } + if(!DateUnitsValidator.hasDateValidCombination(year, month, day)) { + throw new TimeException("Date has not valid combination."); + + } } /** * Checks if month has valid format. * - * @param month + * @param month 1 to 12 + * * @return Result of this control. */ static boolean isMonthValid(int month) { - return (month >= MONTHLOWERBOUND) && (month <= MONTHHIGHERBOUND); + return DateUnitsValidator.isInBound(TimeUnit.MONTH, month); } /** * Checks if day is not more than the highest possible one- 31. * - * @param day + * @param day 1 to 31 + * * @return Result of this control. */ static boolean isDayValid(int day) { - return (day >= DAYLOWERBOUND) && (day <= DAYHIGHERBOUND); + return DateUnitsValidator.isInBound(TimeUnit.DAY, day); } /** * Checks if date has valid combination. * - * @param year - * @param month - * @param day + * @param year year value + * @param month month value + * @param day day value * * @return true if the date combination is valid, otherwise false. */ - static boolean hasDateValidCombination(int year, int month, int day) { + public static boolean hasDateValidCombination(int year, int month, int day) { return day <= getMaximumDay(year, month); } /** * - * @param year - * @param month + * @param year year value + * @param month month value + * * @return maximum day for the given month in the given year. - * @exception PowerRuntimeException if month is out of range and is invalid. + * + * @throws PowerException if month is out of range and is invalid. */ - private static int getMaximumDay(int year, int month) {//NOSONAR - if (!isMonthValid(month)) { - throw new PowerRuntimeException("Month is not valid."); + private static int getMaximumDay(int year, + int month) {//NOSONAR + if(!isMonthValid(month)) { + throw new TimeException("Month is not valid."); } - if (hasMonth31Days(month)) { + if(hasMonth31Days(month)) { return 31; } - if (hasMonth30Days(month)) { + if(hasMonth30Days(month)) { return 30; } - if (hasMonth29Days(year, month)) { + if(hasMonth29Days(year, month)) { return MAXIMUMDAYFORFEBRUARYANDLEAPYEAR; } - if (hasMonth28Days(year, month)) { + if(hasMonth28Days(year, month)) { return MAXIMUMDAYFORFEBRUARYANDNOTLEAPYEAR; } - throw new PowerRuntimeException(year + " " + month + " " + "I am not able to find out the maximum day for the given year and month."); + throw new TimeException(year + " " + month + " " + "I am not able to find out the maximum day for the given year and month."); } /** * - * @param month + * @param month month value + * * @return true if the given month in the given year has 31 days, otherwise * false. */ private static boolean hasMonth31Days(int month) { - ArrayList monthWithMaximumDay31 = new ArrayList<>(); - monthWithMaximumDay31.add(1); - monthWithMaximumDay31.add(3); - monthWithMaximumDay31.add(5); - monthWithMaximumDay31.add(7); - monthWithMaximumDay31.add(8); - monthWithMaximumDay31.add(10); - monthWithMaximumDay31.add(12); - return monthWithMaximumDay31.contains(month); + + return LIST_OF_MONTH_HAVING_MAXIMUM_DAY_31.contains(month); } /** * - * @param month + * @param month month value + * * @return true if the given month in the given year has 30 days, otherwise * false. */ @@ -135,8 +177,9 @@ class DateUnitsValidator { /** * - * @param year - * @param month + * @param year year value + * @param month month value + * * @return true if the given month in the given year has 29 days, otherwise * false. */ @@ -146,8 +189,9 @@ class DateUnitsValidator { /** * - * @param year - * @param month + * @param year year value + * @param month month value + * * @return true if the given month in the given year has 28 days, otherwise * false. */ @@ -155,4 +199,11 @@ class DateUnitsValidator { return (month == 2) && (!LocalDate.isYearLeap(year)); } + /** + * Constructor + * + * Not meant to be instantiated. + */ + private DateUnitsValidator() { + } } diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/utils/LocalSettings.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/LocalSettings.java new file mode 100644 index 0000000..5b07e4d --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/LocalSettings.java @@ -0,0 +1,55 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; + +import org.nanoboot.powerframework.time.moment.TimeZone; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class LocalSettings { + + private static TimeZone timeZone = new TimeZone("UTC"); + + /** + * + * @param timeZoneIn TimeZone instance + */ + public static void setLocalTimeZone(TimeZone timeZoneIn) { + timeZone = timeZoneIn; + } + + /** + * + * @return TimeZone instance + */ + public static TimeZone getLocalTimeZone() { + return timeZone; + } + + private LocalSettings() { + } + +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/utils/RandomDateTimeUnitsGenerator.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/RandomDateTimeUnitsGenerator.java new file mode 100644 index 0000000..d473426 --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/RandomDateTimeUnitsGenerator.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +class RandomDateTimeUnitsGenerator { + +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/utils/RemainingTimeCalculator.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/RemainingTimeCalculator.java new file mode 100644 index 0000000..740f19a --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/RemainingTimeCalculator.java @@ -0,0 +1,68 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +class RemainingTimeCalculator { + private long startNanoTime = 0; + private long total; + private long done = 0; + + public RemainingTimeCalculator(final int total) { + this.total = total; + this.start(); + } + private void start() { + this.startNanoTime = System.nanoTime(); + } + + private boolean started() { + return this.startNanoTime != 0; + } + public long elapsedSecondSinceStart() { + return (System.nanoTime() - this.startNanoTime) / 1000000000; + } + + public void nextDone() { + this.done++; + if (this.done > this.total) { + System.err.println("done is greater than total: " + "done=" + this.done + ", total=" + this.total); + } + } + + public long remainingSecondsUntilEnd() { + long remains = this.total - this.done; + long remainsSeconds = (this.elapsedSecondSinceStart() / this.done) * remains; + return remainsSeconds; + } + + public long getDoneCount() { + return this.done; + } + + public String getMessage() { + return "Time elapsed: " + this.elapsedSecondSinceStart() + " seconds. Time left: " + this.remainingSecondsUntilEnd() + " seconds. Done: " + this.getDoneCount() + " tasks."; + } +} diff --git a/src/main/java/org/nanoboot/powerframework/PowerRuntimeException.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeException.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/PowerRuntimeException.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeException.java index d18127f..b18c8cc 100644 --- a/src/main/java/org/nanoboot/powerframework/PowerRuntimeException.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeException.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,21 +18,23 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework; +package org.nanoboot.powerframework.time.utils; + +import org.nanoboot.powerframework.core.PowerException; /** - * Exception for Power library + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class PowerRuntimeException extends RuntimeException { +public class TimeException extends PowerException { /** - * Constructor with message. * * @param message */ - public PowerRuntimeException(String message) { + public TimeException(String message) { super(message); } diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnit.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnit.java new file mode 100644 index 0000000..9954fba --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnit.java @@ -0,0 +1,203 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; + +import org.nanoboot.powerframework.random.generators.RandomGenerator; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum TimeUnit { + + /** + * + */ + YEAR("year", 1, Integer.MIN_VALUE, Integer.MAX_VALUE), + + /** + * + */ + MONTH("month", 2, 1, 12), + + /** + * + */ + DAY("day", 3, 1, 31), + + /** + * + */ + HOUR("hour", 4, 0, 23), + + /** + * + */ + MINUTE("minute", 5, 0, 59), + + /** + * + */ + SECOND("second", 6, 0, 59), + + /** + * + */ + MILLISECOND("millisecond", 7, 0, 999); + private final String description; + private final int asNumber; + private final int lowerBound; + private final int higherBound; + + /** + * + * @param timeUnitFrom + * @param timeUnitTo + * + * @return + */ + public static TimeUnit getRandom(TimeUnit timeUnitFrom, + TimeUnit timeUnitTo) { + RandomGenerator randomGenerator = RandomGenerator.getDefaultImplStatic(); + return TimeUnit.getFromNumber(randomGenerator.nextInt(timeUnitFrom.asNumber, timeUnitTo.asNumber)); + } + + TimeUnit(String description, + int asNumber, + int lowerBound, + int higherBound) { + this.description = description; + this.asNumber = asNumber; + this.lowerBound = lowerBound; + this.higherBound = higherBound; + } + + /** + * + * @return + */ + public String getDescription() { + return this.description; + } + + /** + * + * @return + */ + public TimeUnit getSmallerUnit() { + switch (this) { + case YEAR: + return MONTH; + case MONTH: + return DAY; + case DAY: + return HOUR; + case HOUR: + return MINUTE; + case MINUTE: + return SECOND; + case SECOND: + return MILLISECOND; + default: + throw new TimeException("Can't get smaller time unit."); + } + } + + /** + * + * @return + */ + public TimeUnit getBiggerUnit() { + switch (this) { + + case MONTH: + return YEAR; + case DAY: + return MONTH; + case HOUR: + return DAY; + case MINUTE: + return HOUR; + case SECOND: + return MINUTE; + case MILLISECOND: + return SECOND; + default: + throw new TimeException("Can't get bigger time unit."); + } + } + + /** + * + * @param asNumber + * + * @return + */ + public static TimeUnit getFromNumber(int asNumber) { + switch (asNumber) { + case 1: + return YEAR; + case 2: + return MONTH; + case 3: + return DAY; + case 4: + return HOUR; + case 5: + return MINUTE; + case 6: + return SECOND; + case 7: + return MILLISECOND; + default: + throw new TimeException("Can't get TimeUnit from number."); + } + } + + /** + * + * @return + */ + public int getLowerBound() { + return lowerBound; + } + + /** + * + * @return + */ + public int getHigherBound() { + return higherBound; + } + + /** + * + * @return + */ + public int getRandomValue() { + int from = this == YEAR ? 0 : this.lowerBound; + int to = this == YEAR ? 3000 : this.higherBound; + return RandomGenerator.getDefaultImplStatic().nextInt(from, to); + } + +} diff --git a/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitConvertor.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitConvertor.java new file mode 100644 index 0000000..26f4520 --- /dev/null +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitConvertor.java @@ -0,0 +1,96 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TimeUnitConvertor { + + private static final long DAYHASHOURS = 24; + private static final long HOURHASMINUTES = 60; + private static final long MINUTEHASSECONDS = 60; + private static final long SECONDHASMILLISECONDS = 1000; + + /** + * + * @param timeUnitFrom DAY,HOUR,MINUTE,SECOND,MILLISECOND + * @param timeUnitTo DAY,HOUR,MINUTE,SECOND,MILLISECOND umst be smaller than + * timeUnitFrom + * @param value + * + * @return + */ + public static long convert(long value, + TimeUnit timeUnitFrom, + TimeUnit timeUnitTo) { + + if(timeUnitFrom == timeUnitTo) { + return value; + } + + long returnValue = value; + + TimeUnit tempTimeUnit = timeUnitFrom; + + while (true) { + tempTimeUnit = tempTimeUnit.getSmallerUnit(); + if(tempTimeUnit != TimeUnit.DAY) { + returnValue *= TimeUnitConvertor.timeUnitHasSmallerTimeUnits(tempTimeUnit.getBiggerUnit()); + } + if(timeUnitTo == tempTimeUnit) { + return returnValue; + } + + if(timeUnitTo == TimeUnit.MILLISECOND && tempTimeUnit == timeUnitTo) { + break; + } + + } + + throw new TimeException("Can't convert value " + value + " " + " from unit " + timeUnitFrom + " to unit " + timeUnitTo); + } + + private static long timeUnitHasSmallerTimeUnits(TimeUnit timeUnit) { + switch (timeUnit) { + case DAY: + return DAYHASHOURS; + case HOUR: + return HOURHASMINUTES; + case MINUTE: + return MINUTEHASSECONDS; + case SECOND: + return SECONDHASMILLISECONDS; + } + throw new TimeException("Can't get smaller time units of time unit " + timeUnit.getDescription()); + } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private TimeUnitConvertor() { + } +} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/TimeUnitsValidator.java b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidator.java similarity index 51% rename from src/main/java/org/nanoboot/powerframework/datetime/TimeUnitsValidator.java rename to power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidator.java index 44f03b7..3b3628b 100644 --- a/src/main/java/org/nanoboot/powerframework/datetime/TimeUnitsValidator.java +++ b/power-time/src/main/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidator.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,23 +18,85 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; - -import org.nanoboot.powerframework.PowerRuntimeException; +package org.nanoboot.powerframework.time.utils; /** * Validates time units. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ -class TimeUnitsValidator { +public class TimeUnitsValidator extends AbstractValidator { - private static final int HOURLOWERBOUND = 0; - private static final int HOURHIGHERBOUND = 23; - private static final int MINUTEORSECONDLOWERBOUND = 0; - private static final int MINUTEORSECONDHIGHERBOUND = 59; - private static final int MILLISECONDLOWERBOUND = 0; - private static final int MILLISECONDHIGHERBOUND = 999; + /** + * + * @param hour + * @param minute + * @param second + * @param millisecond + */ + public static void validate(int hour, + int minute, + int second, + int millisecond) { + if(!TimeUnitsValidator.isHourValid(hour)) { + throw new TimeException("Hour is not valid."); + } + if(!TimeUnitsValidator.isMinuteValid(minute)) { + throw new TimeException("Minute is not valid."); + } + if(!TimeUnitsValidator.isSecondValid(second)) { + throw new TimeException("Second is not valid."); + } + if(!TimeUnitsValidator.isMillisecondValid(millisecond)) { + throw new TimeException("Millisecond is not valid."); + } + } + + /** + * Checks if hour has valid format. + * + * @param hour + * + * @return Result of this control. + */ + static boolean isHourValid(int hour) { + return isInBound(TimeUnit.HOUR, hour); + } + + /** + * Checks if minute has valid format. + * + * @param minute + * + * @return Result of this control. + */ + static boolean isMinuteValid(int minute) { + return isInBound(TimeUnit.MINUTE, minute); + } + + /** + * Checks if second has valid format. + * + * @param second + * + * @return Result of this control. + */ + static boolean isSecondValid(int second) { + return isInBound(TimeUnit.SECOND, second); + } + + /** + * Checks if millisecond has valid format. + * + * @param millisecond + * + * @return Result of this control. + */ + static boolean isMillisecondValid(int millisecond) { + return isInBound(TimeUnit.MILLISECOND, millisecond); + } /** * Constructor @@ -43,76 +105,4 @@ class TimeUnitsValidator { */ private TimeUnitsValidator() { } - - /** - * Checks if hour has valid format. - * - * @param hour - * @return Result of this control. - */ - static boolean isHourValid(int hour) { - return (hour >= HOURLOWERBOUND) && (hour <= HOURHIGHERBOUND); - } - - /** - * Checks if minuteOrSecond has valid format. - * - * @param minuteOrSecond - * @return Result of this control. - */ - private static boolean isMinuteOrSecondValid(int minuteOrSecond) { - return (minuteOrSecond >= MINUTEORSECONDLOWERBOUND) && (minuteOrSecond <= MINUTEORSECONDHIGHERBOUND); - } - - /** - * Checks if minute has valid format. - * - * @param minute - * @return Result of this control. - */ - static boolean isMinuteValid(int minute) { - return isMinuteOrSecondValid(minute); - } - - /** - * Checks if second has valid format. - * - * @param second - * @return Result of this control. - */ - static boolean isSecondValid(int second) { - return isMinuteOrSecondValid(second); - } - - /** - * Checks if millisecond has valid format. - * - * @param millisecond - * @return Result of this control. - */ - static boolean isMillisecondValid(int millisecond) { - return (millisecond >= MILLISECONDLOWERBOUND) && (millisecond <= MILLISECONDHIGHERBOUND); - } - - /** - * Checks if all the given time values are valid. - * - * @param hour - * @param minute - * @param second - * @param millisecond - * * @return Result of this control. - */ - static boolean areAllTimeUnitsValid(int hour, int minute, int second, int millisecond) { - return isHourValid(hour) - && (isMinuteValid(minute)) - && (isSecondValid(second)) - && (isMillisecondValid(millisecond)); - } - - static void checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException(int hour, int minute, int second, int millisecond) { - if (!areAllTimeUnitsValid(hour, minute, second, millisecond)) { - throw new PowerRuntimeException("One or more values of time units have invalid format."); - } - } } diff --git a/power-time/src/main/resources/.gitkeep b/power-time/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-time/src/test/java/org/nanoboot/powerframework/time/duration/DurationTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/duration/DurationTest.java new file mode 100644 index 0000000..cdf87ce --- /dev/null +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/duration/DurationTest.java @@ -0,0 +1,877 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DurationTest { +// +// /** +// +// */ +// public DurationTest() { +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_5Args_ThereShouldBeThrownNoPowerRuntimeException() { +// //arrange +// boolean isExceptionThrown = false; +// //act +// try { +// Duration duration = new Duration(23, 5, 3, 43, 97); +// } catch (PowerException e) { +// isExceptionThrown = true; +// } +// //assert +// if(isExceptionThrown) { +// fail("There should be thrown no PowerRuntimeException"); +// } +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_5Args_ThereShouldBeThrownPowerRuntimeException() { +// //arrange +// boolean isExceptionThrown = false; +// //act +// try { +// Duration duration = new Duration(23, 5, 3, 143, 97); +// } catch (PowerException e) { +// isExceptionThrown = true; +// } +// //assert +// if(!isExceptionThrown) { +// fail("There should be thrown PowerRuntimeException"); +// } +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_5Args_ThereShouldBeReturnedIsPositive() { +// //arrange +// boolean expectedValue = true; +// boolean returnedValue; +// Duration duration = new Duration(23, 5, 3, 43, 97); +// //act +// returnedValue = duration.isPositive(); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_6Args_ThereShouldBeReturnedIsPositive() { +// //arrange +// boolean expectedValue = true; +// boolean returnedValue; +// Duration duration = new Duration(true, 23, 5, 3, 43, 97); +// //act +// returnedValue = duration.isPositive(); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_6Args_ThereShouldBeReturnedIsNotPositive() { +// //arrange +// boolean expectedValue = false; +// boolean returnedValue; +// Duration duration = new Duration(false, 23, 5, 3, 43, 97); +// //act +// returnedValue = duration.isPositive(); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_StringArg() { +// //arrange +// String argString = "+00023:05:03:43:097"; +// String expectedString = "+23:5:3:43:97"; +// String returnedString; +// +// Duration duration = new Duration(argString); +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of constructor, of class Duration. +// */ +// @Test +// public void TestDuration_StringArg_ThereShouldBeThrownPowerRuntimeException() { +// //arrange +// boolean isExceptionThrown = false; +// //act +// try { +// String argString = "+23:5:60:43:97"; +// Duration duration = new Duration(argString); +// } catch (PowerException e) { +// isExceptionThrown = true; +// } +// //assert +// if(!isExceptionThrown) { +// fail("There should be thrown PowerRuntimeException"); +// } +// } +// +// /** +// Test of between method, of class Duration. +// */ +// @Test +// public void testBetween1_UniversalDateTime_UniversalDateTime() { +// //arrange +// UniversalDateTime startUniversalDateTime = new UniversalDateTime(1949, 8, 6, 4, 23, 7, 654); +// UniversalDateTime endUniversalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); +// String expectedString = "+21077:4:54:51:300"; +// String returnedString; +// //act +// returnedString = Duration.between(startUniversalDateTime, endUniversalDateTime).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of between method, of class Duration. +// */ +// @Test +// public void testBetween2_UniversalDateTime_UniversalDateTime() { +// //arrange +// UniversalDateTime startUniversalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); +// UniversalDateTime endUniversalDateTime = new UniversalDateTime(1949, 8, 6, 4, 23, 7, 654); +// String expectedString = "-21077:4:54:51:300"; +// String returnedString; +// //act +// returnedString = Duration.between(startUniversalDateTime, endUniversalDateTime).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of between method, of class Duration. +// */ +// @Test +// public void testBetween1_ZonedDateTime_ZonedDateTime() { +// //arrange +// LocalDateTime localDateTime = new LocalDateTime(2016, 10, 29, 11, 19, 34, 276); +// ZonedDateTime startZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Europe/Prague")); +// ZonedDateTime endZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Australia/Sydney")); +// String expectedString = "-0:9:0:0:0"; +// String returnedString; +// //act +// returnedString = Duration.between(startZonedDateTime, endZonedDateTime).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of between method, of class Duration. +// */ +// @Test +// public void testBetween2_ZonedDateTime_ZonedDateTime() { +// //arrange +// LocalDateTime localDateTime = new LocalDateTime(2016, 10, 29, 11, 19, 34, 276); +// ZonedDateTime startZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Australia/Sydney")); +// ZonedDateTime endZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Europe/Prague")); +// String expectedString = "+0:9:0:0:0"; +// String returnedString; +// //act +// returnedString = Duration.between(startZonedDateTime, endZonedDateTime).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of ofDays method, of class Duration. +// */ +// @Test +// public void testOfDays() { +// //arrange +// int days = 13; +// +// Duration duration = Duration.ofDays(days); +// String expectedString = "+13:0:0:0:0"; +// String returnedString; +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of ofHours method, of class Duration. +// */ +// @Test +// public void testOfHours() { +// //arrange +// int hours = 17; +// +// Duration duration = Duration.ofHours(hours); +// String expectedString = "+0:17:0:0:0"; +// String returnedString; +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of ofMinutes method, of class Duration. +// */ +// @Test +// public void testOfMinutes() { +// //arrange +// int minutes = 42; +// +// Duration duration = Duration.ofMinutes(minutes); +// String expectedString = "+0:0:42:0:0"; +// String returnedString; +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of ofSeconds method, of class Duration. +// */ +// @Test +// public void testOfSeconds() { +// //arrange +// int seconds = 9; +// +// Duration duration = Duration.ofSeconds(seconds); +// String expectedString = "+0:0:0:9:0"; +// String returnedString; +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of ofMilliseconds method, of class Duration. +// */ +// @Test +// public void testOfMilliseconds() { +// //arrange +// int milliseconds = 4; +// +// Duration duration = Duration.ofMilliseconds(milliseconds); +// String expectedString = "+0:0:0:0:4"; +// String returnedString; +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of fromUniversalDateTimePlusDurationCreateNewUniversalDateTime +// method, of class Duration. +// */ +// @Test +// public void testFromUniversalDateTimePlusDurationCreateNewUniversalDateTime() { +// //arrange +// UniversalDateTime universalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); +// Duration duration = Duration.ofHours(7); +// String expectedString = "2007-04-21 16:17:58:954"; +// String returnedString; +// //act +// returnedString = Duration.fromUniversalDateTimePlusDurationCreateNewUniversalDateTime(universalDateTime, duration).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime +// method, of class Duration. +// */ +// @Test +// public void testFromUniversalDateTimeMinusDurationCreateNewUniversalDateTime() { +// //arrange +// UniversalDateTime universalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); +// Duration duration = Duration.ofHours(7); +// String expectedString = "2007-04-21 02:17:58:954"; +// String returnedString; +// //act +// returnedString = Duration.fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime(universalDateTime, duration).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of fromZonedDateTimePlusDurationCreateNewZonedDateTime method, of +// class Duration. +// */ +// @Test +// public void testFromZonedDateTimePlusDurationCreateNewZonedDateTime() { +// //arrange +// LocalDateTime localDateTime = new LocalDateTime(2007, 4, 21, 9, 17, 58, 954); +// TimeZone timeZone = new TimeZone("Australia/Sydney"); +// ZonedDateTime zonedDateTime = new ZonedDateTime(localDateTime, timeZone); +// Duration duration = Duration.ofHours(7); +// String expectedString = "2007-04-21 16:17:58:954"; +// String returnedString; +// //act +// returnedString = Duration.fromZonedDateTimePlusDurationCreateNewZonedDateTime(zonedDateTime, duration).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of fromZonedDateTimeMinusDurationCreateNewZonedDateTime method, of +// class Duration. +// */ +// @Test +// public void testFromZonedDateTimeMinusDurationCreateNewZonedDateTime() { +// //arrange +// LocalDateTime localDateTime = new LocalDateTime(2007, 4, 21, 9, 17, 58, 954); +// TimeZone timeZone = new TimeZone("Australia/Sydney"); +// ZonedDateTime zonedDateTime = new ZonedDateTime(localDateTime, timeZone); +// Duration duration = Duration.ofHours(7); +// String expectedString = "2007-04-21 02:17:58:954"; +// String returnedString; +// //act +// returnedString = Duration.fromZonedDateTimeMinusDurationCreateNewZonedDateTime(zonedDateTime, duration).toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of getDays method, of class Duration. +// */ +// @Test +// public void testGetDays() { +// //arrange +// Duration duration = new Duration(23, 5, 3, 43, 97); +// long expectedDays = 23; +// long returnedDays; +// //act +// returnedDays = duration.getDays(); +// //assert +// assertEquals(expectedDays, returnedDays); +// } +// +// /** +// Test of getHours method, of class Duration. +// */ +// @Test +// public void testGetHours() { +// //arrange +// Duration duration = new Duration(23, 5, 3, 43, 97); +// int expectedHours = 5; +// int returnedHours; +// //act +// returnedHours = duration.getHours(); +// //assert +// assertEquals(expectedHours, returnedHours); +// } +// +// /** +// Test of getMinutes method, of class Duration. +// */ +// @Test +// public void testGetMinutes() { +// //arrange +// Duration duration = new Duration(23, 5, 3, 43, 97); +// int expectedMinutes = 3; +// int returnedMinutes; +// //act +// returnedMinutes = duration.getMinutes(); +// //assert +// assertEquals(expectedMinutes, returnedMinutes); +// } +// +// /** +// Test of getSeconds method, of class Duration. +// */ +// @Test +// public void testGetSeconds() { +// //arrange +// Duration duration = new Duration(23, 5, 3, 43, 97); +// int expectedSeconds = 43; +// int returnedSeconds; +// //act +// returnedSeconds = duration.getSeconds(); +// //assert +// assertEquals(expectedSeconds, returnedSeconds); +// } +// +// /** +// Test of getMilliseconds method, of class Duration. +// */ +// @Test +// public void testGetMilliseconds() { +// //arrange +// Duration duration = new Duration(23, 5, 3, 43, 97); +// int expectedMilliseconds = 97; +// int returnedMilliseconds; +// //act +// returnedMilliseconds = duration.getMilliseconds(); +// //assert +// assertEquals(expectedMilliseconds, returnedMilliseconds); +// } +// +// /** +// Test of isPositive method, of class Duration. +// */ +// @Test +// public void testIsPositive() { +// //arrange +// Duration duration = new Duration(false, 23, 5, 3, 43, 97); +// boolean expectedValue = false; +// boolean returnedValue; +// //act +// returnedValue = duration.isPositive(); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of negated method, of class Duration. +// */ +// @Test +// public void testNegated() { +// //arrange +// Duration duration = new Duration(23, 5, 3, 43, 97); +// Duration negatedDuration; +// +// boolean expectedValue = false; +// boolean returnedValue; +// //act +// negatedDuration = duration.negated(); +// returnedValue = negatedDuration.isPositive(); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of abs method, of class Duration. +// */ +// @Test +// public void testAbs() { +// //arrange +// Duration duration = new Duration(false, 23, 5, 3, 43, 97); +// Duration absDuration; +// +// boolean expectedValue = true; +// boolean returnedValue; +// //act +// absDuration = duration.abs(); +// returnedValue = absDuration.isPositive(); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of plusDuration method, of class Duration. +// */ +// @Test +// public void testPlusDuration() { +// //arrange +// Duration duration = new Duration(12, 0, 0, 0, 0); +// Duration durationToAdd = new Duration(0, 5, 4, 2, 7); +// Duration returnedDuration; +// String expectedString = "+12:5:4:2:7"; +// String returnedString; +// +// //act +// returnedDuration = duration.plusDuration(durationToAdd); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of plusDays method, of class Duration. +// */ +// @Test +// public void testPlusDays() { +// //arrange +// Duration duration = new Duration(12, 0, 0, 0, 0); +// long daysToAdd = 1; +// Duration returnedDuration; +// String expectedString = "+13:0:0:0:0"; +// String returnedString; +// +// //act +// returnedDuration = duration.plusDays(daysToAdd); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of plusHours method, of class Duration. +// */ +// @Test +// public void testPlusHours() { +// //arrange +// Duration duration = new Duration(12, 0, 0, 0, 0); +// int hoursToAdd = 1; +// Duration returnedDuration; +// String expectedString = "+12:1:0:0:0"; +// String returnedString; +// +// //act +// returnedDuration = duration.plusHours(hoursToAdd); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of plusMinutes method, of class Duration. +// */ +// @Test +// public void testPlusMinutes() { +// //arrange +// Duration duration = new Duration(12, 0, 0, 0, 0); +// int minutesToAdd = 1; +// Duration returnedDuration; +// String expectedString = "+12:0:1:0:0"; +// String returnedString; +// +// //act +// returnedDuration = duration.plusMinutes(minutesToAdd); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of plusSeconds method, of class Duration. +// */ +// @Test +// public void testPlusSeconds() { +// //arrange +// Duration duration = new Duration(12, 0, 0, 0, 0); +// int secondsToAdd = 1; +// Duration returnedDuration; +// String expectedString = "+12:0:0:1:0"; +// String returnedString; +// +// //act +// returnedDuration = duration.plusSeconds(secondsToAdd); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of plusMilliseconds method, of class Duration. +// */ +// @Test +// public void testPlusMilliseconds() { +// //arrange +// Duration duration = new Duration(12, 0, 0, 0, 0); +// int millisecondsToAdd = 1; +// Duration returnedDuration; +// String expectedString = "+12:0:0:0:1"; +// String returnedString; +// +// //act +// returnedDuration = duration.plusMilliseconds(millisecondsToAdd); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of minusDuration method, of class Duration. +// */ +// @Test +// public void testMinusDuration() { +// //arrange +// Duration duration = new Duration(12, 5, 4, 2, 7); +// Duration durationToSubtract = new Duration(0, 5, 4, 2, 7); +// Duration returnedDuration; +// String expectedString = "+12:0:0:0:0"; +// String returnedString; +// +// //act +// returnedDuration = duration.minusDuration(durationToSubtract); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of minusDays method, of class Duration. +// */ +// @Test +// public void testMinusDays() { +// //arrange +// Duration duration = new Duration(12, 5, 4, 2, 7); +// long daysToSubtract = 1; +// Duration returnedDuration; +// String expectedString = "+11:5:4:2:7"; +// String returnedString; +// +// //act +// returnedDuration = duration.minusDays(daysToSubtract); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of minusHours method, of class Duration. +// */ +// @Test +// public void testMinusHours() { +// //arrange +// Duration duration = new Duration(12, 5, 4, 2, 7); +// int hoursToSubtract = 1; +// Duration returnedDuration; +// String expectedString = "+12:4:4:2:7"; +// String returnedString; +// +// //act +// returnedDuration = duration.minusHours(hoursToSubtract); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of minusMinutes method, of class Duration. +// */ +// @Test +// public void testMinusMinutes() { +// //arrange +// Duration duration = new Duration(12, 5, 4, 2, 7); +// int minutesToSubtract = 1; +// Duration returnedDuration; +// String expectedString = "+12:5:3:2:7"; +// String returnedString; +// +// //act +// returnedDuration = duration.minusMinutes(minutesToSubtract); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of minusSeconds method, of class Duration. +// */ +// @Test +// public void testMinusSeconds() { +// //arrange +// Duration duration = new Duration(12, 5, 4, 2, 7); +// int secondsToSubtract = 1; +// Duration returnedDuration; +// String expectedString = "+12:5:4:1:7"; +// String returnedString; +// +// //act +// returnedDuration = duration.minusSeconds(secondsToSubtract); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of minusMilliseconds method, of class Duration. +// */ +// @Test +// public void testMinusMilliseconds() { +// //arrange +// Duration duration = new Duration(12, 5, 4, 2, 7); +// int millisecondsToSubtract = 1; +// Duration returnedDuration; +// String expectedString = "+12:5:4:2:6"; +// String returnedString; +// +// //act +// returnedDuration = duration.minusMilliseconds(millisecondsToSubtract); +// returnedString = returnedDuration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of toTotalDays method, of class Duration. +// */ +// @Test +// public void testToTotalDays() { +// //arrange +// Duration duration = new Duration(14, 9, 17, 53, 834); +// long expectedValue = 14; +// long returnedValue; +// //act +// returnedValue = (long) Math.floor(duration.toTotalDays()); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of toTotalHours method, of class Duration. +// */ +// @Test +// public void testToTotalHours() { +// //arrange +// Duration duration = new Duration(14, 9, 17, 53, 834); +// long expectedValue = 345; +// long returnedValue; +// //act +// returnedValue = (long) Math.floor(duration.toTotalHours()); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of toTotalMinutes method, of class Duration. +// */ +// @Test +// public void testToTotalMinutes() { +// //arrange +// Duration duration = new Duration(14, 9, 17, 53, 834); +// long expectedValue = 20717; +// long returnedValue; +// //act +// returnedValue = (long) Math.floor(duration.toTotalMinutes()); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of toTotalSeconds method, of class Duration. +// */ +// @Test +// public void testToTotalSeconds() { +// //arrange +// Duration duration = new Duration(14, 9, 17, 53, 834); +// long expectedValue = 1243073; +// long returnedValue; +// //act +// returnedValue = (long) Math.floor(duration.toTotalSeconds()); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of toTotalMilliseconds method, of class Duration. +// */ +// @Test +// public void testToTotalMilliseconds() { +// //arrange +// Duration duration = new Duration(14, 9, 17, 53, 834); +// long expectedValue = 1243073834; +// long returnedValue; +// //act +// returnedValue = (long) Math.floor(duration.toTotalMilliseconds()); +// //assert +// assertEquals(expectedValue, returnedValue); +// } +// +// /** +// Test of toJavaDuration method, of class Duration. +// */ +// @Test +// public void testToJavaDuration() { +// //arrange +// Duration duration = new Duration(14, 9, 17, 53, 834); +// long expectedTotalSeconds = (long) Math.floor(duration.toTotalSeconds()); +// long returnedSeconds; +// java.time.Duration javaDuration; +// //act +// javaDuration = duration.toJavaDuration(); +// returnedSeconds = javaDuration.getSeconds(); +// //assert +// assertEquals(expectedTotalSeconds, returnedSeconds); +// } +// +// /** +// Test of toString method, of class Duration. +// */ +// @Test +// public void testToString1_ConstructorWithLongArgUsed() { +// //arrange +// String expectedString = "+23:5:3:43:97"; +// String returnedString; +// long countOfTotalMilliseconds = 2005423097; +// +// Duration duration = new Duration(countOfTotalMilliseconds); +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of toString method, of class Duration. +// */ +// @Test +// public void testToString2_ConstructorWithLongArgUsed() { +// //arrange +// String expectedString = "-23:5:3:43:97"; +// String returnedString; +// long countOfTotalMilliseconds = -2005423097; +// +// Duration duration = new Duration(countOfTotalMilliseconds); +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +// +// /** +// Test of toString method, of class Duration. +// */ +// @Test +// public void testToString3_ConstructorWithLongArgUsed() { +// //arrange +// String expectedString = "+0:0:0:0:0"; +// String returnedString; +// long countOfTotalMilliseconds = 0; +// +// Duration duration = new Duration(countOfTotalMilliseconds); +// //act +// returnedString = duration.toString(); +// //assert +// assertEquals(expectedString, returnedString); +// } +} diff --git a/power-time/src/test/java/org/nanoboot/powerframework/time/duration/StopWatchTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/duration/StopWatchTest.java new file mode 100644 index 0000000..2d2588f --- /dev/null +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/duration/StopWatchTest.java @@ -0,0 +1,279 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.duration; + +import static org.junit.Assert.assertEquals; + +import org.nanoboot.powerframework.time.utils.TimeUnit; +import org.junit.*; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class StopWatchTest { + + public StopWatchTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of getCurrentStopWatchState method, of class StopWatch. + */ + @Test + public void testGetStopWatchState_shouldBeClear() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.CLEAR; + StopWatchState returnedValue; + //act + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of getCurrentStopWatchState method, of class StopWatch. + */ + @Test + public void testGetStopWatchState_shouldBeRunning() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.RUNNING; + StopWatchState returnedValue; + //act + stopWatch.start(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of clear method, of class StopWatch. + */ + @Test + public void testClear() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.CLEAR; + StopWatchState returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.clear(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of clear method, of class StopWatch. + */ + @Test + public void testClear2() { + //arrange + StopWatch stopWatch = new StopWatch(); + int expectedValue = 0; + int returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.clear(); + returnedValue = (int) stopWatch.getCurrentDuration().toTotal(TimeUnit.MILLISECOND); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of start method, of class StopWatch. + */ + @Test + public void testStart() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.RUNNING; + StopWatchState returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of start method, of class StopWatch. + */ + @Test + public void testStart2() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.RUNNING; + StopWatchState returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.clear(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of stop method, of class StopWatch. + */ + @Test + public void testStop() { //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.STOPPED; + StopWatchState returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.clear(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of getCurrentDuration method, of class StopWatch. + */ + @Test + public void testGetCurrentDuration() { + StopWatch stopWatch = new StopWatch(); + boolean expectedValue = true; + boolean returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.clear(); + stopWatch.start(); + stopWatch.stop(); + returnedValue = stopWatch.getCurrentDuration().toTotal(TimeUnit.MILLISECOND) == 0; + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of isClear method, of class StopWatch. + */ + @Test + public void testIsClear() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.CLEAR; + StopWatchState returnedValue; + //act + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of isRunning method, of class StopWatch. + */ + @Test + public void testIsRunning() { + //arrange + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.RUNNING; + StopWatchState returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + + /** + * Test of isStopped method, of class StopWatch. + */ + @Test + public void testIsStopped() { + StopWatch stopWatch = new StopWatch(); + StopWatchState expectedValue = StopWatchState.STOPPED; + StopWatchState returnedValue; + //act + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.clear(); + stopWatch.start(); + stopWatch.stop(); + stopWatch.start(); + stopWatch.stop(); + returnedValue = stopWatch.getStopWatchState(); + //assert + assertEquals(expectedValue, returnedValue); + } + +} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/DateTimeTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/DateTimeTest.java similarity index 80% rename from src/test/java/org/nanoboot/powerframework/datetime/DateTimeTest.java rename to power-time/src/test/java/org/nanoboot/powerframework/time/moment/DateTimeTest.java index 6d0c018..7ed9798 100644 --- a/src/test/java/org/nanoboot/powerframework/datetime/DateTimeTest.java +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/DateTimeTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,25 +18,36 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; -import static org.junit.Assert.*; +import org.nanoboot.powerframework.core.PowerException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class DateTimeTest { private class DateTimeImpl extends DateTime { - public DateTimeImpl(LocalDate localDate, LocalTime localTime) { + public DateTimeImpl(LocalDate localDate, + LocalTime localTime) { super(localDate, localTime); } - public DateTimeImpl(int year, int month, int day, int hour24Format, int minute, int second, int millisecond) { + public DateTimeImpl(int year, + int month, + int day, + int hour24Format, + int minute, + int second, + int millisecond) { super(year, month, day, hour24Format, minute, second, millisecond); } @@ -47,6 +58,9 @@ public class DateTimeTest { public DateTimeImpl(String dateTimeInString) { super(dateTimeInString); } + public DateTimeImpl(long dateTimeAsLong) { + super(dateTimeAsLong); + } } @@ -67,11 +81,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl(new LocalDate(1994, 5, 6), new LocalTime(21, 45, 6, 32)); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -87,11 +101,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl(new LocalDate(1994, 15, 6), new LocalTime(21, 45, 6, 32)); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -107,11 +121,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl(1994, 5, 6, 21, 45, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -127,11 +141,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl(1994, 15, 6, 21, 45, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -146,11 +160,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl(new DateTimeImpl(1994, 5, 6, 21, 45, 6, 32)); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -165,11 +179,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl(new DateTimeImpl(1994, 15, 6, 21, 45, 6, 32)); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -184,11 +198,11 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl("1994-05-06 21:45:06:032"); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -203,14 +217,28 @@ public class DateTimeTest { //act try { DateTimeImpl dateTimeImpl = new DateTimeImpl("1994-15-06 21:45:06:032"); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } + /** + * Test of constructor of class DateTime. (String dateTimeInString) + */ + @Test + public void testDateTime_longConstructor() { + String expectedResult = "19940506214506032"; + String result; + DateTimeImpl dateTimeImpl; + //act + dateTimeImpl = new DateTimeImpl(19940506214506032l); + result = String.valueOf(dateTimeImpl.toLong()); + //assert + assertEquals(expectedResult, result); + } /** * Test of getYear method, of class LocalDate. @@ -339,4 +367,19 @@ public class DateTimeTest { assertEquals(expectedResult, result); } + + /** + * Test of toString method, of class LocalDate. + */ + @Test + public void testToLong() { //arrange + String expectedResult = "19940506214506032"; + String result; + DateTimeImpl dateTimeImpl; + //act + dateTimeImpl = new DateTimeImpl(1994, 5, 6, 21, 45, 6, 32); + result = String.valueOf(dateTimeImpl.toLong()); + //assert + assertEquals(expectedResult, result); + } } diff --git a/src/test/java/org/nanoboot/powerframework/datetime/LocalDateTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTest.java similarity index 83% rename from src/test/java/org/nanoboot/powerframework/datetime/LocalDateTest.java rename to power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTest.java index 4aa9f7d..e395a20 100644 --- a/src/test/java/org/nanoboot/powerframework/datetime/LocalDateTest.java +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,15 +18,19 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; +import org.nanoboot.powerframework.core.PowerException; import static org.junit.Assert.*; +import org.nanoboot.powerframework.time.utils.TimeException; +import org.junit.*; + /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class LocalDateTest { @@ -46,15 +50,41 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1994, 5, 6); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } + /** + * Test of constructor of class LocalDate . + */ + @Test(expected = TimeException.class) + public void testLocalDate_stringIsLonger_ThereShouldBeThrownTimeException() { + //arrange + //act + LocalDate localDate = new LocalDate("1994-05-012"); + + //assert + } + /** + * Test of constructor of class LocalDate . + */ + @Test() + public void testLocalDate_aDateIsExpected() { + //arrange + //act + String dateAsString = "1994-05-12"; + LocalDate localDate = new LocalDate(dateAsString); + assertEquals(localDate.getYear(),1994); + assertEquals(localDate.getMonth(),5); + assertEquals(localDate.getDay(),12); + //assert + } + /** * Test of constructor of class LocalDate . */ @@ -65,11 +95,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1994, 0, 6); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -84,11 +114,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1994, 50, 6); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -103,11 +133,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1994, 5, 0); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -122,11 +152,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1994, 5, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -141,11 +171,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1994, 9, 31); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -160,11 +190,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1992, 2, 31); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -179,11 +209,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1993, 2, 30); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -198,11 +228,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1993, 2, 29); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -217,11 +247,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1993, 2, 28); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -236,11 +266,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1993, 2, 27); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } @@ -256,11 +286,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1992, 2, 31); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -275,11 +305,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1992, 2, 30); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -294,11 +324,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1992, 2, 29); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -313,11 +343,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1992, 2, 28); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } @@ -332,11 +362,11 @@ public class LocalDateTest { //act try { LocalDate localDate = new LocalDate(1992, 2, 27); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } diff --git a/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTimeTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTimeTest.java new file mode 100644 index 0000000..514315e --- /dev/null +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalDateTimeTest.java @@ -0,0 +1,167 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.moment; + +/** + * + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class LocalDateTimeTest { +// +// /** +// +// */ +// public LocalDateTimeTest() { +// } +// +// /** +// Test of constructor of class LocalDateTime. (String dateTimeInString) +// */ +// @Test +// public void testLocalDateTime_1argString_day6MustBeReturned() { +// //arrange +// LocalDateTime localDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// localDateTime = new LocalDateTime("1994-05-06 21:45:06:032"); +// returnedDay = localDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of constructor of class LocalDateTime. (int year, int month, int +// day, int hour24Format, int minute, int second, int millisecond) +// */ +// @Test +// public void testLocalDateTime_7args_day6MustBeReturned() { +// //arrange +// LocalDateTime localDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); +// returnedDay = localDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of constructor of class LocalDateTime. (UniversalDateTime +// universalDateTime) +// */ +// @Test +// public void testLocalDateTime_1argUniversalDateTime_day6MustBeReturned() { +// //arrange +// LocalDateTime localDateTime; +// UniversalDateTime universalDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); +// localDateTime = new LocalDateTime(universalDateTime); +// returnedDay = localDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of constructor of class LocalDateTime. (ZonedDateTime zonedDateTime) +// */ +// @Test +// public void testLocalDateTime_1argZonedDateTime_day6MustBeReturned() { +// //arrange +// LocalDateTime localDateTime; +// TimeZone timeZone; +// ZonedDateTime zonedDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// timeZone = new TimeZone("Australia/Sydney"); +// zonedDateTime = new ZonedDateTime(new LocalDateTime(1994, 5, 6, 21, 45, 6, 32), timeZone); +// localDateTime = new LocalDateTime(zonedDateTime); +// returnedDay = localDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of toUniversalDateTime method, of class LocalDateTime. +// */ +// @Test +// public void testToUniversalDateTime() { +// //arrange +// LocalDateTime localDateTime; +// UniversalDateTime universalDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); +// universalDateTime = localDateTime.addUniversalTimeZone(); +// returnedDay = universalDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of toZonedDateTime method, of class LocalDateTime. +// */ +// @Test +// public void testToZonedDateTime() { +// //arrange +// LocalDateTime localDateTime; +// TimeZone timeZone; +// ZonedDateTime zonedDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// timeZone = new TimeZone("Australia/Sydney"); +// localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); +// zonedDateTime = localDateTime.addTimeZone(timeZone); +// returnedDay = zonedDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of toJavaLocalDateTime method, of class LocalDateTime. +// */ +// @Test +// public void testToJavaLocalDateTime() { +// //arrange +// LocalDateTime localDateTime; +// java.time.LocalDateTime javaLocalDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); +// javaLocalDateTime = localDateTime.toJavaLocalDateTime(); +// returnedDay = javaLocalDateTime.getDayOfMonth(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } + +} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/LocalTimeTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalTimeTest.java similarity index 80% rename from src/test/java/org/nanoboot/powerframework/datetime/LocalTimeTest.java rename to power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalTimeTest.java index a201269..ef6be97 100644 --- a/src/test/java/org/nanoboot/powerframework/datetime/LocalTimeTest.java +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/LocalTimeTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,16 +18,22 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; -import static org.junit.Assert.*; +import org.nanoboot.powerframework.core.PowerException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.nanoboot.powerframework.time.utils.TimeException; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class LocalTimeTest { /** @@ -46,15 +52,40 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, 45, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (isExceptionThrown) { + if(isExceptionThrown) { fail("There should be thrown no PowerRuntimeException"); } } + /** + * Test of constructor of class LocalTime . + */ + @Test(expected = TimeException.class) + public void testLocalTime_stringIsLonger_ThereShouldBeThrownTimeException() { + //arrange + //act + LocalTime localTime = new LocalTime("21:45:06:0037"); + //assert + } + /** + * Test of constructor of class LocalTime . + */ + @Test() + public void testLocalTime_aTimeIsExpected() { + //arrange + //act + String timeAsString = "21:45:06:037"; + LocalTime localTime = new LocalTime(timeAsString); + assertEquals(localTime.getHour(),21); + assertEquals(localTime.getMinute(),45); + assertEquals(localTime.getSecond(),06); + assertEquals(localTime.getMillisecond(),37); + //assert + } /** * Test of constructor of class LocalTime. */ @@ -65,11 +96,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(-1, 45, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -84,11 +115,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(24, 45, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -104,11 +135,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, -1, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -123,11 +154,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, 60, 6, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -142,11 +173,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, 45, -1, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -161,11 +192,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, 45, 60, 32); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -180,11 +211,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, 45, 6, -1); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } @@ -199,11 +230,11 @@ public class LocalTimeTest { //act try { LocalTime localTime = new LocalTime(21, 45, 6, 1000); - } catch (PowerRuntimeException e) { + } catch (PowerException e) { isExceptionThrown = true; } //assert - if (!isExceptionThrown) { + if(!isExceptionThrown) { fail("There should be thrown PowerRuntimeException"); } } diff --git a/src/test/java/org/nanoboot/powerframework/datetime/TimeZoneTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/TimeZoneTest.java similarity index 77% rename from src/test/java/org/nanoboot/powerframework/datetime/TimeZoneTest.java rename to power-time/src/test/java/org/nanoboot/powerframework/time/moment/TimeZoneTest.java index 95d3743..8fb5e68 100644 --- a/src/test/java/org/nanoboot/powerframework/datetime/TimeZoneTest.java +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/TimeZoneTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,15 +18,18 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.moment; -import java.util.List; -import org.junit.Test; -import static org.junit.Assert.*; +import java.util.*; + +import static org.junit.Assert.assertEquals; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class TimeZoneTest { @@ -46,7 +49,7 @@ public class TimeZoneTest { boolean expectedValue = true; boolean result; //act - listOfTimeZoneIDs = TimeZone.getListOfTimeZoneIDs(); + listOfTimeZoneIDs = org.nanoboot.powerframework.time.moment.TimeZone.getListOfTimeZoneIDs(); result = listOfTimeZoneIDs.contains("Australia/Sydney"); //assert assertEquals(expectedValue, result); @@ -62,7 +65,7 @@ public class TimeZoneTest { boolean expectedValue = false; boolean result; //act - listOfTimeZoneIDs = TimeZone.getListOfTimeZoneIDs(); + listOfTimeZoneIDs = org.nanoboot.powerframework.time.moment.TimeZone.getListOfTimeZoneIDs(); result = listOfTimeZoneIDs.contains("Amflkfd/Adfkjldfk"); //assert assertEquals(expectedValue, result); @@ -77,7 +80,7 @@ public class TimeZoneTest { boolean expectedValue = true; boolean result; //act - result = TimeZone.isTimeZoneIDValid("Australia/Sydney"); + result = org.nanoboot.powerframework.time.moment.TimeZone.isTimeZoneIDValid("Australia/Sydney"); //assert assertEquals(expectedValue, result); } @@ -91,7 +94,7 @@ public class TimeZoneTest { boolean expectedValue = false; boolean result; //act - result = TimeZone.isTimeZoneIDValid("Jehjujfdue/Eklfglsdi"); + result = org.nanoboot.powerframework.time.moment.TimeZone.isTimeZoneIDValid("Jehjujfdue/Eklfglsdi"); //assert assertEquals(expectedValue, result); } @@ -104,7 +107,7 @@ public class TimeZoneTest { //arrange String expectedValue = "Australia/Sydney"; String result; - TimeZone timeZone = new TimeZone("Australia/Sydney"); + org.nanoboot.powerframework.time.moment.TimeZone timeZone = new org.nanoboot.powerframework.time.moment.TimeZone("Australia/Sydney"); //act result = timeZone.toString(); //assert @@ -119,7 +122,7 @@ public class TimeZoneTest { //arrange String expectedValue = "Australia/Sydney"; String result; - TimeZone timeZone = new TimeZone("Australia/Sydney"); + org.nanoboot.powerframework.time.moment.TimeZone timeZone = new TimeZone("Australia/Sydney"); //act result = timeZone.getTimeZoneID(); //assert diff --git a/power-time/src/test/java/org/nanoboot/powerframework/time/moment/UniversalDateTimeTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/UniversalDateTimeTest.java new file mode 100644 index 0000000..4e20411 --- /dev/null +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/UniversalDateTimeTest.java @@ -0,0 +1,146 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.moment; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class UniversalDateTimeTest { +// +// /** +// +// */ +// public UniversalDateTimeTest() { +// } +// +// /** +// Test of constructor of class UniversalDateTime. (String dateTimeInString) +// */ +// @Test +// public void testUniversalDateTime_1argString_day6MustBeReturned() { +// //arrange +// UniversalDateTime universalDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// universalDateTime = new UniversalDateTime("1994-05-06 21:45:06:032"); +// returnedDay = universalDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of constructor of class UniversalDateTime. (int year, int month, int +// day, int hour24Format, int minute, int second, int millisecond) +// */ +// @Test +// public void testUniversalDateTime_7args_day6MustBeReturned() { +// //arrange +// UniversalDateTime universalDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); +// returnedDay = universalDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of constructor of class UniversalDateTime. (ZonedDateTime +// zonedDateTime) +// */ +// @Test +// public void testUniversalDateTime_1argZonedDateTime_day6MustBeReturned() { +// //arrange +// UniversalDateTime universalDateTime; +// TimeZone timeZone; +// ZonedDateTime zonedDateTime; +// int expectedDay = 5; +// int returnedDay; +// //act +// timeZone = new TimeZone("Australia/Sydney"); +// zonedDateTime = new ZonedDateTime(new LocalDateTime(1994, 5, 6, 21, 45, 6, 32), timeZone); +// universalDateTime = new UniversalDateTime(zonedDateTime); +// returnedDay = universalDateTime.getMonth(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of constructor of class UniversalDateTime. (LocalDateTime +// localDateTime) +// */ +// @Test +// public void testUniversalDateTime_1argLocalDateTime_day6MustBeReturned() { +// //arrange +// UniversalDateTime universalDateTime; +// LocalDateTime localDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); +// universalDateTime = new UniversalDateTime(localDateTime); +// +// returnedDay = localDateTime.getDay(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } +// +// /** +// Test of toZonedDateTime method, of class LocalDateTime. +// */ +// @Test +// public void testToZonedDateTime() { +// //arrange +// UniversalDateTime universalDateTime; +// ZonedDateTime zonedDateTime; +// int expectedMonth = 5; +// int returnedMonth; +// //act +// universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); +// zonedDateTime = universalDateTime.toZonedDateTime(); +// returnedMonth = zonedDateTime.getMonth(); +// //assert +// assertEquals(expectedMonth, returnedMonth); +// } +// +// /** +// Test of testToLocalDateTime method, of class LocalDateTime. +// */ +// @Test +// public void testToLocalDateTime() { +// //arrange +// UniversalDateTime universalDateTime; +// LocalDateTime localDateTime; +// +// int expectedMonth = 5; +// int returnedMonth; +// //act +// universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); +// localDateTime = universalDateTime.toLocalDateTime(); +// returnedMonth = universalDateTime.getMonth(); +// //assert +// assertEquals(expectedMonth, returnedMonth); +// } +} diff --git a/power-time/src/test/java/org/nanoboot/powerframework/time/moment/ZonedDateTimeTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/ZonedDateTimeTest.java new file mode 100644 index 0000000..5e93e21 --- /dev/null +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/moment/ZonedDateTimeTest.java @@ -0,0 +1,155 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.moment; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ZonedDateTimeTest { +// +// /** +// +// */ +// public ZonedDateTimeTest() { +// } +// +// /** +// Test of convertDateTimeFromOneTimeZoneToAnother method, of class +// ZonedDateTime. +// */ +// @Test +// public void testConvertDateTimeFromOneTimeZoneToAnother() { +// //arrange +// TimeZone oldTimeZone = new TimeZone("Australia/West"); +// ZonedDateTime oldZonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 11, 5, 10, 5, 4, 64), oldTimeZone); +// String stringRepresentationOfOldZonedDateTime = oldZonedDateTime.toString(); +// +// String expectedStringValue = "1995-11-05 13:05:04:064"; +// String returnedStringValue; +// TimeZone newTimeZone = new TimeZone("Australia/Sydney"); +// //act +// returnedStringValue = ZonedDateTime.convertDateTimeFromOneTimeZoneToAnother(stringRepresentationOfOldZonedDateTime, oldTimeZone, newTimeZone); +// //assert +// assertEquals(expectedStringValue, returnedStringValue); +// } +// +// /** +// Test of getTimeZone method, of class ZonedDateTime. +// */ +// @Test +// public void testGetTimeZone() { +// //arrange +// String timeZoneID = "Australia/West"; +// TimeZone timeZone = new TimeZone(timeZoneID); +// ZonedDateTime zonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 8, 5, 10, 5, 4, 64), timeZone); +// TimeZone returnedTimeZone; +// String returnedZoneID; +// //act +// returnedTimeZone = zonedDateTime.getTimeZone(); +// returnedZoneID = returnedTimeZone.getTimeZoneID(); +// //assert +// assertEquals(timeZoneID, returnedZoneID); +// +// } +// +// /** +// Test of toUniversalDateTime method, of class ZonedDateTime. +// */ +// @Test +// public void testToUniversalDateTime() { +// //arrange +// TimeZone oldTimeZone = new TimeZone("Australia/West"); +// ZonedDateTime zonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 8, 5, 10, 5, 4, 64), oldTimeZone); +// String stringRepresentationOfZonedDateTime = zonedDateTime.toString(); +// +// String expectedStringValue = "1995-08-05 02:05:04:064"; +// String returnedStringValue; +// //act +// UniversalDateTime universalDateTime = zonedDateTime.toUniversalDateTime(); +// returnedStringValue = universalDateTime.toString(); +// //assert +// assertEquals(expectedStringValue, returnedStringValue); +// } +// +// /** +// Test of toLocalDateTime method, of class ZonedDateTime. +// */ +// @Test +// public void testToLocalDateTime() { +// //arrange +// TimeZone oldTimeZone = new TimeZone("Australia/West"); +// ZonedDateTime zonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 8, 5, 10, 5, 4, 64), oldTimeZone); +// String stringRepresentationOfZonedDateTime = zonedDateTime.toString(); +// +// String expectedStringValue = "1995-08-05 10:05:04:064"; +// String returnedStringValue; +// //act +// LocalDateTime localDateTime = zonedDateTime.toLocalDateTime(); +// returnedStringValue = localDateTime.toString(); +// //assert +// assertEquals(expectedStringValue, returnedStringValue); +// } +// +// /** +// Test of toZonedDateTime method, of class ZonedDateTime. +// */ +// @Test +// public void testToZonedDateTime() { +// //arrange +// TimeZone oldTimeZone = new TimeZone("Australia/West"); +// ZonedDateTime oldZonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 11, 5, 10, 5, 4, 64), oldTimeZone); +// String stringRepresentationOfOldZonedDateTime = oldZonedDateTime.toString(); +// +// TimeZone newTimeZone = new TimeZone("Australia/Sydney"); +// ZonedDateTime newZonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 11, 5, 13, 5, 4, 64), oldTimeZone); +// +// String expectedStringValue = "1995-11-05 13:05:04:064"; +// String returnedStringValue; +// //act +// String stringRepresentationOfNewZonedDateTime = newZonedDateTime.toString(); +// returnedStringValue = stringRepresentationOfNewZonedDateTime; +// //assert +// assertEquals(expectedStringValue, returnedStringValue); +// } +// +// /** +// Test of toJavaZonedDateTime method, of class ZonedDateTime. +// */ +// @Test +// public void testToJavaZonedDateTime() { +// //arrange +// TimeZone timeZone = new TimeZone("Australia/West"); +// ZonedDateTime zonedDateTime; +// zonedDateTime = new ZonedDateTime(new LocalDateTime(1994, 5, 6, 21, 45, 6, 32), timeZone); +// java.time.ZonedDateTime javaZonedDateTime; +// int expectedDay = 6; +// int returnedDay; +// //act +// +// javaZonedDateTime = zonedDateTime.toJavaZonedDateTime(); +// returnedDay = javaZonedDateTime.getDayOfMonth(); +// //assert +// assertEquals(expectedDay, returnedDay); +// } + +} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/DateUnitsValidatorTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/utils/DateUnitsValidatorTest.java similarity index 95% rename from src/test/java/org/nanoboot/powerframework/datetime/DateUnitsValidatorTest.java rename to power-time/src/test/java/org/nanoboot/powerframework/time/utils/DateUnitsValidatorTest.java index 69ab5a5..16a88dd 100644 --- a/src/test/java/org/nanoboot/powerframework/datetime/DateUnitsValidatorTest.java +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/utils/DateUnitsValidatorTest.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,15 +18,19 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.datetime; +package org.nanoboot.powerframework.time.utils; -import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.*; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class DateUnitsValidatorTest { /** diff --git a/power-time/src/test/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidatorTest.java b/power-time/src/test/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidatorTest.java new file mode 100644 index 0000000..c0af852 --- /dev/null +++ b/power-time/src/test/java/org/nanoboot/powerframework/time/utils/TimeUnitsValidatorTest.java @@ -0,0 +1,286 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.time.utils; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TimeUnitsValidatorTest { +// +// /** +// +// */ +// public TimeUnitsValidatorTest() { +// } +// +// /** +// Test of isHourValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsHourValid_HourIs13_ThereShouldBeReturnedTrue() { +// //arrange +// int hour = 13; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isHourValid(hour); +// //assert +// assertTrue(returnedValue); +// } +// +// /** +// Test of isHourValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsHourValid_HourIsMinus1_ThereShouldBeReturneFalse() { +// //arrange +// int hour = -1; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isHourValid(hour); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isHourValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsHourValid_HourIs24_ThereShouldBeReturneFalse() { +// //arrange +// int hour = 24; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isHourValid(hour); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isMinuteValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsMinuteValid_MinuteIs34__ThereShouldBeReturnedTrue() { +// //arrange +// int minute = 34; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isMinuteValid(minute); +// //assert +// assertTrue(returnedValue); +// } +// +// /** +// Test of isMinuteValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsMinuteValid_MinuteIsMinus1_ThereShouldBeReturneFalse() { +// //arrange +// int minute = -1; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isMinuteValid(minute); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isMinuteValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsMinuteValid_MinuteIs60_ThereShouldBeReturneFalse() { +// //arrange +// int minute = 60; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isMinuteValid(minute); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isSecondValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsSecondValid_SecondIs46__ThereShouldBeReturnedTrue() { +// //arrange +// int second = 46; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isSecondValid(second); +// //assert +// assertTrue(returnedValue); +// } +// +// /** +// Test of isSecondValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsSecondValid_SecondIsMinus1__ThereShouldBeReturneFalse() { +// //arrange +// int second = -1; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isSecondValid(second); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isSecondValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsSecondValid_SecondIs60__ThereShouldBeReturneFalse() { +// //arrange +// int second = 60; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isSecondValid(second); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isMillisecondValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsMillisecondValid_MillisecondIs843__ThereShouldBeReturnedTrue() { +// //arrange +// int millisecond = 843; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isMillisecondValid(millisecond); +// //assert +// assertTrue(returnedValue); +// } +// +// /** +// Test of isMillisecondValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsMillisecondValid_MillisecondIsMinus1_ThereShouldBeReturneFalse() { +// //arrange +// int millisecond = -1; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isMillisecondValid(millisecond); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of isMillisecondValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testIsMillisecondValid_MillisecondIs1000_ThereShouldBeReturneFalse() { +// //arrange +// int millisecond = 1000; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.isMillisecondValid(millisecond); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of areAllTimeUnitsValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testAreAllTimeUnitsValid_ThereShouldBeReturneTrue() { +// //arrange +// int hour = 2; +// int minute = 34; +// int second = 23; +// int millisecond = 428; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.areAllTimeUnitsValid(hour, minute, second, millisecond); +// //assert +// assertTrue(returnedValue); +// } +// +// /** +// Test of areAllTimeUnitsValid method, of class TimeUnitsValidator. +// */ +// @Test +// public void testAreAllTimeUnitsValid_ThereShouldBeReturneFalse() { +// //arrange +// int hour = 112; +// int minute = 134; +// int second = 123; +// int millisecond = 1428; +// boolean returnedValue; +// //act +// returnedValue = TimeUnitsValidator.areAllTimeUnitsValid(hour, minute, second, millisecond); +// //assert +// assertFalse(returnedValue); +// } +// +// /** +// Test of checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException +// method, of class TimeUnitsValidator. +// */ +// @Test +// public void testCheckInputValuesForTimeAndIfThereIsAnInvalidOneThrowException_ThereShouldBeThrownNoPowerRuntimeException() { +// //arrange +// int hour = 12; +// int minute = 34; +// int second = 23; +// int millisecond = 428; +// boolean isExceptionThrown = false; +// //act +// try { +// TimeUnitsValidator.validate(hour, minute, second, millisecond); +// } catch (PowerException e) { +// isExceptionThrown = true; +// } +// //assert +// if(isExceptionThrown) { +// fail("There should be thrown no PowerRuntimeException"); +// } +// } +// +// /** +// Test of checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException +// method, of class TimeUnitsValidator. +// */ +// @Test +// public void testCheckInputValuesForTimeAndIfThereIsAnInvalidOneThrowException_ThereShouldBeThrownPowerRuntimeException() { +// //arrange +// int hour = 112; +// int minute = 134; +// int second = 123; +// int millisecond = 1428; +// boolean isExceptionThrown = false; +// //act +// try { +// TimeUnitsValidator.validate(hour, minute, second, millisecond); +// } catch (PowerException e) { +// isExceptionThrown = true; +// } +// //assert +// if(!isExceptionThrown) { +// fail("There should be thrown PowerRuntimeException"); +// } +// } +} diff --git a/power-utils/pom.xml b/power-utils/pom.xml new file mode 100644 index 0000000..76d7cdc --- /dev/null +++ b/power-utils/pom.xml @@ -0,0 +1,69 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-utils + jar + + Power Utils + Utils for the Power library + + + true + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-reflection + ${power.version} + + + org.projectlombok + lombok + + + org.jgrapht + jgrapht-core + 1.5.1 + + + org.nanoboot.powerframework + power-text + ${power.version} + compile + + + + diff --git a/power-utils/src/main/java/module-info.java b/power-utils/src/main/java/module-info.java new file mode 100644 index 0000000..a7a392c --- /dev/null +++ b/power-utils/src/main/java/module-info.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.utils { + requires powerframework.core; + requires lombok; + requires powerframework.text; + requires powerframework.reflection; + requires org.jgrapht.core; + exports org.nanoboot.powerframework.utils; + exports org.nanoboot.powerframework.utils.annotations; + exports org.nanoboot.powerframework.utils.dependencies; +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/CommandReader.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/CommandReader.java new file mode 100644 index 0000000..7b31eb9 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/CommandReader.java @@ -0,0 +1,252 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import org.nanoboot.powerframework.text.AsciiCharacter; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CommandReader { + + /** + * Space regexp. + */ + private static final String SPACE_REGEXP = "\\s+"; + /** + * Double colon delimiter. + */ + private static final String SPACE_COLON_COLON_SPACE_DELIMITER = " :: "; + /** + * Default current index. + */ + private static final int DEFAULT_CURRENT_INDEX = -1; + /** + * Array. + */ + private final String[] commands; + /** + * Array index. + */ + private int currentIndex = DEFAULT_CURRENT_INDEX; + + /** + * Current command. + */ + private String currentCommand = null; + + /** + * Constructor. + * + * @param stringToSplit string to be split + */ + public CommandReader(final String stringToSplit) { + if (stringToSplit == null) { + throw new UtilsException("stringToSplit must not be null."); + } + commands = stringToSplit.split(SPACE_REGEXP); + } + + /** + * Returns size of the split commands. + * @return size of the split commands + */ + public int size() { + return commands.length; + } + + /** + * Returns size of the split commands. + * @return size of the split commands + */ + public int isEmpty() { + return commands.length; + } + /** + * Returns current command. + * + * @return current command + */ + public String current() { + return currentCommand; + } + + /** + * Increments the pointer to the current word. + */ + private void incrementCurrentIndex() { + if (!hasNext()) { + throw new UtilsException("CommandReader has no next command."); + } + currentIndex++; + } + /** + * Checks, if there is a next command. + * @return true, if there is a next command, otherwise false + */ + public boolean hasNext() { + int nextIndex = currentIndex + 1; + return isIndexValid(nextIndex); + } + + /** + * Checks, if the index is valid. + * @param index index to be checked + * @return true, if the index is at least zero and + * less than the size, otherwise false + */ + private boolean isIndexValid(final int index) { + return index >= 0 && index < size(); + } + + /** + * Returns next command. + * + * @return next command + */ + public String next() { + incrementCurrentIndex(); + this.currentCommand = commands[currentIndex]; + return current(); + } + + /** + * Almost same as next(). + * The only difference is, that the current number is not updated. + * @return next command, if exists, otherwise an exception is thrown. + */ + public String nextPreview() { + int nextNumber = currentNumber() + 1; + return getCommandByNumber(nextNumber); + } + + /** + * Converts index to number. (one is added) + * @param index index (starting from 0) + * @return number + */ + private int convertIndexToNumber(final int index) { + return index + 1; + } + /** + * Converts number to index. (one is removed) + * @param number number (starting from 1) + * @return number + */ + private int convertNumberToIndex(final int number) { + return number - 1; + } + /** + * Returns command by number. + * @param number number + * @return command + */ + public String getCommandByNumber(final int number) { + if (!isNumberValid(number)) { + throw new UtilsException("Number " + number + " is not valid."); + } + int index = convertNumberToIndex(number); + return this.commands[index]; + } + /** + * Resets this command reader. + */ + public void reset() { + this.currentIndex = DEFAULT_CURRENT_INDEX; + this.currentCommand = null; + } + /** + * Checks, if a number is valid. + * @param number number + * @return true, if the number is valid, otherwise false + */ + public boolean isNumberValid(final int number) { + int index = convertNumberToIndex(number); + return isIndexValid(index); + } + /** + * Returns next as int. + * @return next as int + */ + public int nextAsInt() { + return Integer.parseInt(next()); + } + + /** + * Returns current number. + * @return current number + */ + public int currentNumber() { + return convertIndexToNumber(currentIndex); + } + + /** + * Creates String array representing this CommandReader. + * @return String array + */ + public String[] toArray() { + String[] returnArray = new String[this.commands.length]; + int index = 0; + for (String e: this.commands) { + returnArray[index] = e; + index++; + } + return returnArray; + } + /** + * Creates debugging string. + * @return string representation + * of the command reader for debugging purposes + */ + public String toStringForDebuggingPurposes() { + StringBuilder stringBuilder = new StringBuilder(); + + for (int i = 0; i < commands.length; i++) { + String element = commands[i]; + if (i == this.currentIndex) { + stringBuilder.append('['); + } + stringBuilder.append(element); + if (i == this.currentIndex) { + stringBuilder.append(']'); + } + if (i != (commands.length - 1)) { + stringBuilder.append(AsciiCharacter.SPACE.toChar()); + } + } + return stringBuilder.toString(); + } + + @Override + public final String toString() { + StringBuilder stringBuilder = new StringBuilder(); + for (String element : this.commands) { + stringBuilder + .append(element) + .append(SPACE_COLON_COLON_SPACE_DELIMITER); + } + return stringBuilder.toString(); + } +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConvention.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConvention.java new file mode 100644 index 0000000..93405c7 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConvention.java @@ -0,0 +1,73 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import lombok.Data; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum NamingConvention { + + /** + * Database. + * Example: MY_OBJECT + */ + DATABASE, + + /** + * Java. + * Example: myObject + * Duplicate of JAVA_FIELD + * Example: MyObject + */ + @Deprecated + JAVA, + + /** + * Java. + * Example: myObject + */ + JAVA_FIELD, + + /** + * Java. + * Example: MyObject + */ + JAVA_CLASS, + + + /** + * Human. + * Example: my object + */ + HUMAN, + + /** + * Unknown. + * Used only for test purposes. + */ + UNKNOWN; +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConventionConvertor.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConventionConvertor.java new file mode 100644 index 0000000..df4ab2e --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/NamingConventionConvertor.java @@ -0,0 +1,287 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import org.nanoboot.powerframework.text.AsciiCharacter; + +import java.util.ArrayList; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class NamingConventionConvertor { + + /** + * Delimiter for databases. + */ + private static final String DATABASE_DELIMITER = + AsciiCharacter.UNDERSCORE.asString(); + /** + * Delimiter for humans. + */ + private static final String HUMAN_DELIMITER = + AsciiCharacter.SPACE.asString(); + + /** + * @param name name to convert + * @param inputNamingConvention input naming convention + * @param outputNamingConvention output naming convention + * @return converted name + */ + public static String convert( + final String name, + final NamingConvention inputNamingConvention, + final NamingConvention outputNamingConvention) { + System.out.println("Going to convert name=" + name + " in=" + inputNamingConvention + " out=" + outputNamingConvention); + check(name, inputNamingConvention); + String[] array = convertToArray(name, inputNamingConvention); + StringBuilder stringBuilder = new StringBuilder(); + + if (outputNamingConvention == null) { + throw new UtilsException("Output naming convention is null."); + } + switch (outputNamingConvention) { + case JAVA: + return convertToJavaField(array, stringBuilder); + case JAVA_FIELD: + return convertToJavaField(array, stringBuilder); + case JAVA_CLASS: + return convertToJavaClass(array, stringBuilder); + case DATABASE: + return convertToDatabase(array, stringBuilder); + case HUMAN: + return convertToHuman(array, stringBuilder); + default: + throw new UtilsException( + "Unknown NamingConvention" + inputNamingConvention); + } + + } + + + /** + * Checks name validity. + * + * @param name name to be checked + * @param inputNamingConvention input naming convention + */ + private static void check(final String name, + final NamingConvention inputNamingConvention) { + NamingConvention detectedNamingConvention = detectNamingConvention(name); + boolean valid = detectedNamingConvention == inputNamingConvention; + + if (!valid) { + if (inputNamingConvention == NamingConvention.JAVA && detectedNamingConvention == NamingConvention.JAVA_FIELD) { + valid = true; + } + } + if (!valid) { + String msg = "Wrong name and input naming convention combination: name=" + + name + ", in=" + inputNamingConvention + ", but detected is=" + detectedNamingConvention; + throw new UtilsException(msg); + } + } + + /** + * Detects naming convention. + * + * @param name name to detect + * @return detected naming convention + */ + public static NamingConvention detectNamingConvention( + final String name) { + boolean databasePredicate = name.contains(DATABASE_DELIMITER) || stringHasAllUpperCase(name); + boolean humanPredicate = name.contains(HUMAN_DELIMITER); + if (databasePredicate && !humanPredicate) { + return NamingConvention.DATABASE; + } + if (!databasePredicate && humanPredicate) { + return NamingConvention.HUMAN; + } + if (databasePredicate /*&& humanPredicate*/) { + String msg = "The name contain database and also human delimiters."; + throw new UtilsException(msg); + } + return Character.isUpperCase(name.charAt(0)) ? NamingConvention.JAVA_CLASS : NamingConvention.JAVA_FIELD; + } + + private static boolean stringHasAllUpperCase(final String s) { + for (char ch : s.toCharArray()) { + if (Character.isLetter(ch)) { + if (Character.isLowerCase(ch)) { + return false; + } + } + } + return true; + } + + /** + * Converts the Strings to Human representation. + * + * @param array array + * @param stringBuilder stringBuilder + * @return human words + */ + private static String convertToHuman(final String[] array, + final StringBuilder stringBuilder) { + for (String element : array) { + stringBuilder.append(element.toLowerCase()).append(HUMAN_DELIMITER); + } + String tempString = stringBuilder.toString(); + return tempString.substring(0, tempString.length() - 1); + } + + /** + * Converts the Strings to database representation. + * + * @param array array + * @param stringBuilder stringBuilder + * @return database words + */ + private static String convertToDatabase(final String[] array, + final StringBuilder stringBuilder) { + for (String element : array) { + stringBuilder + .append(element.toUpperCase()).append(DATABASE_DELIMITER); + } + String tempString = stringBuilder.toString(); + return tempString.substring(0, tempString.length() - 1); + } + + /** + * Converts the Strings to Java representation. + * + * @param array array + * @param stringBuilder stringBuilder + * @return Java words + */ + private static String convertToJavaField(final String[] array, + final StringBuilder stringBuilder) { + String string = convertToJavaClass(array, stringBuilder); + return Character.toLowerCase( + string.charAt(0)) + string.substring(1); + + } + + private static String convertToJavaClass(String[] array, StringBuilder stringBuilder) { + for (String element : array) { + if (element.length() != 0) { + stringBuilder.append(Character.toUpperCase(element.charAt(0))); + stringBuilder.append(element.substring(1, element.length())); + } + } + String tempString = stringBuilder.toString(); + return tempString; + } + + /** + * Converts input string to array, all characters are changed to lower case. + * + * @param name name to convert + * @param inputNamingConvention input naming convention + * @return String array + */ + private static String[] convertToArray( + final String name, + final NamingConvention inputNamingConvention) { + + switch (inputNamingConvention) { + case DATABASE: + return name.toLowerCase().split(DATABASE_DELIMITER); + case JAVA: + return getArrayFromJavaConvention(name); + case JAVA_FIELD: + return getArrayFromJavaConvention(name); + case JAVA_CLASS: + return getArrayFromJavaConvention(name); + case HUMAN: + return name.toLowerCase().split(HUMAN_DELIMITER); + default: + String msg = "Unknown NamingConvention" + inputNamingConvention; + throw new UtilsException(msg); + } + } + + /** + * Creates array from Java convention. + * + * @param name name + * @return String array + */ + private static String[] getArrayFromJavaConvention(final String name) { + String finalName = name; + if (Character.isUpperCase(finalName.charAt(0))) { + finalName = finalName.substring(0, 1).toLowerCase() + finalName.substring(1); + } + + ArrayList upperCharPositions = getIndexesOfUpperChars(finalName); + String[] result = new String[upperCharPositions.size() + 1]; + int startIndex; + int endIndex = 0; + int resultIndex = 0; + for (int element : upperCharPositions) { + if (element == 0) { + continue; + } + startIndex = endIndex; + endIndex = element; + result[resultIndex] = finalName + .substring(startIndex, endIndex).toLowerCase(); + resultIndex++; + } + startIndex = endIndex; + endIndex = finalName.length(); + result[resultIndex] = finalName.substring(startIndex, endIndex); + + return result; + } + + /** + * Returns indexes of all upper characters of the String. + * + * @param name name + * @return String array with indexes + */ + private static ArrayList getIndexesOfUpperChars( + final String name) { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < name.length(); i++) { + char ch = name.charAt(i); + if (Character.isUpperCase(ch)) { + list.add(i); + } + } + return list; + } + + /** + * Constructor. + *

+ * Not meant to be instantiated. + */ + private NamingConventionConvertor() { + //Not meant to be instantiated. + } +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/StringTemplate.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/StringTemplate.java new file mode 100644 index 0000000..a5b0eab --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/StringTemplate.java @@ -0,0 +1,65 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +/** + * + * @author robertvokac + */ + +import java.util.HashMap; +import java.util.Map; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class StringTemplate { + public static final String VAR_START = "{{{{"; + public static final String VAR_END = "}}}}"; + private final String template; + + public StringTemplate(String template) { + this.template = template; + } + public String apply(Map map) { + String result = template; + for(String key:map.keySet()) { + String var = VAR_START + key + VAR_END; + String value = map.get(key); + result = result.replace(var, value); + } + if(result.contains(VAR_START)) { + throw new UtilsException("Template \"" + result + "\"still contains \"" + VAR_START + "\"."); + } + + if(result.contains(VAR_END)) { + throw new UtilsException("Template \"" + result + "\"still contains \"" + VAR_END + "\"."); + } + return result; + } + public Map createEmptyMap() { + return new HashMap<>(); + } +} + + diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/StringUtils.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/StringUtils.java new file mode 100644 index 0000000..33b0f30 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/StringUtils.java @@ -0,0 +1,84 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class StringUtils { + + /** + * "" Constant. + */ + public static final String EMPTY_STRING = ""; + + /** + * Appends objects. + * @param objects objects to append + * + * @return appended objects + */ + public static String appendObjects(final Object... objects) { + StringBuilder stringBuilder = new StringBuilder(); + for (Object element : objects) { + stringBuilder.append(element); + } + return stringBuilder.toString(); + } + + /** + * Checks, if a string is empty. + * @param string string to check + * @return true, if the string is empty, otherwise false. + */ + public static boolean isEmpty(final String string) { + return string.equals(EMPTY_STRING); + } + + /** + * Converts string to int. + * @param string string to convert + * @return int + */ + public static int toInt(final String string) { + return Integer.valueOf(string); + } + + /** + * Creates lines from a String. + * @param string string to split + * @return splitted string + */ + public static String[] toLines(final String string) { + return string.split("\\r?\\n"); + } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private StringUtils() { + } +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/UtilsException.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/UtilsException.java new file mode 100644 index 0000000..272ea39 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/UtilsException.java @@ -0,0 +1,42 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class UtilsException extends PowerException { + + /** + * Constructor. + * @param message detail of the exception + */ + public UtilsException(final String message) { + super(message); + } + +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/Done.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/Done.java new file mode 100644 index 0000000..801f849 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/Done.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.annotations; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public @interface Done { + +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/InProgress.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/InProgress.java new file mode 100644 index 0000000..698dc2f --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/InProgress.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.annotations; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public @interface InProgress { + /** + * Description. + * @return text + */ + String description() default ""; +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToDo.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToDo.java new file mode 100644 index 0000000..a05f769 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToDo.java @@ -0,0 +1,35 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.annotations; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public @interface ToDo { + /** + * Description. + * @return text + */ + String description() default ""; +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToRemove.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToRemove.java new file mode 100644 index 0000000..bdef6db --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/ToRemove.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.annotations; + +/** + * Describes a work (code). + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public @interface ToRemove { + +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/package-info.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/package-info.java new file mode 100644 index 0000000..0dc3f69 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/annotations/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Some annotations. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.utils.annotations; diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/AbstractBuilder.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/AbstractBuilder.java new file mode 100644 index 0000000..842243a --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/AbstractBuilder.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.builder; + +import org.nanoboot.powerframework.reflection.ReflectionUtils; + +/** + * Builder abstract implementation. + * @param + * + * @author Robert Vokac + * @since 0.0.0 + */ +public abstract class AbstractBuilder implements Builder { + /** + * The object, which is modified and finally returned by build() method. + */ + protected final T result = (T) ReflectionUtils + .newInstance(ReflectionUtils.getConstructor(getClassUsedByThisBuilder())); + abstract Class getClassUsedByThisBuilder(); + @Override + public final T build() { + return result; + } +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/Builder.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/Builder.java new file mode 100644 index 0000000..22dd366 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/Builder.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.builder; + +/** + * Builder generic interface for builders. + * @param Class for this generic interface + * + * @author Robert Vokac + * @since 0.0.0 + */ +public interface Builder { + /** + * Builds the final object. + * @return object instance + */ + T build(); +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/package-info.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/package-info.java new file mode 100644 index 0000000..0f88f78 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/builder/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Builder utilities. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.utils.builder; diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/collections/ListSplitter.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/collections/ListSplitter.java new file mode 100644 index 0000000..0f3b566 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/collections/ListSplitter.java @@ -0,0 +1,67 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.collections; + +import java.util.ArrayList; +import java.util.List; +import org.nanoboot.powerframework.utils.UtilsException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class ListSplitter { + private ListSplitter() { + //Not meant to be instantiated. + } + public static List> splitListToSublists(List inputList, int sizePerSublist) { + if(sizePerSublist < 2) { + throw new UtilsException("sizePerSublist is " + sizePerSublist + ", but it must be 2 or more."); + } + List> outputList = new ArrayList<>(); + if(inputList.isEmpty()) { + return outputList; + } + List tmpList = null; + for(int i = 0; i < inputList.size(); i++) { + if(tmpList == null) { + tmpList = new ArrayList<>(); + } + T element = inputList.get(i); + tmpList.add(element); + if(tmpList.size() == sizePerSublist) { + outputList.add(tmpList); + tmpList = null; + } + } + if(tmpList != null) { + outputList.add(tmpList); + tmpList = null; + } + return outputList; +} + + + +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/compression/.gitkeep b/power-utils/src/main/java/org/nanoboot/powerframework/utils/compression/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyNode.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyNode.java new file mode 100644 index 0000000..01f53dc --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyNode.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.dependencies; + +import java.util.ArrayList; +import java.util.List; +import lombok.Data; +import lombok.ToString; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +@ToString +public class DependencyNode { + + private final String name; + private List dependencies = new ArrayList<>(); + + public DependencyNode(String nameIn, List dependenciesIn) { + this.name = nameIn; + for (String s : dependenciesIn) { + this.dependencies.add(s); + } + } + + DependencyNode(String nameIn) { + this.name = nameIn; + } + +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolver.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolver.java new file mode 100644 index 0000000..6c48c79 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolver.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.dependencies; + +import java.util.List; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface DependencyResolver { + List resolve(List dependencyNodesIn); +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImpl.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImpl.java new file mode 100644 index 0000000..8fc475d --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImpl.java @@ -0,0 +1,61 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.dependencies; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.jgrapht.Graph; +import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.graph.DirectedAcyclicGraph; +import org.jgrapht.traverse.TopologicalOrderIterator; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DependencyResolverJGraphTImpl implements DependencyResolver{ + public List resolve(List dependencyNodesIn) { + // DirectAcyclicGraph to prevent circular dependency + Graph directedGraph = new DirectedAcyclicGraph<>(DefaultEdge.class); + List dependencyNodes = dependencyNodesIn; + Map taskNameToTaskMap = dependencyNodes.stream() + .collect(Collectors.toMap(task -> task.getName(), task -> task)); + for (DependencyNode task : dependencyNodes) { + directedGraph.addVertex(task); + for (String predecessor : task.getDependencies()) { + DependencyNode predecessorTask = taskNameToTaskMap.get(predecessor); + directedGraph.addVertex(predecessorTask); + directedGraph.addEdge(predecessorTask, task); + } + } + TopologicalOrderIterator moreDependencyFirstIterator = new TopologicalOrderIterator<>( + directedGraph); + List result = new ArrayList<>(); + moreDependencyFirstIterator.forEachRemaining(dependencyNode -> result.add(dependencyNode.getName())); + return result; + } + +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/minitext/.gitkeep b/power-utils/src/main/java/org/nanoboot/powerframework/utils/minitext/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/package-info.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/package-info.java new file mode 100644 index 0000000..d2069de --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Utils. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.utils; diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/MethodInvoker.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/MethodInvoker.java new file mode 100644 index 0000000..02fa161 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/MethodInvoker.java @@ -0,0 +1,33 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.proxy; + +import java.lang.reflect.Method; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public interface MethodInvoker { + Object invoke(Object original, Object proxy, Method method, Object[] args) throws Exception; +} diff --git a/power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/ProxyUtils.java b/power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/ProxyUtils.java new file mode 100644 index 0000000..4c26c93 --- /dev/null +++ b/power-utils/src/main/java/org/nanoboot/powerframework/utils/proxy/ProxyUtils.java @@ -0,0 +1,136 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.List; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ProxyUtils { + + private static class InvocationHandlerImpl implements InvocationHandler { + + private final T original; + private final MethodInvoker methodInvoker; + + public InvocationHandlerImpl(T original, MethodInvoker methodInvoker) { + this.original = original; + this.methodInvoker = methodInvoker; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Exception { + return this.methodInvoker.invoke(original, proxy, method, args); + } + } + + + + public static void main(String[] args) { + // class ListHandler implements InvocationHandler { + // + // private final List originalList; + // + // public ListHandler(List originalList) { + // this.originalList = originalList; + // } + // + // @Override + // public Object invoke(Object proxy, Method method, Object[] args) throws Exception { + // StringBuilder argsAsOneString = new StringBuilder(); + // if (args != null) { + // for (Object arg : args) { + // argsAsOneString.append(arg).append(", "); + // } + // } + // String argsAsOneStringStr = argsAsOneString.toString(); + // if (!argsAsOneStringStr.isEmpty()) { + // argsAsOneStringStr = argsAsOneStringStr.substring(0, argsAsOneStringStr.length() - 2); + // } + // System.out.println("Calling List method: " + method.getName() + "(" + argsAsOneStringStr + ")"); + // Object o = method.invoke(originalList, args); // zavolá původní metodu + // if (method.getName().equals("size")) { + // return ((Integer) o) * 2; + // } + // if (method.getName().equals("add")) { + // //again- for second time + // return method.invoke(originalList, args); // zavolá původní metodu + // } + // return o; + // } + // } + + List list = new ArrayList<>(); + + // List proxyList = (List) Proxy.newProxyInstance(List.class.getClassLoader(), + // new Class[] {List.class}, new ListHandler(list)); + + MethodInvoker methodInvoker = new MethodInvoker() { + @Override + public Object invoke(Object original, Object proxy, Method method, Object[] args) throws Exception { + StringBuilder argsAsOneString = new StringBuilder(); + if (args != null) { + for (Object arg : args) { + argsAsOneString.append(arg).append(", "); + } + } + String argsAsOneStringStr = argsAsOneString.toString(); + if (!argsAsOneStringStr.isEmpty()) { + argsAsOneStringStr = argsAsOneStringStr.substring(0, argsAsOneStringStr.length() - 2); + } + System.out.println("Calling List method: " + method.getName() + "(" + argsAsOneStringStr + ")"); + Object o = method.invoke(original, args); // zavolá původní metodu + if (method.getName().equals("size")) { + return ((Integer) o) * 2; + } + if (method.getName().equals("add")) { + //again- for second time + return method.invoke(original, args); // zavolá původní metodu + } + return o; + } + }; + List proxyList2 = createProxy(list, List.class, methodInvoker); + proxyList2.add("ahoj"); + proxyList2.add("dobry den"); + proxyList2.add("na shledanou"); + proxyList2.add("zdar"); + System.out.println("proxyList.size()=" + proxyList2.size()); + proxyList2.get(0); + for (String s : proxyList2) { + System.out.println("s = " + s); + } + } + + public static T createProxy(T original, Class interfaceClazz, MethodInvoker methodInvoker) { + return (T) Proxy.newProxyInstance(interfaceClazz.getClassLoader(), + new Class[] {interfaceClazz}, new InvocationHandlerImpl(original, methodInvoker)); + } +} + + diff --git a/power-utils/src/main/resources/.gitkeep b/power-utils/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-utils/src/test/java/.gitkeep b/power-utils/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-utils/src/test/java/org/nanoboot/powerframework/utils/CommandReaderTest.java b/power-utils/src/test/java/org/nanoboot/powerframework/utils/CommandReaderTest.java new file mode 100644 index 0000000..05276a9 --- /dev/null +++ b/power-utils/src/test/java/org/nanoboot/powerframework/utils/CommandReaderTest.java @@ -0,0 +1,263 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CommandReaderTest { + + @Test(expected = UtilsException.class) + public void constructor_exception() { + //prepare + CommandReader commandReader = new CommandReader(null); + //execute + //assert + } + + @Test + public void size() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertEquals(5, commandReader.size()); + } + + @Test + public void current() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertNull(commandReader.current()); + commandReader.next(); + assertEquals("A", commandReader.current()); + commandReader.next(); + assertEquals("B", commandReader.current()); + commandReader.nextPreview(); + assertEquals("B", commandReader.current()); + } + + @Test + public void hasNext() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertTrue(commandReader.hasNext()); + commandReader.next(); + assertTrue(commandReader.hasNext()); + commandReader.next(); + assertTrue(commandReader.hasNext()); + commandReader.next(); + assertTrue(commandReader.hasNext()); + commandReader.next(); + assertTrue(commandReader.hasNext()); + commandReader.next(); + assertFalse(commandReader.hasNext()); + } + + @Test + public void next() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertEquals("A", commandReader.next()); + assertEquals("B", commandReader.next()); + assertEquals("C", commandReader.next()); + assertEquals("D", commandReader.nextPreview()); + assertEquals("D", commandReader.next()); + assertEquals("E", commandReader.next()); + assertFalse(commandReader.hasNext()); + } + @Test(expected = UtilsException.class) + public void next_exception() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + commandReader.next(); + commandReader.next(); + commandReader.next(); + commandReader.next(); + commandReader.next(); + commandReader.next(); + } + + @Test + public void nextPreview() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertEquals("A", commandReader.next()); + assertEquals("B", commandReader.nextPreview()); + assertEquals("B", commandReader.nextPreview()); + assertEquals("B", commandReader.nextPreview()); + assertEquals("B", commandReader.nextPreview()); + assertEquals("B", commandReader.next()); + assertEquals("C", commandReader.next()); + assertEquals("D", commandReader.next()); + assertEquals("E", commandReader.nextPreview()); + assertEquals("E", commandReader.nextPreview()); + assertEquals("E", commandReader.nextPreview()); + assertEquals("E", commandReader.next()); + } + + @Test + public void getCommandByNumber() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertEquals("A", commandReader.getCommandByNumber(1)); + assertEquals("B", commandReader.getCommandByNumber(2)); + assertEquals("C", commandReader.getCommandByNumber(3)); + assertEquals("D", commandReader.getCommandByNumber(4)); + assertEquals("E", commandReader.getCommandByNumber(5)); + } + + @Test(expected = UtilsException.class) + public void getCommandByNumber_exception1() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + commandReader.getCommandByNumber(0); + } + + @Test(expected = UtilsException.class) + public void getCommandByNumber_exception2() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + commandReader.getCommandByNumber(6); + } + + @Test + public void reset() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + commandReader.next(); + commandReader.next(); + commandReader.next(); + commandReader.reset(); + //assert + assertEquals("A", commandReader.next()); + assertEquals("B", commandReader.next()); + assertEquals("C", commandReader.next()); + commandReader.reset(); + assertEquals("A", commandReader.next()); + assertEquals("B", commandReader.next()); + } + + @Test + public void isNumberValid() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + for(int number = -5; number < 20; number++) { + boolean numberIsValid = commandReader.isNumberValid(number); + if (number >= 1 && number <= 5) { + assertTrue(numberIsValid); + } else { + assertFalse(numberIsValid); + } + } + } + + @Test + public void nextAsInt() { + //prepare + CommandReader commandReader = new CommandReader("A B 4 D E"); + //execute + commandReader.next(); + commandReader.next(); + //assert + assertEquals(4, commandReader.nextAsInt()); + } + + @Test + public void currentNumber() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertEquals(0, commandReader.currentNumber()); + commandReader.next(); + assertEquals(1, commandReader.currentNumber()); + commandReader.next(); + assertEquals(2, commandReader.currentNumber()); + commandReader.next(); + assertEquals(3, commandReader.currentNumber()); + commandReader.next(); + assertEquals(4, commandReader.currentNumber()); + commandReader.next(); + assertEquals(5, commandReader.currentNumber()); + } + + @Test + public void toArray() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + //assert + assertArrayEquals((new String[] {"A", "B", "C", "D", "E"}), commandReader.toArray()); + } + + @Test + public void toStringForDebuggingPurposes() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + commandReader.next(); + commandReader.next(); + commandReader.next(); + commandReader.next(); + //assert + assertEquals("A B C [D] E", commandReader.toStringForDebuggingPurposes()); + } + + @Test + public void testToString() { + //prepare + CommandReader commandReader = new CommandReader("A B C D E"); + //execute + commandReader.next(); + commandReader.next(); + commandReader.next(); + commandReader.next(); + //assert + assertEquals("A :: B :: C :: D :: E :: ", commandReader.toString()); + } +} diff --git a/power-utils/src/test/java/org/nanoboot/powerframework/utils/NamingConventionConvertorTest.java b/power-utils/src/test/java/org/nanoboot/powerframework/utils/NamingConventionConvertorTest.java new file mode 100644 index 0000000..74382c1 --- /dev/null +++ b/power-utils/src/test/java/org/nanoboot/powerframework/utils/NamingConventionConvertorTest.java @@ -0,0 +1,224 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class NamingConventionConvertorTest { + + private static final String DATABASE_STRING = "MY_BEST_FRIEND"; + private static final String HUMAN_STRING = "my best friend"; + private static final String JAVA_STRING = "myBestFriend"; + private static final String UNKNOWN_STRING = "my-best-friend"; + @Test + public void convert_database_human() { + //prepare + String input = DATABASE_STRING; + String expected = HUMAN_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.DATABASE; + NamingConvention outputNamingConvention = NamingConvention.HUMAN; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + @Test + public void convert_database_java() { + //prepare + String input = DATABASE_STRING; + String expected = JAVA_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.DATABASE; + NamingConvention outputNamingConvention = NamingConvention.JAVA_FIELD; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + @Test + public void convert_human_database() { + //prepare + String input = HUMAN_STRING; + String expected = DATABASE_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.HUMAN; + NamingConvention outputNamingConvention = NamingConvention.DATABASE; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + @Test + public void convert_human_java() { + //prepare + String input = HUMAN_STRING; + String expected = JAVA_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.HUMAN; + NamingConvention outputNamingConvention = NamingConvention.JAVA_FIELD; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + @Test + public void convert_java_database() { + //prepare + String input = JAVA_STRING; + String expected = DATABASE_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.JAVA_FIELD; + NamingConvention outputNamingConvention = NamingConvention.DATABASE; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + @Test + public void convert_java_human() { + //prepare + String input = JAVA_STRING; + String expected = HUMAN_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.JAVA_FIELD; + NamingConvention outputNamingConvention = NamingConvention.HUMAN; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + + @Test + public void convert_database_database() { + //prepare + String input = DATABASE_STRING; + String expected = DATABASE_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.DATABASE; + NamingConvention outputNamingConvention = NamingConvention.DATABASE; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + + @Test + public void convert_human_human() { + //prepare + String input = HUMAN_STRING; + String expected = HUMAN_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.HUMAN; + NamingConvention outputNamingConvention = NamingConvention.HUMAN; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + + @Test + public void convert_java_java() { + //prepare + String input = JAVA_STRING; + String expected = JAVA_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.JAVA_FIELD; + NamingConvention outputNamingConvention = NamingConvention.JAVA_FIELD; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + + @Test(expected = UtilsException.class) + public void convert_java_unknwon() { + //prepare + String input = JAVA_STRING; + String expected = UNKNOWN_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.JAVA_FIELD; + NamingConvention outputNamingConvention = NamingConvention.UNKNOWN; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + + @Test(expected = UtilsException.class) + public void convert_exception() { + //prepare + String input = JAVA_STRING; + String expected = JAVA_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.JAVA_FIELD; + NamingConvention outputNamingConvention = null; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + @Test(expected = UtilsException.class) + public void convert_invalidArguments_exception() { + //prepare + String input = HUMAN_STRING; + String expected = DATABASE_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.JAVA_FIELD; + NamingConvention outputNamingConvention = NamingConvention.DATABASE; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } + + @Test + public void detectNamingConvention() { + assertEquals(NamingConvention.DATABASE, NamingConventionConvertor.detectNamingConvention("ABC_DEF_GHI")); + assertEquals(NamingConvention.HUMAN, NamingConventionConvertor.detectNamingConvention("abc def ghi")); + assertEquals(NamingConvention.JAVA_FIELD, NamingConventionConvertor.detectNamingConvention("abcDefGhi")); + } + @Test(expected = UtilsException.class) + public void detectNamingConvention2() { + assertEquals(NamingConvention.DATABASE, NamingConventionConvertor.detectNamingConvention("ABC_DEF GHI")); + } + + @Test(expected = UtilsException.class) + public void convert_unknwon_java() { + //prepare + String input = UNKNOWN_STRING; + String expected = JAVA_STRING; + String returned; + NamingConvention inputNamingConvention = NamingConvention.UNKNOWN; + NamingConvention outputNamingConvention = NamingConvention.JAVA_FIELD; + //execute + returned = NamingConventionConvertor.convert(input, inputNamingConvention, outputNamingConvention); + //assert + assertEquals(expected, returned); + } +} diff --git a/power-utils/src/test/java/org/nanoboot/powerframework/utils/StringUtilsTest.java b/power-utils/src/test/java/org/nanoboot/powerframework/utils/StringUtilsTest.java new file mode 100644 index 0000000..20c4e72 --- /dev/null +++ b/power-utils/src/test/java/org/nanoboot/powerframework/utils/StringUtilsTest.java @@ -0,0 +1,55 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class StringUtilsTest { + + @Test + public void appendObjects() { + String result = StringUtils.appendObjects(6, "b", true, 5l, "gf", "abc"); + assertEquals("6btrue5gfabc", result); + } + + @Test + public void isEmpty() { + assertTrue(StringUtils.isEmpty("")); + assertFalse(StringUtils.isEmpty("abc")); + } + + @Test + public void toInt() { + assertEquals(5, StringUtils.toInt("5")); + } + + @Test + public void toLines() { + assertArrayEquals(new String[] {"a", "b", "c"}, StringUtils.toLines("a\nb\nc")); + } +} diff --git a/power-utils/src/test/java/org/nanoboot/powerframework/utils/UtilsExceptionTest.java b/power-utils/src/test/java/org/nanoboot/powerframework/utils/UtilsExceptionTest.java new file mode 100644 index 0000000..a492ed7 --- /dev/null +++ b/power-utils/src/test/java/org/nanoboot/powerframework/utils/UtilsExceptionTest.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils; + +import org.junit.Test; + +import static org.junit.Assert.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class UtilsExceptionTest { + @Test + public void constructor_String() { + assertEquals("An error", new UtilsException("An error").getMessage()); + } +} diff --git a/power-utils/src/test/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImplTest.java b/power-utils/src/test/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImplTest.java new file mode 100644 index 0000000..b7b71b6 --- /dev/null +++ b/power-utils/src/test/java/org/nanoboot/powerframework/utils/dependencies/DependencyResolverJGraphTImplTest.java @@ -0,0 +1,83 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.utils.dependencies; + +import org.junit.Test; + +import static org.junit.Assert.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DependencyResolverJGraphTImplTest { + + public DependencyResolverJGraphTImplTest() { + } + + /** + * Test of resolve method, of class DependencyResolverJGraphTImpl. + */ + @Test + public void testResolve() { + System.out.println("resolve"); + //prepare + List dependencyNodes = new ArrayList<>(); + + dependencyNodes.add(new DependencyNode("development", Arrays.asList("task"))); + dependencyNodes.add(new DependencyNode("task")); + dependencyNodes.add(new DependencyNode("person", Arrays.asList("task"))); + dependencyNodes.add(new DependencyNode("encyclopedia")); + dependencyNodes.add(new DependencyNode("system")); + dependencyNodes.add(new DependencyNode("favorite", Arrays.asList())); + dependencyNodes.add(new DependencyNode("action-log", Arrays.asList())); + dependencyNodes.add(new DependencyNode("pinning", Arrays.asList())); + dependencyNodes.add(new DependencyNode("reminder", Arrays.asList())); + dependencyNodes.add(new DependencyNode("whining", Arrays.asList())); + for (DependencyNode dn : dependencyNodes) { + if (!dn.getName().equals("system")) { + dn.getDependencies().add("system"); + } + if (dn.getName().equals("action-log") || dn.getName().equals("favorite") || dn.getName().equals("pinning") || dn.getName().equals("reminder") || dn.getName().equals("whining") || dn.getName().equals("system")) { + //nothing to do + } else { + dn.getDependencies().addAll(Arrays.asList("action-log", "favorite", "pinning", "reminder", "whining")); + } + } + + DependencyResolverJGraphTImpl instance = new DependencyResolverJGraphTImpl(); + List expResult = new ArrayList<>(); + expResult.addAll(Arrays.asList("system", "favorite", "action-log", "pinning", "reminder", "whining", "task", "encyclopedia", "development", "person")); + //execute + List result = instance.resolve(dependencyNodes); + for (String s : result) { + } + //assert + assertEquals(expResult, result); + } + +} diff --git a/power-view/pom.xml b/power-view/pom.xml new file mode 100644 index 0000000..af7e0f3 --- /dev/null +++ b/power-view/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-view + jar + + Power View + View functionality for the Power library + + 19 + + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + + org.nanoboot.powerframework + power-random + ${power.version} + + + + junit + junit + 4.12 + test + + + org.openjfx + javafx-controls + ${javafx.version} + + + diff --git a/power-view/src/main/java/module-info.java b/power-view/src/main/java/module-info.java new file mode 100644 index 0000000..2707477 --- /dev/null +++ b/power-view/src/main/java/module-info.java @@ -0,0 +1,38 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.view { + requires javafx.graphics; + requires javafx.controls; + requires java.logging; + requires powerframework.random; + requires powerframework.core; + exports org.nanoboot.powerframework.view; + exports org.nanoboot.powerframework.view.window; + exports org.nanoboot.powerframework.view.window.controls; + exports org.nanoboot.powerframework.view.layouts; + exports org.nanoboot.powerframework.view.boxes; +} diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/EnumColour.java b/power-view/src/main/java/org/nanoboot/powerframework/view/EnumColour.java similarity index 81% rename from src/main/java/org/nanoboot/powerframework/simplicity/EnumColour.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/EnumColour.java index bea95c4..882c9ce 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/EnumColour.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/EnumColour.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,16 +18,24 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity; +package org.nanoboot.powerframework.view; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.pseudorandom.PseudoRandomGenerator; +import org.nanoboot.powerframework.random.generators.linearcongruent.combined.w5.W5RandomGenerator; /** * Represents one of 16 colours, or there is no colour. * - * @author Robert Vokac robertvokac@nanoboot.org + * @author Robert Vokáč robertvokac@nanoboot.org */ +//To be removed +@Deprecated +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + public enum EnumColour { /** @@ -113,14 +121,15 @@ public enum EnumColour { /** * - * @param number - * @return + * @param numberIn number representation of the enum EnumColour + * + * @return EnumColour instance based on the numberIn value */ - public static EnumColour convertNumberToEnumColour(int number) {//NOSONAR - if (!isNumberRepresentationValid(number)) { - throw new PowerRuntimeException("Number you want co convert to EnumColour must be at least 0 and at most 16."); + public static EnumColour convertNumberToEnumColour(int numberIn) {//NOSONAR + if(!isNumberRepresentationValid(numberIn)) { + throw new ViewException("Number you want co convert to EnumColour must be at least 0 and at most 16."); } - switch (number) { + switch (numberIn) { case 0: return EnumColour.NOCOLOUR; case 1: @@ -170,7 +179,7 @@ public enum EnumColour { * @return random EnumColour */ public static EnumColour getRandom() { - int i = PseudoRandomGenerator.getInstance().getInt(1, 16); + int i = W5RandomGenerator.getStaticInstance().nextInt(1, 16); return EnumColour.convertNumberToEnumColour(i); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/JavaFXApplication.java b/power-view/src/main/java/org/nanoboot/powerframework/view/JavaFXApplication.java similarity index 83% rename from src/main/java/org/nanoboot/powerframework/simplicity/JavaFXApplication.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/JavaFXApplication.java index c956140..1ccec08 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/JavaFXApplication.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/JavaFXApplication.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,30 +18,31 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity; +package org.nanoboot.powerframework.view; -import javafx.application.Application; -import javafx.stage.Stage; +import javafx.application.*; +import javafx.stage.*; /** * Represents Java FX application. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class JavaFXApplication extends Application { - void launchJavaFXApplication() { - launch(); - } - static void startJavaFXApplication() { JavaFXApplication javaFXApplication = new JavaFXApplication(); javaFXApplication.launchJavaFXApplication(); } + void launchJavaFXApplication() { + launch(); + } + @Override public void start(final Stage stage) { Screen.initScreen(); - Simplicity.getSimplicityRunner().run(); + View.getSimplicityRunner().runApp(); } } diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/PowerApplication.java b/power-view/src/main/java/org/nanoboot/powerframework/view/PowerApplication.java new file mode 100644 index 0000000..5b2da6c --- /dev/null +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/PowerApplication.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.view; + +/** + * Power application. + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class PowerApplication { + /** + * Constructor. + */ + private PowerApplication() { + //Not meant to be instantiated. + } + /** + * Runs the Power application. + * @param classInstance class instance + */ + public static void run(final Class classInstance) { + //todo + } +} diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/Screen.java b/power-view/src/main/java/org/nanoboot/powerframework/view/Screen.java similarity index 91% rename from src/main/java/org/nanoboot/powerframework/simplicity/Screen.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/Screen.java index 9e7d43a..ccdebf0 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/Screen.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/Screen.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,30 +18,22 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity; +package org.nanoboot.powerframework.view; import javafx.geometry.Rectangle2D; /** * Represents screen. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public final class Screen { +public class Screen { private static double dpmm; private static double dpi; private static double zoom = 100; - /** - * Constructor - * - * Not meant to be instantiated. - */ - private Screen() { - //Not meant to be instantiated. - } - /** * Initialises screen. */ @@ -71,12 +63,12 @@ public final class Screen { */ private static void updateDpmm() { double currentDpi = getDpi(); - if (currentDpi > 0) { + if(currentDpi > 0) { dpmm = currentDpi / 25.4; } else { dpmm = 6; } - dpmm = dpmm * (getZoom() / 100); + dpmm *= (getZoom() / 100); } /** @@ -97,7 +89,7 @@ public final class Screen { /** * - * @param zoom 100% is 100, 100% is default + * @param newZoom 100 for 100% */ public static void setZoom(double newZoom) { zoom = newZoom; @@ -143,4 +135,13 @@ public final class Screen { public static int getVisualHeight() { return (int) getVisualBounds().getHeight(); } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private Screen() { + //Not meant to be instantiated. + } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/Simplicity.java b/power-view/src/main/java/org/nanoboot/powerframework/view/View.java similarity index 73% rename from src/main/java/org/nanoboot/powerframework/simplicity/Simplicity.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/View.java index 14fc4da..8f21c2f 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/Simplicity.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/View.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,39 +18,33 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity; +package org.nanoboot.powerframework.view; import javafx.application.Platform; -import org.nanoboot.powerframework.simplicity.window.WindowColourSkin; +import org.nanoboot.powerframework.view.window.WindowColourSkin; /** * Represents Simplicity package main class. * - * @author Robert Vokac robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ -public final class Simplicity { +public class View { - private static SimplicityRunnerI simplicityRunner; + private static ViewRunner simplicityRunner; private static WindowColourSkin defaultWindowColourSkin; - /** - * Constructor - * - * Not meant to be instantiated. - */ - private Simplicity() { - //Not meant to be instantiated. - Platform.setImplicitExit(false); - } /** * This method must be called before using Simplicity. * * @param runner This object implements runObjectI interface and its method * run contains some logic. - * @param defaultWindowColourSkin + * @param defaultWindowColourSkin WindowColourSkin instance used as default in the Simplicity library. */ - public static void startSimplicity(SimplicityRunnerI runner, WindowColourSkin defaultWindowColourSkin) { - Simplicity.setDefaultWindowColourSkin(defaultWindowColourSkin); + public static void startSimplicity(ViewRunner runner, + WindowColourSkin defaultWindowColourSkin) { + View.setDefaultWindowColourSkin(defaultWindowColourSkin); simplicityRunner = runner; JavaFXApplication.startJavaFXApplication(); } @@ -66,7 +60,7 @@ public final class Simplicity { * * @return Simplicity runner */ - public static SimplicityRunnerI getSimplicityRunner() { + public static ViewRunner getSimplicityRunner() { return simplicityRunner; } @@ -84,21 +78,25 @@ public final class Simplicity { * @return default window colour skin */ public static WindowColourSkin getDefaultWindowColourSkin() { - return Simplicity.defaultWindowColourSkin; + return View.defaultWindowColourSkin; } /** * - * @param windowColourSkin + * @param windowColourSkin WindowColourSkin instance */ public static void setDefaultWindowColourSkin(WindowColourSkin windowColourSkin) { - Simplicity.defaultWindowColourSkin = windowColourSkin; + View.defaultWindowColourSkin = windowColourSkin; } + /** + * + * @return information about Simplicity as String + */ public static String getInformation() { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("\ndefaultWindowColourSkin: ").append(Simplicity.getDefaultWindowColourSkin()); - stringBuilder.append("\ndpmm: ").append(Simplicity.getDpmm()); + stringBuilder.append("\ndefaultWindowColourSkin: ").append(View.getDefaultWindowColourSkin()); + stringBuilder.append("\ndpmm: ").append(View.getDpmm()); stringBuilder.append("\nzoom: ").append(Screen.getZoom()); stringBuilder.append("\ndpi: ").append(Screen.getDpi()); stringBuilder.append("\nheight: ").append(Screen.getHeight()); @@ -107,4 +105,14 @@ public final class Simplicity { stringBuilder.append("\nvisual width: ").append(Screen.getVisualWidth()); return stringBuilder.toString(); } + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private View() { + //Not meant to be instantiated. + Platform.setImplicitExit(false); + } } diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/ViewException.java b/power-view/src/main/java/org/nanoboot/powerframework/view/ViewException.java new file mode 100644 index 0000000..5bc0b2b --- /dev/null +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/ViewException.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.view; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class ViewException extends PowerException { + + /** + * + * @param messageIn exception description + */ + public ViewException(String messageIn) { + super(messageIn); + } + +} diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/SimplicityRunnerI.java b/power-view/src/main/java/org/nanoboot/powerframework/view/ViewRunner.java similarity index 82% rename from src/main/java/org/nanoboot/powerframework/simplicity/SimplicityRunnerI.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/ViewRunner.java index 7fdf9a8..212cf18 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/SimplicityRunnerI.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/ViewRunner.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,19 +18,20 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity; +package org.nanoboot.powerframework.view; /** * Represents entry point for Simplicity application. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ @FunctionalInterface -public interface SimplicityRunnerI { +public interface ViewRunner { /** * Contains logic called after Simplicity was started. */ - public void run(); + public void runApp(); } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/boxes/AlertBox.java b/power-view/src/main/java/org/nanoboot/powerframework/view/boxes/AlertBox.java similarity index 66% rename from src/main/java/org/nanoboot/powerframework/simplicity/boxes/AlertBox.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/boxes/AlertBox.java index ac2c7b0..f448860 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/boxes/AlertBox.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/boxes/AlertBox.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,42 +18,46 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.boxes; +package org.nanoboot.powerframework.view.boxes; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.controls.Button; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.transform.Rotate; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.controls.Button; /** * Represents a alert box- a window used to alarm user. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ public class AlertBox extends Box { - private AlertBox(String titleText, String text) { - super(titleText, text); - } - /** * - * @param windowColourSkin * @param titleText * @param text */ - public static void showBox(String titleText, String text) { + public static void showBox(String titleText, + String text) { AlertBox alertBox = new AlertBox(titleText, text); alertBox.showAndWait(); } - void init() { + private AlertBox(String titleText, + String text) { + super(titleText, text); + } + + @Override + void initBox() { circle.setFill(Color.rgb(237, 103, 103)); - Rectangle rectangle1 = new Rectangle(2 * Simplicity.getDpmm(), 8 * Simplicity.getDpmm()); - Rectangle rectangle2 = new Rectangle(2 * Simplicity.getDpmm(), 8 * Simplicity.getDpmm()); - Rotate rotate45 = new Rotate(45, 1.0 * Simplicity.getDpmm(), 4.0 * Simplicity.getDpmm()); - Rotate rotateMinus45 = new Rotate(-45, 1.0 * Simplicity.getDpmm(), 4.0 * Simplicity.getDpmm()); + Rectangle rectangle1 = new Rectangle(2 * View.getDpmm(), 8 * View.getDpmm()); + Rectangle rectangle2 = new Rectangle(2 * View.getDpmm(), 8 * View.getDpmm()); + Rotate rotate45 = new Rotate(45, 1.0 * View.getDpmm(), 4.0 * View.getDpmm()); + Rotate rotateMinus45 = new Rotate(-45, 1.0 * View.getDpmm(), 4.0 * View.getDpmm()); rectangle1.getTransforms().addAll(rotate45); rectangle2.getTransforms().addAll(rotateMinus45); this.icon.getChildren().addAll(rectangle1, rectangle2); @@ -64,7 +68,7 @@ public class AlertBox extends Box { Button okButton = new Button("OK"); this.placeForButtons.getChildren().add(okButton); - okButton.setMaxWidth(20 * Simplicity.getDpmm()); + okButton.setMaxWidth(20 * View.getDpmm()); okButton.setOnAction(this::handleOKButtonAction); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/boxes/Box.java b/power-view/src/main/java/org/nanoboot/powerframework/view/boxes/Box.java similarity index 68% rename from src/main/java/org/nanoboot/powerframework/simplicity/boxes/Box.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/boxes/Box.java index f1cef56..2136b10 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/boxes/Box.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/boxes/Box.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,11 +18,8 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.boxes; +package org.nanoboot.powerframework.view.boxes; -import org.nanoboot.powerframework.simplicity.window.SLayout; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.Window; import javafx.event.ActionEvent; import javafx.geometry.Pos; import javafx.geometry.VPos; @@ -33,11 +30,16 @@ import javafx.scene.shape.Circle; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.stage.Modality; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.layouts.SLayout; +import org.nanoboot.powerframework.view.window.Window; /** * Represents a box- a window used to give information to user. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ abstract class Box extends Window { @@ -46,10 +48,11 @@ abstract class Box extends Window { protected StackPane icon = new StackPane(); protected StackPane icon2 = new StackPane(); protected SLayout gridLayout = new SLayout(); - Circle circle = new Circle(6 * Simplicity.getDpmm()); + Circle circle = new Circle(6 * View.getDpmm()); protected StackPane placeForButtons = new StackPane(); - Box(String titleText, String text) { + Box(String titleText, + String text) { initModality(Modality.APPLICATION_MODAL); this.setWindowTitle(titleText); this.text = text; @@ -58,16 +61,16 @@ abstract class Box extends Window { this.showOnlyTheCloseButton(); RowConstraints rc2 = new RowConstraints(); - rc2.setMinHeight(12 * Simplicity.getDpmm()); - rc2.setMaxHeight(12 * Simplicity.getDpmm()); + rc2.setMinHeight(12 * View.getDpmm()); + rc2.setMaxHeight(12 * View.getDpmm()); rc2.setValignment(VPos.CENTER); ColumnConstraints cc1 = new ColumnConstraints(); - cc1.setMinWidth(12 * Simplicity.getDpmm()); - cc1.setMaxWidth(12 * Simplicity.getDpmm()); + cc1.setMinWidth(12 * View.getDpmm()); + cc1.setMaxWidth(12 * View.getDpmm()); ColumnConstraints cc2 = new ColumnConstraints(); - cc2.setMinWidth(text.length() * 4 * Simplicity.getDpmm()); - cc2.setMaxWidth(text.length() * 4 * Simplicity.getDpmm()); + cc2.setMinWidth(text.length() * 4 * View.getDpmm()); + cc2.setMaxWidth(text.length() * 4 * View.getDpmm()); this.gridLayout.getRowConstraints().addAll(rc2, this.gridLayout.getDataRowConstraint()); this.gridLayout.getColumnConstraints().addAll(cc1, cc2); @@ -77,20 +80,20 @@ abstract class Box extends Window { this.gridLayout.add(icon, 0, 0); Text newText = new Text(text); - newText.setFont(Font.font(3 * Simplicity.getDpmm())); + newText.setFont(Font.font(3 * View.getDpmm())); newText.setText(text); this.gridLayout.add(newText, 1, 0); this.gridLayout.add(this.placeForButtons, 0, 1, 2, 1); this.placeForButtons.setAlignment(Pos.CENTER); this.applicationArea.getChildren().add(gridLayout); - this.setHeight(4.5 * Simplicity.getDpmm() + 3 * 3 * Simplicity.getDpmm() + 12 * Simplicity.getDpmm() + 6 * Simplicity.getDpmm() + 2 / 3 * Simplicity.getDpmm()); - this.setWidth(text.length() * 2 * Simplicity.getDpmm() + 2 / 3 * Simplicity.getDpmm() + 9 * Simplicity.getDpmm() + 16 * Simplicity.getDpmm()); + this.setHeight(4.5 * View.getDpmm() + 3 * 3 * View.getDpmm() + 12 * View.getDpmm() + 6 * View.getDpmm() + 2 / 3 * View.getDpmm()); + this.setWidth(text.length() * 2 * View.getDpmm() + 2 / 3 * View.getDpmm() + 9 * View.getDpmm() + 16 * View.getDpmm()); - this.init(); + this.initBox(); } - abstract void init(); + abstract void initBox(); protected void handleOKButtonAction(ActionEvent event) { // Button was clicked, do something... @@ -99,7 +102,7 @@ abstract class Box extends Window { } @Override - public void initAreaForUserInteraction() { + public void initAreaForUserInteraction(Object... args) { } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/boxes/MessageBox.java b/power-view/src/main/java/org/nanoboot/powerframework/view/boxes/MessageBox.java similarity index 66% rename from src/main/java/org/nanoboot/powerframework/simplicity/boxes/MessageBox.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/boxes/MessageBox.java index 121fdd3..374a698 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/boxes/MessageBox.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/boxes/MessageBox.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,53 +18,58 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.boxes; +package org.nanoboot.powerframework.view.boxes; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.controls.Button; import javafx.geometry.Pos; +import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.controls.Button; /** * Represents a message box- a window used to inform user about something. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class MessageBox extends Box { - private MessageBox(String titleText, String text) { - super(titleText, text); - } +public class MessageBox extends Box { /** * - * @param windowColourSkin * @param titleText * @param text */ - public static void showBox(String titleText, String text) { + public static void showBox(String titleText, + String text) { MessageBox messageBox = new MessageBox(titleText, text); messageBox.showAndWait(); } - void init() { + private MessageBox(String titleText, + String text) { + super(titleText, text); + } + + @Override + void initBox() { circle.setFill(Color.rgb(114, 159, 207)); - Rectangle rectangle1 = new Rectangle(2 * Simplicity.getDpmm(), 5 * Simplicity.getDpmm()); - Rectangle rectangle2 = new Rectangle(2 * Simplicity.getDpmm(), 2 * Simplicity.getDpmm()); + Rectangle rectangle1 = new Rectangle(2 * View.getDpmm(), 5 * View.getDpmm()); + Rectangle rectangle2 = new Rectangle(2 * View.getDpmm(), 2 * View.getDpmm()); this.icon2.getChildren().addAll(rectangle1, rectangle2); this.icon.getChildren().add(icon2); - this.icon2.setAlignment(rectangle1, Pos.BOTTOM_CENTER); - this.icon2.setAlignment(rectangle2, Pos.TOP_CENTER); - this.icon2.setMaxHeight(8 * Simplicity.getDpmm()); + StackPane.setAlignment(rectangle1, Pos.BOTTOM_CENTER); + StackPane.setAlignment(rectangle2, Pos.TOP_CENTER); + this.icon2.setMaxHeight(8 * View.getDpmm()); rectangle1.setFill(Color.rgb(238, 238, 238)); rectangle2.setFill(Color.rgb(238, 238, 238)); Button okButton = new Button("OK"); this.placeForButtons.getChildren().add(okButton); - okButton.setMaxWidth(20 * Simplicity.getDpmm()); + okButton.setMaxWidth(20 * View.getDpmm()); okButton.setOnAction(this::handleOKButtonAction); } } diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/AnalogClock.java b/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/AnalogClock.java new file mode 100644 index 0000000..87fda7c --- /dev/null +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/AnalogClock.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.view.clocks; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class AnalogClock { + +} diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/Clock.java b/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/Clock.java new file mode 100644 index 0000000..c6633f7 --- /dev/null +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/Clock.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.view.clocks; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Clock { + +} diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/DigitalClock.java b/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/DigitalClock.java new file mode 100644 index 0000000..7f97f92 --- /dev/null +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/clocks/DigitalClock.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.view.clocks; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class DigitalClock { + +} diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/CellLayout.java b/power-view/src/main/java/org/nanoboot/powerframework/view/layouts/CellLayout.java similarity index 74% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/CellLayout.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/layouts/CellLayout.java index 9432ce7..37b36e6 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/CellLayout.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/layouts/CellLayout.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,7 +18,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.layouts; import java.util.ArrayList; import java.util.List; @@ -29,27 +29,28 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.RowConstraints; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.simplicity.Simplicity; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.ViewException; /** + * * - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class CellLayout extends AnchorPane { + +public final class CellLayout extends AnchorPane { private static final RowConstraints dataRowConstraint = new RowConstraints(); private static final String PERCENT = "%"; private static final String MM = "mm"; - private final GridPane gridPane = new GridPane(); - static { - dataRowConstraint.setMinHeight(6 * Simplicity.getDpmm()); - dataRowConstraint.setMaxHeight(6 * Simplicity.getDpmm()); + dataRowConstraint.setMinHeight(6 * View.getDpmm()); + dataRowConstraint.setMaxHeight(6 * View.getDpmm()); dataRowConstraint.setValignment(VPos.CENTER); } + private final GridPane gridPane = new GridPane(); private final int rows; private final int columns; @@ -60,7 +61,9 @@ public class CellLayout extends AnchorPane { * @param columns * @param columnConstraintsString */ - public CellLayout(int columns, int rows, String columnConstraintsString) { + public CellLayout(int columns, + int rows, + String columnConstraintsString) { this.getChildren().add(gridPane); AnchorPane.setTopAnchor(gridPane, 0d); @@ -88,20 +91,20 @@ public class CellLayout extends AnchorPane { private void setColumnConstraints(String columnConstraintsString) { String[] columnConstraint = columnConstraintsString.split("\\s+"); - List list = new ArrayList(); + List list = new ArrayList<>(); for (String element : columnConstraint) { int number; ColumnConstraints tempColumnConstraints = new ColumnConstraints(); - if (element.endsWith(PERCENT)) { + if(element.endsWith(PERCENT)) { number = Integer.parseInt(element.substring(0, element.length() - 1)); tempColumnConstraints.setPercentWidth(number); - } else if (element.endsWith(MM)) { + } else if(element.endsWith(MM)) { number = Integer.parseInt(element.substring(0, element.length() - 2)); - double mmLenght = number * Simplicity.getDpmm(); + double mmLenght = number * View.getDpmm(); tempColumnConstraints.setMaxWidth(mmLenght); tempColumnConstraints.setMinWidth(mmLenght); } else { - throw new PowerRuntimeException("Column constraint string is not valid. " + element + " is not valid."); + throw new ViewException("Column constraint string is not valid. " + "Element " + element + " is not valid."); } list.add(tempColumnConstraints); } @@ -114,7 +117,9 @@ public class CellLayout extends AnchorPane { * @param column from 1 * @param row from 1 */ - public void addNode(Node node, int column, int row) { + public void addNode(Node node, + int column, + int row) { gridPane.add(node, column - 1, row - 1); } @@ -126,7 +131,11 @@ public class CellLayout extends AnchorPane { * @param columnSpan * @param rowSpan */ - public void addNode(Node node, int column, int row, int columnSpan, int rowSpan) { + public void addNode(Node node, + int column, + int row, + int columnSpan, + int rowSpan) { gridPane.add(node, column - 1, row - 1, columnSpan, rowSpan); } @@ -136,7 +145,8 @@ public class CellLayout extends AnchorPane { * @param row starting from 1 * @param nodes */ - public void addNodes(int row, Node... nodes) { + public void addNodes(int row, + Node... nodes) { gridPane.addRow(row - 1, nodes); } @@ -145,10 +155,10 @@ public class CellLayout extends AnchorPane { * @param value */ public void setSpacing(boolean value) { - if (value) { - gridPane.setVgap(3 * Simplicity.getDpmm()); - gridPane.setHgap(3 * Simplicity.getDpmm()); - gridPane.setPadding(new Insets(3 * Simplicity.getDpmm())); + if(value) { + gridPane.setVgap(3 * View.getDpmm()); + gridPane.setHgap(3 * View.getDpmm()); + gridPane.setPadding(new Insets(3 * View.getDpmm())); } else { gridPane.setVgap(0); gridPane.setHgap(0); @@ -176,11 +186,13 @@ public class CellLayout extends AnchorPane { * * @param col * @param row + * * @return */ - public Node getNodeFromGridPane(int col, int row) { + public Node getNodeFromGridPane(int col, + int row) { for (Node node : this.getChildren()) { - if (GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) { + if(GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) { return node; } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/SLayout.java b/power-view/src/main/java/org/nanoboot/powerframework/view/layouts/SLayout.java similarity index 73% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/SLayout.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/layouts/SLayout.java index 951666a..66889f9 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/SLayout.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/layouts/SLayout.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,19 +18,20 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.layouts; -import org.nanoboot.powerframework.simplicity.Simplicity; import javafx.geometry.Insets; import javafx.geometry.VPos; import javafx.scene.Node; import javafx.scene.layout.GridPane; import javafx.scene.layout.RowConstraints; +import org.nanoboot.powerframework.view.View; /** * Represents a layout. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class SLayout extends GridPane { @@ -42,8 +43,8 @@ public class SLayout extends GridPane { public SLayout() { this.setSpacing(true); - dataRowConstraint.setMinHeight(6 * Simplicity.getDpmm()); - dataRowConstraint.setMaxHeight(6 * Simplicity.getDpmm()); + dataRowConstraint.setMinHeight(6 * View.getDpmm()); + dataRowConstraint.setMaxHeight(6 * View.getDpmm()); dataRowConstraint.setValignment(VPos.CENTER); } @@ -52,10 +53,10 @@ public class SLayout extends GridPane { * @param value */ public void setSpacing(boolean value) { - if (value) { - this.setVgap(3 * Simplicity.getDpmm()); - this.setHgap(3 * Simplicity.getDpmm()); - this.setPadding(new Insets(3 * Simplicity.getDpmm())); + if(value) { + this.setVgap(3 * View.getDpmm()); + this.setHgap(3 * View.getDpmm()); + this.setPadding(new Insets(3 * View.getDpmm())); } else { this.setVgap(0); this.setHgap(0); @@ -76,11 +77,14 @@ public class SLayout extends GridPane { * @param gridPane * @param col * @param row + * * @return */ - public Node getNodeFromGridPane(GridPane gridPane, int col, int row) { + public Node getNodeFromGridPane(GridPane gridPane, + int col, + int row) { for (Node node : gridPane.getChildren()) { - if (GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) { + if(GridPane.getColumnIndex(node) == col && GridPane.getRowIndex(node) == row) { return node; } } diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/package-info.java b/power-view/src/main/java/org/nanoboot/powerframework/view/package-info.java new file mode 100644 index 0000000..5f73db1 --- /dev/null +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/package-info.java @@ -0,0 +1,27 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * View classes. + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.goldrabbit.powerframework.view; diff --git a/power-view/src/main/java/org/nanoboot/powerframework/view/svg/.gitkeep b/power-view/src/main/java/org/nanoboot/powerframework/view/svg/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/ColourVariant.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/ColourVariant.java similarity index 85% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/ColourVariant.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/ColourVariant.java index 2541454..dc69fb0 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/ColourVariant.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/ColourVariant.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,12 +18,13 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; /** * Colour variants of a window colour skin. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public enum ColourVariant { diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/MoveableArea.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/MoveableArea.java similarity index 77% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/MoveableArea.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/MoveableArea.java index e50c12c..29d794d 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/MoveableArea.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/MoveableArea.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,9 +18,14 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +package org.nanoboot.powerframework.view.window; -import org.nanoboot.powerframework.simplicity.Simplicity; import javafx.geometry.Insets; import javafx.geometry.Pos; import static javafx.scene.layout.HBox.setHgrow; @@ -28,14 +33,15 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; import javafx.scene.text.Font; import javafx.scene.text.Text; +import org.nanoboot.powerframework.view.View; /** * Represents the part of window, where is the window title placed and is used * to move window * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokáč e-mail: robertvokac@nanoboot.org */ -public class MoveableArea extends StackPane { +public final class MoveableArea extends StackPane { private final Text titleText = new Text(""); private final Window window; @@ -49,15 +55,15 @@ public class MoveableArea extends StackPane { public MoveableArea(Window window) { this.window = window; getChildren().add(titleText); - setStyle("-fx-background-color: rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");"); + setStyle("-fx-background-color: rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");"); setAlignment(Pos.CENTER_LEFT); setHgrow(this, Priority.ALWAYS); - titleText.setFont(Font.font(Simplicity.getDpmm() * 3)); - titleText.setFill(Simplicity.getDefaultWindowColourSkin().getColourForText(ColourVariant.DARK)); + titleText.setFont(Font.font(View.getDpmm() * 3)); + titleText.setFill(View.getDefaultWindowColourSkin().getColourForText(ColourVariant.DARK)); titleText.setScaleX(1.2); - setPadding(new Insets(0, 0, 0, Simplicity.getDpmm())); + setPadding(new Insets(0, 0, 0, View.getDpmm())); this.setCanBeMoved(true); } @@ -67,7 +73,7 @@ public class MoveableArea extends StackPane { */ public void setCanBeMoved(boolean value) { moveable = value; - if (value) { + if(value) { setOnMousePressed(window::handleMovingWindowStarted); setOnMouseDragged(window::handleMovingWindowEnded); } else { diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/ResizingGrid.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/ResizingGrid.java similarity index 78% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/ResizingGrid.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/ResizingGrid.java index 87cd570..55e9600 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/ResizingGrid.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/ResizingGrid.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,25 +18,25 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; import javafx.scene.layout.GridPane; -import org.nanoboot.powerframework.simplicity.Simplicity; +import org.nanoboot.powerframework.view.View; /** * Represents place used to resize window. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class ResizingGrid extends GridPane { /** * - * @param windowColourSkin */ public ResizingGrid() { - this.setMaxHeight(Simplicity.getDpmm() * 6); - this.setMaxWidth(Simplicity.getDpmm() * 6); + this.setMaxHeight(View.getDpmm() * 6); + this.setMaxWidth(View.getDpmm() * 6); this.add(new ResizingGridRectangle(), 3, 0); this.add(new ResizingGridRectangle(), 2, 1); this.add(new ResizingGridRectangle(), 3, 1); @@ -48,7 +48,7 @@ public class ResizingGrid extends GridPane { this.add(new ResizingGridRectangle(), 2, 3); this.add(new ResizingGridRectangle(), 3, 3); this.setStyle("-fx-padding: 0;-fx-insets: 0;"); - this.setHgap(Simplicity.getDpmm() / 2); - this.setVgap(Simplicity.getDpmm() / 2); + this.setHgap(View.getDpmm() / 2); + this.setVgap(View.getDpmm() / 2); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/ResizingGridRectangle.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/ResizingGridRectangle.java similarity index 73% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/ResizingGridRectangle.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/ResizingGridRectangle.java index 7b0cb52..72dafe2 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/ResizingGridRectangle.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/ResizingGridRectangle.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,15 +18,16 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; import javafx.scene.shape.Rectangle; -import org.nanoboot.powerframework.simplicity.Simplicity; +import org.nanoboot.powerframework.view.View; /** * Represents button used to resize the window. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class ResizingGridRectangle extends Rectangle { @@ -34,8 +35,8 @@ public class ResizingGridRectangle extends Rectangle { * Constructor */ public ResizingGridRectangle() { - this.setFill(Simplicity.getDefaultWindowColourSkin().getColour(ColourVariant.DARK)); - this.setHeight(Simplicity.getDpmm()); - this.setWidth(Simplicity.getDpmm()); + this.setFill(View.getDefaultWindowColourSkin().getColour(ColourVariant.DARK)); + this.setHeight(View.getDpmm()); + this.setWidth(View.getDpmm()); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/TitleBar.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/TitleBar.java similarity index 84% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/TitleBar.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/TitleBar.java index 3bb3933..8660f69 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/TitleBar.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/TitleBar.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,19 +18,20 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.titlebuttons.CloseButton; -import org.nanoboot.powerframework.simplicity.window.titlebuttons.MaximizeRestoreButton; -import org.nanoboot.powerframework.simplicity.window.titlebuttons.MinimizeButton; import javafx.geometry.Insets; import javafx.scene.layout.HBox; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.titlebuttons.CloseButton; +import org.nanoboot.powerframework.view.window.titlebuttons.MaximizeRestoreButton; +import org.nanoboot.powerframework.view.window.titlebuttons.MinimizeButton; /** * Represents title bar of a window. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class TitleBar extends HBox { @@ -41,7 +42,7 @@ public class TitleBar extends HBox { /** * Space between buttons in millimeters. */ - private final Insets spaceBeforeButtons = new Insets(0, 0, 0, Simplicity.getDpmm() * 1.5); + private final Insets spaceBeforeButtons = new Insets(0, 0, 0, View.getDpmm() * 1.5); /** * StackPane for title bar icon. */ @@ -68,14 +69,13 @@ public class TitleBar extends HBox { /** * - * @param windowColourSkin * @param window */ public TitleBar(Window window) { - WindowColourSkin tempWindowColourSkin = Simplicity.getDefaultWindowColourSkin(); + WindowColourSkin tempWindowColourSkin = View.getDefaultWindowColourSkin(); setFillHeight(true); - setMinHeight(Simplicity.getDpmm() * TITLEBARHEIGHT); - setMaxHeight(Simplicity.getDpmm() * TITLEBARHEIGHT); + setMinHeight(View.getDpmm() * TITLEBARHEIGHT); + setMaxHeight(View.getDpmm() * TITLEBARHEIGHT); titleIcon = new TitleIcon(); moveableArea = new MoveableArea(window); @@ -153,7 +153,7 @@ public class TitleBar extends HBox { */ public void showOnlyTheCloseButton() { - if (!this.isShowedOnlyTheCloseButton()) { + if(!this.isShowedOnlyTheCloseButton()) { getChildren().removeAll(minimizeButton, maximizeRestoreButton); } @@ -173,7 +173,7 @@ public class TitleBar extends HBox { */ public void showAllTitleButtons() { - if (this.isShowedOnlyTheCloseButton()) { + if(this.isShowedOnlyTheCloseButton()) { getChildren().addAll(minimizeButton, maximizeRestoreButton); setMargin(minimizeButton, spaceBeforeButtons); setMargin(maximizeRestoreButton, spaceBeforeButtons); diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/TitleIcon.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/TitleIcon.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/TitleIcon.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/TitleIcon.java index 0bc0412..e0e2236 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/TitleIcon.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/TitleIcon.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,34 +18,34 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; -import org.nanoboot.powerframework.simplicity.Simplicity; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.StackPane; +import org.nanoboot.powerframework.view.View; /** * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class TitleIcon extends StackPane { + private static final double TITLEICONHEIGHT = 4.5; /** * Title bar icon image. */ private final ImageView imageView = new ImageView(); - private static final double TITLEICONHEIGHT = 4.5; /** * Constructor * - * @param windowColourSkin */ TitleIcon() { - setStyle("-fx-background-color: rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");"); - imageView.setFitWidth(Simplicity.getDpmm() * TITLEICONHEIGHT); - imageView.setFitHeight(Simplicity.getDpmm() * TITLEICONHEIGHT); + setStyle("-fx-background-color: rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");"); + imageView.setFitWidth(View.getDpmm() * TITLEICONHEIGHT); + imageView.setFitHeight(View.getDpmm() * TITLEICONHEIGHT); imageView.setPreserveRatio(true); imageView.setSmooth(true); imageView.setCache(true); @@ -57,6 +57,7 @@ public class TitleIcon extends StackPane { * @param path */ public void setIcon(String path) { + System.out.println("path="+path); Image image = new Image(path); imageView.setImage(image); } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/Window.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/Window.java similarity index 82% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/Window.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/Window.java index 5ec7da5..cbd5dc9 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/Window.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/Window.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,34 +18,40 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; import static java.lang.Thread.sleep; + import java.util.logging.Level; import java.util.logging.Logger; -import org.nanoboot.powerframework.simplicity.Simplicity; -import javafx.event.EventHandler; + +import javafx.event.Event; import javafx.geometry.Pos; +import javafx.geometry.Rectangle2D; import javafx.scene.Scene; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.VBox; import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.stage.Screen; import javafx.stage.Stage; import javafx.stage.StageStyle; -import javafx.geometry.Rectangle2D; -import javafx.stage.Screen; -import javafx.stage.WindowEvent; +import org.nanoboot.powerframework.view.View; /** * Represents window. Window is place for everything player sees. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public abstract class Window extends Stage { private VBox windowVBox; - private TitleBar titleBar; + private final TitleBar titleBar; + + /** + * + */ protected StackPane applicationArea = new StackPane(); private ResizingGrid resizingGrid = null; @@ -65,8 +71,7 @@ public abstract class Window extends Stage { /** * Constructor */ - public Window() { - + public Window(Object... args) { this.centerOnScreen(); titleBar = new TitleBar(this); @@ -75,7 +80,7 @@ public abstract class Window extends Stage { setDefaultSizeAndPosition(); - initAreaForUserInteraction(); + initAreaForUserInteraction(args); setValuesForRestoredWindow(); if (this.canBeResized()) { this.resizingGrid.toFront(); @@ -83,27 +88,21 @@ public abstract class Window extends Stage { } private void setDefaultSizeAndPosition() { - setWidth((org.nanoboot.powerframework.simplicity.Screen.getVisualWidth()) / 2); - setHeight((org.nanoboot.powerframework.simplicity.Screen.getVisualHeight()) / 8 * 6); - setX((org.nanoboot.powerframework.simplicity.Screen.getVisualWidth() - this.getWidth()) / 2); - setY((org.nanoboot.powerframework.simplicity.Screen.getVisualHeight() - this.getHeight()) / 2); + setWidth((org.nanoboot.powerframework.view.Screen.getVisualWidth()) / 2); + setHeight((org.nanoboot.powerframework.view.Screen.getVisualHeight()) / 8 * 6); + setX((org.nanoboot.powerframework.view.Screen.getVisualWidth() - this.getWidth()) / 2); + setY((org.nanoboot.powerframework.view.Screen.getVisualHeight() - this.getHeight()) / 2); } private void initWindowVBox() { - this.setOnCloseRequest(new EventHandler() { - @Override - public void handle(final WindowEvent event) { - - event.consume(); - } - }); + this.setOnCloseRequest(Event::consume); this.initStyle(StageStyle.TRANSPARENT); windowVBox = new VBox(); windowVBox.setFillWidth(true); this.setScene(new Scene(windowVBox, 400, 300)); this.setFullScreenExitHint(""); - windowVBox.setVgrow(applicationArea, Priority.ALWAYS); + VBox.setVgrow(applicationArea, Priority.ALWAYS); windowVBox.getChildren().addAll(applicationArea); } @@ -116,7 +115,6 @@ public abstract class Window extends Stage { } /** - * * @param path */ public void setIcon(String path) { @@ -128,7 +126,6 @@ public abstract class Window extends Stage { } /** - * * @param title */ public void setWindowTitle(String title) { @@ -137,7 +134,6 @@ public abstract class Window extends Stage { } /** - * * @return title */ public String getWindowTitle() { @@ -163,7 +159,6 @@ public abstract class Window extends Stage { } /** - * * @return boolean value */ public boolean isShowedOnlyTheCloseButton() { @@ -179,7 +174,6 @@ public abstract class Window extends Stage { } /** - * * @return boolean value */ public boolean areShowedAllTitleButtons() { @@ -193,7 +187,7 @@ public abstract class Window extends Stage { resizingGrid = new ResizingGrid(); resizingGrid.setOnMouseDragged(this::handleResizeWindowAction); applicationArea.getChildren().add(resizingGrid); - applicationArea.setAlignment(resizingGrid, Pos.BOTTOM_RIGHT); + StackPane.setAlignment(resizingGrid, Pos.BOTTOM_RIGHT); } else { this.applicationArea.getChildren().remove(this.resizingGrid); this.resizingGrid = null; @@ -250,7 +244,7 @@ public abstract class Window extends Stage { } /** - ** Window's size and position can not be changed. The size is the biggest + * * Window's size and position can not be changed. The size is the biggest */ public void switchToFullScreen() { this.windowSizeMode = WindowSizeMode.FULLSCREEN; @@ -277,31 +271,35 @@ public abstract class Window extends Stage { Logger.getLogger(Window.class.getName()).log(Level.SEVERE, null, ex); Thread.currentThread().interrupt(); } - for(int i=0;i<=10;i++) - {try { - sleep(50); - } catch (InterruptedException ex) { - Logger.getLogger(Window.class.getName()).log(Level.SEVERE, null, ex); - Thread.currentThread().interrupt(); + for (int i = 0; i <= 10; i++) { + try { + sleep(50); + } catch (InterruptedException ex) { + Logger.getLogger(Window.class.getName()).log(Level.SEVERE, null, ex); + Thread.currentThread().interrupt(); + } + this.onResizingWindow(); } - this.onResizingWindow();} - + }); thread.setDaemon(true); thread.start(); } + /** + * @return + */ public WindowSizeMode getWindowSizeMode() { return this.windowSizeMode; } private void setBorder(boolean value) { if (value) { - windowVBox.setStyle("-fx-background-color: rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.LIGHT) + ");" - + "-fx-border-width: " + Simplicity.getDpmm() / 3 + ";" - + "-fx-border-color: rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");"); + windowVBox.setStyle("-fx-background-color: rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.LIGHT) + ");" + + "-fx-border-width: " + View.getDpmm() / 3 + ";" + + "-fx-border-color: rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");"); } else { - windowVBox.setStyle("-fx-background-color: rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.LIGHT) + ");" + windowVBox.setStyle("-fx-background-color: rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.LIGHT) + ");" + "-fx-border-width: 0;"); } @@ -320,7 +318,6 @@ public abstract class Window extends Stage { } /** - * * @param e */ public void handleMovingWindowStarted(MouseEvent e) { @@ -329,7 +326,6 @@ public abstract class Window extends Stage { } /** - * * @param e */ public void handleMovingWindowEnded(MouseEvent e) { @@ -339,7 +335,6 @@ public abstract class Window extends Stage { } /** - * * @param event */ public void handleMinimizeButtonAction(MouseEvent event) { @@ -347,7 +342,6 @@ public abstract class Window extends Stage { } /** - * * @param event */ public void handleMaximizeRestoreButtonAction(MouseEvent event) { @@ -359,7 +353,6 @@ public abstract class Window extends Stage { } /** - * * @param value */ public void setCloseable(boolean value) { @@ -367,7 +360,6 @@ public abstract class Window extends Stage { } /** - * * @return */ public boolean isCloseable() { @@ -375,7 +367,6 @@ public abstract class Window extends Stage { } /** - * * @param event */ public void handleCloseButtonAction(MouseEvent event) { @@ -385,6 +376,9 @@ public abstract class Window extends Stage { } } + /** + * + */ protected void onClosingWindow() { } @@ -406,12 +400,24 @@ public abstract class Window extends Stage { this.onResizingWindow(); } + /** + * + */ protected void onResizingWindow() { } + /** + * + */ protected void onMovingWindow() { } - protected abstract void initAreaForUserInteraction(); + + /** + * + */ + protected void initAreaForUserInteraction(Object... args) { + + } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/WindowColourSkin.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/WindowColourSkin.java similarity index 91% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/WindowColourSkin.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/WindowColourSkin.java index b67aaff..a561475 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/WindowColourSkin.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/WindowColourSkin.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,15 +18,16 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; -import org.nanoboot.powerframework.simplicity.EnumColour; import javafx.scene.paint.Color; +import org.nanoboot.powerframework.view.EnumColour; /** * Represents colour skin of Window. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class WindowColourSkin { @@ -75,7 +76,7 @@ public class WindowColourSkin { colour[1][16] = Color.rgb(75, 83, 32); } - private EnumColour enumColour; + private final EnumColour enumColour; /** * @@ -88,10 +89,11 @@ public class WindowColourSkin { /** * * @param colourVariant + * * @return */ public Color getColour(ColourVariant colourVariant) { - if (colourVariant == ColourVariant.LIGHT) { + if(colourVariant == ColourVariant.LIGHT) { return colour[0][enumColour.ordinal()]; } else { return colour[1][enumColour.ordinal()]; @@ -125,19 +127,20 @@ public class WindowColourSkin { /** * * @param lightOrDarkBackground + * * @return */ public Color getColourForText(ColourVariant lightOrDarkBackground) { int colourNumber = this.getEnumColour().getNumber(); - if (lightOrDarkBackground == ColourVariant.DARK) { + if(lightOrDarkBackground == ColourVariant.DARK) { int[] intArray = {3, 6, 7, 14, 16}; for (int element : intArray) { - if (colourNumber == element) { + if(colourNumber == element) { return Color.rgb(255, 255, 255); } } } else { - if (colourNumber == 14) { + if(colourNumber == 14) { return Color.rgb(255, 255, 255); } } @@ -150,6 +153,7 @@ public class WindowColourSkin { * with commas. * * @param lightOrDark + * * @return css String representation of colour */ public String getRGBStringForCSS(ColourVariant lightOrDark) { @@ -163,6 +167,7 @@ public class WindowColourSkin { /** * * @param color + * * @return */ public String getRGBStringForCSS(Color color) { diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/WindowSizeMode.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/WindowSizeMode.java similarity index 88% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/WindowSizeMode.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/WindowSizeMode.java index de416aa..2c050c2 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/WindowSizeMode.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/WindowSizeMode.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,12 +18,13 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window; +package org.nanoboot.powerframework.view.window; /** * Window size modes. * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public enum WindowSizeMode { diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/Button.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/Button.java similarity index 75% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/Button.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/Button.java index 2e77e6e..ae3b701 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/Button.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/Button.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,41 +18,43 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; import javafx.geometry.Insets; import javafx.scene.input.MouseEvent; import javafx.scene.text.Font; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ + public class Button extends javafx.scene.control.Button { - private String setStyleStartString + private final String setStyleStartString = new StringBuilder("-fx-border-insets:0;-fx-background-insets:0;-fx-background-radius:0;-fx-background-color: rgb(") - .append(Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK)) + .append(View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK)) .append(");-fx-border-color:rgb(") .toString(); - private String setStyleEndString = new StringBuilder(");-fx-border-width: ") - .append(Simplicity.getDpmm() / 2) + private final String setStyleEndString = new StringBuilder(");-fx-border-width: ") + .append(View.getDpmm() / 2) .append(";") .toString(); /** * - * @param windowColourSkin * @param text */ public Button(String text) { super(text); this.setMaxWidth(Double.MAX_VALUE); - this.setMaxHeight(6 * Simplicity.getDpmm()); + this.setMaxHeight(6 * View.getDpmm()); this.setPadding(new Insets(0, 0, 0, 0)); - this.setFont(Font.font(3 * Simplicity.getDpmm())); + this.setFont(Font.font(3 * View.getDpmm())); this.setStyle(getSetStyleString("186, 186, 186")); setOnMouseEntered(this::handleMouseEnteredAction); setOnMouseExited(this::handleMouseExitedAction); diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/NumericMinusPlus.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/NumericMinusPlus.java similarity index 83% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/NumericMinusPlus.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/NumericMinusPlus.java index dbf2281..c79a9c3 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/NumericMinusPlus.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/NumericMinusPlus.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,12 +18,13 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; /** * Represents numeric minus plus control. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class NumericMinusPlus { diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/PasswordField.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/PasswordField.java similarity index 68% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/PasswordField.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/PasswordField.java index 2d56594..ac7cf05 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/PasswordField.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/PasswordField.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,15 +18,17 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; import javafx.scene.text.Font; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class PasswordField extends javafx.scene.control.PasswordField { @@ -34,8 +36,8 @@ public class PasswordField extends javafx.scene.control.PasswordField { * Constructor */ public PasswordField() { - this.setFont(Font.font(3 * Simplicity.getDpmm())); - this.setMaxHeight(6 * Simplicity.getDpmm()); - this.setStyle("-fx-padding:0;-fx-border-insets:0;-fx-background-insets:0;-fx-background-radius:0;-fx-background-color: rgb(255,255,255);-fx-border-color:rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");-fx-border-width: " + Simplicity.getDpmm() / 2 + ";"); + this.setFont(Font.font(3 * View.getDpmm())); + this.setMaxHeight(6 * View.getDpmm()); + this.setStyle("-fx-padding:0;-fx-border-insets:0;-fx-background-insets:0;-fx-background-radius:0;-fx-background-color: rgb(255,255,255);-fx-border-color:rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");-fx-border-width: " + View.getDpmm() / 2 + ";"); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/RadioButton.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/RadioButton.java similarity index 70% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/RadioButton.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/RadioButton.java index 0d41386..e28b113 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/RadioButton.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/RadioButton.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,29 +18,32 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; import javafx.scene.paint.Color; import javafx.scene.text.Font; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** * Represents radio button. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class RadioButton extends javafx.scene.control.RadioButton { -/** - * Constructor - * - * @param text - */ + + /** + * Constructor + * + * @param text + */ public RadioButton(String text) { super(text); - - setFont(Font.font(3 * Simplicity.getDpmm())); - Color color=Simplicity.getDefaultWindowColourSkin().getColourForText(ColourVariant.LIGHT); + + setFont(Font.font(3 * View.getDpmm())); + Color color = View.getDefaultWindowColourSkin().getColourForText(ColourVariant.LIGHT); this.setTextFill(color); } + } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/RadioButtonGroup.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/RadioButtonGroup.java similarity index 82% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/RadioButtonGroup.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/RadioButtonGroup.java index b58360b..8707270 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/RadioButtonGroup.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/RadioButtonGroup.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,12 +18,14 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class RadioButtonGroup { - + } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SCheckBox.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SCheckBox.java similarity index 71% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SCheckBox.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SCheckBox.java index 3414631..a2ba8cd 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SCheckBox.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SCheckBox.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,10 +18,8 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.input.MouseEvent; @@ -29,37 +27,41 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Line; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ -public class SCheckBox extends HBox { +public final class SCheckBox extends HBox { private StackPane checkBoxStackPane = new StackPane(); private SLabel checkBoxSLabel = new SLabel(); private boolean selected = false; private boolean disabled = false; - Line line1 = new Line(0, 0, 3 * Simplicity.getDpmm(), 3 * Simplicity.getDpmm()); - Line line2 = new Line(0, 3 * Simplicity.getDpmm(), 3 * Simplicity.getDpmm(), 0); + Line line1 = new Line(0, 0, 3 * View.getDpmm(), 3 * View.getDpmm()); + Line line2 = new Line(0, 3 * View.getDpmm(), 3 * View.getDpmm(), 0); /** * Constructor */ public SCheckBox() { this.line1.setStroke(Color.rgb(153, 153, 153)); - this.line1.setStrokeWidth(0.5 * Simplicity.getDpmm()); + this.line1.setStrokeWidth(0.5 * View.getDpmm()); this.line2.setStroke(Color.rgb(153, 153, 153)); - this.line2.setStrokeWidth(0.5 * Simplicity.getDpmm()); + this.line2.setStrokeWidth(0.5 * View.getDpmm()); this.setAlignment(Pos.CENTER_LEFT); this.getChildren().addAll(this.checkBoxStackPane, this.checkBoxSLabel); - setMargin(checkBoxStackPane, new Insets(0, 1 * Simplicity.getDpmm(), 0, 0)); + setMargin(checkBoxStackPane, new Insets(0, 1 * View.getDpmm(), 0, 0)); setOnMouseClicked(this::handleMouseClicked); - this.checkBoxStackPane.setMinSize(6 * Simplicity.getDpmm(), 6 * Simplicity.getDpmm()); - this.checkBoxStackPane.setMaxSize(6 * Simplicity.getDpmm(), 6 * Simplicity.getDpmm()); - this.checkBoxStackPane.setStyle("-fx-background-radius:0;-fx-background-color: rgb(255,255,255);-fx-border-color:rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");-fx-border-width: " + Simplicity.getDpmm() / 2 + ";"); + this.checkBoxStackPane.setMinSize(6 * View.getDpmm(), 6 * View.getDpmm()); + this.checkBoxStackPane.setMaxSize(6 * View.getDpmm(), 6 * View.getDpmm()); + this.checkBoxStackPane.setStyle("-fx-background-radius:0;-fx-background-color: rgb(255,255,255);-fx-border-color:rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");-fx-border-width: " + View.getDpmm() / 2 + ";"); } /** @@ -91,10 +93,14 @@ public class SCheckBox extends HBox { this.setSelected(!this.isSelected()); } + /** + * + * @param value + */ public void setSelected(boolean value) { this.selected = value; this.checkBoxStackPane.getChildren().clear(); - if (value) { + if(value) { this.checkBoxStackPane.getChildren().addAll(this.line1, this.line2); } } @@ -113,11 +119,11 @@ public class SCheckBox extends HBox { */ public void turnDisabled(boolean value) { this.disabled = value; - if (value) { - this.checkBoxStackPane.setStyle("-fx-background-color: rgb(192,192,192);-fx-border-color:rgb(153,153,153);-fx-border-width: " + Simplicity.getDpmm() / 2 + ";"); + if(value) { + this.checkBoxStackPane.setStyle("-fx-background-color: rgb(192,192,192);-fx-border-color:rgb(153,153,153);-fx-border-width: " + View.getDpmm() / 2 + ";"); setOnMouseClicked(null); } else { - this.checkBoxStackPane.setStyle("-fx-background-color: rgb(255,255,255);-fx-border-color:rgb(" + Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");-fx-border-width: " + Simplicity.getDpmm() / 2 + ";"); + this.checkBoxStackPane.setStyle("-fx-background-color: rgb(255,255,255);-fx-border-color:rgb(" + View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK) + ");-fx-border-width: " + View.getDpmm() / 2 + ";"); setOnMouseClicked(this::handleMouseClicked); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SComboBox.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SComboBox.java similarity index 72% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SComboBox.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SComboBox.java index e6e970b..6f071fb 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SComboBox.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SComboBox.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,16 +18,17 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; import javafx.scene.control.ComboBox; import javafx.scene.text.Font; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class SComboBox extends ComboBox { @@ -35,15 +36,15 @@ public class SComboBox extends ComboBox { * Constructor */ public SComboBox() { - this.setMaxHeight(6 * Simplicity.getDpmm()); + this.setMaxHeight(6 * View.getDpmm()); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("-fx-padding:0;-fx-border-insets:0;-fx-background-insets:0;-fx-background-radius:0;-fx-background-color: rgb(255,255,255);-fx-border-color:rgb("); - stringBuilder.append(Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK)); + stringBuilder.append(View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK)); stringBuilder.append(");-fx-border-width: "); - stringBuilder.append(Simplicity.getDpmm() / 2); + stringBuilder.append(View.getDpmm() / 2); stringBuilder.append(";-fx-font-size: "); - stringBuilder.append(Font.font(3 * Simplicity.getDpmm())); + stringBuilder.append(Font.font(3 * View.getDpmm())); stringBuilder.append(";"); this.setStyle(stringBuilder.toString()); } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SLabel.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SLabel.java similarity index 71% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SLabel.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SLabel.java index edeca13..15c1777 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/SLabel.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/SLabel.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,16 +18,18 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; import javafx.scene.paint.Color; -import org.nanoboot.powerframework.simplicity.Simplicity; import javafx.scene.text.Font; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class SLabel extends javafx.scene.control.Label { @@ -46,10 +48,11 @@ public class SLabel extends javafx.scene.control.Label { * @param text * @param colourVariant */ - public SLabel(String text, ColourVariant colourVariant) { + public SLabel(String text, + ColourVariant colourVariant) { super(text); - setFont(Font.font(3 * Simplicity.getDpmm())); - Color color = Simplicity.getDefaultWindowColourSkin().getColourForText(colourVariant); + setFont(Font.font(3 * View.getDpmm())); + Color color = View.getDefaultWindowColourSkin().getColourForText(colourVariant); this.setTextFill(color); } @@ -57,7 +60,7 @@ public class SLabel extends javafx.scene.control.Label { * Constructor */ public SLabel() { - setFont(Font.font(3 * Simplicity.getDpmm())); + setFont(Font.font(3 * View.getDpmm())); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/TabPane.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/TabPane.java similarity index 82% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/TabPane.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/TabPane.java index 68b0ab2..b0705d1 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/TabPane.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/TabPane.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,14 +18,19 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; /** + * * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class TabPane extends javafx.scene.control.TabPane { + /** + * + */ public TabPane() { //Not yet implemented. } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/TextField.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/TextField.java similarity index 72% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/controls/TextField.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/TextField.java index 77a13f5..f73e8af 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/controls/TextField.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/controls/TextField.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,22 +18,25 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.controls; +package org.nanoboot.powerframework.view.window.controls; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; import javafx.scene.text.Font; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; /** * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ public class TextField extends javafx.scene.control.TextField { -/** - * Constructor - * - * @param value - */ + + /** + * Constructor + * + * @param value + */ public TextField(String value) { super(value); setTextField(); @@ -47,14 +50,14 @@ public class TextField extends javafx.scene.control.TextField { } private void setTextField() { - this.setFont(Font.font(3 * Simplicity.getDpmm())); - this.setMaxHeight(6 * Simplicity.getDpmm()); + this.setFont(Font.font(3 * View.getDpmm())); + this.setMaxHeight(6 * View.getDpmm()); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("-fx-padding:0;-fx-border-insets:0;-fx-background-insets:0;-fx-background-radius:0;-fx-background-color: rgb(255,255,255);-fx-border-color:rgb("); - stringBuilder.append(Simplicity.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK)); + stringBuilder.append(View.getDefaultWindowColourSkin().getRGBStringForCSS(ColourVariant.DARK)); stringBuilder.append(");-fx-border-width: "); - stringBuilder.append(Simplicity.getDpmm() / 2); + stringBuilder.append(View.getDpmm() / 2); stringBuilder.append(";"); this.setStyle(stringBuilder.toString()); } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/CloseButton.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/CloseButton.java similarity index 73% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/CloseButton.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/CloseButton.java index c009794..259648a 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/CloseButton.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/CloseButton.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,36 +18,39 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.titlebuttons; +package org.nanoboot.powerframework.view.window.titlebuttons; import javafx.geometry.Pos; import javafx.scene.shape.Line; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.Window; -import org.nanoboot.powerframework.simplicity.window.WindowColourSkin; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.Window; +import org.nanoboot.powerframework.view.window.WindowColourSkin; /** * Represents close button. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ public class CloseButton extends WindowTitleButton { - Line line1 = new Line(0, 0, 5 * Simplicity.getDpmm(), 2.5 * Simplicity.getDpmm()); - Line line2 = new Line(0, 2.5 * Simplicity.getDpmm(), 5 * Simplicity.getDpmm(), 0); + Line line1 = new Line(0, 0, 5 * View.getDpmm(), 2.5 * View.getDpmm()); + Line line2 = new Line(0, 2.5 * View.getDpmm(), 5 * View.getDpmm(), 0); /** * * @param windowColourSkin * @param window */ - public CloseButton(WindowColourSkin windowColourSkin, Window window) { + public CloseButton(WindowColourSkin windowColourSkin, + Window window) { super(windowColourSkin); setOnMouseClicked(window::handleCloseButtonAction); line1.setStroke(this.windowColourSkin.getColourForInactiveWindowTitleButton()); - line1.setStrokeWidth(0.5 * Simplicity.getDpmm()); + line1.setStrokeWidth(0.5 * View.getDpmm()); line2.setStroke(this.windowColourSkin.getColourForInactiveWindowTitleButton()); - line2.setStrokeWidth(0.5 * Simplicity.getDpmm()); + line2.setStrokeWidth(0.5 * View.getDpmm()); getChildren().addAll(line1, line2); setAlignment(line1, Pos.CENTER); setAlignment(line2, Pos.CENTER); diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/LineInWindowTitleButton.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/LineInWindowTitleButton.java similarity index 80% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/LineInWindowTitleButton.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/LineInWindowTitleButton.java index 6205bcb..e8ca4d6 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/LineInWindowTitleButton.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/LineInWindowTitleButton.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,19 +18,23 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.titlebuttons; +package org.nanoboot.powerframework.view.window.titlebuttons; import javafx.scene.paint.Color; import javafx.scene.shape.Line; -import org.nanoboot.powerframework.simplicity.Simplicity; +import org.nanoboot.powerframework.view.View; /** * Represents a line of a window title button * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class LineInWindowTitleButton extends Line { + /** + * + */ protected Color inactiveLinesColour = Color.rgb(153, 153, 153); /** @@ -38,6 +42,6 @@ public class LineInWindowTitleButton extends Line { */ public LineInWindowTitleButton() { setStroke(inactiveLinesColour); - setStrokeWidth(0.5 * Simplicity.getDpmm()); + setStrokeWidth(0.5 * View.getDpmm()); } } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/MaximizeRestoreButton.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/MaximizeRestoreButton.java similarity index 61% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/MaximizeRestoreButton.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/MaximizeRestoreButton.java index 1f42a84..1a536bf 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/MaximizeRestoreButton.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/MaximizeRestoreButton.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,55 +18,58 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.titlebuttons; +package org.nanoboot.powerframework.view.window.titlebuttons; import javafx.geometry.Pos; import javafx.scene.paint.Color; import javafx.scene.shape.Polyline; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.Window; -import org.nanoboot.powerframework.simplicity.window.WindowColourSkin; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.Window; +import org.nanoboot.powerframework.view.window.WindowColourSkin; /** * Represents maximize/restore button. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * + * @author Robert Vokac + * @since 0.0.0 */ -public class MaximizeRestoreButton extends WindowTitleButton { +public final class MaximizeRestoreButton extends WindowTitleButton { - private Polyline restorePolyline = new Polyline( - 1.5 * Simplicity.getDpmm(), 1 * Simplicity.getDpmm(), - 1.5 * Simplicity.getDpmm(), 0, - 5.5 * Simplicity.getDpmm(), 0, - 5.5 * Simplicity.getDpmm(), 2.0 * Simplicity.getDpmm(), - 4 * Simplicity.getDpmm(), 2.0 * Simplicity.getDpmm(), - 4 * Simplicity.getDpmm(), 3.0 * Simplicity.getDpmm(), - 0 * Simplicity.getDpmm(), 3.0 * Simplicity.getDpmm(), - 0 * Simplicity.getDpmm(), 1 * Simplicity.getDpmm(), - 4 * Simplicity.getDpmm(), 1 * Simplicity.getDpmm(), - 4 * Simplicity.getDpmm(), 2.0 * Simplicity.getDpmm() + private final Polyline restorePolyline = new Polyline( + 1.5 * View.getDpmm(), 1 * View.getDpmm(), + 1.5 * View.getDpmm(), 0, + 5.5 * View.getDpmm(), 0, + 5.5 * View.getDpmm(), 2.0 * View.getDpmm(), + 4 * View.getDpmm(), 2.0 * View.getDpmm(), + 4 * View.getDpmm(), 3.0 * View.getDpmm(), + 0 * View.getDpmm(), 3.0 * View.getDpmm(), + 0 * View.getDpmm(), 1 * View.getDpmm(), + 4 * View.getDpmm(), 1 * View.getDpmm(), + 4 * View.getDpmm(), 2.0 * View.getDpmm() ); - private Polyline maximizePolyline = new Polyline( - 0.25 * Simplicity.getDpmm(), 0.25 * Simplicity.getDpmm(), - 5.25 * Simplicity.getDpmm(), 0.25 * Simplicity.getDpmm(), - 5.25 * Simplicity.getDpmm(), 3 * Simplicity.getDpmm(), - 0.25 * Simplicity.getDpmm(), 3 * Simplicity.getDpmm(), - 0.25 * Simplicity.getDpmm(), 0.25 * Simplicity.getDpmm()); + private final Polyline maximizePolyline = new Polyline( + 0.25 * View.getDpmm(), 0.25 * View.getDpmm(), + 5.25 * View.getDpmm(), 0.25 * View.getDpmm(), + 5.25 * View.getDpmm(), 3 * View.getDpmm(), + 0.25 * View.getDpmm(), 3 * View.getDpmm(), + 0.25 * View.getDpmm(), 0.25 * View.getDpmm()); /** * * @param windowColourSkin * @param window */ - public MaximizeRestoreButton(WindowColourSkin windowColourSkin, Window window) { + public MaximizeRestoreButton(WindowColourSkin windowColourSkin, + Window window) { super(windowColourSkin); setOnMouseClicked(window::handleMaximizeRestoreButtonAction); restorePolyline.setStroke(this.windowColourSkin.getColourForInactiveWindowTitleButton()); - restorePolyline.setStrokeWidth(0.5 * Simplicity.getDpmm()); + restorePolyline.setStrokeWidth(0.5 * View.getDpmm()); restorePolyline.setFill(Color.TRANSPARENT); maximizePolyline.setStroke(this.windowColourSkin.getColourForInactiveWindowTitleButton()); - maximizePolyline.setStrokeWidth(0.5 * Simplicity.getDpmm()); + maximizePolyline.setStrokeWidth(0.5 * View.getDpmm()); maximizePolyline.setFill(Color.TRANSPARENT); this.setAlignment(Pos.CENTER); diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/MinimizeButton.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/MinimizeButton.java similarity index 69% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/MinimizeButton.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/MinimizeButton.java index bb64449..09580d2 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/MinimizeButton.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/MinimizeButton.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,37 +18,39 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.titlebuttons; +package org.nanoboot.powerframework.view.window.titlebuttons; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.shape.Line; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.Window; -import org.nanoboot.powerframework.simplicity.window.WindowColourSkin; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.Window; +import org.nanoboot.powerframework.view.window.WindowColourSkin; /** * Represents minimize button. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public class MinimizeButton extends WindowTitleButton { - Line line1 = new Line(1 * Simplicity.getDpmm(), 3.5 * Simplicity.getDpmm(), 6 * Simplicity.getDpmm(), 3.5 * Simplicity.getDpmm()); + Line line1 = new Line(1 * View.getDpmm(), 3.5 * View.getDpmm(), 6 * View.getDpmm(), 3.5 * View.getDpmm()); /** * * @param windowColourSkin * @param window */ - public MinimizeButton(WindowColourSkin windowColourSkin, Window window) { + public MinimizeButton(WindowColourSkin windowColourSkin, + Window window) { super(windowColourSkin); setOnMouseClicked(window::handleMinimizeButtonAction); line1.setStroke(this.windowColourSkin.getColourForInactiveWindowTitleButton()); - line1.setStrokeWidth(0.5 * Simplicity.getDpmm()); + line1.setStrokeWidth(0.5 * View.getDpmm()); getChildren().addAll(line1); setAlignment(line1, Pos.BOTTOM_CENTER); - this.setPadding(new Insets(Simplicity.getDpmm(), Simplicity.getDpmm(), Simplicity.getDpmm(), Simplicity.getDpmm())); + this.setPadding(new Insets(View.getDpmm(), View.getDpmm(), View.getDpmm(), View.getDpmm())); } diff --git a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/WindowTitleButton.java b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/WindowTitleButton.java similarity index 81% rename from src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/WindowTitleButton.java rename to power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/WindowTitleButton.java index 26e5edb..e577512 100644 --- a/src/main/java/org/nanoboot/powerframework/simplicity/window/titlebuttons/WindowTitleButton.java +++ b/power-view/src/main/java/org/nanoboot/powerframework/view/window/titlebuttons/WindowTitleButton.java @@ -5,7 +5,7 @@ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; +// License as published by the Free Software Foundation; // version 2.1 of the License only. // // This library is distributed in the hope that it will be useful, @@ -18,24 +18,28 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA /////////////////////////////////////////////////////////////////////////////////////////////// -package org.nanoboot.powerframework.simplicity.window.titlebuttons; +package org.nanoboot.powerframework.view.window.titlebuttons; import javafx.scene.input.MouseEvent; import javafx.scene.layout.StackPane; import javafx.scene.shape.Line; -import org.nanoboot.powerframework.simplicity.Simplicity; -import org.nanoboot.powerframework.simplicity.window.ColourVariant; -import org.nanoboot.powerframework.simplicity.window.WindowColourSkin; +import org.nanoboot.powerframework.view.View; +import org.nanoboot.powerframework.view.window.ColourVariant; +import org.nanoboot.powerframework.view.window.WindowColourSkin; /** * Represents window title button. * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org + * @author Robert Vokac + * @since 0.0.0 */ public abstract class WindowTitleButton extends StackPane { private static final int BUTTONWIDTH = 7; + /** + * + */ protected WindowColourSkin windowColourSkin; /** @@ -45,8 +49,8 @@ public abstract class WindowTitleButton extends StackPane { public WindowTitleButton(WindowColourSkin windowColourSkin) { this.windowColourSkin = windowColourSkin; this.setStyle("-fx-background-color: rgb(" + windowColourSkin.getRGBStringForCSS(ColourVariant.DARK) + ");"); - setMinWidth(BUTTONWIDTH * Simplicity.getDpmm()); - setMaxWidth(BUTTONWIDTH * Simplicity.getDpmm()); + setMinWidth(BUTTONWIDTH * View.getDpmm()); + setMaxWidth(BUTTONWIDTH * View.getDpmm()); setOnMouseEntered(this::handleMouseEnteredAction); setOnMouseExited(this::handleMMouseExitedAction); @@ -65,7 +69,7 @@ public abstract class WindowTitleButton extends StackPane { */ public void makeLine(Line line) { line.setStroke(this.windowColourSkin.getColourForInactiveWindowTitleButton()); - line.setStrokeWidth(0.5 * Simplicity.getDpmm()); + line.setStrokeWidth(0.5 * View.getDpmm()); } private void handleMouseEnteredAction(MouseEvent event) {//NOSONAR diff --git a/power-view/src/main/resources/.gitkeep b/power-view/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-view/src/test/java/.gitkeep b/power-view/src/test/java/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-web/pom.xml b/power-web/pom.xml new file mode 100644 index 0000000..5bf9d78 --- /dev/null +++ b/power-web/pom.xml @@ -0,0 +1,67 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-web + jar + + Power Web + Web functionality for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-xml + ${power.version} + + + + + junit + junit + 4.12 + test + + + org.projectlombok + lombok + + + org.jsoup + jsoup + 1.12.1 + + + diff --git a/power-web/src/main/java/module-info.java b/power-web/src/main/java/module-info.java new file mode 100644 index 0000000..0eef5f6 --- /dev/null +++ b/power-web/src/main/java/module-info.java @@ -0,0 +1,36 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +module powerframework.web { + requires lombok; + requires org.jsoup; + requires powerframework.xml; + exports org.nanoboot.powerframework.web.html; + exports org.nanoboot.powerframework.web.html.attributes; + exports org.nanoboot.powerframework.web.html.tags; + exports org.nanoboot.powerframework.web; +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/PowerWebException.java b/power-web/src/main/java/org/nanoboot/powerframework/web/PowerWebException.java new file mode 100644 index 0000000..3d3b67f --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/PowerWebException.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PowerWebException extends RuntimeException { + public PowerWebException(String s) { + super(s); + } +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/PrettyPrinter.java b/power-web/src/main/java/org/nanoboot/powerframework/web/PrettyPrinter.java new file mode 100644 index 0000000..c104624 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/PrettyPrinter.java @@ -0,0 +1,37 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class PrettyPrinter { + public static String makePretty(String html) { + Document doc = Jsoup.parse(html); + return doc.toString(); + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/TestMain.java b/power-web/src/main/java/org/nanoboot/powerframework/web/TestMain.java new file mode 100644 index 0000000..5b5229e --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/TestMain.java @@ -0,0 +1,66 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web; + +import org.nanoboot.powerframework.web.html.WebPage; +import org.nanoboot.powerframework.web.html.attributes.Content; +import org.nanoboot.powerframework.web.html.attributes.Href; +import org.nanoboot.powerframework.web.html.attributes.HttpEquiv; +import org.nanoboot.powerframework.web.html.attributes.Rel; +import org.nanoboot.powerframework.web.html.tags.*; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class TestMain { + public static void main(String[] args) { + WebPage page=new WebPage(); + Html html=page.getRootElement(); + + Head head = getHead(); + + + Body body = getBody(); + + html.add(head,body); + System.out.println(page.build()); + } + + private static Head getHead() { + Head head=new Head(); + Meta meta=new Meta(); + meta.add(new HttpEquiv("content-type"),new Content("text/html; charset=UTF-8")); + head.add(meta); + head.add(new Title("Tree Base | Home")); + head.add(new Link(new Rel("stylesheet"),new Href("/styles/styles.css"))); + + return head; + } + + private static Body getBody() { + Body body=new Body(); + return body; + } + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyle.java b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyle.java new file mode 100644 index 0000000..5b10832 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyle.java @@ -0,0 +1,62 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.css; + +import org.nanoboot.powerframework.web.PowerWebException; +import lombok.Getter; +import lombok.Setter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CssStyle { + @Getter + private final String name; + @Getter + @Setter + private String value; + + public CssStyle(String nameValue) { + String[] a=nameValue.split(":"); + if(a.length!=2){ + throw new PowerWebException("nameValue "+nameValue+"is not a valid css style. Because just one colon : is expected"); + } + this.name=a[0]; + this.value=a[1]; + + } + + public CssStyle(String name, String value) { + this.name=name; + this.value=value; + + } + public String build() { + return name + ':'+ value; + } + + public String toString() { + return build(); + } +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyles.java b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyles.java new file mode 100644 index 0000000..730dff0 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStyles.java @@ -0,0 +1,117 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.css; + +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class CssStyles { + + public static final String SEPARATOR = "; "; + + @Getter + private final List cssStyles = new ArrayList<>(); + + public CssStyles(String moreStyles){ + String[] a=moreStyles.split(";"); + for(String e:a){ + if(e.isEmpty()){ + continue; + } + this.add(new CssStyle(e)); + } + } + + public CssStyles(CssStyle... cssStyles) { + this.addAll(cssStyles); + } + + + public void add(String name, String value) { + cssStyles.add(new CssStyle(name, value)); + } + + public void add(CssStyle cssStyle) { + + cssStyles.add(cssStyle); + } + + public void addAll(CssStyle... cssStyle) { + + for (CssStyle a : cssStyle) { + cssStyles.add(a); + } + } + + public boolean has(String name) { + if (this.cssStyles == null) { + return false; + } + for (CssStyle a : this.cssStyles) { + if (a.getName().equals(name)) { + + return true; + } + } + return false; + } + + public String get(String name) { + + for (CssStyle a : this.cssStyles) { + if (a.getName().equals(name)) { + return a.getValue(); + } + } + throw new RuntimeException("There is no style " + name); + } + + public void set(String name, String value) { + if (!has(name)) { + throw new RuntimeException("There is no style " + name); + } + for (CssStyle a : this.cssStyles) { + if (a.getName().equals(name)) { + a.setValue(value); + return; + } + } + throw new RuntimeException("There is no style " + name); + } + public String build() { + StringBuilder sb = new StringBuilder(); + for (CssStyle a : this.getCssStyles()) { + sb.append(a); + sb.append(SEPARATOR);} + sb.toString(); + return sb.toString(); + } + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelector.java b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelector.java new file mode 100644 index 0000000..99e2854 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelector.java @@ -0,0 +1,42 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.css; + +import lombok.AllArgsConstructor; +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +@AllArgsConstructor +public class CssStylesSelector { + private String selector; + private CssStyles cssStyles; + public String build(){ + StringBuilder sb=new StringBuilder(); + sb.append(selector).append(" ").append("{").append(cssStyles.build()).append("}").append("\n\n"); + return sb.toString(); + } +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelectors.java b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelectors.java new file mode 100644 index 0000000..1aae4a5 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/css/CssStylesSelectors.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.css; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +@AllArgsConstructor +public class CssStylesSelectors { + +private final String uuid= UUID.randomUUID().toString(); +private final List list=new ArrayList<>(); +public String build(){ + if(list.isEmpty()){ + return ""; + } + StringBuilder sb=new StringBuilder(); + for(CssStylesSelector e:list){ + sb.append(e.build()).append("\n"); + } + return sb.toString(); +} + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/WebElement.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/WebElement.java new file mode 100644 index 0000000..aedfb14 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/WebElement.java @@ -0,0 +1,71 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html; + +import org.nanoboot.powerframework.web.css.CssStylesSelectors; +import org.nanoboot.powerframework.xml.ElementType; +import org.nanoboot.powerframework.xml.Element; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Getter; + +/** + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class WebElement extends Element { + + @Getter + private final CssStylesSelectors cssStylesSelectors=new CssStylesSelectors(); + + public WebElement(String elementName, String content) { + super(elementName, content); + } + public WebElement(String elementName, XmlTypeI... xmlTypes) { + super(elementName, xmlTypes); + } + + public WebElement(String elementName, ElementType elementType, XmlTypeI... xmlTypes) { + super(elementName, elementType, xmlTypes); + + } + + /** + * Creates new paired element + * + * @param elementName + */ + public WebElement(String elementName) { + super(elementName); + } + + /** + * Creates new element with the specified type + * + * @param elementName + * @param elementType + */ + public WebElement(String elementName, ElementType elementType) { + super(elementName, elementType); + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/WebPage.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/WebPage.java new file mode 100644 index 0000000..ac0d6ac --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/WebPage.java @@ -0,0 +1,119 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html; + +import org.nanoboot.powerframework.web.PrettyPrinter; +import org.nanoboot.powerframework.web.css.CssStylesSelectors; +import org.nanoboot.powerframework.web.html.tags.Head; +import org.nanoboot.powerframework.web.html.tags.Html; +import org.nanoboot.powerframework.web.html.tags.Style; +import org.nanoboot.powerframework.xml.Buildable; +import org.nanoboot.powerframework.xml.Element; +import lombok.Data; +import lombok.Getter; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class WebPage implements Buildable { + @Getter + private Html rootElement = new Html(); + + public WebPage() { + Map allCssStylesSelectors = loadAllCssStylesSelectors(); + if (!allCssStylesSelectors.isEmpty()) { + Head head = (Head) this.getElementByNamePath(("html.head")); + Style style = (Style) head.getByElementName("style"); + if (style == null) { + style = new Style(); + head.add(style); + } + for (Map.Entry entry : allCssStylesSelectors.entrySet()) { + + style.getElements().addInnerText(entry.getValue().build()); + } + } + } + + + public String build() { + String result = " \n" + rootElement.build(); + String prettyResult = null; + try { + prettyResult = PrettyPrinter.makePretty(result); + } catch (Exception e) { + System.err.println(e); + } + return prettyResult == null ? result : prettyResult; + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public String getCache() { + return null; + } + + /** + * Remove me + * + * @param elementNamePath + * @return + */ + @Deprecated + public WebElement getElementByNamePath(String elementNamePath) { + return null; + } + + private Map loadAllCssStylesSelectors() { + Map map = new HashMap<>(); + + for (Element e : loadAllElements()) { + WebElement we = (WebElement) e; + if (we.getCssStylesSelectors() == null) { + break; + } + if (map.containsKey(we.getCssStylesSelectors().getUuid())) { + continue; + } + map.put(we.getCssStylesSelectors().getUuid(), we.getCssStylesSelectors()); + + } + + + return map; + } + + private List loadAllElements() { + return this.rootElement.getElements().loadElements(); + + + } +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Action.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Action.java new file mode 100644 index 0000000..b3f6ab6 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Action.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Action extends Attribute { + public static final String NAME="action"; + + public Action(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Charset.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Charset.java new file mode 100644 index 0000000..5674b6c --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Charset.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Charset extends Attribute { + public static final String NAME="charset"; + + public Charset(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Class.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Class.java new file mode 100644 index 0000000..b0ebde4 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Class.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Class extends Attribute { + public static final String NAME="class"; + + public Class(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Content.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Content.java new file mode 100644 index 0000000..526382d --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Content.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Content extends Attribute { + public static final String NAME="content"; + + public Content(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Height.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Height.java new file mode 100644 index 0000000..780be56 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Height.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Height extends Attribute { + public static final String NAME="height"; + + public Height(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Href.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Href.java new file mode 100644 index 0000000..53f8554 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Href.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Href extends Attribute { + public static final String NAME="href"; + + public Href(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/HttpEquiv.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/HttpEquiv.java new file mode 100644 index 0000000..5db43fe --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/HttpEquiv.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class HttpEquiv extends Attribute { + public static final String NAME="http-equiv"; + + public HttpEquiv(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Id.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Id.java new file mode 100644 index 0000000..7b03887 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Id.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Id extends Attribute { + public static final String NAME="id"; + + public Id(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Method.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Method.java new file mode 100644 index 0000000..bd4b7c3 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Method.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Method extends Attribute { + public static final String NAME="method"; + + public Method(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Name.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Name.java new file mode 100644 index 0000000..f6ad1a4 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Name.java @@ -0,0 +1,41 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Name extends Attribute { + public static final String NAME="name"; + + public Name(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Rel.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Rel.java new file mode 100644 index 0000000..ea7c2b4 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Rel.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Rel extends Attribute { + public static final String NAME="rel"; + + public Rel(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Src.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Src.java new file mode 100644 index 0000000..e10975d --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Src.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Src extends Attribute { + public static final String NAME="src"; + + public Src(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Style.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Style.java new file mode 100644 index 0000000..b201d1b --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Style.java @@ -0,0 +1,60 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +import org.nanoboot.powerframework.web.css.CssStyle; +import org.nanoboot.powerframework.web.css.CssStyles; +import lombok.Getter; +import lombok.Setter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Style extends Attribute { + public static final String NAME="style"; + + @Getter + @Setter + private CssStyles cssStyles = new CssStyles(); + + public Style(String moreStyles) { + this(new CssStyles(moreStyles)); + } + + public Style(CssStyle cssStyle) { + super(NAME, cssStyle.build());//?? + this.cssStyles.add(cssStyle); + } + public Style(CssStyles cssStyles) { + super(NAME, cssStyles.build()); + for(CssStyle e: cssStyles.getCssStyles()){ + this.cssStyles.add(e); + } + } + public String build(){ + this.setValue(cssStyles.build()); + return super.build(); + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Template.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Template.java new file mode 100644 index 0000000..0d13152 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Template.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Template extends Attribute { + public static final String NAME="id"; + + public Template(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Title.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Title.java new file mode 100644 index 0000000..54630ef --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Title.java @@ -0,0 +1,40 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Title extends Attribute { + public static final String NAME="title"; + + public Title(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Type.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Type.java new file mode 100644 index 0000000..9be842a --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Type.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Type extends Attribute { + public static final String NAME="type"; + + public Type(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Value.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Value.java new file mode 100644 index 0000000..89a6d25 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Value.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Value extends Attribute { + public static final String NAME="value"; + + public Value(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Width.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Width.java new file mode 100644 index 0000000..fe7fb26 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/attributes/Width.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.attributes; + +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Width extends Attribute { + public static final String NAME="width"; + + public Width(String value) { + super(NAME,value); + } + + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/A.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/A.java new file mode 100644 index 0000000..7067830 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/A.java @@ -0,0 +1,73 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.attributes.Href; +import org.nanoboot.powerframework.web.html.attributes.Title; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class A extends WebElement { + public static final String NAME = "a"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(Href.NAME, Title.NAME); + + public A(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public A() { + super(NAME); + + } + + public A(String href) { + this(href, href); + + + } + + public A(String href, String title) { + this(); + this.add(new Href(href)); + if (title != null) { + this.add(new Title(title)); + } + } + + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Body.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Body.java new file mode 100644 index 0000000..4a3bd58 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Body.java @@ -0,0 +1,59 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public class Body extends WebElement { + public static final String NAME = "body"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(); + public Body(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Body() { + super(NAME); + + } + + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Br.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Br.java new file mode 100644 index 0000000..0dd4329 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Br.java @@ -0,0 +1,43 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.ElementType; +import lombok.Data; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public final class Br extends WebElement { + public static final String NAME = "br"; + + public Br() { + super(NAME, ElementType.NOT_PAIRED); + + } + + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Div.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Div.java new file mode 100644 index 0000000..a4067a8 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Div.java @@ -0,0 +1,59 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; + +import java.util.Set; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Div extends WebElement { + private static final String NAME = "div"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(""); + + public Div(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Div() { + super(NAME); + + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Form.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Form.java new file mode 100644 index 0000000..cdef108 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Form.java @@ -0,0 +1,83 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.attributes.Id; +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.attributes.Action; +import org.nanoboot.powerframework.web.html.attributes.Method; +import org.nanoboot.powerframework.web.html.attributes.Name; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.NoElement; +import org.nanoboot.powerframework.xml.XmlTypeI; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Form extends WebElement { + + public static final String NAME = "form"; + public static final Set ALLOWED_ELEMENTS + = XmlUtils.createNewSet(Input.NAME, Br.NAME, Label.NAME, Select.NAME); + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(Name.NAME, Action.NAME, Method.NAME, NoElement.NAME, Id.NAME); + + public Form(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Form() { + super(NAME); + + } + + public Form(String action, FormMethod method) { + this(); + getAttributes().add("action", action); + getAttributes().add("method", method.name()); + + } + + public Form(String action, String method) { + this(); + getAttributes().add("action", action); + getAttributes().add("method", method); + + } + + @Override + public Set getAllowedElements() { + return ALLOWED_ELEMENTS; + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/FormMethod.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/FormMethod.java new file mode 100644 index 0000000..97cca6d --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/FormMethod.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum FormMethod { + GET, POST; +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H1.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H1.java new file mode 100644 index 0000000..65a1468 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H1.java @@ -0,0 +1,62 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import org.nanoboot.powerframework.xml.XmlUtils; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class H1 extends WebElement { + private static final String NAME = "h1"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(""); + + public H1(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public H1() { + super(NAME); + + } + + public H1(String title) { + this(); + setInnerText(title); + } + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H2.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H2.java new file mode 100644 index 0000000..accedd2 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H2.java @@ -0,0 +1,62 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import org.nanoboot.powerframework.xml.XmlUtils; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class H2 extends WebElement { + private static final String NAME = "h2"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(""); + + public H2(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public H2() { + super(NAME); + + } + + public H2(String title) { + this(); + setInnerText(title); + } + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H3.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H3.java new file mode 100644 index 0000000..24ebaac --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/H3.java @@ -0,0 +1,62 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import org.nanoboot.powerframework.xml.XmlUtils; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class H3 extends WebElement { + private static final String NAME = "h3"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(""); + + public H3(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public H3() { + super(NAME); + + } + + public H3(String title) { + this(); + setInnerText(title); + } + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Head.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Head.java new file mode 100644 index 0000000..22d8178 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Head.java @@ -0,0 +1,57 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public class Head extends WebElement { + public static final String NAME="head"; + public static final Set ALLOWED_ELEMENTS= XmlUtils.createNewSet(Meta.NAME,Title.NAME,Link.NAME); + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(); + + + public Head(XmlTypeI xmlTypes) { + this(); + } + + public Head() { + super(NAME); + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HiddenInput.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HiddenInput.java new file mode 100644 index 0000000..ce873a3 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HiddenInput.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class HiddenInput extends Input { + public HiddenInput(String name, String value) { + super(InputType.HIDDEN, name, value); + } +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Hr.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Hr.java new file mode 100644 index 0000000..0015f8a --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Hr.java @@ -0,0 +1,55 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import org.nanoboot.powerframework.xml.XmlUtils; +import lombok.Data; + +import java.util.Set; +import org.nanoboot.powerframework.xml.ElementType; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Hr extends WebElement { + private static final String NAME = "hr"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(""); + + + public Hr() { + super(NAME, ElementType.NOT_PAIRED); + + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Html.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Html.java new file mode 100644 index 0000000..90e97c1 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Html.java @@ -0,0 +1,54 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public final class Html extends WebElement { + public static final String NAME = "html"; + public static final Set ALLOWED_ELEMENTS= XmlUtils.createNewSet(Head.NAME,Body.NAME); + + public Html() { + super(NAME); + } + + public Html(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + @Override + public Set getAllowedElements() { + return ALLOWED_ELEMENTS; + } +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HtmlElement.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HtmlElement.java new file mode 100644 index 0000000..40dd292 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/HtmlElement.java @@ -0,0 +1,65 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.ElementType; +import org.nanoboot.powerframework.xml.XmlTypeI; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Deprecated +public class HtmlElement extends WebElement { + + //private final CssStylesSelectors cssStylesSelectors=new CssStylesSelectors(); + public HtmlElement(String elementName, XmlTypeI... xmlTypes) { + super(elementName, xmlTypes); + } + + public HtmlElement(String elementName, ElementType elementType, XmlTypeI... xmlTypes) { + super(elementName, elementType, xmlTypes); + + } + + /** + * Creates new paired element + * + * @param elementName + */ + public HtmlElement(String elementName) { + super(elementName); + } + + /** + * Creates new element with the specified type + * + * @param elementName + * @param elementType + */ + public HtmlElement(String elementName, ElementType elementType) { + super(elementName, elementType); + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Img.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Img.java new file mode 100644 index 0000000..391693c --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Img.java @@ -0,0 +1,63 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.ElementType; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; +import org.nanoboot.powerframework.web.html.attributes.Height; +import org.nanoboot.powerframework.web.html.attributes.Src; +import org.nanoboot.powerframework.web.html.attributes.Width; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public final class Img extends WebElement { + public static final String NAME = "img"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(Src.NAME, Width.NAME, Height.NAME); + + public Img(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Img() { + super(NAME, ElementType.NOT_PAIRED); + + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Input.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Input.java new file mode 100644 index 0000000..baf4a0b --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Input.java @@ -0,0 +1,101 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.ElementType; +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.attributes.Name; +import org.nanoboot.powerframework.web.html.attributes.Type; +import org.nanoboot.powerframework.web.html.attributes.Value; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlTypeI; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Input extends WebElement { + + public static final String NAME = "input"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(Name.NAME, Type.NAME, Value.NAME); + + public Input(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Input() { + super(NAME, ElementType.NOT_PAIRED); + + } + + public Input(String name, String value) { + this(null, name, value); + } + + public Input(InputType type, String name, String value) { + this(); + if (type != null) { + withType(type); + } + withNameAndValue(name, value); + } + + public Input withType(InputType type) { + this.add(new Type(type.name().toLowerCase())); + return this; + } + + public Input withType(String type) { + this.add(new Type(type)); + return this; + } + + public Input withNameAndValue(String name, String value) { + withName(name); + withValue(value); + return this; + } + + public Input withName(String name) { + if (name != null) { + this.add(new Name(name)); + } + return this; + } + + public Input withValue(String value) { + this.add(new Value(value)); + return this; + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/InputType.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/InputType.java new file mode 100644 index 0000000..a7f98ef --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/InputType.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum InputType { + TEXT, PASSWORD, HIDDEN, RADIO, CHECKBOX, SUBMIT; +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Label.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Label.java new file mode 100644 index 0000000..143107e --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Label.java @@ -0,0 +1,58 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.XmlUtils; + +import java.util.Set; +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Label extends WebElement { + public static final String NAME = "label"; + + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet("for"); + + public Label(String title, String forId) { + this(title); + this.add(new Attribute("for",forId)); + } + + public Label(String title) { + super(NAME); + setInnerText(title); + + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Li.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Li.java new file mode 100644 index 0000000..d9213bb --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Li.java @@ -0,0 +1,60 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.NoElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import org.nanoboot.powerframework.xml.XmlUtils; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public final class Li extends WebElement { + public static final String NAME = "li"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(); + + public Li(String string) { + this(new NoElement(string)); + } + public Li(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Li() { + super(NAME); + + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Link.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Link.java new file mode 100644 index 0000000..76a43f6 --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Link.java @@ -0,0 +1,63 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.attributes.Href; +import org.nanoboot.powerframework.web.html.attributes.Rel; +import org.nanoboot.powerframework.web.html.attributes.Type; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.ElementType; +import org.nanoboot.powerframework.xml.XmlTypeI; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +@Data +public final class Link extends WebElement { + public static final String NAME = "link"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(Rel.NAME, Href.NAME, Type.NAME); + + + public Link() { + super(NAME,ElementType.NOT_PAIRED); + + } + public Link(XmlTypeI... xmlTypes) { + this(); + + this.add(xmlTypes); + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Meta.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Meta.java new file mode 100644 index 0000000..a623e9f --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Meta.java @@ -0,0 +1,57 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.xml.XmlUtils; +import org.nanoboot.powerframework.web.html.attributes.Charset; +import org.nanoboot.powerframework.web.html.attributes.Content; +import org.nanoboot.powerframework.web.html.attributes.HttpEquiv; +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.ElementType; +import lombok.Data; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public final class Meta extends WebElement { + public static final String NAME = "meta"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(HttpEquiv.NAME, Content.NAME, Charset.NAME); + + public Meta() { + super(NAME, ElementType.NOT_PAIRED); + + } + + + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Ol.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Ol.java new file mode 100644 index 0000000..620de6b --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Ol.java @@ -0,0 +1,56 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.xml.NoElement; +import org.nanoboot.powerframework.xml.XmlTypeI; +import org.nanoboot.powerframework.xml.XmlUtils; + +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public final class Ol extends WebElement { + public static final String NAME = "ol"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet(); + + public Ol(XmlTypeI xmlTypes) { + this(); + add(xmlTypes); + } + + public Ol() { + super(NAME); + + } + + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } + +} diff --git a/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Option.java b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Option.java new file mode 100644 index 0000000..8264d5e --- /dev/null +++ b/power-web/src/main/java/org/nanoboot/powerframework/web/html/tags/Option.java @@ -0,0 +1,74 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.web.html.tags; + +import org.nanoboot.powerframework.web.html.WebElement; +import org.nanoboot.powerframework.web.html.attributes.Id; +import org.nanoboot.powerframework.web.html.attributes.Name; +import org.nanoboot.powerframework.xml.XmlUtils; + +import java.util.Set; +import org.nanoboot.powerframework.xml.Attribute; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class Option extends WebElement { + public static final String NAME = "option"; + + public static final Set ALLOWED_ATTRIBUTES + = XmlUtils.createNewSet("label", "value", "selected"); + + public Option() { + super(NAME); + + } + public Option(String title) { + this(); + setInnerText(title); + + } + public Option withSelected() { + this.add(new Attribute("selected", "selected")); + return this; + } + public Option withValue(String value) { + this.add(new Attribute("value", value)); + return this; + } + public Option withLabel(String label) { + this.add(new Attribute("label", label)); + return this; + } + public Option withEmptyLabel() { + this.add(new Attribute("label", " ")); + return this; + } + @Override + public Set getAllowedAttributes() { + return ALLOWED_ATTRIBUTES; + } +} +// +//

"; + public static final String H1_END = "

"; + public static final String H2_START = "

"; + public static final String H2_END = "

"; + public static final String H3_START = "

"; + public static final String H3_END = "

"; + public static final String H4_START = "

"; + public static final String H4_END = "

"; + public static final String H5_START = "
"; + public static final String H5_END = "
"; + public static final String H6_START = "
"; + public static final String H6_END = "
"; + + public static final String OL_START = "
    "; + public static final String OL_END = "
"; + public static final String UL_START = "
    "; + public static final String UL_END = "
"; + public static final String LI_START = "
  • "; + public static final String LI_END = "
  • "; + public static final String P_START = "

    "; + public static final String P_END = "

    "; + + public static final String TABLE_START = ""; + public static final String TABLE_END = "
    "; + public static final String TR_START = ""; + public static final String TR_END = ""; + public static final String TH_START = ""; + public static final String TH_END = ""; + public static final String TD_START = ""; + public static final String TD_END = ""; + + public static final String HR4 = "
    "; + public static final String HR5 = "
    "; + public static final String HR6 = "
    "; + public static final String HR7 = "
    "; + public static final String HR8 = "
    "; + public static final String HR9 = "
    "; + public static final String HR10 = "
    "; + + public static final String COMMENT_TEMPLATE = ""; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private HtmlTags() { + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/Macro.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/Macro.java new file mode 100644 index 0000000..e508312 --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/Macro.java @@ -0,0 +1,65 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Macro { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(Macro.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String content; + private final String value; + + /** + * Constructor + * + * Constructor description + * + * @param nameIn + */ + public Macro(String content, TextProcessorI processor) { + this.content = content; + this.value = processor.process(content); + } + + public String getValue() { + return value; + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/StringSource.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/StringSource.java new file mode 100644 index 0000000..2b23885 --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/StringSource.java @@ -0,0 +1,75 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class StringSource { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(StringSource.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String string; + private int position = 0; + + /** + * Constructor + * + */ + public StringSource(String string) { + this.string = string; + } + + public char getNext() { + return string.charAt(position++); + } + + public char getLast() { + if(position - 1 == 0) { + return ' '; + } + return string.charAt(position - 1); + } + + public boolean hasNext() { + return position <= string.length() - 1; + } + + public char get(int number) { + return string.charAt(position + number); + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextFormatter.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextFormatter.java new file mode 100644 index 0000000..e560e48 --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextFormatter.java @@ -0,0 +1,81 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +/** + * Here goes the description of this class. + * + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class TextFormatter { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(TextFormatter.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private TextFormatter() { + } + + public static String format(String text) { + StringSource stringSource = new StringSource(text); + StringBuilder out = new StringBuilder(); + StringBuilder buffer = new StringBuilder(); + while (stringSource.hasNext()) { + char ch = stringSource.getNext(); + + if(ch == '[' && stringSource.getLast() == '[') { + ch = stringSource.getNext(); + while (!(ch == ']' && stringSource.get(1) == ']')) { + buffer.append(ch); + if(!stringSource.hasNext()) { + break; + } + ch = stringSource.getNext(); + } + out.append(buffer.toString()); + buffer.delete(0, buffer.length()); + }; + + } + + return out.toString(); + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextProcessorI.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextProcessorI.java new file mode 100644 index 0000000..8d44412 --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/TextProcessorI.java @@ -0,0 +1,34 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public interface TextProcessorI { + + public String process(String text); + + public String getName(); +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiException.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiException.java new file mode 100644 index 0000000..f825fda --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiException.java @@ -0,0 +1,53 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +import org.nanoboot.powerframework.core.PowerException; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class WikiException extends PowerException { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(WikiException.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + public WikiException(String messageIn) { + super(messageIn); + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiMarks.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiMarks.java new file mode 100644 index 0000000..df0d2ba --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiMarks.java @@ -0,0 +1,108 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class WikiMarks { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(WikiMarks.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + public static final String BOLD = "\\*\\*"; + public static final String ITALIC = "//"; + public static final String UNDERLINED = "__"; + public static final String COLOURED = "$$"; + public static final String BACKGROUND_HIGHLIGHTED = "##"; + public static final String SUPERSCRIPT = "^"; + public static final String SUBSCRIPT = ",,"; + public static final String MONOSPACE = "`"; + public static final String STROKE = "--"; + public static final String SMALLER_START = "~-"; + public static final String SMALLER_END = "-~"; + public static final String LARGER_START = "~+"; + public static final String LARGER_END = "+~"; + + public static final String LINK_START = "[["; + public static final String LINK_END = "]]"; + public static final String EMBED_START = "{{"; + public static final String EMBED_END = "}}"; + public static final String SIZE = "&&"; + + public static final String MACRO_START = "<<"; + public static final String MACRO_END = ">>"; + + public static final String PARSER_START = "{{{"; + public static final String PARSER_END = "}}}"; + + public static final String HEADING1_START = "= "; + public static final String HEADING2_START = "== "; + public static final String HEADING3_START = "=== "; + public static final String HEADING4_START = "==== "; + public static final String HEADING5_START = "===== "; + public static final String HEADING6_START = "====== "; + public static final String HEADING1_END = " ="; + public static final String HEADING2_END = " =="; + public static final String HEADING3_END = " ==="; + public static final String HEADING4_END = " ===="; + public static final String HEADING5_END = " ====="; + public static final String HEADING6_END = " ======"; + public static final String UNORDERED_LIST = " *"; + public static final String ORDERED_LIST = " 1."; + public static final String TABLE_BORDER = " || "; + public static final String TABLE_COLOURED = "$$$"; + public static final String TABLE_BACKGROUND_HIGHLIGHTED = "###"; + + public static final String HORIZONTAL_RULE_4 = "----"; + public static final String HORIZONTAL_RULE_5 = "-----"; + public static final String HORIZONTAL_RULE_6 = "------"; + public static final String HORIZONTAL_RULE_7 = "-------"; + public static final String HORIZONTAL_RULE_8 = "--------"; + public static final String HORIZONTAL_RULE_9 = "---------"; + public static final String HORIZONTAL_RULE_10 = "----------"; + public static final String COMMENT_LINE_BEGINNING = "####"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private WikiMarks() { + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiParser.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiParser.java new file mode 100644 index 0000000..149771f --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/WikiParser.java @@ -0,0 +1,192 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; +import org.nanoboot.powerframework.utils.StringUtils; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class WikiParser { + + /** + * Logger for this class. + */ + //private static final org.nanoboot.powerframework.logging.Logger LOG = org.nanoboot.powerframework.logging.Logger.getLogger(WikiParser.class); + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private static TextProcessorI linkProcessor; + private static final Map macroProcessorsList = new HashMap<>(); + + /** + * Constructor + * + * Not meant to be instantiated. + */ + public static void setLinkProcessor(TextProcessorI linkProcessorIn) { + linkProcessor = linkProcessorIn; + } + + public String convertWiki(String wikiText) { + System.out.println("Converting wiki text:\n\n"+wikiText); + ArrayList blocks = splitWikiTextToBlocks(wikiText); + StringBuilder stringBuilder = new StringBuilder(); + for (Block block : blocks) { + System.out.println("\n====================\n"+block.getBlockType()+"\n\n"); + String html = block.toHtml(); + System.out.println(block.getOrig()); + System.out.println("VVVVVVVVVVVVVVVVVVVV"); +System.out.println(html); + stringBuilder.append(html).append('\n').append('\n'); + } + String string = stringBuilder.toString(); + return string; + } + + public void setStyle(String string) { + + } + + public void addMacroProcessor(TextProcessorI macroProcessor) { + macroProcessorsList.put(macroProcessor.getName(), macroProcessor); + } + + public TextProcessorI getMacroProcessor(String macroName) { + return macroProcessorsList.get(macroName); + } + + @Deprecated + public static String convert(String wikiText) { + + //System.err.println("\n\n\nWIKI" + "\n{\n" + wikiText + "\n}######$$$"); + while (true) { + if(wikiText.contains(WikiMarks.BOLD)) { + wikiText = wikiText.replaceFirst(WikiMarks.BOLD, HtmlTags.B_START); + //System.err.println(String.format("Replacing %s by %s", BOLD, B_START)); + } + if(wikiText.contains(WikiMarks.BOLD)) { + wikiText = wikiText.replaceFirst(WikiMarks.BOLD, HtmlTags.B_END); + //System.err.println(String.format("Replacing %s by %s", BOLD, B_END)); + } + + if(!wikiText.contains(WikiMarks.BOLD)) { + break; + } + } + + while (true) { + + if(wikiText.contains(WikiMarks.ITALIC)) { + wikiText = wikiText.replaceFirst(WikiMarks.ITALIC, HtmlTags.I_START); + //System.err.println(String.format("Replacing %s by %s", ITALIC, I_START)); + } + if(wikiText.contains(WikiMarks.ITALIC)) { + wikiText = wikiText.replaceFirst(WikiMarks.ITALIC, HtmlTags.I_END); + //System.err.println(String.format("Replacing %s by %s", ITALIC, I_END)); + } + if(!wikiText.contains(WikiMarks.ITALIC)) { + break; + } + } + StringBuilder stringBuilder = new StringBuilder(); + + ArrayList blocks = splitWikiTextToBlocks(wikiText); + +// StringBuilder stringBuilder2 = new StringBuilder("Adding block\n\n"); +// for (Block block : blocks) { +// stringBuilder2.append("\n###{\n").append(block.toHtml()).append("\n}\n"); +// } + //System.err.println(stringBuilder2); +// try { +// Thread.sleep(10000); +// } catch (InterruptedException ex) { +// Logger.getLogger(WikiParser.class.getName()).log(Level.SEVERE, null, ex); +// } + for (Block block : blocks) { + String html = block.toHtml(); + + stringBuilder.append(html).append('\n').append('\n'); + } + String string = stringBuilder.toString(); + //System.out.println("Wiki convertor returned\n\n\n{\n" + string + "\n}\n\n\n"); + return string; + } + + @Deprecated + private String processText(String text) { + StringSource stringSource = new StringSource(text); + StringBuilder out = new StringBuilder(); + StringBuilder buffer = new StringBuilder(); + while (stringSource.hasNext()) { + char ch = stringSource.getNext(); + + if(ch == '[' && stringSource.getLast() == '[') { + ch = stringSource.getNext(); + while (!(ch == ']' && stringSource.get(1) == ']')) { + buffer.append(ch); + if(!stringSource.hasNext()) { + break; + } + ch = stringSource.getNext(); + } + out.append(buffer.toString()); + buffer.delete(0, buffer.length()); + }; + + } + + return out.toString(); + } + + @Deprecated + public static void replaceOccurences(StringBuilder stringBuilder, String what, String replacement) { + Pattern.compile(what).matcher(stringBuilder).replaceAll(replacement); + } + + public static ArrayList splitWikiTextToBlocks(String wikiText) { + BlockList blockList = new BlockList(); + + ArrayList blocks; + String[] lines = StringUtils.toLines(wikiText); + + for (String line : lines) { + blockList.addLine(line); + } + blocks = blockList.getList(); + + return blocks; + } + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/convertors/ListConvertor.java b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/convertors/ListConvertor.java new file mode 100644 index 0000000..124c680 --- /dev/null +++ b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/convertors/ListConvertor.java @@ -0,0 +1,89 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.wiki.convertors; + +import org.nanoboot.powerframework.core.PowerObject; + +/** + * Here goes the description of this class. + * + * @author Robert Vokac + * @since 0.0.0 + * + */ +public class ListConvertor extends PowerObject { + + /** + * Logger for this class. + */ + private static final org.nanoboot.powerframework.log.Logger LOG = org.nanoboot.powerframework.log.Logger.getLogger(ListConvertor.class); + + /** + * Constant description + */ + private static final String CONSTANT = "constant"; + + /** + * Field description + */ + private String name; + + /** + * Constructor + * + * Not meant to be instantiated. + */ + private ListConvertor() { + } + + /** + * Constructor + * + * Constructor description + * + * @param nameIn + */ + public ListConvertor(String nameIn) { + this.name = nameIn; + } + + /** + * Setter for name. + * + * @param nameIn + */ + public void setName(String nameIn) { + LOG.traceStartOfMethod(this, "setName", "name", name); + this.name = nameIn; + } + + /** + * Getter for name. + * + * @return name + */ + public String getName() { + LOG.traceStartOfMethod(this, "getName"); + return this.name; + } + + +} diff --git a/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/macroprocessors/.gitkeep b/power-wiki/src/main/java/org/nanoboot/powerframework/wiki/macroprocessors/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-wiki/src/main/resources/.gitkeep b/power-wiki/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-wiki/src/test/java/org/nanoboot/powerframework/wiki/.gitkeep b/power-wiki/src/test/java/org/nanoboot/powerframework/wiki/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-xml/pom.xml b/power-xml/pom.xml new file mode 100644 index 0000000..c7e4fb7 --- /dev/null +++ b/power-xml/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + + org.nanoboot.powerframework + power-framework + 2.0.0-SNAPSHOT + + + power-xml + jar + + Power XML + XML for the Power library + + + + + org.nanoboot.powerframework + power-core + ${power.version} + + + org.nanoboot.powerframework + power-log + ${power.version} + + + + + junit + junit + 4.12 + test + + + org.projectlombok + lombok + + + diff --git a/power-xml/src/main/java/module-info.java b/power-xml/src/main/java/module-info.java new file mode 100644 index 0000000..50af5ba --- /dev/null +++ b/power-xml/src/main/java/module-info.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +module powerframework.xml { + exports org.nanoboot.powerframework.xml; + requires lombok; + requires powerframework.core; +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/.gitkeep b/power-xml/src/main/java/org/nanoboot/powerframework/xml/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/Attribute.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Attribute.java new file mode 100644 index 0000000..727d33a --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Attribute.java @@ -0,0 +1,76 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import lombok.Getter; +import lombok.Setter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Attribute implements XmlTypeI,Buildable{ + @Getter + private final String name; + @Getter + @Setter + private String value; + + public Attribute(String name) { + this(name, null); + } + + public Attribute(String name, String value) { + this.name=name; + this.value=value; + } + + public final Attribute copy() { + return new Attribute(name, value); + } + + public String build() { + if (value == null) { + return name; + } + return name + '=' + '"' + value + '"'; + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public String getCache() { + return null; + } + + public String toString() { + return build(); + } + + public XmlType getXmlType(){ + return XmlType.ATTRIBUTE; + } +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/Attributes.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Attributes.java new file mode 100644 index 0000000..2e77323 --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Attributes.java @@ -0,0 +1,208 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import org.nanoboot.powerframework.core.PowerException; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Attributes implements Buildable { + + public static final char ELEMENT_SPACE = ' '; + + @Getter + private final List list = new ArrayList<>(); + private final Set allowedAttributes; + private boolean allowAnyAttribute = false; + + public boolean isAllowAnyAttribute() { + return allowAnyAttribute; + } + + public void setAllowAnyAttribute(boolean allowAnyAttribute) { + this.allowAnyAttribute = allowAnyAttribute; + } + + + public Attributes(Set allowedAttributes) { + + this.allowedAttributes = allowedAttributes; + } + + public void add(String name, String value) { + + list.add(new Attribute(name, value)); + } + + + public void add(Attribute attribute) { + if (allowedAttributes != null) { + String attributeName = attribute.getName(); + boolean attributeIsAllowed = XmlUtils.containsSetTheValue(allowedAttributes, attributeName) || allowAnyAttribute; + boolean attributeIsId = attributeName.equals("id"); + boolean attributeIsClass = attributeName.equals("class"); + if (!(attributeIsAllowed || attributeIsId || attributeIsClass)) { + throw new PowerException("Attribute " + attribute.getName() + " is not allowed. Only listed attributes are allowed: " + allowedAttributes.toString()); + } + } + + list.add(attribute); + } + + public void addAll(Attribute... attribute) { + + for (Attribute a : attribute) { + add(a); + } + } + + /** + * @param name + * @return removed attribute, if the attribute was found, otherwise null + */ + public Attribute remove(String name) { + if (this.list == null) { + return null; + } + Attribute attributeToBeRemoved = null; + for (Attribute a : this.list) { + if (a.getName().equals(name)) { + attributeToBeRemoved = a; + break; + } + } + if (attributeToBeRemoved != null) { + this.getList().remove(attributeToBeRemoved); + return attributeToBeRemoved; + } else { + return null; + } + + } + + public boolean has(String name) { + if (this.list == null) { + return false; + } + for (Attribute a : this.list) { + if (a.getName().equals(name)) { + + return true; + } + } + return false; + } + + public String get(String name) { + return getAsAttribute(name).getValue(); + + } + + public Attribute getAsAttribute(String name) { + + //System.out.println("seaching attribute " + name + " this.list size is " + this.list.size()); + for(int i = 0; i toList() { + List listToReturn = new ArrayList<>(); + for (Attribute a : this.list) { + listToReturn.add(a.copy()); + } + return listToReturn; + } + + @Override + public boolean isModified() { + return false; + } + + @Override + public String getCache() { + return null; + } + + public Attributes copy() { + Set set = this.allowedAttributes == null ? null : new HashSet<>(); + if (set != null) { + for (String e : this.allowedAttributes) { + set.add(e); + } + } + + Attributes as = new Attributes(this.allowedAttributes); + + List list2 = new ArrayList<>();//todo + for (Attribute a : this.list) { + as.add(a.copy()); + } + + return as; + } +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/Buildable.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Buildable.java new file mode 100644 index 0000000..89579b5 --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Buildable.java @@ -0,0 +1,39 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public interface Buildable { + public String build(); + + public boolean isModified(); + + public String getCache(); + + default boolean hasCache() { + return getCache() != null; + } +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/Constants.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Constants.java new file mode 100644 index 0000000..7c773c5 --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Constants.java @@ -0,0 +1,32 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +class Constants { + + static final char NEW_LINE = '\n'; +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/Element.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Element.java new file mode 100644 index 0000000..6efba6f --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Element.java @@ -0,0 +1,220 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import org.nanoboot.powerframework.core.PowerException; +import lombok.Getter; +import lombok.Setter; + +import java.util.Set; + +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Element implements XmlTypeI, Buildable { + public static final char TAG_START = '<'; + public static final char TAG_END = '>'; + public static final char ELEMENT_END = '/'; + public static final char ELEMENT_SPACE = ' '; + + @Getter + private final String elementName; + + @Getter + private final ElementType elementType; + + @Getter + @Setter + private Elements elements = new Elements(this, this.getAllowedElements()); + + @Getter + @Setter + private Attributes attributes = new Attributes(this.getAllowedAttributes()); + + /** + * @return null if all attributes are allowed + */ + public Set getAllowedAttributes() { + return null; + } + + /** + * @return null if all attributes are allowed + */ + public Set getAllowedElements() { + return null; + } + + + public Element(String elementName, String content) { + this(elementName); + this.getNoElement().setPlainText(content); + } + public Element(String elementName, XmlTypeI... xmlTypes) { + this(elementName); + add(xmlTypes); + } + + public Element(String elementName, ElementType elementType, XmlTypeI... xmlTypes) { + this(elementName, elementType); + add(xmlTypes); + + } + + public void add(XmlTypeI... xmlTypeIs) { + for (XmlTypeI e : xmlTypeIs) { + add(e); + } + } + public void add(XmlTypeI xmlTypeIs) { + boolean isElement = xmlTypeIs instanceof Element; + boolean isAttribute = xmlTypeIs instanceof Attribute; + if (isElement) { + Element var = (Element) xmlTypeIs; + this.getElements().add(var); + return; + } + if (isAttribute) { + Attribute var = (Attribute) xmlTypeIs; + this.getAttributes().add(var); + return; + } + throw new PowerException("It is not an XmlTypeI"); + + } + /** + * Creates new paired element + * + * @param elementName + */ + public Element(String elementName) { + this(elementName, ElementType.PAIRED); + } + + /** + * Creates new element with the specified type + * + * @param elementName + * @param elementType + */ + public Element(String elementName, ElementType elementType) { + this.elementName = elementName; + this.elementType = elementType; + } + + public Element getByElementName(String elementName) { + return elements.getByElementName(elementName); + } + + public boolean isPaired() { + return this.elementType == ElementType.PAIRED; + } + + public Element setInnerText(String text) { + this.getNoElement().setPlainText(text); + return this; + } + + public NoElement getNoElement() { + NoElement ne = null; + try { + ne = (NoElement) getByElementName(NoElement.NAME); + } catch (Exception e) { + + } + + if(ne==null){ + ne = new NoElement(); + this.add(ne); + } + return ne; + + } + + public String build() { + + StringBuilder sb = new StringBuilder(); + sb.append(TAG_START); + sb.append(elementName); + if (attributes != null) { + sb.append(attributes.build()); + } + + if (isPaired()) { + sb.append(TAG_END); + + sb.append(elements.build()); + +// sb.append(Constants.NEW_LINE); + sb.append(TAG_START); + sb.append(ELEMENT_END); + sb.append(elementName); + sb.append(TAG_END); + } + if (!isPaired()) { + sb.append(ELEMENT_SPACE); + sb.append(ELEMENT_END); + sb.append(TAG_END); + } + return sb.toString(); + } + + + @Override + public boolean isModified() { + return false; + } + + @Override + public String getCache() { + return null; + } + + public String toString() { + return build(); + } + + public XmlType getXmlType() { + return XmlType.ELEMENT; + } + + public final Element copy() { + Element e = new Element(this.elementName, this.elementType); + //TODO: elements and attributes should also call a copy method. + for (Element ee : this.elements.toList()) { + e.add(ee); + } + + for (Attribute aa : this.attributes.toList()) { + e.add(aa); + } + return e; + + } + + public Elements getElements() { + return elements; + } +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/ElementType.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/ElementType.java new file mode 100644 index 0000000..33c1cab --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/ElementType.java @@ -0,0 +1,31 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public enum ElementType { + PAIRED,NOT_PAIRED; +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/Elements.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Elements.java new file mode 100644 index 0000000..508dae3 --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/Elements.java @@ -0,0 +1,163 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import org.nanoboot.powerframework.core.PowerException; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ + +public class Elements implements Buildable { + + @Getter + private final List list = new ArrayList<>(); + + @Getter + private final Element parent; + + private final Set allowedElements; + private boolean allowAnyElement = false; + + public boolean isAllowAnyElement() { + return allowAnyElement; + } + + public void setAllowAnyElement(boolean allowAnyElement) { + this.allowAnyElement = allowAnyElement; + } + + public Elements(Element parent, Set allowedElements) { + this.parent = parent; + this.allowedElements = allowedElements; + } + + public Elements addInnerText(String innerText) { + this.add(new NoElement(innerText)); + return this; + } + + public Elements add(Element element) { + if (!this.parent.isPaired()) { + throw new PowerException("Only paired elements can have children"); + } + if (element == null) { + throw new RuntimeException("Element is null"); + } + + if (allowedElements != null) { + if (!allowAnyElement && !XmlUtils.containsSetTheValue(allowedElements, element.getElementName())) { + throw new PowerException("Element " + element.getElementName() + " is not allowed. Only listed elements are allowed: " + allowedElements.toString()); + } + + + } + this.list.add(element); + return this; + } + + public Elements addAll(Element... elements) { + for (Element element : elements) { + + add(element); + } + return this; + } + + public void removeAll() { + this.list.clear(); + } + + + public List toList() { + List listToReturn = new ArrayList<>(); + for (Element e : this.list) { + listToReturn.add(e.copy()); + } + return listToReturn; + } + + public String build() { + if (this.list.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (Element element : this.list) { + if (element == null) { + throw new RuntimeException("Element is null"); + } + sb.append(Constants.NEW_LINE); + sb.append(element.build()); + } + return sb.toString(); + } + + public Element getByElementName(String... a) { + + for (Element e : this.list) { + if (e.getElementName().equals(a[0])) { + if(a.length==1) { + return e; + }else{ + getByElementName(removeFirstField(a)); + } + + } + } + return null; + } + + public String[] removeFirstField(String[] ar){ + String[] a=new String[ar.length-1]; + for(int i=1;i loadElements(){ + List list=new ArrayList<>(); + for(Element e:this.list){ + list.addAll(e.getElements().loadElements()); + } + + return list; + } + +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/NoElement.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/NoElement.java new file mode 100644 index 0000000..5d091dc --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/NoElement.java @@ -0,0 +1,50 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import lombok.Getter; +import lombok.Setter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class NoElement extends Element { + public static final String NAME = "noelement"; + + @Getter + @Setter + private String plainText; + public NoElement(){super(NAME); + } + public NoElement(String plainText){ + this(); + this.plainText=plainText; + } + public String build(){ + return this.getPlainText(); + } + public void add(XmlTypeI xmltypes) { + throw new RuntimeException("NoElement cannot have children"); + } + +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlComment.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlComment.java new file mode 100644 index 0000000..43ec65a --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlComment.java @@ -0,0 +1,47 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import lombok.Getter; +import lombok.Setter; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class XmlComment extends Element { + public static final String NAME = "comment"; + + @Getter + @Setter + private String plainText; + public XmlComment(){super(NAME); + } + public XmlComment(String plainText){ + this(); + this.plainText=plainText; + } + public String build(){ + return ""; + } + +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlType.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlType.java new file mode 100644 index 0000000..21b8481 --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlType.java @@ -0,0 +1,30 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public enum XmlType { + ELEMENT,ATTRIBUTE; +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlTypeI.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlTypeI.java new file mode 100644 index 0000000..7188e53 --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlTypeI.java @@ -0,0 +1,30 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public interface XmlTypeI { + public XmlType getXmlType(); +} diff --git a/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlUtils.java b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlUtils.java new file mode 100644 index 0000000..9bd6c0a --- /dev/null +++ b/power-xml/src/main/java/org/nanoboot/powerframework/xml/XmlUtils.java @@ -0,0 +1,52 @@ + +/////////////////////////////////////////////////////////////////////////////////////////////// +// power-framework: Java library with many purposes of usage. +// Copyright (C) 2016-2022 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License only. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.nanoboot.powerframework.xml; + +import java.util.HashSet; +import java.util.Set; +/** + * + * + * @author Robert Vokac + * @since 0.0.0 + */ +public class XmlUtils { + private XmlUtils(){ + //instantiation not needed + } + + public static Set createNewSet(String... a){ + Set set=new HashSet<>(); + for(String e:a){ + set.add(e); + } + return set; + } + public static boolean containsSetTheValue(Set set,String string){ + for(String e:set){ + //System.err.println(e); + if(e.equals(string)){ + return true; + } + } + return false; + } +} diff --git a/power-xml/src/main/resources/.gitkeep b/power-xml/src/main/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/power-xml/src/test/java/org/nanoboot/powerframework/xml/.gitkeep b/power-xml/src/test/java/org/nanoboot/powerframework/xml/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/org/nanoboot/powerframework/collections/Dictionary.java b/src/main/java/org/nanoboot/powerframework/collections/Dictionary.java deleted file mode 100644 index 561a2c0..0000000 --- a/src/main/java/org/nanoboot/powerframework/collections/Dictionary.java +++ /dev/null @@ -1,214 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Represents dictionary data structure. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - * @param - */ -public class Dictionary { - - private int countOfItems = 0; - - private DictionaryNode currentNode = null; - private DictionaryNode stopNode = null; - - private DictionaryNode firstNode = null; - private DictionaryNode lastNode = null; - - private DictionaryNode tempNode = null; - private DictionaryNode previousTempNode = null; - - /** - * - * @return size of this dictionary - */ - public int getCountOfItems() { - return countOfItems; - } - - /** - * - * @return result of this control - */ - public boolean isEmpty() { - return getCountOfItems() == 0; - } - - /** - * - * @param key - * @return result of this control - */ - public boolean containsValueWithKey(String key) { - DictionaryKeyIterator dictionaryKeyIterator = this.getKeyIterator(); - boolean result = false; - while (dictionaryKeyIterator.hasNext()) { - if (dictionaryKeyIterator.getNextKey().equals(key)) { - result = true; - } - } - - return result; - } - - /** - * Add new dictionary entry. - * - * @param key - * @param value - * @return - */ - public Dictionary addValue(String key, T value) { - - DictionaryNode nodeToAdd = new DictionaryNode<>(key, value); - tempNode = lastNode; - lastNode = nodeToAdd; - if (isEmpty()) { - firstNode = nodeToAdd; - } else { - tempNode.setNext(lastNode); - } - countOfItems++; - return this; - } - - /** - * Return a dictionary entry with the given key. - * - * @param key - * @return - */ - public T getValue(String key) { - moveCurrentNodeToTheNodeWithTheKey(key); - - return currentNode.getElement(); - - } - - private void moveCurrentNodeToTheNodeWithTheKey(String key) { - stopNode = stopNode == null ? firstNode : stopNode; - currentNode = stopNode; - - while (!currentNodeIsAtTheEnd(key)) { - - if (currentNode.getNext() == null) { - currentNode = firstNode; - } else { - currentNode = currentNode.getNext(); - } - } - this.stopNode = currentNode; - - if (!currentNodeHasTheKey(key)) { - throw new PowerRuntimeException("There is no element with key: " + key); - } - } - - private boolean currentNodeIsAtTheEnd(String key) { - return (currentNodeHasTheKey(key)) || (currentNodeIsBeforeStopNode()); - } - - private boolean currentNodeHasTheKey(String key) { - return currentNode.getKey().equals(key); - } - - private boolean currentNodeIsBeforeStopNode() { - if ((currentNode == lastNode) && (stopNode == firstNode)) { - return true; - } - return currentNode.getNext() == stopNode; - } - - /** - * Updates the dictionary entry with the given key to the given value. - * - * @param key - * @param value - */ - public void updateValue(String key, T value) { - moveCurrentNodeToTheNodeWithTheKey(key); - currentNode.setElement(value); - } - - /** - * Removes the dictionary entry with the given key. - * - * @param key - * @return dictionary - */ - public Dictionary removeValue(String key) { - if (isEmpty()) { - throw new PowerRuntimeException("This dictionary is empty. No dictionary entry can be removed."); - } - tempNode = firstNode; - while ((!(tempNode.getKey().equals(key))) && (tempNode.getNext() != null)) { - this.previousTempNode = tempNode; - tempNode = tempNode.getNext(); - } - if (!(tempNode.getKey().equals(key))) { - throw new PowerRuntimeException("There is no key: " + key); - } else if (tempNode == firstNode) { - firstNode = firstNode.getNext(); - } else if (tempNode == lastNode) { - lastNode = previousTempNode; - lastNode.setNext(null); - } else { - this.previousTempNode.setNext(tempNode.getNext()); - } - countOfItems--; - return this; - } - - /** - * - * @return KeyIterator for this dictionary - */ - public DictionaryKeyIterator getKeyIterator() { - return new DictionaryKeyIterator(firstNode); - } - - @Override - public String toString() { - StringBuilder stringBuilder = new StringBuilder(); - DictionaryKeyIterator dictionaryKeyIterator = this.getKeyIterator(); - String key; - T value; - String valueAsString; - final char colon = ':'; - final String newLine = "\n"; - - while (dictionaryKeyIterator.hasNext()) { - key = dictionaryKeyIterator.getNextKey(); - value = this.getValue(key); - valueAsString = value.toString(); - stringBuilder.append(key); - stringBuilder.append(colon); - stringBuilder.append(valueAsString); - stringBuilder.append(newLine); - } - return stringBuilder.toString(); - } -} diff --git a/src/main/java/org/nanoboot/powerframework/collections/DictionaryKeyIterator.java b/src/main/java/org/nanoboot/powerframework/collections/DictionaryKeyIterator.java deleted file mode 100644 index 3db1ac3..0000000 --- a/src/main/java/org/nanoboot/powerframework/collections/DictionaryKeyIterator.java +++ /dev/null @@ -1,87 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Is used to iterate entries through dictionary. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class DictionaryKeyIterator { - - private final DictionaryNode firstNode; - private DictionaryNode currentNode; - private boolean currentNodeIsNotFirst = false; - - DictionaryKeyIterator(DictionaryNode value) { - this.firstNode = value; - this.reset(); - } - - /** - * - * @return next key - */ - public String getNextKey() { - String key; - if (firstNode == null) { - throw new PowerRuntimeException("Dictionary is empty. There is no key."); - } - if ((currentNode == firstNode) && (!this.currentNodeIsNotFirst)) { - key = currentNode.getKey(); - this.currentNodeIsNotFirst = true; - } else { - if (!hasNext()) { - throw new PowerRuntimeException("There is no next key."); - } - this.currentNode = this.currentNode.getNext(); - key = currentNode.getKey(); - } - return key; - } - - /** - * - * @return true if there is a next key, otherwise false - */ - public boolean hasNext() { - if (this.firstNode == null) { - return false; - } - if ((firstNode.getNext() == null) && (!currentNodeIsNotFirst)) { - return true; - } - if ((firstNode.getNext() == null) && (currentNodeIsNotFirst)) { - return false; - } - return this.currentNode.getNext() != null; - } - - /** - * Moves the current key to the first. - */ - public void reset() { - this.currentNode = this.firstNode; - currentNodeIsNotFirst = false; - } -} diff --git a/src/main/java/org/nanoboot/powerframework/collections/Queue.java b/src/main/java/org/nanoboot/powerframework/collections/Queue.java deleted file mode 100644 index 4d0de9f..0000000 --- a/src/main/java/org/nanoboot/powerframework/collections/Queue.java +++ /dev/null @@ -1,107 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Represents Queue- linear data structure. - * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org - * @param object - */ -public class Queue { - - private int total; - - private Node first; - private Node last; - - private class Node { - - private T element; - private Node next; - } - - /** - * - * @return size of this queue - */ - public int getCountOfItems() { - return this.total; - } - - /** - * - * @return true if this queue is empty, otherwise false - */ - public boolean isEmpty() { - return this.getCountOfItems() == 0; - } - - /** - * Enqueues new element. - * - * @param element - * @return new element - */ - public Queue enqueue(T element) { - Node current = last; - last = new Node(); - last.element = element; - - if (total++ == 0) { - first = last; - } else { - current.next = last; - } - - return this; - } - - /** - * Dequeues element. - * - * @return removed element - */ - public T dequeue() { - if (total == 0) { - throw new PowerRuntimeException("No such element"); - } - T ele = first.element; - first = first.next; - if (--total == 0) { - last = null; - } - return ele; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - Node tmp = first; - while (tmp != null) { - sb.append(tmp.element).append(", "); - tmp = tmp.next; - } - return sb.toString(); - } -} diff --git a/src/main/java/org/nanoboot/powerframework/collections/Stack.java b/src/main/java/org/nanoboot/powerframework/collections/Stack.java deleted file mode 100644 index bdfce77..0000000 --- a/src/main/java/org/nanoboot/powerframework/collections/Stack.java +++ /dev/null @@ -1,141 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import java.util.Iterator; -import java.util.NoSuchElementException; -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Represents Stack- linear data structure. - * - * @author Robert Vokac robertvokac@nanoboot.orgt Vokáč robertvokac@nanoboot.org - * @param object - */ -public class Stack implements Iterable { - - private int total = 0; - - private Node first; - - @Override - public Iterator iterator() { - return new StackIterator(); - } - - private class Node { - - private T element; - private Node next; - } - - private class StackIterator implements Iterator { - - @Override - public boolean hasNext() { - return !isEmpty(); - } - - @Override - public T next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - return pop(); - } - } - - /** - * - * @return size of this stack - */ - public int getCountOfItems() { - return this.total; - } - - /** - * - * @return true if this stack is empty, otherwise false - */ - public boolean isEmpty() { - return this.getCountOfItems() == 0; - } - - /** - * Pushes new element. - * - * @param element - * @return pushed element - */ - public Stack push(T element) { - Node current = first; - first = new Node(); - first.element = element; - first.next = current; - total++; - return this; - } - - /** - * Pops element. - * - * @return popped element - */ - public T pop() { - if (first == null) { - throw new PowerRuntimeException("No such element"); - } - T element = first.element; - first = first.next; - total--; - return element; - } - - /** - * - * @return the top element of this stack without removing this element - */ - public T peek() { - if (first == null) { - throw new PowerRuntimeException("No such element"); - } - return first.element; - } -/** - * Deletes all items of this stack. - */ - public void clear() { - total = 0; - first = null; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - Node tmp = first; - while (tmp != null) { - sb.append(tmp.element).append(", "); - tmp = tmp.next; - } - return sb.toString(); - } - -} diff --git a/src/main/java/org/nanoboot/powerframework/database/DatabaseConnection.java b/src/main/java/org/nanoboot/powerframework/database/DatabaseConnection.java deleted file mode 100644 index f67e4bc..0000000 --- a/src/main/java/org/nanoboot/powerframework/database/DatabaseConnection.java +++ /dev/null @@ -1,351 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.database; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.json.*; - -/** - * Represents connection to a database. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class DatabaseConnection { - - private Connection connection = null; - private Statement statement = null; - private final String databaseName; - - private final String jdbcUrl; - - DatabaseConnection(String databaseName) { - this.databaseName = databaseName; - StringBuilder stringBuilder = new StringBuilder().append("jdbc:sqlite:"); - if (databaseName != "") { - stringBuilder.append(databaseName).append(".sqlite").toString(); - } - this.jdbcUrl = stringBuilder.toString(); - } - - /** - * - * @return name of the database of this database connection - */ - public String getDatabaseName() { - return databaseName; - } - - private void setConnection() { - try { - Class.forName("org.sqlite.JDBC"); - connection = DriverManager.getConnection(jdbcUrl); - statement = connection.createStatement(); - statement.execute("PRAGMA foreign_keys = ON;"); - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - } - } - - /** - * Executes sql command, which returns no result. - * - * @param command - * @return last inserted row id - */ - public int execute(String command) { - int lastInsertedRowId = 0; - setConnection(); - ResultSet resultSet = null; - try { - statement.executeUpdate(command); - resultSet = statement.executeQuery("SELECT last_insert_rowid() AS LASTINSERTEDROWID;"); - resultSet.next(); - lastInsertedRowId = resultSet.getInt(1); - resultSet.close(); - connection.close(); - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - } finally { - if (resultSet != null) { - try { - resultSet.close(); - } catch (SQLException ex) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, ex); - } - } - - } - return lastInsertedRowId; - } - - /** - * Executes sql commands from the command queue. - * - * @param commandQueue - */ - public void executeMoreCommands(SqlCommandQueue commandQueue) { - setConnection(); - - try { - connection.setAutoCommit(false); - while (commandQueue.isThereANextCommand()) { - String command = commandQueue.loadNextCommand(); - statement.executeUpdate(command); - - } - - //No changes has been made in the database yet, so now we will commit - //the changes. - connection.commit(); - } catch (SQLException ex) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, ex); - try { - //An error occured so we rollback the changes. - connection.rollback(); - } catch (SQLException ex1) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, ex1); - throw new PowerRuntimeException("Fatal error happened. I was not able to rollback"); - } - } finally { - try { - if (statement != null) { - statement.close(); - connection.close(); - } - } catch (SQLException ex) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, ex); - } - } - } - - /** - * Executes sql commands from the given String, which is split by ; - * character. - * - * @param commands - */ - public void executeMoreCommands(String commands) { - SqlCommandQueue commandQueue = new SqlCommandQueue(); - String[] commandsArray = commands.split(";"); - for (String part : commandsArray) { - commandQueue.add(part); - } - this.executeMoreCommands(commandQueue); - } - - /** - * Executes sql command, which returns result. - * - * @param command - * @return - */ - public ResultOfSqlQuery executeAndReturn(String command) { - JsonObject table = new JsonObject(); - - JsonArray columns = new JsonArray(); - JsonArray rows = new JsonArray(); - - table.addString("query", command); - table.addArray("columns", columns); - table.addArray("rows", rows); - - setConnection(); - ResultSet resultSet = null; - try { - resultSet = statement.executeQuery(command); - - ResultSetMetaData rsmd = resultSet.getMetaData(); - int columnCount = rsmd.getColumnCount(); - for (int i = 1; i <= columnCount; i++) { - String columnName = rsmd.getColumnName(i); - columns.addString(columnName); - } - - while (resultSet.next()) { - JsonArray row = new JsonArray(); - for (int i = 0; i < columns.getCountOfItems(); i++) { - String columnName = columns.getString(i); - String value = resultSet.getString(columnName); - row.addString(value); - } - rows.addArray(row); - } - - connection.close(); - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - } finally { - closeConnectionAndResultSet(resultSet); - } - return new ResultOfSqlQuery(table); - } - - private void closeConnectionAndResultSet(ResultSet resultSet) { - try { - if (resultSet != null) { - resultSet.close(); - } - if (!connection.isClosed()) { - connection.close(); - } - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - } - } - - /** - * Updates value. - * - * @param tableName - * @param id - * @param columnName - * @param newValue - */ - public void updateValue(String tableName, int id, String columnName, String newValue) { - String string - = "UPDATE " + tableName + " SET " + columnName + " = '" + newValue + "' WHERE ID = " + id; - this.execute(string); - } - - /** - * Updates value. - * - * @param tableName - * @param id - * @param columnName - * @param newValue - */ - public void updateValue(String tableName, int id, String columnName, int newValue) { - String string - = "UPDATE " + tableName + " SET " + columnName + " = " + newValue + " WHERE ID = " + id; - this.execute(string); - } - - /** - * - * @param tableName - * @param id - * @return row with the given id from the given table as a json object - */ - public JsonObject getRow(String tableName, int id) { - JsonObject row = new JsonObject(); - - JsonArray columns = new JsonArray(); - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("select * from "); - stringBuilder.append(tableName); - stringBuilder.append(" where id="); - stringBuilder.append(id); - - String command = stringBuilder.toString(); - - setConnection(); - ResultSet resultSet = null; - try { - resultSet = statement.executeQuery(command); - - ResultSetMetaData rsmd = resultSet.getMetaData(); - int columnCount = rsmd.getColumnCount(); - for (int i = 1; i <= columnCount; i++) { - String columnName = rsmd.getColumnName(i); - columns.addString(columnName); - } - - if (!resultSet.next()) { - throw new PowerRuntimeException("There is no row with id " + id + " in table " + tableName); - } - - for (int i = 0; i < columns.getCountOfItems(); i++) { - String columnName = columns.getString(i); - String value = resultSet.getString(columnName); - row.addString(columnName, value); - } - - connection.close(); - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - throw new IllegalStateException(); - } finally { - - try { - if (resultSet != null) { - resultSet.close(); - } - if (!connection.isClosed()) { - connection.close(); - } - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - } - } - return row; - } - - /** - * - * @param tableName - * @return true, if the table is empty, otherwise false. - */ - public boolean isTableEmpty(String tableName) { - ResultOfSqlQuery resultOfSqlQuery = this.executeAndReturn("SELECT * FROM " + tableName); - return resultOfSqlQuery.isEmpty(); - } - - /** - * - * @param table table name - * @param column column name - * @param whereClause for example: year_of_birth>1995 - * @return String value from a table and first row - */ - public String getString(String table, String column, String whereClause) { - String command = "SELECT " + column + " FROM " + table + " WHERE " + whereClause; - String value = null; - - setConnection(); - ResultSet resultSet = null; - try { - resultSet = statement.executeQuery(command); - - if (resultSet.next()) { - value = resultSet.getString(column); - } - connection.close(); - } catch (Exception e) { - Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e); - } finally { - - closeConnectionAndResultSet(resultSet); - - } - - return value; - } -} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/DateTime.java b/src/main/java/org/nanoboot/powerframework/datetime/DateTime.java deleted file mode 100644 index 7f8fdff..0000000 --- a/src/main/java/org/nanoboot/powerframework/datetime/DateTime.java +++ /dev/null @@ -1,189 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import java.text.SimpleDateFormat; - -/** - * This class represents date and time and is immutable. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public abstract class DateTime { - - /** - * - */ - protected static class SimpleDateTimeFormatByTimeZone extends SimpleDateFormat { - - /** - * - * @param timeZone - * @param formatText - */ - protected SimpleDateTimeFormatByTimeZone(TimeZone timeZone, String formatText) { - super(formatText); - setTimeZone(java.util.TimeZone.getTimeZone(timeZone.toString())); - } - } - - private final LocalDate date; - private final LocalTime time; - - /** - * Constructor - * - * Sets all values. - * - * @param localDate Represents a date. - * @param localTime Represents a time. - */ - DateTime(LocalDate localDate, LocalTime localTime) { - this.date = localDate; - this.time = localTime; - } - - /** - * Constructor - * - * Sets all values. - * - * @param year Represents a year. - * @param month Represents a month. - * @param day Represents a day. - * @param hour24Format Represents an hour. - * @param minute Represents a minute - * @param second Represents a second. - * @param millisecond Represents a millisecond. - */ - DateTime(int year, int month, int day, int hour24Format, int minute, int second, int millisecond) { - this.date = new LocalDate(year, month, day); - this.time = new LocalTime(hour24Format, minute, second, millisecond); - } - - /** - * Constructor - * - * Sets all values from another object. - * - * @param dateTime - */ - protected DateTime(DateTime dateTime) { - int year = dateTime.getYear(); - int month = dateTime.getMonth(); - int day = dateTime.getDay(); - date = new LocalDate(year, month, day); - - int hour24Format = dateTime.getHour(); - int minute = dateTime.getMinute(); - int second = dateTime.getSecond(); - int millisecond = dateTime.getMillisecond(); - time = new LocalTime(hour24Format, minute, second, millisecond); - } - - /** - * Constructor - * - * Sets all values from String - * - * @param dateTimeInString This String has following format: 2016-12-31 - * 24:45:14:453 yyyy-MM-dd HH:mm:ss:SSS - */ - public DateTime(String dateTimeInString) { - int year = Integer.parseInt(dateTimeInString.substring(0, 4)); - int month = Integer.parseInt(dateTimeInString.substring(5, 7)); - int day = Integer.parseInt(dateTimeInString.substring(8, 10)); - date = new LocalDate(year, month, day); - - int hour = Integer.parseInt(dateTimeInString.substring(11, 13)); - int minute = Integer.parseInt(dateTimeInString.substring(14, 16)); - int second = Integer.parseInt(dateTimeInString.substring(17, 19)); - int millisecond = Integer.parseInt(dateTimeInString.substring(20, 23)); - time = new LocalTime(hour, minute, second, millisecond); - } - - /** - * - * @return year - */ - public int getYear() { - return this.date.getYear(); - } - - /** - * - * @return month - */ - public int getMonth() { - return this.date.getMonth(); - } - - /** - * - * @return day - */ - public int getDay() { - return this.date.getDay(); - } - - /** - * - * @return hour - */ - public int getHour() { - return this.time.getHour(); - } - - /** - * - * @return minute - */ - public int getMinute() { - return this.time.getMinute(); - } - - /** - * - * @return second - */ - public int getSecond() { - return this.time.getSecond(); - } - - /** - * - * @return millisecond - */ - public int getMillisecond() { - return this.time.getMillisecond(); - } - - @Override - public String toString() { - StringBuilder stringBuffer = new StringBuilder(); - stringBuffer.append(this.date.toString()); - stringBuffer.append(" "); - stringBuffer.append(this.time.toString()); - - return stringBuffer.toString(); - } - -} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/Duration.java b/src/main/java/org/nanoboot/powerframework/datetime/Duration.java deleted file mode 100644 index 4d3e0a6..0000000 --- a/src/main/java/org/nanoboot/powerframework/datetime/Duration.java +++ /dev/null @@ -1,626 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.pseudorandom.PseudoRandomGenerator; - -/** - * Is used to do arithmetics with Date and Time. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class Duration { - - private static final int MILLISECONDSPERSECOND = 1000; - private static final int SECONDSPERMINUTE = 60; - private static final int MILLISECONDSPERMINUTE = MILLISECONDSPERSECOND * SECONDSPERMINUTE; - private static final int MINUTESPERHOUR = 60; - private static final int MILLISECONDSPERHOUR = MILLISECONDSPERMINUTE * MINUTESPERHOUR; - private static final int HOURSPERDAY = 24; - private static final int MILLISECONDSPERDAY = MILLISECONDSPERHOUR * HOURSPERDAY; - private static final String PLUS = "+"; - private static final String MINUS = "-"; - private static final String COLON = ":"; - - private final long countOfTotalMilliseconds; - private final int days; - private final int hours; - private final int minutes; - private final int seconds; - private final int milliseconds; - private final boolean positive; - - /** - * Constructor - * - * Creates new Duration from count of milliseconds. - * - * @param countOfMilliseconds - */ - public Duration(long countOfMilliseconds) { - if (countOfMilliseconds >= 0) { - positive = true; - } else { - positive = false; - } - this.countOfTotalMilliseconds = Math.abs(countOfMilliseconds); - - this.days = (int) Math.floor(this.toTotalDays()); - this.hours = (int) Math.floor(this.toTotalHours()) - (days * HOURSPERDAY); - this.minutes = (int) Math.floor(this.toTotalMinutes()) - (days * HOURSPERDAY * MINUTESPERHOUR) - (hours * MINUTESPERHOUR); - this.seconds = (int) Math.floor(this.toTotalSeconds()) - (days * HOURSPERDAY * MINUTESPERHOUR * SECONDSPERMINUTE) - (hours * MINUTESPERHOUR * SECONDSPERMINUTE) - (minutes * SECONDSPERMINUTE); - this.milliseconds = (int) this.toTotalMilliseconds() - (days * HOURSPERDAY * MINUTESPERHOUR * SECONDSPERMINUTE * MILLISECONDSPERSECOND) - (hours * MINUTESPERHOUR * SECONDSPERMINUTE * MILLISECONDSPERSECOND) - (minutes * SECONDSPERMINUTE * MILLISECONDSPERSECOND) - (seconds * MILLISECONDSPERSECOND); - - } - - /** - * Constructor - * - * Creates new Duration from the given values. - * - * @param days - * @param hours - * @param minutes - * @param seconds - * @param milliseconds - */ - public Duration(long days, int hours, int minutes, int seconds, int milliseconds) { - this( - true, days, hours, minutes, seconds, milliseconds - ); - } - - /** - * Constructor - * - * Creates new Duration from the given values. - * - * @param positive - * @param days - * @param hours - * @param minutes - * @param seconds - * @param milliseconds - */ - public Duration(boolean positive, long days, int hours, int minutes, int seconds, int milliseconds) { - this( - (positive ? 1 : (-1)) - * (convertDaysToMilliseconds(days) - + convertHoursToMilliseconds(hours) - + convertMinutesToMilliseconds(minutes) - + convertSecondsToMilliseconds(seconds) - + milliseconds) - ); - TimeUnitsValidator.checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException(hours, minutes, seconds, milliseconds); - } - - /** - * Constructor - * - * Creates new Duration from the String. - * - * @param string - */ - public Duration(String string) { - String[] splitString = string.split("\\:+"); - if (splitString.length != 5) { - throw new PowerRuntimeException("Input String has wrong format."); - } - try { - this.days = Integer.parseInt(splitString[0]); - this.hours = Integer.parseInt(splitString[1]); - this.minutes = Integer.parseInt(splitString[2]); - this.seconds = Integer.parseInt(splitString[3]); - this.milliseconds = Integer.parseInt(splitString[4]); - this.countOfTotalMilliseconds = convertDaysToMilliseconds(days) - + convertHoursToMilliseconds(hours) - + convertMinutesToMilliseconds(minutes) - + convertSecondsToMilliseconds(seconds) - + milliseconds; - this.positive = string.charAt(0) == '+'; - } catch (Exception e) {//NOSONAR - throw new PowerRuntimeException("Input String has wrong format."); - } - TimeUnitsValidator.checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException(hours, minutes, seconds, milliseconds); - } - - /** - * - * @return random duration - */ - public static Duration createRandomDuration() { - Duration duration; - PseudoRandomGenerator pseudoRandomNumberGenerator = PseudoRandomGenerator.getInstance(); - long days = pseudoRandomNumberGenerator.getInt(0, 6000); - int hours = pseudoRandomNumberGenerator.getInt(0, 23); - int minutes = pseudoRandomNumberGenerator.getInt(0, 59); - int seconds = pseudoRandomNumberGenerator.getInt(0, 59); - int milliseconds = pseudoRandomNumberGenerator.getInt(0, 999); - duration = new Duration(days, hours, minutes, seconds, milliseconds); - return duration; - } - - /** - * Creates new Duration from startUniversalDateTime minus - * endUniversalDateTime. - * - * @param startUniversalDateTime - * @param endUniversalDateTime - * @return new instance of Duration - */ - public static Duration between(UniversalDateTime startUniversalDateTime, UniversalDateTime endUniversalDateTime) { - java.time.LocalDateTime javaStartLocalDateTime = startUniversalDateTime.toLocalDateTime().toJavaLocalDateTime(); - java.time.LocalDateTime javaEndLocalDateTime = endUniversalDateTime.toLocalDateTime().toJavaLocalDateTime(); - java.time.Duration javaDuration = java.time.Duration.between(javaStartLocalDateTime, javaEndLocalDateTime); - return new Duration(javaDuration.toMillis()); - - } - - /** - * Creates new Duration from startZonedDateTime minus endZonedDateTime. - * - * @param startZonedDateTime - * @param endZonedDateTime - * @return new instance of Duration - */ - public static Duration between(ZonedDateTime startZonedDateTime, ZonedDateTime endZonedDateTime) { - return between(startZonedDateTime.toUniversalDateTime(), endZonedDateTime.toUniversalDateTime()); - } - - private static int getMillisecondsPerDay() { - return MILLISECONDSPERDAY; - } - - private static long convertDaysToMilliseconds(long days) { - return days * getMillisecondsPerDay(); - } - - /** - * - * @param days - * @return an instance of Duration class with the given count of days - */ - public static Duration ofDays(long days) { - return new Duration(convertDaysToMilliseconds(days)); - } - - private static int getMillisecondsPerHour() { - return MILLISECONDSPERHOUR; - } - - private static long convertHoursToMilliseconds(long hours) { - return hours * getMillisecondsPerHour(); - } - - /** - * - * @param hours - * @return an instance of Duration class with the given count of hours - */ - public static Duration ofHours(long hours) { - return new Duration(convertHoursToMilliseconds(hours)); - } - - private static int getMillisecondsPerMinute() { - return MILLISECONDSPERMINUTE; - } - - private static long convertMinutesToMilliseconds(long minutes) { - return minutes * getMillisecondsPerMinute(); - } - - /** - * - * @param minutes - * @return an instance of Duration class with the given count of minutes - */ - public static Duration ofMinutes(long minutes) { - return new Duration(convertMinutesToMilliseconds(minutes)); - } - - private static int getMillisecondsPerSecond() { - return MILLISECONDSPERSECOND; - } - - private static long convertSecondsToMilliseconds(long seconds) { - return seconds * getMillisecondsPerSecond(); - } - - /** - * - * @param seconds - * @return an instance of Duration class with the given count of seconds - */ - public static Duration ofSeconds(long seconds) { - return new Duration(convertSecondsToMilliseconds(seconds)); - } - - /** - * - * @param milliseconds - * @return an instance of Duration class with the given count of - * milliseconds - */ - public static Duration ofMilliseconds(long milliseconds) { - return new Duration(milliseconds); - } - - /** - * - * @param universalDateTime - * @param duration - * @return add to universalDateTime duration and return result - */ - public static UniversalDateTime fromUniversalDateTimePlusDurationCreateNewUniversalDateTime(UniversalDateTime universalDateTime, Duration duration) { - return addToUniversalDateTimeDuration(universalDateTime, duration, true); - } - - /** - * - * @param universalDateTime - * @param duration - * @return subtract from universalDateTime duration and return result - */ - public static UniversalDateTime fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime(UniversalDateTime universalDateTime, Duration duration) { - return addToUniversalDateTimeDuration(universalDateTime, duration, false); - } - - private static UniversalDateTime addToUniversalDateTimeDuration(UniversalDateTime universalDateTime, Duration duration, boolean trueForAddingFalseForSubtracting) { - java.time.LocalDateTime javaLocalDateTime = universalDateTime.toLocalDateTime().toJavaLocalDateTime(); - java.time.Duration javaDuration = duration.toJavaDuration(); - java.time.LocalDateTime newJavaLocalDateTime; - if (trueForAddingFalseForSubtracting) { - newJavaLocalDateTime = javaLocalDateTime.plus(javaDuration); - } else { - newJavaLocalDateTime = javaLocalDateTime.minus(javaDuration); - } - - int year = newJavaLocalDateTime.getYear(); - int day = newJavaLocalDateTime.getDayOfMonth(); - int month = newJavaLocalDateTime.getMonth().getValue(); - int hour = newJavaLocalDateTime.getHour(); - int minute = newJavaLocalDateTime.getMinute(); - int second = newJavaLocalDateTime.getSecond(); - final int nanosecondspermillisecond; - nanosecondspermillisecond = 1000000; - int millisecond = newJavaLocalDateTime.getNano() / nanosecondspermillisecond; - - return new UniversalDateTime(year, month, day, hour, minute, second, millisecond); - } - - /** - * - * @param zonedDateTime - * @param duration - * @return add to zonedDateTime duration and return result - */ - public static ZonedDateTime fromZonedDateTimePlusDurationCreateNewZonedDateTime(ZonedDateTime zonedDateTime, Duration duration) { - return addToZonedDateTimeDuration(zonedDateTime, duration, true); - } - - /** - * - * @param zonedDateTime - * @param duration - * @return subtract from zonedDateTime duration and return result - */ - public static ZonedDateTime fromZonedDateTimeMinusDurationCreateNewZonedDateTime(ZonedDateTime zonedDateTime, Duration duration) { - return addToZonedDateTimeDuration(zonedDateTime, duration, false); - } - - private static ZonedDateTime addToZonedDateTimeDuration(ZonedDateTime zonedDateTime, Duration duration, boolean trueForAddingFalseForSubtracting) { - UniversalDateTime universalDateTime = zonedDateTime.toUniversalDateTime(); - UniversalDateTime newUniversalDateTime; - if (trueForAddingFalseForSubtracting) { - newUniversalDateTime = fromUniversalDateTimePlusDurationCreateNewUniversalDateTime(universalDateTime, duration); - } else { - newUniversalDateTime = fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime(universalDateTime, duration); - } - - return new ZonedDateTime(newUniversalDateTime).toZonedDateTime(zonedDateTime.getTimeZone()); - } - - /** - * - * @return count of days - * - *

    Example
    - *
    - * Duration duration=new Duration(6,19,46,12,754);
    - * long days=duration.getDays();
    - *
    - * days is 6 - */ - public long getDays() { - return days; - } - - /** - * - * @return count of hours - * - *

    Example
    - *
    - * Duration duration=new Duration(6,19,46,12,754);
    - * long hours=duration.getHours();
    - *
    - * hours is 19 - */ - public int getHours() { - return hours; - } - - /** - * - * @return count of minutes - * - *

    Example
    - *
    - * Duration duration=new Duration(6,19,46,12,754);
    - * long minutes=duration.getMinutes();
    - *
    - * minutes is 46 - */ - public int getMinutes() { - return minutes; - } - - /** - * - * @return count of seconds - * - *

    Example
    - *
    - * Duration duration=new Duration(6,19,46,12,754);
    - * long seconds=duration.getSeconds();
    - *
    - * seconds is 12 - */ - public int getSeconds() { - return seconds; - } - - /** - * - * @return count of milliseconds - * - *

    Example
    - *
    - * Duration duration=new Duration(6,19,46,12,754);
    - * long milliseconds=duration.Milliseconds();
    - *
    - * milliseconds is 754 - */ - public int getMilliseconds() { - return milliseconds; - } - - /** - * - * @return result of this control - */ - public boolean isPositive() { - return this.positive; - } - - /** - * - * @return new Duration instance created from negated this object - */ - public Duration negated() { - return new Duration(this.toTotalMilliseconds() * (-1)); - } - - /** - * - * @return new Duration instance created from this object, if this object is - * negative, returned Duration is not negative - */ - public Duration abs() { - long absCountOfTotalMilliseconds; - absCountOfTotalMilliseconds = this.countOfTotalMilliseconds >= 0 ? countOfTotalMilliseconds : (countOfTotalMilliseconds * (-1)); - return new Duration(absCountOfTotalMilliseconds); - } - - /** - * - * @param durationToAdd - * @return from this object plus the given durationToAdd new Duration - */ - public Duration plusDuration(Duration durationToAdd) { - return new Duration(this.toTotalMilliseconds() + durationToAdd.toTotalMilliseconds()); - } - - /** - * - * @param daysToAdd - * @return from this object plus the given daysToAdd new Duration - */ - public Duration plusDays(long daysToAdd) { - return this.plusMilliseconds(Duration.convertDaysToMilliseconds(daysToAdd)); - } - - /** - * - * @param hoursToAdd - * @return from this object plus the given hoursToAdd new Duration - */ - public Duration plusHours(long hoursToAdd) { - return this.plusMilliseconds(Duration.convertHoursToMilliseconds(hoursToAdd)); - } - - /** - * - * @param minutesToAdd - * @return from this object plus the given minutesToAdd new Duration - */ - public Duration plusMinutes(long minutesToAdd) { - return this.plusMilliseconds(Duration.convertMinutesToMilliseconds(minutesToAdd)); - } - - /** - * - * @param secondsToAdd - * @return from this object plus the given secondsToAdd new Duration - */ - public Duration plusSeconds(long secondsToAdd) { - return this.plusMilliseconds(Duration.convertSecondsToMilliseconds(secondsToAdd)); - } - - /** - * - * @param millisecondsToAdd - * @return from this object plus the given millisecondsToAdd new Duration - */ - public Duration plusMilliseconds(long millisecondsToAdd) { - return new Duration(this.toTotalMilliseconds() + millisecondsToAdd); - } - - /** - * - * @param durationToSubtract - * @return from this object minus the given durationToSubtract new Duration - */ - public Duration minusDuration(Duration durationToSubtract) { - return new Duration(this.toTotalMilliseconds() - durationToSubtract.toTotalMilliseconds()); - } - - /** - * - * @param daysToSubtract - * @return from this object minus the given daysToSubtract new Duration - */ - public Duration minusDays(long daysToSubtract) { - return this.minusMilliseconds(Duration.convertDaysToMilliseconds(daysToSubtract)); - } - - /** - * - * @param hoursToSubtract - * @return from this object minus the given hoursToSubtract new Duration - */ - public Duration minusHours(long hoursToSubtract) { - return this.minusMilliseconds(Duration.convertHoursToMilliseconds(hoursToSubtract)); - } - - /** - * - * @param minutesToSubtract - * @return from this object minus the given minutesToSubtract new Duration - */ - public Duration minusMinutes(long minutesToSubtract) { - return this.minusMilliseconds(Duration.convertMinutesToMilliseconds(minutesToSubtract)); - } - - /** - * - * @param secondsToSubtract - * @return from this object minus the given secondsToSubtract new Duration - */ - public Duration minusSeconds(long secondsToSubtract) { - return this.minusMilliseconds(Duration.convertSecondsToMilliseconds(secondsToSubtract)); - } - - /** - * - * @param millisecondsToSubtract - * @return from this object minus the given millisecondsToSubtract new - * Duration - */ - public Duration minusMilliseconds(long millisecondsToSubtract) { - return new Duration(this.toTotalMilliseconds() - millisecondsToSubtract); - } - - /** - * - * @return representation of this object in days - */ - public double toTotalDays() { - return countOfTotalMilliseconds / getMillisecondsPerDay(); - } - - /** - * - * @return representation of this object in hours - */ - public double toTotalHours() { - return countOfTotalMilliseconds / getMillisecondsPerHour(); - } - - /** - * - * @return representation of this object in minutes - */ - public double toTotalMinutes() { - return countOfTotalMilliseconds / getMillisecondsPerMinute(); - } - - /** - * - * @return representation of this object in seconds - */ - public double toTotalSeconds() { - return countOfTotalMilliseconds / getMillisecondsPerSecond(); - } - - /** - * - * @return representation of this object in milliseconds - */ - public long toTotalMilliseconds() { - return countOfTotalMilliseconds; - } - - /** - * - * @return java.time.duration representation of this object - */ - java.time.Duration toJavaDuration() { - java.time.Duration javaDuration = java.time.Duration.ofMillis(this.toTotalMilliseconds()); - if (!this.isPositive()) { - javaDuration.negated(); - } - return javaDuration; - } - - @Override - public String toString() { - StringBuilder stringBuilder; - stringBuilder = new StringBuilder(); - if (this.isPositive()) { - stringBuilder.append(PLUS); - } else { - stringBuilder.append(MINUS); - } - stringBuilder.append(this.getDays()); - stringBuilder.append(COLON); - stringBuilder.append(this.getHours()); - stringBuilder.append(COLON); - stringBuilder.append(this.getMinutes()); - stringBuilder.append(COLON); - stringBuilder.append(this.getSeconds()); - stringBuilder.append(COLON); - stringBuilder.append(this.getMilliseconds()); - return stringBuilder.toString(); - - } -} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/LocalDateTime.java b/src/main/java/org/nanoboot/powerframework/datetime/LocalDateTime.java deleted file mode 100644 index 73432d7..0000000 --- a/src/main/java/org/nanoboot/powerframework/datetime/LocalDateTime.java +++ /dev/null @@ -1,112 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import java.time.format.DateTimeFormatter; - -/** - * This class stores date time without time zone information. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public final class LocalDateTime extends DateTime { - - /** - * Constructor - * - * Creates new LocalDateTime from String. - * - * @param dateTimeInString - */ - protected LocalDateTime(String dateTimeInString) { - super(dateTimeInString); - } - - /** - * Constructor - * - * Creates new LocalDateTime with these parameters. - * - * @param year - * @param month - * @param day - * @param hour24Format - * @param minute - * @param second - * @param millisecond - */ - public LocalDateTime(int year, int month, int day, int hour24Format, int minute, int second, int millisecond) { - super(year, month, day, hour24Format, minute, second, millisecond); - } - - /** - * Constructor - * - * Creates new LocalDateTime from UniversalDateTime. - * - * @param universalDateTime - */ - public LocalDateTime(UniversalDateTime universalDateTime) { - super(universalDateTime); - } - - /** - * Constructor - * - * Creates new LocalDateTime from ZonedDateTime. - * - * @param zonedDateTime - */ - public LocalDateTime(ZonedDateTime zonedDateTime) { - super(zonedDateTime); - } - - /** - * - * - * @return a UniversalDateTime instance from this object - */ - public UniversalDateTime toUniversalDateTime() { - return new UniversalDateTime(this); - } - - /** - * - * - * @param timeZone time zone of new created ZonedDateTime - * @return a ZonedDateTime instance from this object - */ - public ZonedDateTime toZonedDateTime(org.nanoboot.powerframework.datetime.TimeZone timeZone) { - return new ZonedDateTime(this, timeZone); - } - - /** - * - * - * @return a java.time.LocalDateTime instance from this object - */ - java.time.LocalDateTime toJavaLocalDateTime() { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS"); - String stringRepresentationOfThisObject = this.toString(); - return java.time.LocalDateTime.parse(stringRepresentationOfThisObject, dateTimeFormatter); - } - -} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/LocalTime.java b/src/main/java/org/nanoboot/powerframework/datetime/LocalTime.java deleted file mode 100644 index de58f35..0000000 --- a/src/main/java/org/nanoboot/powerframework/datetime/LocalTime.java +++ /dev/null @@ -1,115 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Represents Time without date and time zone information. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public final class LocalTime { - - private static final String COLON = ":"; - - private final int hour; - private final int minute; - private final int second; - private final int millisecond; - - /** - * Constructor - * - * @param hour - * @param minute - * @param second - * @param millisecond - * @exception PowerRuntimeException if parameters are invalid. - */ - public LocalTime(int hour, int minute, int second, int millisecond) { - TimeUnitsValidator.checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException(hour, minute, second, millisecond); - this.hour = hour; - this.minute = minute; - this.second = second; - this.millisecond = millisecond; - } - - /** - * - * @return hour of this time. - */ - public int getHour() { - return hour; - } - - /** - * - * @return minute of this time. - */ - public int getMinute() { - return minute; - } - - /** - * - * @return second of this time. - */ - public int getSecond() { - return second; - } - - /** - * - * @return millisecond of this time. - */ - public int getMillisecond() { - return millisecond; - } - - @Override - public String toString() { - StringBuilder stringBuilder = new StringBuilder(); - - if (hour < 10) { - stringBuilder.append("0"); - } - stringBuilder.append(this.getHour()); - stringBuilder.append(COLON); - if (minute < 10) { - stringBuilder.append("0"); - } - stringBuilder.append(this.getMinute()); - stringBuilder.append(COLON); - if (second < 10) { - stringBuilder.append("0"); - } - stringBuilder.append(this.getSecond()); - stringBuilder.append(COLON); - if (millisecond < 10) { - stringBuilder.append("00"); - } else if (millisecond < 100) { - stringBuilder.append("0"); - } - stringBuilder.append(this.getMillisecond()); - return stringBuilder.toString(); - } -} diff --git a/src/main/java/org/nanoboot/powerframework/datetime/package-info.java b/src/main/java/org/nanoboot/powerframework/datetime/package-info.java deleted file mode 100644 index 65f290b..0000000 --- a/src/main/java/org/nanoboot/powerframework/datetime/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This package contains date and time utilities. - */ -package org.nanoboot.powerframework.datetime; diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonObject.java b/src/main/java/org/nanoboot/powerframework/json/JsonObject.java deleted file mode 100644 index 03fe0a7..0000000 --- a/src/main/java/org/nanoboot/powerframework/json/JsonObject.java +++ /dev/null @@ -1,540 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.json; - -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.collections.Dictionary; -import org.nanoboot.powerframework.collections.DictionaryKeyIterator; - -/** - * Represents json object of json. * @author Robert Vokac e-mail: - * robertvokac@nanoboot.org - */ -public class JsonObject { - - private final Dictionary dictionary = new Dictionary<>(); - - /** - * Constructor - * - * Used to create empty jsonObject. - */ - public JsonObject() { - // Used to create empty jsonObject. - } - - /** - * Constructor - * - * From String creates json object. - * - * @param textToParse - */ - public JsonObject(String textToParse) { - JsonObjectParser.parseStringToJsonObject(this, textToParse); - } - - /** - * - * @return count of items(keys and its values) of this json object - */ - public int getCountOfItems() { - return dictionary.getCountOfItems(); - } - - /** - * - * @return result of this control - */ - public boolean isEmpty() { - return dictionary.isEmpty(); - } - - /** - * - * @param key - * @return result of this control - */ - public boolean containsValueWithKey(String key) { - return this.dictionary.containsValueWithKey(key); - } - - /** - * Add to this json object new key, object is converted to the most suitable - * json value type and is set as value of the key. - * - * @param key - * @param object - * @return - */ - public JsonObject add(String key, Object object) {//NOSONAR - if (object == null) { - addNull(key); - } else { - switch (object.getClass().getName()) { - case "org.nanoboot.powerframework.json.JsonObject": - addObject(key, (JsonObject) object); - break; - case "org.nanoboot.powerframework.json.JsonArray": - addArray(key, (JsonArray) object); - break; - case "java.lang.Boolean": - addBoolean(key, (boolean) object); - break; - case "java.lang.String": - addString(key, (String) object); - break; - case "java.lang.Character": - addChar(key, (char) object); - break; - case "java.lang.Integer": - addInt(key, (int) object); - break; - case "java.lang.Long": - addLong(key, (long) object); - break; - case "java.lang.Float": - addFloat(key, (float) object); - break; - case "java.lang.Double": - addDouble(key, (double) object); - break; - default: - throw new PowerRuntimeException("I can't add the given object as value."); - } - } - return this; - } - - /** - * Add to this json object new key with null as value. - * - * @param key - * @return - */ - public JsonObject addNull(String key) { - this.dictionary.addValue(key, new JsonValue()); - return this; - } - - /** - * Add to this json object new key with json object as value. - * - * @param key - * @param value - * @return - */ - public JsonObject addObject(String key, JsonObject value) { - this.dictionary.addValue(key, new JsonValue(value)); - return this; - } - - /** - **Add to this json object new key with json array as value. - * - * @param key - * @param value - * @return - */ - public JsonObject addArray(String key, JsonArray value) { - this.dictionary.addValue(key, new JsonValue(value)); - return this; - } - - /** - * Add to this json object new key with the value of the boolean as the - * value of the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addBoolean(String key, boolean value) { - this.dictionary.addValue(key, new JsonValue(new JsonBoolean(value))); - return this; - } - - /** - * Add to this json object new key with the value of the String as the value - * of the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addString(String key, String value) { - this.dictionary.addValue(key, new JsonValue(new JsonString(value))); - return this; - } - - /** - * Add to this json object new key with the value of the char as the value - * of the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addChar(String key, char value) { - this.dictionary.addValue(key, new JsonValue(new JsonChar(value))); - return this; - } - - /** - * Add to this json object new key with the value of the int as the value of - * the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addInt(String key, int value) { - this.dictionary.addValue(key, new JsonValue(new JsonInt(value))); - return this; - } - - /** - * Add to this json object new key with the value of the long as the value - * of the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addLong(String key, long value) { - this.dictionary.addValue(key, new JsonValue(new JsonLong(value))); - return this; - } - - /** - * Add to this json object new key with the value of the float as the value - * of the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addFloat(String key, float value) { - this.dictionary.addValue(key, new JsonValue(new JsonFloat(value))); - return this; - } - - /** - * Add to this json object new key with the value of the double as the value - * of the key. - * - * @param key - * @param value - * @return - */ - public JsonObject addDouble(String key, double value) { - this.dictionary.addValue(key, new JsonValue(new JsonDouble(value))); - return this; - } - - /** - * - * @param key - * @return value type of the value of the given key - */ - public JsonValueType getJsonValueType(String key) { - return dictionary.getValue(key).getJsonValueType(); - } - - /** - * - * @param key - * @return object instance converted from the value of the given key - */ - public Object get(String key) { - return dictionary.getValue(key).toObject(); - } - - /** - * - * @param key - * @return json object from the value of the given key - */ - public JsonObject getObject(String key) { - return this.dictionary.getValue(key).getJsonObject(); - } - - /** - * - * @param key - * @return json array from the value of the given key - */ - public JsonArray getArray(String key) { - return this.dictionary.getValue(key).getJsonArray(); - } - - /** - * - * @param key - * @return boolean from the value of the given key - */ - public boolean getBoolean(String key) { - return this.dictionary.getValue(key).getJsonBoolean().getBoolean(); - } - - /** - * - * @param key - * @return String from the value of the given key - */ - public String getString(String key) { - return this.dictionary.getValue(key).getJsonString().getString(); - } - - /** - * - * @param key - * @return char from the value of the given key - */ - public char getChar(String key) { - return this.dictionary.getValue(key).getJsonChar().getChar(); - } - - /** - * - * @param key - * @return int from the value of the given key - */ - public int getInt(String key) { - return this.dictionary.getValue(key).getJsonInt().getInt(); - } - - /** - * - * @param key - * @return long from the value of the given key - */ - public long getLong(String key) { - return this.dictionary.getValue(key).getJsonLong().getLong(); - } - - /** - * - * @param key - * @return float from the value of the given key - */ - public float getFloat(String key) { - return this.dictionary.getValue(key).getJsonFloat().getFloat(); - } - - /** - * - * @param key - * @return double from the value of the given key - */ - public double getDouble(String key) { - return this.dictionary.getValue(key).getJsonDouble().getDouble(); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param object - */ - public void update(String key, Object object) {//NOSONAR - if (object == null) { - updateNull(key); - } else { - switch (object.getClass().getName()) { - case "org.nanoboot.powerframework.json.JsonObject": - updateObject(key, (JsonObject) object); - break; - case "org.nanoboot.powerframework.json.JsonArray": - updateArray(key, (JsonArray) object); - break; - case "java.lang.Boolean": - updateBoolean(key, (boolean) object); - break; - case "java.lang.String": - updateString(key, (String) object); - break; - case "java.lang.Character": - updateChar(key, (char) object); - break; - case "java.lang.Integer": - updateInt(key, (int) object); - break; - case "java.lang.Long": - updateLong(key, (long) object); - break; - case "java.lang.Float": - updateFloat(key, (float) object); - break; - case "java.lang.Double": - updateDouble(key, (double) object); - break; - default: - throw new PowerRuntimeException("I can't add the given object as value."); - } - } - } - - /** - * Updates the value of the given key. - * - * @param key - */ - public void updateNull(String key) { - this.dictionary.updateValue(key, new JsonValue()); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateObject(String key, JsonObject value) { - this.dictionary.updateValue(key, new JsonValue(value)); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateArray(String key, JsonArray value) { - this.dictionary.updateValue(key, new JsonValue(value)); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateBoolean(String key, boolean value) { - this.dictionary.updateValue(key, new JsonValue(new JsonBoolean(value))); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateString(String key, String value) { - this.dictionary.updateValue(key, new JsonValue(new JsonString(value))); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateChar(String key, char value) { - this.dictionary.updateValue(key, new JsonValue(new JsonChar(value))); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateInt(String key, int value) { - this.dictionary.updateValue(key, new JsonValue(new JsonInt(value))); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateLong(String key, long value) { - this.dictionary.updateValue(key, new JsonValue(new JsonLong(value))); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateFloat(String key, float value) { - this.dictionary.updateValue(key, new JsonValue(new JsonFloat(value))); - } - - /** - * Updates the value of the given key. - * - * @param key - * @param value - */ - public void updateDouble(String key, double value) { - this.dictionary.updateValue(key, new JsonValue(new JsonDouble(value))); - } - - /** - * Removes the key and its value. - * - * @param key - */ - public void removeJsonValue(String key) { - this.dictionary.removeValue(key); - } - - /** - * - * @return String representation of this json object in minimal version - */ - public String toMinimalString() { - return JsonObjectPrinter.toMinimalString(this); - } - - /** - * - * @return String representation of this json object in pretty print version - */ - public String toPrettyString() { - return JsonObjectPrinter.toPrettyString(this); - } - - /** - * - * @return copy of this json object - */ - public JsonObject getCopy() { - String stringRepresentationOfThisObject = this.toMinimalString(); - return new JsonObject(stringRepresentationOfThisObject); - } - - /** - * - * @return key iterator - */ - public DictionaryKeyIterator getKeyIterator() { - return this.dictionary.getKeyIterator(); - } - - JsonValue getJsonValue(String key) { - return this.dictionary.getValue(key); - } -} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java b/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java deleted file mode 100644 index c6f6d67..0000000 --- a/src/main/java/org/nanoboot/powerframework/json/JsonObjectParser.java +++ /dev/null @@ -1,110 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.json; - -import java.util.ArrayList; -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Is used to create json objects from strings. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -class JsonObjectParser extends JsonParser { - - /** - * Constructor - * - * Not meant to be instantiated. - */ - private JsonObjectParser() { - //Not meant to be instantiated. - } - - /** - * Parses String to empty json object. - * - * @param jsonObject - * @param stringRepresentationOfJsonObject - * @return json object from parsed String - */ - static JsonObject parseStringToJsonObject(JsonObject jsonObject, String stringRepresentationOfJsonObject) { - if (!jsonObject.isEmpty()) { - throw new PowerRuntimeException("I can't parse. The json object is not empty."); - } - String trimmedStringRepresentationOfJsonObject = stringRepresentationOfJsonObject.trim(); - if (!isStringJsonObject(trimmedStringRepresentationOfJsonObject)) { - throw new PowerRuntimeException("I can't parse. The trimmed String does not start with { or does not end with }"); - } - String collectionsOfValuesOfTheJsonObjectString = deleteTheCharAtTheStartAndTheEnd(trimmedStringRepresentationOfJsonObject); - - fillJsonObjectWithParsedValues(jsonObject, collectionsOfValuesOfTheJsonObjectString); - return jsonObject; - } - - private static boolean isStringJsonObject(String trimmedStringRepresentationOfJsonObject) { - return (getFirstCharOfTheString(trimmedStringRepresentationOfJsonObject) == JsonSpecialCharSequences.getObjectLeft()) && (getLastCharOfTheString(trimmedStringRepresentationOfJsonObject) == JsonSpecialCharSequences.getObjectRight()); - } - - private static void fillJsonObjectWithParsedValues(JsonObject jsonObject, String collectionsOfValuesOfTheJsonObjectString) { - - ArrayList listOfCommas = getListOfIndexesOfTheStringWhereCharIsCommaAndNestingIsZero(collectionsOfValuesOfTheJsonObjectString); - int beginIndex; - int indexOfComma = 0; - for (int i = 0; i < listOfCommas.size(); i++) { - beginIndex = ++indexOfComma; - indexOfComma = listOfCommas.get(i); - if (i == 0) { - beginIndex = 0; - } - String fraction = collectionsOfValuesOfTheJsonObjectString.substring(beginIndex, indexOfComma); - - String key = getKeyFromKeyValue(fraction).trim(); - key = key.substring(1, key.length() - 1); - Object parsedObject = JsonParser.parseStringToValue(getValueFromKeyValue(fraction)); - - jsonObject.add(key, parsedObject); - } - - } - - private static String getKeyFromKeyValue(String string) { - return getKeyOrValueFromKeyValue(string, true); - } - - private static String getValueFromKeyValue(String string) { - return getKeyOrValueFromKeyValue(string, false); - } - - private static String getKeyOrValueFromKeyValue(String string, boolean trueForKeyFalseForValue) { - String stringToReturn; - int intToSaveColonIndex; - for (intToSaveColonIndex = 0; intToSaveColonIndex < string.length(); intToSaveColonIndex++) { - char currentChar = string.charAt(intToSaveColonIndex); - if (currentChar == JsonSpecialCharSequences.getColon()) { - break; - } - } - stringToReturn = trueForKeyFalseForValue ? string.substring(0, intToSaveColonIndex) : string.substring(++intToSaveColonIndex, string.length()); - - return stringToReturn; - } -} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonParser.java b/src/main/java/org/nanoboot/powerframework/json/JsonParser.java deleted file mode 100644 index e8e5463..0000000 --- a/src/main/java/org/nanoboot/powerframework/json/JsonParser.java +++ /dev/null @@ -1,176 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.json; - -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Pattern; -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Used to parse String representation of JsonObject or JsonArray to their - * object representation. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -class JsonParser { - - /** - * Constructor - * - * Not meant to be instantiated. - */ - JsonParser() { - //Not meant to be instantiated. - } - - static char getFirstCharOfTheString(String string) { - return string.charAt(0); - } - - static char getLastCharOfTheString(String string) { - return string.charAt(string.length() - 1); - } - - protected static String deleteTheCharAtTheStartAndTheEnd(String string) { - return string.substring(1, string.length() - 1); - } - - protected static Object parseStringToValue(String stringToParse) {//NOSONAR - String trimmedStringToParse = stringToParse.trim(); - if ("null".equals(trimmedStringToParse)) { - return null; - } - if ("{".equals(trimmedStringToParse.substring(0, 1))) { - return new JsonObject(trimmedStringToParse); - } - if ("[".equals(trimmedStringToParse.substring(0, 1))) { - return new JsonArray(trimmedStringToParse); - } - if ("true".equals(trimmedStringToParse)) { - return true; - } - if ("false".equals(trimmedStringToParse)) { - return false; - } - if ("\"".equals(trimmedStringToParse.substring(0, 1))) { - return parseStringToStringOrChar(trimmedStringToParse); - } - try { - return parseStringToIntOrLongOrFloatOrDouble(trimmedStringToParse); - } catch (Exception e) { - throw new PowerRuntimeException("Something went wrong. I am not able to parse: \"" + stringToParse + "\". " + e); - } - - } - - private static Object parseStringToStringOrChar(String stringToParse) { - String stringWithoutQuotes = deleteTheCharAtTheStartAndTheEnd(stringToParse); - if (stringWithoutQuotes.length() == 1) { - return stringWithoutQuotes.charAt(0); - } else { - return stringWithoutQuotes; - } - } - - private static Object parseStringToIntOrLongOrFloatOrDouble(String stringToParse) { - String intOrLongPattern = "[0-9]*"; - String floatOrDoublePattern = "([0-9]*)\\.([0-9]*)"; - - if (Pattern.matches(floatOrDoublePattern, stringToParse)) { - return parseStringToFloatOrDouble(stringToParse); - } - if (Pattern.matches(intOrLongPattern, stringToParse)) { - return parseStringToIntOrLong(stringToParse); - } - throw new PowerRuntimeException("I am not able to parse: \"" + stringToParse + "\"."); - } - - private static Object parseStringToIntOrLong(String stringToParse) { - try { - return Integer.parseInt(stringToParse); - } catch (Exception e) { - Logger.getLogger(JsonParser.class.getName()).log(Level.SEVERE, null, e); - try { - return Long.parseLong(stringToParse); - } catch (Exception e2) { - Logger.getLogger(JsonParser.class.getName()).log(Level.SEVERE, null, e2); - throw new PowerRuntimeException("The number is too long."); - } - } - - } - - private static Object parseStringToFloatOrDouble(String stringToParse) { - int digitsPrecision = 0; - for (int i = 0; i < stringToParse.length(); i++) { - char currentChar = stringToParse.charAt(i); - if (currentChar == '.') { - digitsPrecision = stringToParse.length() - 1 - i; - break; - } - } - if (digitsPrecision > 6) { - try { - return Double.parseDouble(stringToParse); - } catch (Exception e) {//NOSONAR - throw new PowerRuntimeException("The number is too long."); - } - } else { - return Float.parseFloat(stringToParse); - } - } - - protected static ArrayList getListOfIndexesOfTheStringWhereCharIsCommaAndNestingIsZero(String collectionsOfValuesOfTheJsonArrayString) { - int nesting = 0; - ArrayList listOfCommas = new ArrayList<>(); - char currentChar; - for (int i = 0; i < collectionsOfValuesOfTheJsonArrayString.length(); i++) { - currentChar = collectionsOfValuesOfTheJsonArrayString.charAt(i); - if ((currentChar == '\"') && (nesting == 0)) { - i++;//NOSONAR - while ('\"' != collectionsOfValuesOfTheJsonArrayString.charAt(i)) { - i++;//NOSONAR - } - } - if ((currentChar == ',') && (nesting == 0)) { - listOfCommas.add(i); - } - if (nestingWillBeIncreased(currentChar)) { - nesting++; - } - if (nestingWillBeDecreased(currentChar)) { - nesting--; - } - } - listOfCommas.add(collectionsOfValuesOfTheJsonArrayString.length()); - return listOfCommas; - } - - private static boolean nestingWillBeIncreased(char charToCheck) { - return (charToCheck == '{') || (charToCheck == '['); - } - - private static boolean nestingWillBeDecreased(char charToCheck) { - return (charToCheck == '}') || (charToCheck == ']'); - } -} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonSpecialCharSequences.java b/src/main/java/org/nanoboot/powerframework/json/JsonSpecialCharSequences.java deleted file mode 100644 index d9825bc..0000000 --- a/src/main/java/org/nanoboot/powerframework/json/JsonSpecialCharSequences.java +++ /dev/null @@ -1,99 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.json; - -/** - * Used to store char and String constants used to parse or print json objects - * or arrays. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -class JsonSpecialCharSequences { - - private static final char OBJECTLEFT = '{'; - private static final char OBJECTRIGHT = '}'; - private static final char ARRAYLEFT = '['; - private static final char ARRAYRIGHT = ']'; - private static final char COMMA = ','; - private static final char COLON = ':'; - private static final char APOSTROPHE = '"'; - private static final String LINEBREAK = "\n"; - private static final String NULL = "null"; - private static final String TRUE = "true"; - private static final String FALSE = "false"; - private static final String TAB = " "; - private static final char SPACE = ' '; - - private JsonSpecialCharSequences() { - } - - static char getObjectLeft() { - return OBJECTLEFT; - } - - static char getObjectRight() { - return OBJECTRIGHT; - } - - static char getArrayLeft() { - return ARRAYLEFT; - } - - static char getArrayRight() { - return ARRAYRIGHT; - } - - static char getComma() { - return COMMA; - } - - static char getColon() { - return COLON; - } - - static char getApostrophe() { - return APOSTROPHE; - } - - static String getLineBreak() { - return LINEBREAK; - } - - static String getNull() { - return NULL; - } - - static String getTrue() { - return TRUE; - } - - static String getFalse() { - return FALSE; - } - - static String getTab() { - return TAB; - } - - static char getSpace() { - return SPACE; - } -} diff --git a/src/main/java/org/nanoboot/powerframework/json/JsonValue.java b/src/main/java/org/nanoboot/powerframework/json/JsonValue.java deleted file mode 100644 index 4336a4c..0000000 --- a/src/main/java/org/nanoboot/powerframework/json/JsonValue.java +++ /dev/null @@ -1,290 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.json; - -import org.nanoboot.powerframework.PowerRuntimeException; - -/** - * Represents json value. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -class JsonValue { - - private JsonValueType jsonValueType = null; - - private JsonObject jsonObject = null; - private JsonArray jsonArray = null; - private JsonBoolean jsonBoolean = null; - private JsonString jsonString = null; - private JsonChar jsonChar = null; - private JsonInt jsonInt = null; - private JsonLong jsonLong = null; - private JsonFloat jsonFloat = null; - private JsonDouble jsonDouble = null; - - JsonValue() { - this.jsonValueType = JsonValueType.NULL; - } - - JsonValue(JsonObject jsonObject) { - this.jsonValueType = JsonValueType.OBJECT; - this.jsonObject = jsonObject; - } - - JsonValue(JsonArray jsonArray) { - this.jsonValueType = JsonValueType.ARRAY; - this.jsonArray = jsonArray; - } - - JsonValue(JsonBoolean jsonBoolean) { - this.jsonValueType = JsonValueType.BOOLEAN; - this.jsonBoolean = jsonBoolean; - } - - JsonValue(JsonString jsonString) { - this.jsonValueType = JsonValueType.STRING; - this.jsonString = jsonString; - } - - JsonValue(JsonChar jsonLiteral) { - this.jsonValueType = JsonValueType.CHAR; - this.jsonChar = jsonLiteral; - } - - JsonValue(JsonInt jsonInt) { - this.jsonValueType = JsonValueType.INT; - this.jsonInt = jsonInt; - } - - JsonValue(JsonLong jsonLong) { - this.jsonValueType = JsonValueType.LONG; - this.jsonLong = jsonLong; - } - - JsonValue(JsonFloat jsonFloat) { - this.jsonValueType = JsonValueType.FLOAT; - this.jsonFloat = jsonFloat; - } - - JsonValue(JsonDouble jsonDouble) { - this.jsonValueType = JsonValueType.DOUBLE; - this.jsonDouble = jsonDouble; - } - - JsonValueType getJsonValueType() { - return this.jsonValueType; - } - - boolean isNull() { - return this.jsonValueType == JsonValueType.NULL; - } - - boolean isObject() { - return this.jsonValueType == JsonValueType.OBJECT; - } - - boolean isArray() { - return this.jsonValueType == JsonValueType.ARRAY; - } - - boolean isBoolean() { - return this.jsonValueType == JsonValueType.BOOLEAN; - } - - boolean isString() { - return this.jsonValueType == JsonValueType.STRING; - } - - boolean isChar() { - return this.jsonValueType == JsonValueType.CHAR; - } - - boolean isInt() { - return this.jsonValueType == JsonValueType.INT; - } - - boolean isLong() { - return this.jsonValueType == JsonValueType.LONG; - } - - boolean isFloat() { - return this.jsonValueType == JsonValueType.FLOAT; - } - - boolean isDouble() { - return this.jsonValueType == JsonValueType.DOUBLE; - } - - JsonObject getJsonObject() { - if (this.isObject()) { - return this.jsonObject; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonObject"); - } - } - - JsonArray getJsonArray() { - if (this.isArray()) { - return this.jsonArray; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonArray"); - } - } - - JsonBoolean getJsonBoolean() { - if (this.isBoolean()) { - return this.jsonBoolean; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonBoolean"); - } - } - - JsonString getJsonString() { - if (this.isString()) { - return this.jsonString; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonString"); - } - } - - JsonChar getJsonChar() { - if (this.isChar()) { - return this.jsonChar; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonChar"); - } - } - - JsonInt getJsonInt() { - if (this.isInt()) { - return this.jsonInt; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonInt"); - } - } - - JsonLong getJsonLong() { - if (this.isLong()) { - return this.jsonLong; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonLong"); - } - } - - JsonFloat getJsonFloat() { - if (this.isFloat()) { - return this.jsonFloat; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonFloat"); - } - } - - JsonDouble getJsonDouble() { - if (this.isDouble()) { - return this.jsonDouble; - } else { - throw new PowerRuntimeException("This JsonValue has no type JsonDouble"); - } - } - - String toPrettyString() { - return toString(true); - } - - String toMinimalString() { - return toString(false); - } - - String toString(boolean printAsPrettyVersion) {//NOSONAR - switch (this.jsonValueType) { - case NULL: - return JsonSpecialCharSequences.getNull(); - case OBJECT: - if (printAsPrettyVersion) { - return this.getJsonObject().toPrettyString(); - } else { - return this.getJsonObject().toMinimalString(); - } - case ARRAY: - if (printAsPrettyVersion) { - return this.getJsonArray().toPrettyString(); - } else { - return this.getJsonArray().toMinimalString(); - } - case BOOLEAN: - return this.getJsonBoolean().toString(); - - case STRING: - return this.getJsonString().toString(); - case CHAR: - return this.getJsonChar().toString(); - case INT: - return this.getJsonInt().toString(); - case LONG: - return this.getJsonLong().toString(); - case FLOAT: - return this.getJsonFloat().toString(); - case DOUBLE: - return this.getJsonDouble().toString(); - default: - throw new IllegalStateException("Enum error."); - } - } - - Object toObject() {//NOSONAR - switch (jsonValueType) { - case NULL: - return null; - - case OBJECT: - return this.getJsonObject(); - - case ARRAY: - return this.getJsonArray(); - - case BOOLEAN: - return this.getJsonBoolean().getBoolean(); - - case STRING: - return this.getJsonString().getString(); - - case CHAR: - return this.getJsonChar().getChar(); - - case INT: - return this.getJsonInt().getInt(); - - case LONG: - return this.getJsonLong().getLong(); - - case FLOAT: - return this.getJsonFloat().getFloat(); - - case DOUBLE: - return this.getJsonDouble().getDouble(); - - default: - throw new IllegalStateException("Enum error."); - } - - } -} diff --git a/src/main/java/org/nanoboot/powerframework/package-info.java b/src/main/java/org/nanoboot/powerframework/package-info.java deleted file mode 100644 index fccdfde..0000000 --- a/src/main/java/org/nanoboot/powerframework/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * This package represents Power library. - * Power contains many general-purpose packages and classes suitable to more than one use. - */ -package org.nanoboot.powerframework; diff --git a/src/main/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGenerator.java b/src/main/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGenerator.java deleted file mode 100644 index c56f589..0000000 --- a/src/main/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGenerator.java +++ /dev/null @@ -1,131 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.pseudorandom; - -import org.nanoboot.powerframework.PowerRuntimeException; -import org.nanoboot.powerframework.datetime.DateTime; -import org.nanoboot.powerframework.datetime.UniversalDateTime; - -/** - * Used to generate pseudo random values. - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class PseudoRandomGenerator { - - private final Seed magicSeed; - private final Seed[] seed = new Seed[2]; - private static final PseudoRandomGenerator pseudoRandomGenerator; - - /** - * Constructor - * - * @param magicNumber - * @param dateTime - */ - public PseudoRandomGenerator(long magicNumber, DateTime dateTime) { - this.magicSeed = new Seed(magicNumber); - long year = dateTime.getYear(); - long month = dateTime.getMonth(); - long day = dateTime.getDay(); - long hour = dateTime.getHour(); - long minute = dateTime.getMinute(); - long second = dateTime.getSecond(); - long millisecond = dateTime.getMillisecond(); - this.seed[0] = new Seed(1000 * (minute + day) + millisecond); - this.seed[1] = new Seed(hour * 100000000 + year * 10000 + second * 100 + month); - - } - - static { - UniversalDateTime currentUniversalDateTime = UniversalDateTime.getCurrentUniversalDateTime(); - int currentDay = currentUniversalDateTime.getMonth(); - int currentMillisecond = currentUniversalDateTime.getMillisecond(); - long magicNumber = (long) currentDay * 1000 + (long) currentMillisecond; - pseudoRandomGenerator = new PseudoRandomGenerator(magicNumber, currentUniversalDateTime); - } - - /** - * @return static instance - */ - public static PseudoRandomGenerator getInstance() { - return pseudoRandomGenerator; - } - - /** - * - * @param from - * @param to - * @return pseudo random long - */ - public long getLong(long from, long to) { - if (from > to) { - throw new IllegalArgumentException("from is greater than to."); - } - - long[] numberFractions = new long[2]; - - for (int i = 0; i <= 1; i++) { - this.seed[0].jump(); - this.seed[1].jump(); - - if (((magicSeed.getNextNumber()) % 2) == 0) { - this.seed[0].jump(); - } - if (((magicSeed.getNextNumber()) % 2) == 1) { - this.seed[1].jump(); - } - long number1 = seed[0].getNextNumber(); - long number2 = seed[1].getNextNumber(); - if ((magicSeed.getNextNumber() % 2) == 1) { - number2 = number2 * (-1); - } - numberFractions[i] = (Math.abs(number1 + number2)) % 1000000000; - } - long number = (numberFractions[0] * 1000000000) + numberFractions[1]; - - number = (number % (to - from + 1)) + from; - - return number; - } - - /** - * - * @param from - * @param to - * @return pseudo random int - */ - public int getInt(int from, int to) { - if (to > Integer.MAX_VALUE) { - throw new PowerRuntimeException("The parameter \"to\" is too big."); - } - return (int) getLong(from, to); - } - - /** - * - * @return pseudo random boolean - */ - public boolean getBoolean() { - int value = getInt(0, 1); - return value == 1; - } -} diff --git a/src/test/java/org/nanoboot/powerframework/collections/DictionaryKeyIteratorTest.java b/src/test/java/org/nanoboot/powerframework/collections/DictionaryKeyIteratorTest.java deleted file mode 100644 index 55cde57..0000000 --- a/src/test/java/org/nanoboot/powerframework/collections/DictionaryKeyIteratorTest.java +++ /dev/null @@ -1,205 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class DictionaryKeyIteratorTest { - - /** - * - */ - public DictionaryKeyIteratorTest() { - } - - /** - * Test of getNextKey method, of class DictionaryKeyIterator. - */ - @Test - public void testGetNextKey() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - StringBuilder stringBuilder = new StringBuilder(); - String key1; - String key2; - String key3; - String value1; - String value2; - String value3; - String expectedString = "JohnJohnycalm"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - dictionary.addValue("personality", "calm"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - key1 = dictionaryKeyIterator.getNextKey(); - key2 = dictionaryKeyIterator.getNextKey(); - key3 = dictionaryKeyIterator.getNextKey(); - - value1 = dictionary.getValue(key1); - value2 = dictionary.getValue(key2); - value3 = dictionary.getValue(key3); - - stringBuilder.append(value1); - stringBuilder.append(value2); - stringBuilder.append(value3); - returnedString = stringBuilder.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of hasNext method, of class DictionaryKeyIterator. - */ - @Test - public void testHasNext() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - boolean expectedValue = true; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - dictionary.addValue("personality", "calm"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - dictionaryKeyIterator.getNextKey(); - dictionaryKeyIterator.getNextKey(); - returnedValue = dictionaryKeyIterator.hasNext(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of hasNext method, of class DictionaryKeyIterator. - */ - @Test - public void testHasNext2() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - boolean expectedValue = false; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - dictionary.addValue("personality", "calm"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - dictionaryKeyIterator.getNextKey(); - dictionaryKeyIterator.getNextKey(); - dictionaryKeyIterator.getNextKey(); - returnedValue = dictionaryKeyIterator.hasNext(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of hasNext method, of class DictionaryKeyIterator. - */ - @Test - public void testHasNext3() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - boolean expectedValue = false; - boolean returnedValue; - //act - dictionary.addValue("name", "John"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - dictionaryKeyIterator.getNextKey(); - returnedValue = dictionaryKeyIterator.hasNext(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of hasNext method, of class DictionaryKeyIterator. - */ - @Test - public void testHasNext4() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - boolean expectedValue = false; - boolean returnedValue; - //act - - dictionaryKeyIterator = dictionary.getKeyIterator(); - - returnedValue = dictionaryKeyIterator.hasNext(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of hasNext method, of class DictionaryKeyIterator. - */ - @Test - public void testHasNext5() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - boolean expectedValue = true; - boolean returnedValue; - //act - dictionary.addValue("name", "John"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - - returnedValue = dictionaryKeyIterator.hasNext(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of reset method, of class DictionaryKeyIterator. - */ - @Test - public void testReset() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - String firstKey; - - String expectedString = "John"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - dictionary.addValue("personality", "calm"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - for (int i = 0; i < 3; i++) { - dictionaryKeyIterator.getNextKey(); - } - dictionaryKeyIterator.reset(); - firstKey = dictionaryKeyIterator.getNextKey(); - returnedString = dictionary.getValue(firstKey); - //assert - assertEquals(expectedString, returnedString); - } - -} diff --git a/src/test/java/org/nanoboot/powerframework/collections/DictionaryNodeTest.java b/src/test/java/org/nanoboot/powerframework/collections/DictionaryNodeTest.java deleted file mode 100644 index 05df7d1..0000000 --- a/src/test/java/org/nanoboot/powerframework/collections/DictionaryNodeTest.java +++ /dev/null @@ -1,137 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class DictionaryNodeTest { - - /** - * - */ - public DictionaryNodeTest() { - } - - /** - * Test of getElement method, of class DictionaryNode. - */ - @Test - public void testGetElement() { - //arrange - DictionaryNode dictionaryNode = new DictionaryNode<>("name", "John"); - String expectedString = "John"; - String returnedString; - //act - returnedString = dictionaryNode.getElement(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of setElement method, of class DictionaryNode. - */ - @Test - public void testSetElement() { - //arrange - DictionaryNode dictionaryNode = new DictionaryNode<>("name", "John"); - String expectedString = "Jack"; - String returnedString; - //act - dictionaryNode.setElement("Jack"); - returnedString = dictionaryNode.getElement(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of getNext method, of class DictionaryNode. - */ - @Test - public void testGetNext() { - //arrange - DictionaryNode dictionaryNode = new DictionaryNode<>("name", "John"); - DictionaryNode dictionaryNode2 = new DictionaryNode<>("surname", "Black"); - String expectedString = "Black"; - String returnedString; - //act - dictionaryNode.setNext(dictionaryNode2); - DictionaryNode returnedDictionaryNode = dictionaryNode.getNext(); - returnedString = returnedDictionaryNode.getElement(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of setNext method, of class DictionaryNode. - */ - @Test - public void testSetNext() { - //arrange - DictionaryNode dictionaryNode = new DictionaryNode<>("name", "John"); - DictionaryNode dictionaryNode2 = new DictionaryNode<>("surname", "White"); - String expectedString = "White"; - String returnedString; - //act - dictionaryNode.setNext(dictionaryNode2); - DictionaryNode returnedDictionaryNode = dictionaryNode.getNext(); - returnedString = returnedDictionaryNode.getElement(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of getKey method, of class DictionaryNode. - */ - @Test - public void testGetKey() { - //arrange - DictionaryNode dictionaryNode = new DictionaryNode<>("name", "John"); - String expectedString = "name"; - String returnedString; - //act - returnedString = dictionaryNode.getKey(); - //assert - assertEquals(expectedString, returnedString); - - } - - /** - * Test of setKey method, of class DictionaryNode. - */ - @Test - public void testSetKey() { - //arrange - DictionaryNode dictionaryNode = new DictionaryNode<>("name", "John"); - String expectedString = "nick"; - String returnedString; - //act - dictionaryNode.setKey("nick"); - returnedString = dictionaryNode.getKey(); - //assert - assertEquals(expectedString, returnedString); - } - -} diff --git a/src/test/java/org/nanoboot/powerframework/collections/DictionaryTest.java b/src/test/java/org/nanoboot/powerframework/collections/DictionaryTest.java deleted file mode 100644 index 9fd3de7..0000000 --- a/src/test/java/org/nanoboot/powerframework/collections/DictionaryTest.java +++ /dev/null @@ -1,381 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.collections; - -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class DictionaryTest { - - /** - * - */ - public DictionaryTest() { - } - - /** - * Test of getCountOfItems method, of class Dictionary. - */ - @Test - public void testGetCountOfItems() { - //arrange - Dictionary dictionary = new Dictionary<>(); - int expectedValue = 0; - int returnedValue; - //act - returnedValue = dictionary.getCountOfItems(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of getCountOfItems method, of class Dictionary. - */ - @Test - public void testGetCountOfItems2() { - //arrange - Dictionary dictionary = new Dictionary<>(); - int expectedValue = 0; - int returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black"); - dictionary.removeValue("name").removeValue("surname"); - returnedValue = dictionary.getCountOfItems(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of getCountOfItems method, of class Dictionary. - */ - @Test - public void testGetCountOfItems3() { - //arrange - Dictionary dictionary = new Dictionary<>(); - int expectedValue = 2; - int returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - returnedValue = dictionary.getCountOfItems(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of getCountOfItems method, of class Dictionary. - */ - @Test - public void testGetCountOfItems4() { - //arrange - Dictionary dictionary = new Dictionary<>(); - int expectedValue = 1; - int returnedValue; - //act - dictionary.addValue("surname", "Black"); - returnedValue = dictionary.getCountOfItems(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of isEmpty method, of class Dictionary. - */ - @Test - public void testIsEmpty() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = true; - boolean returnedValue; - //act - returnedValue = dictionary.isEmpty(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of isEmpty method, of class Dictionary. - */ - @Test - public void testIsEmpty2() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = true; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black"); - dictionary.removeValue("name").removeValue("surname"); - returnedValue = dictionary.isEmpty(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of isEmpty method, of class Dictionary. - */ - @Test - public void testIsEmpty3() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = false; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - returnedValue = dictionary.isEmpty(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of getValue method, of class Dictionary. - */ - @Test - public void testIsEmpty4() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = false; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("name"); - returnedValue = dictionary.isEmpty(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of containsValueWithKey method, of class Dictionary. - */ - @Test - public void containsValueWithKey() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = true; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - returnedValue = dictionary.containsValueWithKey("surname"); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of containsValueWithKey method, of class Dictionary. - */ - @Test - public void containsValueWithKey2() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = false; - boolean returnedValue; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - returnedValue = dictionary.containsValueWithKey("job"); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of containsValueWithKey method, of class Dictionary. - */ - @Test - public void containsValueWithKey3() { - //arrange - Dictionary dictionary = new Dictionary<>(); - boolean expectedValue = true; - boolean returnedValue; - //act - dictionary.addValue("name", "John"); - returnedValue = dictionary.containsValueWithKey("name"); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of addValue method, of class Dictionary. - */ - @Test - public void testAddValue() { - //arrange - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Johny"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - returnedString = dictionary.getValue("nick"); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of addValue method, of class Dictionary. - */ - @Test - public void testAddValue2() { - //arrang - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Johny"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("name"); - returnedString = dictionary.getValue("nick"); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of addValue method, of class Dictionary. - */ - @Test - public void testAddValue3() { - //arrange - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Black"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("nick"); - returnedString = dictionary.getValue("surname"); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of getValue method, of class Dictionary. - */ - @Test - public void testGetValue() { - //arrange - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Black"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("name"); - returnedString = dictionary.getValue("surname"); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of getValue method, of class Dictionary. - */ - @Test - public void testGetValue2() { - //arrange - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Johny"; - String returnedString; - //act - dictionary.addValue("nick", "Johny"); - returnedString = dictionary.getValue("nick"); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of updateValue method, of class Dictionary. - */ - @Test - public void testUpdateValue() { - //arrange - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Blue"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.updateValue("surname", "Blue"); - returnedString = dictionary.getValue("surname"); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of removeValue method, of class Dictionary. - */ - @Test - public void testRemoveValue() { - //arrange - boolean isExceptionThrown = false; - Dictionary dictionary = new Dictionary<>(); - String expectedString = "Black"; - String returnedString; - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - //act - try { - returnedString = dictionary.getValue("surname"); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } - //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); - } - } - - /** - * Test of getKeyIterator method, of class Dictionary. - */ - @Test - public void testGetKeyIterator() { - //arrange - Dictionary dictionary = new Dictionary<>(); - DictionaryKeyIterator dictionaryKeyIterator; - String expectedString = "Johny"; - String returnedString; - String secondKey; - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - dictionary.removeValue("surname"); - dictionaryKeyIterator = dictionary.getKeyIterator(); - //act - dictionaryKeyIterator.getNextKey(); - secondKey = dictionaryKeyIterator.getNextKey(); - returnedString = dictionary.getValue(secondKey); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of toString method, of class Dictionary. - */ - @Test - public void testToString() { - //arrange - Dictionary dictionary = new Dictionary<>(); - String expectedString = "name:John\nsurname:Black\nnick:Johny\n"; - String returnedString; - //act - dictionary.addValue("name", "John").addValue("surname", "Black").addValue("nick", "Johny"); - returnedString = dictionary.toString(); - //assert - assertEquals(expectedString, returnedString); - } - -} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/DurationTest.java b/src/test/java/org/nanoboot/powerframework/datetime/DurationTest.java deleted file mode 100644 index c5e73c9..0000000 --- a/src/test/java/org/nanoboot/powerframework/datetime/DurationTest.java +++ /dev/null @@ -1,878 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class DurationTest { - - /** - * - */ - public DurationTest() { - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_5Args_ThereShouldBeThrownNoPowerRuntimeException() { - //arrange - boolean isExceptionThrown = false; - //act - try { - Duration duration = new Duration(23, 5, 3, 43, 97); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } - //assert - if (isExceptionThrown) { - fail("There should be thrown no PowerRuntimeException"); - } - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_5Args_ThereShouldBeThrownPowerRuntimeException() { - //arrange - boolean isExceptionThrown = false; - //act - try { - Duration duration = new Duration(23, 5, 3, 143, 97); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } - //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); - } - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_5Args_ThereShouldBeReturnedIsPositive() { - //arrange - boolean expectedValue = true; - boolean returnedValue; - Duration duration = new Duration(23, 5, 3, 43, 97); - //act - returnedValue = duration.isPositive(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_6Args_ThereShouldBeReturnedIsPositive() { - //arrange - boolean expectedValue = true; - boolean returnedValue; - Duration duration = new Duration(true, 23, 5, 3, 43, 97); - //act - returnedValue = duration.isPositive(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_6Args_ThereShouldBeReturnedIsNotPositive() { - //arrange - boolean expectedValue = false; - boolean returnedValue; - Duration duration = new Duration(false, 23, 5, 3, 43, 97); - //act - returnedValue = duration.isPositive(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_StringArg() { - //arrange - String argString = "+00023:05:03:43:097"; - String expectedString = "+23:5:3:43:97"; - String returnedString; - - Duration duration = new Duration(argString); - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of constructor, of class Duration. - */ - @Test - public void TestDuration_StringArg_ThereShouldBeThrownPowerRuntimeException() { - //arrange - boolean isExceptionThrown = false; - //act - try { - String argString = "+23:5:60:43:97"; - Duration duration = new Duration(argString); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } - //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); - } - } - - /** - * Test of between method, of class Duration. - */ - @Test - public void testBetween1_UniversalDateTime_UniversalDateTime() { - //arrange - UniversalDateTime startUniversalDateTime = new UniversalDateTime(1949, 8, 6, 4, 23, 7, 654); - UniversalDateTime endUniversalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); - String expectedString = "+21077:4:54:51:300"; - String returnedString; - //act - returnedString = Duration.between(startUniversalDateTime, endUniversalDateTime).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of between method, of class Duration. - */ - @Test - public void testBetween2_UniversalDateTime_UniversalDateTime() { - //arrange - UniversalDateTime startUniversalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); - UniversalDateTime endUniversalDateTime = new UniversalDateTime(1949, 8, 6, 4, 23, 7, 654); - String expectedString = "-21077:4:54:51:300"; - String returnedString; - //act - returnedString = Duration.between(startUniversalDateTime, endUniversalDateTime).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of between method, of class Duration. - */ - @Test - public void testBetween1_ZonedDateTime_ZonedDateTime() { - //arrange - LocalDateTime localDateTime = new LocalDateTime(2016, 10, 29, 11, 19, 34, 276); - ZonedDateTime startZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Europe/Prague")); - ZonedDateTime endZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Australia/Sydney")); - String expectedString = "-0:9:0:0:0"; - String returnedString; - //act - returnedString = Duration.between(startZonedDateTime, endZonedDateTime).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of between method, of class Duration. - */ - @Test - public void testBetween2_ZonedDateTime_ZonedDateTime() { - //arrange - LocalDateTime localDateTime = new LocalDateTime(2016, 10, 29, 11, 19, 34, 276); - ZonedDateTime startZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Australia/Sydney")); - ZonedDateTime endZonedDateTime = new ZonedDateTime(localDateTime, new TimeZone("Europe/Prague")); - String expectedString = "+0:9:0:0:0"; - String returnedString; - //act - returnedString = Duration.between(startZonedDateTime, endZonedDateTime).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of ofDays method, of class Duration. - */ - @Test - public void testOfDays() { - //arrange - int days = 13; - - Duration duration = Duration.ofDays(days); - String expectedString = "+13:0:0:0:0"; - String returnedString; - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of ofHours method, of class Duration. - */ - @Test - public void testOfHours() { - //arrange - int hours = 17; - - Duration duration = Duration.ofHours(hours); - String expectedString = "+0:17:0:0:0"; - String returnedString; - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of ofMinutes method, of class Duration. - */ - @Test - public void testOfMinutes() { - //arrange - int minutes = 42; - - Duration duration = Duration.ofMinutes(minutes); - String expectedString = "+0:0:42:0:0"; - String returnedString; - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of ofSeconds method, of class Duration. - */ - @Test - public void testOfSeconds() { - //arrange - int seconds = 9; - - Duration duration = Duration.ofSeconds(seconds); - String expectedString = "+0:0:0:9:0"; - String returnedString; - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of ofMilliseconds method, of class Duration. - */ - @Test - public void testOfMilliseconds() { - //arrange - int milliseconds = 4; - - Duration duration = Duration.ofMilliseconds(milliseconds); - String expectedString = "+0:0:0:0:4"; - String returnedString; - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of fromUniversalDateTimePlusDurationCreateNewUniversalDateTime - * method, of class Duration. - */ - @Test - public void testFromUniversalDateTimePlusDurationCreateNewUniversalDateTime() { - //arrange - UniversalDateTime universalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); - Duration duration = Duration.ofHours(7); - String expectedString = "2007-04-21 16:17:58:954"; - String returnedString; - //act - returnedString = Duration.fromUniversalDateTimePlusDurationCreateNewUniversalDateTime(universalDateTime, duration).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime - * method, of class Duration. - */ - @Test - public void testFromUniversalDateTimeMinusDurationCreateNewUniversalDateTime() { - //arrange - UniversalDateTime universalDateTime = new UniversalDateTime(2007, 4, 21, 9, 17, 58, 954); - Duration duration = Duration.ofHours(7); - String expectedString = "2007-04-21 02:17:58:954"; - String returnedString; - //act - returnedString = Duration.fromUniversalDateTimeMinusDurationCreateNewUniversalDateTime(universalDateTime, duration).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of fromZonedDateTimePlusDurationCreateNewZonedDateTime method, of - * class Duration. - */ - @Test - public void testFromZonedDateTimePlusDurationCreateNewZonedDateTime() { - //arrange - LocalDateTime localDateTime = new LocalDateTime(2007, 4, 21, 9, 17, 58, 954); - TimeZone timeZone = new TimeZone("Australia/Sydney"); - ZonedDateTime zonedDateTime = new ZonedDateTime(localDateTime, timeZone); - Duration duration = Duration.ofHours(7); - String expectedString = "2007-04-21 16:17:58:954"; - String returnedString; - //act - returnedString = Duration.fromZonedDateTimePlusDurationCreateNewZonedDateTime(zonedDateTime, duration).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of fromZonedDateTimeMinusDurationCreateNewZonedDateTime method, of - * class Duration. - */ - @Test - public void testFromZonedDateTimeMinusDurationCreateNewZonedDateTime() { - //arrange - LocalDateTime localDateTime = new LocalDateTime(2007, 4, 21, 9, 17, 58, 954); - TimeZone timeZone = new TimeZone("Australia/Sydney"); - ZonedDateTime zonedDateTime = new ZonedDateTime(localDateTime, timeZone); - Duration duration = Duration.ofHours(7); - String expectedString = "2007-04-21 02:17:58:954"; - String returnedString; - //act - returnedString = Duration.fromZonedDateTimeMinusDurationCreateNewZonedDateTime(zonedDateTime, duration).toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of getDays method, of class Duration. - */ - @Test - public void testGetDays() { - //arrange - Duration duration = new Duration(23, 5, 3, 43, 97); - long expectedDays = 23; - long returnedDays; - //act - returnedDays = duration.getDays(); - //assert - assertEquals(expectedDays, returnedDays); - } - - /** - * Test of getHours method, of class Duration. - */ - @Test - public void testGetHours() { - //arrange - Duration duration = new Duration(23, 5, 3, 43, 97); - int expectedHours = 5; - int returnedHours; - //act - returnedHours = duration.getHours(); - //assert - assertEquals(expectedHours, returnedHours); - } - - /** - * Test of getMinutes method, of class Duration. - */ - @Test - public void testGetMinutes() { - //arrange - Duration duration = new Duration(23, 5, 3, 43, 97); - int expectedMinutes = 3; - int returnedMinutes; - //act - returnedMinutes = duration.getMinutes(); - //assert - assertEquals(expectedMinutes, returnedMinutes); - } - - /** - * Test of getSeconds method, of class Duration. - */ - @Test - public void testGetSeconds() { - //arrange - Duration duration = new Duration(23, 5, 3, 43, 97); - int expectedSeconds = 43; - int returnedSeconds; - //act - returnedSeconds = duration.getSeconds(); - //assert - assertEquals(expectedSeconds, returnedSeconds); - } - - /** - * Test of getMilliseconds method, of class Duration. - */ - @Test - public void testGetMilliseconds() { - //arrange - Duration duration = new Duration(23, 5, 3, 43, 97); - int expectedMilliseconds = 97; - int returnedMilliseconds; - //act - returnedMilliseconds = duration.getMilliseconds(); - //assert - assertEquals(expectedMilliseconds, returnedMilliseconds); - } - - /** - * Test of isPositive method, of class Duration. - */ - @Test - public void testIsPositive() { - //arrange - Duration duration = new Duration(false, 23, 5, 3, 43, 97); - boolean expectedValue = false; - boolean returnedValue; - //act - returnedValue = duration.isPositive(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of negated method, of class Duration. - */ - @Test - public void testNegated() { - //arrange - Duration duration = new Duration(23, 5, 3, 43, 97); - Duration negatedDuration; - - boolean expectedValue = false; - boolean returnedValue; - //act - negatedDuration = duration.negated(); - returnedValue = negatedDuration.isPositive(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of abs method, of class Duration. - */ - @Test - public void testAbs() { - //arrange - Duration duration = new Duration(false, 23, 5, 3, 43, 97); - Duration absDuration; - - boolean expectedValue = true; - boolean returnedValue; - //act - absDuration = duration.abs(); - returnedValue = absDuration.isPositive(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of plusDuration method, of class Duration. - */ - @Test - public void testPlusDuration() { - //arrange - Duration duration = new Duration(12, 0, 0, 0, 0); - Duration durationToAdd = new Duration(0, 5, 4, 2, 7); - Duration returnedDuration; - String expectedString = "+12:5:4:2:7"; - String returnedString; - - //act - returnedDuration = duration.plusDuration(durationToAdd); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of plusDays method, of class Duration. - */ - @Test - public void testPlusDays() { - //arrange - Duration duration = new Duration(12, 0, 0, 0, 0); - long daysToAdd = 1; - Duration returnedDuration; - String expectedString = "+13:0:0:0:0"; - String returnedString; - - //act - returnedDuration = duration.plusDays(daysToAdd); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of plusHours method, of class Duration. - */ - @Test - public void testPlusHours() { - //arrange - Duration duration = new Duration(12, 0, 0, 0, 0); - int hoursToAdd = 1; - Duration returnedDuration; - String expectedString = "+12:1:0:0:0"; - String returnedString; - - //act - returnedDuration = duration.plusHours(hoursToAdd); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of plusMinutes method, of class Duration. - */ - @Test - public void testPlusMinutes() { - //arrange - Duration duration = new Duration(12, 0, 0, 0, 0); - int minutesToAdd = 1; - Duration returnedDuration; - String expectedString = "+12:0:1:0:0"; - String returnedString; - - //act - returnedDuration = duration.plusMinutes(minutesToAdd); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of plusSeconds method, of class Duration. - */ - @Test - public void testPlusSeconds() { - //arrange - Duration duration = new Duration(12, 0, 0, 0, 0); - int secondsToAdd = 1; - Duration returnedDuration; - String expectedString = "+12:0:0:1:0"; - String returnedString; - - //act - returnedDuration = duration.plusSeconds(secondsToAdd); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of plusMilliseconds method, of class Duration. - */ - @Test - public void testPlusMilliseconds() { - //arrange - Duration duration = new Duration(12, 0, 0, 0, 0); - int millisecondsToAdd = 1; - Duration returnedDuration; - String expectedString = "+12:0:0:0:1"; - String returnedString; - - //act - returnedDuration = duration.plusMilliseconds(millisecondsToAdd); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of minusDuration method, of class Duration. - */ - @Test - public void testMinusDuration() { - //arrange - Duration duration = new Duration(12, 5, 4, 2, 7); - Duration durationToSubtract = new Duration(0, 5, 4, 2, 7); - Duration returnedDuration; - String expectedString = "+12:0:0:0:0"; - String returnedString; - - //act - returnedDuration = duration.minusDuration(durationToSubtract); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of minusDays method, of class Duration. - */ - @Test - public void testMinusDays() { - //arrange - Duration duration = new Duration(12, 5, 4, 2, 7); - long daysToSubtract = 1; - Duration returnedDuration; - String expectedString = "+11:5:4:2:7"; - String returnedString; - - //act - returnedDuration = duration.minusDays(daysToSubtract); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of minusHours method, of class Duration. - */ - @Test - public void testMinusHours() { - //arrange - Duration duration = new Duration(12, 5, 4, 2, 7); - int hoursToSubtract = 1; - Duration returnedDuration; - String expectedString = "+12:4:4:2:7"; - String returnedString; - - //act - returnedDuration = duration.minusHours(hoursToSubtract); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of minusMinutes method, of class Duration. - */ - @Test - public void testMinusMinutes() { - //arrange - Duration duration = new Duration(12, 5, 4, 2, 7); - int minutesToSubtract = 1; - Duration returnedDuration; - String expectedString = "+12:5:3:2:7"; - String returnedString; - - //act - returnedDuration = duration.minusMinutes(minutesToSubtract); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of minusSeconds method, of class Duration. - */ - @Test - public void testMinusSeconds() { - //arrange - Duration duration = new Duration(12, 5, 4, 2, 7); - int secondsToSubtract = 1; - Duration returnedDuration; - String expectedString = "+12:5:4:1:7"; - String returnedString; - - //act - returnedDuration = duration.minusSeconds(secondsToSubtract); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of minusMilliseconds method, of class Duration. - */ - @Test - public void testMinusMilliseconds() { - //arrange - Duration duration = new Duration(12, 5, 4, 2, 7); - int millisecondsToSubtract = 1; - Duration returnedDuration; - String expectedString = "+12:5:4:2:6"; - String returnedString; - - //act - returnedDuration = duration.minusMilliseconds(millisecondsToSubtract); - returnedString = returnedDuration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of toTotalDays method, of class Duration. - */ - @Test - public void testToTotalDays() { - //arrange - Duration duration = new Duration(14, 9, 17, 53, 834); - long expectedValue = 14; - long returnedValue; - //act - returnedValue = (long) Math.floor(duration.toTotalDays()); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of toTotalHours method, of class Duration. - */ - @Test - public void testToTotalHours() { - //arrange - Duration duration = new Duration(14, 9, 17, 53, 834); - long expectedValue = 345; - long returnedValue; - //act - returnedValue = (long) Math.floor(duration.toTotalHours()); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of toTotalMinutes method, of class Duration. - */ - @Test - public void testToTotalMinutes() { - //arrange - Duration duration = new Duration(14, 9, 17, 53, 834); - long expectedValue = 20717; - long returnedValue; - //act - returnedValue = (long) Math.floor(duration.toTotalMinutes()); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of toTotalSeconds method, of class Duration. - */ - @Test - public void testToTotalSeconds() { - //arrange - Duration duration = new Duration(14, 9, 17, 53, 834); - long expectedValue = 1243073; - long returnedValue; - //act - returnedValue = (long) Math.floor(duration.toTotalSeconds()); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of toTotalMilliseconds method, of class Duration. - */ - @Test - public void testToTotalMilliseconds() { - //arrange - Duration duration = new Duration(14, 9, 17, 53, 834); - long expectedValue = 1243073834; - long returnedValue; - //act - returnedValue = (long) Math.floor(duration.toTotalMilliseconds()); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of toJavaDuration method, of class Duration. - */ - @Test - public void testToJavaDuration() { - //arrange - Duration duration = new Duration(14, 9, 17, 53, 834); - long expectedTotalSeconds = (long) Math.floor(duration.toTotalSeconds()); - long returnedSeconds; - java.time.Duration javaDuration; - //act - javaDuration = duration.toJavaDuration(); - returnedSeconds = javaDuration.getSeconds(); - //assert - assertEquals(expectedTotalSeconds, returnedSeconds); - } - - /** - * Test of toString method, of class Duration. - */ - @Test - public void testToString1_ConstructorWithLongArgUsed() { - //arrange - String expectedString = "+23:5:3:43:97"; - String returnedString; - long countOfTotalMilliseconds = 2005423097; - - Duration duration = new Duration(countOfTotalMilliseconds); - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of toString method, of class Duration. - */ - @Test - public void testToString2_ConstructorWithLongArgUsed() { - //arrange - String expectedString = "-23:5:3:43:97"; - String returnedString; - long countOfTotalMilliseconds = -2005423097; - - Duration duration = new Duration(countOfTotalMilliseconds); - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } - - /** - * Test of toString method, of class Duration. - */ - @Test - public void testToString3_ConstructorWithLongArgUsed() { - //arrange - String expectedString = "+0:0:0:0:0"; - String returnedString; - long countOfTotalMilliseconds = 0; - - Duration duration = new Duration(countOfTotalMilliseconds); - //act - returnedString = duration.toString(); - //assert - assertEquals(expectedString, returnedString); - } -} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/LocalDateTimeTest.java b/src/test/java/org/nanoboot/powerframework/datetime/LocalDateTimeTest.java deleted file mode 100644 index 3f1bd80..0000000 --- a/src/test/java/org/nanoboot/powerframework/datetime/LocalDateTimeTest.java +++ /dev/null @@ -1,166 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class LocalDateTimeTest { - - /** - * - */ - public LocalDateTimeTest() { - } - - /** - * Test of constructor of class LocalDateTime. (String dateTimeInString) - */ - @Test - public void testLocalDateTime_1argString_day6MustBeReturned() { - //arrange - LocalDateTime localDateTime; - int expectedDay = 6; - int returnedDay; - //act - localDateTime = new LocalDateTime("1994-05-06 21:45:06:032"); - returnedDay = localDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of constructor of class LocalDateTime. (int year, int month, int - * day, int hour24Format, int minute, int second, int millisecond) - */ - @Test - public void testLocalDateTime_7args_day6MustBeReturned() { - //arrange - LocalDateTime localDateTime; - int expectedDay = 6; - int returnedDay; - //act - localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); - returnedDay = localDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of constructor of class LocalDateTime. (UniversalDateTime - * universalDateTime) - */ - @Test - public void testLocalDateTime_1argUniversalDateTime_day6MustBeReturned() { - //arrange - LocalDateTime localDateTime; - UniversalDateTime universalDateTime; - int expectedDay = 6; - int returnedDay; - //act - universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); - localDateTime = new LocalDateTime(universalDateTime); - returnedDay = localDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of constructor of class LocalDateTime. (ZonedDateTime zonedDateTime) - */ - @Test - public void testLocalDateTime_1argZonedDateTime_day6MustBeReturned() { - //arrange - LocalDateTime localDateTime; - TimeZone timeZone; - ZonedDateTime zonedDateTime; - int expectedDay = 6; - int returnedDay; - //act - timeZone = new TimeZone("Australia/Sydney"); - zonedDateTime = new ZonedDateTime(new LocalDateTime(1994, 5, 6, 21, 45, 6, 32), timeZone); - localDateTime = new LocalDateTime(zonedDateTime); - returnedDay = localDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of toUniversalDateTime method, of class LocalDateTime. - */ - @Test - public void testToUniversalDateTime() { - //arrange - LocalDateTime localDateTime; - UniversalDateTime universalDateTime; - int expectedDay = 6; - int returnedDay; - //act - localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); - universalDateTime = localDateTime.toUniversalDateTime(); - returnedDay = universalDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of toZonedDateTime method, of class LocalDateTime. - */ - @Test - public void testToZonedDateTime() { - //arrange - LocalDateTime localDateTime; - TimeZone timeZone; - ZonedDateTime zonedDateTime; - int expectedDay = 6; - int returnedDay; - //act - timeZone = new TimeZone("Australia/Sydney"); - localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); - zonedDateTime = localDateTime.toZonedDateTime(timeZone); - returnedDay = zonedDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of toJavaLocalDateTime method, of class LocalDateTime. - */ - @Test - public void testToJavaLocalDateTime() { - //arrange - LocalDateTime localDateTime; - java.time.LocalDateTime javaLocalDateTime; - int expectedDay = 6; - int returnedDay; - //act - localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); - javaLocalDateTime = localDateTime.toJavaLocalDateTime(); - returnedDay = javaLocalDateTime.getDayOfMonth(); - //assert - assertEquals(expectedDay, returnedDay); - } - -} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/TimeUnitsValidatorTest.java b/src/test/java/org/nanoboot/powerframework/datetime/TimeUnitsValidatorTest.java deleted file mode 100644 index 9a525ed..0000000 --- a/src/test/java/org/nanoboot/powerframework/datetime/TimeUnitsValidatorTest.java +++ /dev/null @@ -1,288 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.nanoboot.powerframework.PowerRuntimeException; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class TimeUnitsValidatorTest { - - /** - * - */ - public TimeUnitsValidatorTest() { - } - - /** - * Test of isHourValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsHourValid_HourIs13_ThereShouldBeReturnedTrue() { - //arrange - int hour = 13; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isHourValid(hour); - //assert - assertTrue(returnedValue); - } - - /** - * Test of isHourValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsHourValid_HourIsMinus1_ThereShouldBeReturneFalse() { - //arrange - int hour = -1; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isHourValid(hour); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isHourValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsHourValid_HourIs24_ThereShouldBeReturneFalse() { - //arrange - int hour = 24; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isHourValid(hour); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isMinuteValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsMinuteValid_MinuteIs34__ThereShouldBeReturnedTrue() { - //arrange - int minute = 34; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isMinuteValid(minute); - //assert - assertTrue(returnedValue); - } - - /** - * Test of isMinuteValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsMinuteValid_MinuteIsMinus1_ThereShouldBeReturneFalse() { - //arrange - int minute = -1; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isMinuteValid(minute); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isMinuteValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsMinuteValid_MinuteIs60_ThereShouldBeReturneFalse() { - //arrange - int minute = 60; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isMinuteValid(minute); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isSecondValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsSecondValid_SecondIs46__ThereShouldBeReturnedTrue() { - //arrange - int second = 46; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isSecondValid(second); - //assert - assertTrue(returnedValue); - } - - /** - * Test of isSecondValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsSecondValid_SecondIsMinus1__ThereShouldBeReturneFalse() { - //arrange - int second = -1; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isSecondValid(second); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isSecondValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsSecondValid_SecondIs60__ThereShouldBeReturneFalse() { - //arrange - int second = 60; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isSecondValid(second); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isMillisecondValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsMillisecondValid_MillisecondIs843__ThereShouldBeReturnedTrue() { - //arrange - int millisecond = 843; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isMillisecondValid(millisecond); - //assert - assertTrue(returnedValue); - } - - /** - * Test of isMillisecondValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsMillisecondValid_MillisecondIsMinus1_ThereShouldBeReturneFalse() { - //arrange - int millisecond = -1; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isMillisecondValid(millisecond); - //assert - assertFalse(returnedValue); - } - - /** - * Test of isMillisecondValid method, of class TimeUnitsValidator. - */ - @Test - public void testIsMillisecondValid_MillisecondIs1000_ThereShouldBeReturneFalse() { - //arrange - int millisecond = 1000; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.isMillisecondValid(millisecond); - //assert - assertFalse(returnedValue); - } - - /** - * Test of areAllTimeUnitsValid method, of class TimeUnitsValidator. - */ - @Test - public void testAreAllTimeUnitsValid_ThereShouldBeReturneTrue() { - //arrange - int hour = 2; - int minute = 34; - int second = 23; - int millisecond = 428; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.areAllTimeUnitsValid(hour, minute, second, millisecond); - //assert - assertTrue(returnedValue); - } - - /** - * Test of areAllTimeUnitsValid method, of class TimeUnitsValidator. - */ - @Test - public void testAreAllTimeUnitsValid_ThereShouldBeReturneFalse() { - //arrange - int hour = 112; - int minute = 134; - int second = 123; - int millisecond = 1428; - boolean returnedValue; - //act - returnedValue = TimeUnitsValidator.areAllTimeUnitsValid(hour, minute, second, millisecond); - //assert - assertFalse(returnedValue); - } - - /** - * Test of checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException - * method, of class TimeUnitsValidator. - */ - @Test - public void testCheckInputValuesForTimeAndIfThereIsAnInvalidOneThrowException_ThereShouldBeThrownNoPowerRuntimeException() { - //arrange - int hour = 12; - int minute = 34; - int second = 23; - int millisecond = 428; - boolean isExceptionThrown = false; - //act - try { - TimeUnitsValidator.checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException(hour, minute, second, millisecond); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } - //assert - if (isExceptionThrown) { - fail("There should be thrown no PowerRuntimeException"); - } - } - - /** - * Test of checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException - * method, of class TimeUnitsValidator. - */ - @Test - public void testCheckInputValuesForTimeAndIfThereIsAnInvalidOneThrowException_ThereShouldBeThrownPowerRuntimeException() { - //arrange - int hour = 112; - int minute = 134; - int second = 123; - int millisecond = 1428; - boolean isExceptionThrown = false; - //act - try { - TimeUnitsValidator.checkInputValuesForTimeAndIfThereIsAnInvalidOneThrowException(hour, minute, second, millisecond); - } catch (PowerRuntimeException e) { - isExceptionThrown = true; - } - //assert - if (!isExceptionThrown) { - fail("There should be thrown PowerRuntimeException"); - } - } -} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/UniversalDateTimeTest.java b/src/test/java/org/nanoboot/powerframework/datetime/UniversalDateTimeTest.java deleted file mode 100644 index 9b55a3b..0000000 --- a/src/test/java/org/nanoboot/powerframework/datetime/UniversalDateTimeTest.java +++ /dev/null @@ -1,148 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class UniversalDateTimeTest { - - /** - * - */ - public UniversalDateTimeTest() { - } - - /** - * Test of constructor of class UniversalDateTime. (String dateTimeInString) - */ - @Test - public void testUniversalDateTime_1argString_day6MustBeReturned() { - //arrange - UniversalDateTime universalDateTime; - int expectedDay = 6; - int returnedDay; - //act - universalDateTime = new UniversalDateTime("1994-05-06 21:45:06:032"); - returnedDay = universalDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of constructor of class UniversalDateTime. (int year, int month, int - * day, int hour24Format, int minute, int second, int millisecond) - */ - @Test - public void testUniversalDateTime_7args_day6MustBeReturned() { - //arrange - UniversalDateTime universalDateTime; - int expectedDay = 6; - int returnedDay; - //act - universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); - returnedDay = universalDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of constructor of class UniversalDateTime. (ZonedDateTime - * zonedDateTime) - */ - @Test - public void testUniversalDateTime_1argZonedDateTime_day6MustBeReturned() { - //arrange - UniversalDateTime universalDateTime; - TimeZone timeZone; - ZonedDateTime zonedDateTime; - int expectedDay = 5; - int returnedDay; - //act - timeZone = new TimeZone("Australia/Sydney"); - zonedDateTime = new ZonedDateTime(new LocalDateTime(1994, 5, 6, 21, 45, 6, 32), timeZone); - universalDateTime = new UniversalDateTime(zonedDateTime); - returnedDay = universalDateTime.getMonth(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of constructor of class UniversalDateTime. (LocalDateTime - * localDateTime) - */ - @Test - public void testUniversalDateTime_1argLocalDateTime_day6MustBeReturned() { - //arrange - UniversalDateTime universalDateTime; - LocalDateTime localDateTime; - int expectedDay = 6; - int returnedDay; - //act - localDateTime = new LocalDateTime(1994, 5, 6, 21, 45, 6, 32); - universalDateTime = new UniversalDateTime(localDateTime); - - returnedDay = localDateTime.getDay(); - //assert - assertEquals(expectedDay, returnedDay); - } - - /** - * Test of toZonedDateTime method, of class LocalDateTime. - */ - @Test - public void testToZonedDateTime() { - //arrange - UniversalDateTime universalDateTime; - ZonedDateTime zonedDateTime; - int expectedMonth = 5; - int returnedMonth; - //act - universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); - zonedDateTime = universalDateTime.toZonedDateTime(); - returnedMonth = zonedDateTime.getMonth(); - //assert - assertEquals(expectedMonth, returnedMonth); - } - - /** - * Test of testToLocalDateTime method, of class LocalDateTime. - */ - @Test - public void testToLocalDateTime() { - //arrange - UniversalDateTime universalDateTime; - LocalDateTime localDateTime; - - int expectedMonth = 5; - int returnedMonth; - //act - universalDateTime = new UniversalDateTime(1994, 5, 6, 21, 45, 6, 32); - localDateTime = universalDateTime.toLocalDateTime(); - returnedMonth = universalDateTime.getMonth(); - //assert - assertEquals(expectedMonth, returnedMonth); - } -} diff --git a/src/test/java/org/nanoboot/powerframework/datetime/ZonedDateTimeTest.java b/src/test/java/org/nanoboot/powerframework/datetime/ZonedDateTimeTest.java deleted file mode 100644 index f60789a..0000000 --- a/src/test/java/org/nanoboot/powerframework/datetime/ZonedDateTimeTest.java +++ /dev/null @@ -1,157 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.datetime; - -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class ZonedDateTimeTest { - - /** - * - */ - public ZonedDateTimeTest() { - } - - /** - * Test of convertDateTimeFromOneTimeZoneToAnother method, of class - * ZonedDateTime. - */ - @Test - public void testConvertDateTimeFromOneTimeZoneToAnother() { - //arrange - TimeZone oldTimeZone = new TimeZone("Australia/West"); - ZonedDateTime oldZonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 11, 5, 10, 5, 4, 64), oldTimeZone); - String stringRepresentationOfOldZonedDateTime = oldZonedDateTime.toString(); - - String expectedStringValue = "1995-11-05 13:05:04:064"; - String returnedStringValue; - TimeZone newTimeZone = new TimeZone("Australia/Sydney"); - //act - returnedStringValue = ZonedDateTime.convertDateTimeFromOneTimeZoneToAnother(stringRepresentationOfOldZonedDateTime, oldTimeZone, newTimeZone); - //assert - assertEquals(expectedStringValue, returnedStringValue); - } - - /** - * Test of getTimeZone method, of class ZonedDateTime. - */ - @Test - public void testGetTimeZone() { - //arrange - String timeZoneID = "Australia/West"; - TimeZone timeZone = new TimeZone(timeZoneID); - ZonedDateTime zonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 8, 5, 10, 5, 4, 64), timeZone); - TimeZone returnedTimeZone; - String returnedZoneID; - //act - returnedTimeZone = zonedDateTime.getTimeZone(); - returnedZoneID = returnedTimeZone.getTimeZoneID(); - //assert - assertEquals(timeZoneID, returnedZoneID); - - } - - /** - * Test of toUniversalDateTime method, of class ZonedDateTime. - */ - @Test - public void testToUniversalDateTime() { - //arrange - TimeZone oldTimeZone = new TimeZone("Australia/West"); - ZonedDateTime zonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 8, 5, 10, 5, 4, 64), oldTimeZone); - String stringRepresentationOfZonedDateTime = zonedDateTime.toString(); - - String expectedStringValue = "1995-08-05 02:05:04:064"; - String returnedStringValue; - //act - UniversalDateTime universalDateTime = zonedDateTime.toUniversalDateTime(); - returnedStringValue = universalDateTime.toString(); - //assert - assertEquals(expectedStringValue, returnedStringValue); - } - - /** - * Test of toLocalDateTime method, of class ZonedDateTime. - */ - @Test - public void testToLocalDateTime() { - //arrange - TimeZone oldTimeZone = new TimeZone("Australia/West"); - ZonedDateTime zonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 8, 5, 10, 5, 4, 64), oldTimeZone); - String stringRepresentationOfZonedDateTime = zonedDateTime.toString(); - - String expectedStringValue = "1995-08-05 10:05:04:064"; - String returnedStringValue; - //act - LocalDateTime localDateTime = zonedDateTime.toLocalDateTime(); - returnedStringValue = localDateTime.toString(); - //assert - assertEquals(expectedStringValue, returnedStringValue); - } - - /** - * Test of toZonedDateTime method, of class ZonedDateTime. - */ - @Test - public void testToZonedDateTime() { - //arrange - TimeZone oldTimeZone = new TimeZone("Australia/West"); - ZonedDateTime oldZonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 11, 5, 10, 5, 4, 64), oldTimeZone); - String stringRepresentationOfOldZonedDateTime = oldZonedDateTime.toString(); - - TimeZone newTimeZone = new TimeZone("Australia/Sydney"); - ZonedDateTime newZonedDateTime = new ZonedDateTime(new LocalDateTime(1995, 11, 5, 13, 5, 4, 64), oldTimeZone); - - String expectedStringValue = "1995-11-05 13:05:04:064"; - String returnedStringValue; - //act - String stringRepresentationOfNewZonedDateTime = newZonedDateTime.toString(); - returnedStringValue = stringRepresentationOfNewZonedDateTime; - //assert - assertEquals(expectedStringValue, returnedStringValue); - } - - /** - * Test of toJavaZonedDateTime method, of class ZonedDateTime. - */ - @Test - public void testToJavaZonedDateTime() { - //arrange - TimeZone timeZone = new TimeZone("Australia/West"); - ZonedDateTime zonedDateTime; - zonedDateTime = new ZonedDateTime(new LocalDateTime(1994, 5, 6, 21, 45, 6, 32), timeZone); - java.time.ZonedDateTime javaZonedDateTime; - int expectedDay = 6; - int returnedDay; - //act - - javaZonedDateTime = zonedDateTime.toJavaZonedDateTime(); - returnedDay = javaZonedDateTime.getDayOfMonth(); - //assert - assertEquals(expectedDay, returnedDay); - } - -} diff --git a/src/test/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGeneratorTest.java b/src/test/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGeneratorTest.java deleted file mode 100644 index 51daf65..0000000 --- a/src/test/java/org/nanoboot/powerframework/pseudorandom/PseudoRandomGeneratorTest.java +++ /dev/null @@ -1,125 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.pseudorandom; - -import org.nanoboot.powerframework.datetime.DateTime; -import org.nanoboot.powerframework.datetime.LocalDateTime; -import org.nanoboot.powerframework.datetime.UniversalDateTime; -import org.nanoboot.powerframework.json.JsonArray; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class PseudoRandomGeneratorTest { - - public PseudoRandomGeneratorTest() { - } - - /** - * Test of getLong method, of class PseudoRandomGenerator. - */ - @Test - public void testGetLong() { - //arrange - PseudoRandomGenerator pseudoRandomGenerator = new PseudoRandomGenerator(987, new LocalDateTime(1991, 5, 24, 6, 28, 53, 862)); - - long expectedValue = 420726198994l; - long returnedValue; - //act - for (int i = 1; i <= 4; i++) { - pseudoRandomGenerator.getLong(0, 499999999999l); - } - returnedValue = pseudoRandomGenerator.getLong(0, 499999999999l); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of getInt method, of class PseudoRandomGenerator. - */ - @Test - public void testGetInt() { - //arrange - PseudoRandomGenerator pseudoRandomGenerator = new PseudoRandomGenerator(987, new LocalDateTime(1991, 5, 24, 6, 28, 53, 862)); - - int expectedValue = 198994; - int returnedValue; - //act - for (int i = 1; i <= 4; i++) { - pseudoRandomGenerator.getInt(0, 499999); - } - returnedValue = pseudoRandomGenerator.getInt(0, 499999); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of getBoolean method, of class PseudoRandomGenerator. - */ - @Test - public void testGetBoolean() { - //arrange - PseudoRandomGenerator pseudoRandomGenerator = new PseudoRandomGenerator(987, new LocalDateTime(1991, 5, 24, 6, 28, 53, 862)); - JsonArray jsonArray = new JsonArray(); - String expectedString = "[true,false,false,true,false,false,false,false,true,true,false,true,false,false,true,true,true,true,true,false,true,true,false,true,true,false,false,true,true,false,false,false,false,false,false,true,false,true,true,true,false,false,false,true,false,true,true,false,false,false]"; - String returnedString; - //act - for (int i = 1; i <= 50; i++) { - jsonArray.addBoolean(pseudoRandomGenerator.getBoolean()); - } - returnedString = jsonArray.toMinimalString(); - //assert - assertEquals(expectedString, returnedString); - } - - @Test - public void testTheSame100thOrderHasTheSame() { - //arrange - int magicNumber = PseudoRandomGenerator.getInstance().getInt(0, 1000000); - DateTime dateTime = UniversalDateTime.getRandomUniversalDateTime(); - PseudoRandomGenerator pseudoRandomGenerator; - pseudoRandomGenerator = new PseudoRandomGenerator(magicNumber, dateTime); - for (int i = 1; i < 100; i++) { - pseudoRandomGenerator.getInt(0, 1000000); - } - int expectedValue = pseudoRandomGenerator.getInt(0, 1000000); - int returnedValue; - - pseudoRandomGenerator = new PseudoRandomGenerator(magicNumber, dateTime); - for (int i = 1; i < 100; i++) { - if (PseudoRandomGenerator.getInstance().getBoolean()) { - pseudoRandomGenerator.getBoolean(); - } else if (PseudoRandomGenerator.getInstance().getBoolean()) { - pseudoRandomGenerator.getInt(0, PseudoRandomGenerator.getInstance().getInt(0, 1000000)); - } else { - pseudoRandomGenerator.getLong(0, PseudoRandomGenerator.getInstance().getInt(0, 1000000)); - } - } - //act - returnedValue = pseudoRandomGenerator.getInt(0, 1000000); - //assert - assertEquals(expectedValue, returnedValue); - } - -} diff --git a/src/test/java/org/nanoboot/powerframework/pseudorandom/SeedTest.java b/src/test/java/org/nanoboot/powerframework/pseudorandom/SeedTest.java deleted file mode 100644 index 7c2eb5c..0000000 --- a/src/test/java/org/nanoboot/powerframework/pseudorandom/SeedTest.java +++ /dev/null @@ -1,71 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////////////////////// -// power-framework: Java library with many purposes of usage. -// Copyright (C) 2016-2022 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; -// version 2.1 of the License only. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -/////////////////////////////////////////////////////////////////////////////////////////////// - -package org.nanoboot.powerframework.pseudorandom; - -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author Robert Vokac e-mail: robertvokac@nanoboot.org - */ -public class SeedTest { - - public SeedTest() { - } - - /** - * Test of getNextNumber method, of class Seed. - */ - @Test - public void testGetNextNumber() { - //arrange - Seed seed = new Seed(5); - long expectedValue = 1679444804; - long returnedValue; - //act - for (int i = 1; i <= 37; i++) { - seed.getNextNumber(); - } - returnedValue = seed.getNextNumber(); - //assert - assertEquals(expectedValue, returnedValue); - } - - /** - * Test of jump method, of class Seed. - */ - @Test - public void testJump() { - //arrange - Seed seed = new Seed(5); - long expectedValue = 1679444804; - long returnedValue; - //act - for (int i = 1; i <= 37; i++) { - seed.jump(); - } - returnedValue = seed.getNextNumber(); - //assert - assertEquals(expectedValue, returnedValue); - } - -}

    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 ^S;u##hq#h*>7c)f6&u@bZcAFvPCd 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