Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
0ed4747a71 | |||
ced1dfe937 |
@ -1,15 +0,0 @@
|
||||
# Path to sources
|
||||
#sonar.sources=.
|
||||
#sonar.exclusions=
|
||||
#sonar.inclusions=
|
||||
|
||||
# Path to tests
|
||||
#sonar.tests=
|
||||
#sonar.test.exclusions=
|
||||
#sonar.test.inclusions=
|
||||
|
||||
# Source encoding
|
||||
#sonar.sourceEncoding=UTF-8
|
||||
|
||||
# Exclusions for copy-paste detection
|
||||
#sonar.cpd.exclusions=
|
@ -1,5 +1,4 @@
|
||||
language: java
|
||||
dist: trusty # Xenial build environment won't allow installation of Java 8
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
|
@ -8,6 +8,6 @@ This will generate code coverage report in each of the modules. In order to view
|
||||
|
||||
Please note that the above folder is created under each of the modules. For example:
|
||||
* adapter/target/site/jacoco/index.html
|
||||
* business-delegate/target/site/jacoco/index.html
|
||||
* busniess-delegate/target/site/jacoco/index.html
|
||||
|
||||
|
||||
|
@ -7,17 +7,17 @@
|
||||
[](https://travis-ci.org/iluwatar/java-design-patterns)
|
||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://sonarcloud.io/dashboard/index/com.iluwatar%3Ajava-design-patterns)
|
||||
|
||||
# Introduction
|
||||
|
||||
Design patterns are the best formalized practices a programmer can use to
|
||||
Design patterns are formalized best practices that the programmer can use to
|
||||
solve common problems when designing an application or system.
|
||||
|
||||
Design patterns can speed up the development process by providing tested, proven
|
||||
development paradigms.
|
||||
|
||||
Reusing design patterns help prevent subtle issues which cause major
|
||||
Reusing design patterns helps to prevent subtle issues that can cause major
|
||||
problems, and it also improves code readability for coders and architects who
|
||||
are familiar with the patterns.
|
||||
|
||||
|
@ -29,14 +29,19 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>abstract-document</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
@ -54,16 +54,17 @@ public abstract class AbstractDocument implements Document {
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
|
||||
Optional<List<Map<String, Object>>> any = Stream.of(get(key)).filter(Objects::nonNull)
|
||||
Optional<List<Map<String, Object>>> any = Stream.of(get(key)).filter(el -> el != null)
|
||||
.map(el -> (List<Map<String, Object>>) el).findAny();
|
||||
return any.map(maps -> maps.stream().map(constructor)).orElseGet(Stream::empty);
|
||||
return any.isPresent() ? any.get().stream().map(constructor) : Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(getClass().getName()).append("[");
|
||||
properties.forEach((key, value) -> builder.append("[").append(key).append(" : ").append(value).append("]"));
|
||||
properties.entrySet()
|
||||
.forEach(e -> builder.append("[").append(e.getKey()).append(" : ").append(e.getValue()).append("]"));
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
@ -22,15 +22,17 @@
|
||||
*/
|
||||
package com.iluwatar.abstractdocument;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.iluwatar.abstractdocument.domain.Car;
|
||||
import com.iluwatar.abstractdocument.domain.HasModel;
|
||||
import com.iluwatar.abstractdocument.domain.HasParts;
|
||||
import com.iluwatar.abstractdocument.domain.HasPrice;
|
||||
import com.iluwatar.abstractdocument.domain.HasType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.iluwatar.abstractdocument.domain.Car;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Abstract Document pattern enables handling additional, non-static
|
||||
@ -53,20 +55,20 @@ public class App {
|
||||
LOGGER.info("Constructing parts and car");
|
||||
|
||||
Map<String, Object> carProperties = new HashMap<>();
|
||||
carProperties.put(Property.MODEL.toString(), "300SL");
|
||||
carProperties.put(Property.PRICE.toString(), 10000L);
|
||||
carProperties.put(HasModel.PROPERTY, "300SL");
|
||||
carProperties.put(HasPrice.PROPERTY, 10000L);
|
||||
|
||||
Map<String, Object> wheelProperties = new HashMap<>();
|
||||
wheelProperties.put(Property.TYPE.toString(), "wheel");
|
||||
wheelProperties.put(Property.MODEL.toString(), "15C");
|
||||
wheelProperties.put(Property.PRICE.toString(), 100L);
|
||||
wheelProperties.put(HasType.PROPERTY, "wheel");
|
||||
wheelProperties.put(HasModel.PROPERTY, "15C");
|
||||
wheelProperties.put(HasPrice.PROPERTY, 100L);
|
||||
|
||||
Map<String, Object> doorProperties = new HashMap<>();
|
||||
doorProperties.put(Property.TYPE.toString(), "door");
|
||||
doorProperties.put(Property.MODEL.toString(), "Lambo");
|
||||
doorProperties.put(Property.PRICE.toString(), 300L);
|
||||
doorProperties.put(HasType.PROPERTY, "door");
|
||||
doorProperties.put(HasModel.PROPERTY, "Lambo");
|
||||
doorProperties.put(HasPrice.PROPERTY, 300L);
|
||||
|
||||
carProperties.put(Property.PARTS.toString(), Arrays.asList(wheelProperties, doorProperties));
|
||||
carProperties.put(HasParts.PROPERTY, Arrays.asList(wheelProperties, doorProperties));
|
||||
|
||||
Car car = new Car(carProperties);
|
||||
|
||||
|
@ -25,15 +25,16 @@ package com.iluwatar.abstractdocument.domain;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.iluwatar.abstractdocument.Document;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
|
||||
/**
|
||||
* HasModel trait for static access to 'model' property
|
||||
*/
|
||||
public interface HasModel extends Document {
|
||||
|
||||
String PROPERTY = "model";
|
||||
|
||||
default Optional<String> getModel() {
|
||||
return Optional.ofNullable((String) get(Property.MODEL.toString()));
|
||||
return Optional.ofNullable((String) get(PROPERTY));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,16 +25,16 @@ package com.iluwatar.abstractdocument.domain;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.iluwatar.abstractdocument.Document;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
|
||||
/**
|
||||
* HasParts trait for static access to 'parts' property
|
||||
*/
|
||||
public interface HasParts extends Document {
|
||||
|
||||
String PROPERTY = "parts";
|
||||
|
||||
default Stream<Part> getParts() {
|
||||
return children(Property.PARTS.toString(), Part::new);
|
||||
return children(PROPERTY, Part::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,16 +25,16 @@ package com.iluwatar.abstractdocument.domain;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.iluwatar.abstractdocument.Document;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
|
||||
/**
|
||||
* HasPrice trait for static access to 'price' property
|
||||
*/
|
||||
public interface HasPrice extends Document {
|
||||
|
||||
String PROPERTY = "price";
|
||||
|
||||
default Optional<Number> getPrice() {
|
||||
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
|
||||
return Optional.ofNullable((Number) get(PROPERTY));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,19 +22,19 @@
|
||||
*/
|
||||
package com.iluwatar.abstractdocument.domain;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.iluwatar.abstractdocument.Document;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* HasType trait for static access to 'type' property
|
||||
*/
|
||||
public interface HasType extends Document {
|
||||
|
||||
String PROPERTY = "type";
|
||||
|
||||
default Optional<String> getType() {
|
||||
return Optional.ofNullable((String) get(Property.TYPE.toString()));
|
||||
return Optional.ofNullable((String) get(PROPERTY));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.abstractdocument.domain.enums;
|
||||
|
||||
/**
|
||||
*
|
||||
* Enum To Describe Property type
|
||||
*
|
||||
*/
|
||||
public enum Property {
|
||||
|
||||
PARTS, TYPE, PRICE, MODEL
|
||||
}
|
@ -32,7 +32,6 @@ import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* AbstractDocument test class
|
||||
@ -82,8 +81,8 @@ public class AbstractDocumentTest {
|
||||
Map<String, Object> props = new HashMap<>();
|
||||
props.put(KEY, VALUE);
|
||||
DocumentImplementation document = new DocumentImplementation(props);
|
||||
assertTrue(document.toString().contains(KEY));
|
||||
assertTrue(document.toString().contains(VALUE));
|
||||
assertNotNull(document.toString().contains(KEY));
|
||||
assertNotNull(document.toString().contains(VALUE));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,17 +22,19 @@
|
||||
*/
|
||||
package com.iluwatar.abstractdocument;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import com.iluwatar.abstractdocument.domain.Car;
|
||||
import com.iluwatar.abstractdocument.domain.HasModel;
|
||||
import com.iluwatar.abstractdocument.domain.HasParts;
|
||||
import com.iluwatar.abstractdocument.domain.HasPrice;
|
||||
import com.iluwatar.abstractdocument.domain.HasType;
|
||||
import com.iluwatar.abstractdocument.domain.Part;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.iluwatar.abstractdocument.domain.Car;
|
||||
import com.iluwatar.abstractdocument.domain.Part;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Test for Part and Car
|
||||
@ -49,9 +51,9 @@ public class DomainTest {
|
||||
@Test
|
||||
public void shouldConstructPart() {
|
||||
Map<String, Object> partProperties = new HashMap<>();
|
||||
partProperties.put(Property.TYPE.toString(), TEST_PART_TYPE);
|
||||
partProperties.put(Property.MODEL.toString(), TEST_PART_MODEL);
|
||||
partProperties.put(Property.PRICE.toString(), TEST_PART_PRICE);
|
||||
partProperties.put(HasType.PROPERTY, TEST_PART_TYPE);
|
||||
partProperties.put(HasModel.PROPERTY, TEST_PART_MODEL);
|
||||
partProperties.put(HasPrice.PROPERTY, TEST_PART_PRICE);
|
||||
Part part = new Part(partProperties);
|
||||
|
||||
assertEquals(TEST_PART_TYPE, part.getType().get());
|
||||
@ -62,9 +64,9 @@ public class DomainTest {
|
||||
@Test
|
||||
public void shouldConstructCar() {
|
||||
Map<String, Object> carProperties = new HashMap<>();
|
||||
carProperties.put(Property.MODEL.toString(), TEST_CAR_MODEL);
|
||||
carProperties.put(Property.PRICE.toString(), TEST_CAR_PRICE);
|
||||
carProperties.put(Property.PARTS.toString(), Arrays.asList(new HashMap<>(), new HashMap<>()));
|
||||
carProperties.put(HasModel.PROPERTY, TEST_CAR_MODEL);
|
||||
carProperties.put(HasPrice.PROPERTY, TEST_CAR_PRICE);
|
||||
carProperties.put(HasParts.PROPERTY, Arrays.asList(new HashMap<>(), new HashMap<>()));
|
||||
Car car = new Car(carProperties);
|
||||
|
||||
assertEquals(TEST_CAR_MODEL, car.getModel().get());
|
||||
|
@ -181,7 +181,7 @@ Use the Abstract Factory pattern when:
|
||||
* Source code http://java-design-patterns.com/patterns/abstract-factory/
|
||||
|
||||
</textarea>
|
||||
<script src="https://remarkjs.com/downloads/remark-latest.min.js">
|
||||
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
|
||||
</script>
|
||||
<script>
|
||||
var slideshow = remark.create();
|
||||
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>abstract-factory</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -29,17 +29,14 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class ElfKingdomFactory implements KingdomFactory {
|
||||
|
||||
@Override
|
||||
public Castle createCastle() {
|
||||
return new ElfCastle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public King createKing() {
|
||||
return new ElfKing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Army createArmy() {
|
||||
return new ElfArmy();
|
||||
}
|
||||
|
@ -29,17 +29,14 @@ package com.iluwatar.abstractfactory;
|
||||
*/
|
||||
public class OrcKingdomFactory implements KingdomFactory {
|
||||
|
||||
@Override
|
||||
public Castle createCastle() {
|
||||
return new OrcCastle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public King createKing() {
|
||||
return new OrcKing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Army createArmy() {
|
||||
return new OrcArmy();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>acyclic-visitor</artifactId>
|
||||
@ -56,6 +56,11 @@
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -47,7 +47,7 @@ public class App {
|
||||
Zoom zoom = new Zoom();
|
||||
Hayes hayes = new Hayes();
|
||||
|
||||
hayes.accept(conDos); // Hayes modem with Dos configurator
|
||||
hayes.accept(conDos); // Hayes modem with Unix configurator
|
||||
zoom.accept(conDos); // Zoom modem with Dos configurator
|
||||
hayes.accept(conUnix); // Hayes modem with Unix configurator
|
||||
zoom.accept(conUnix); // Zoom modem with Unix configurator
|
||||
|
@ -33,12 +33,10 @@ public class ConfigureForDosVisitor implements AllModemVisitor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
||||
|
||||
@Override
|
||||
public void visit(Hayes hayes) {
|
||||
LOGGER.info(hayes + " used with Dos configurator.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Zoom zoom) {
|
||||
LOGGER.info(zoom + " used with Dos configurator.");
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForUnixVisitor.class);
|
||||
|
||||
@Override
|
||||
public void visit(Zoom zoom) {
|
||||
LOGGER.info(zoom + " used with Unix configurator.");
|
||||
}
|
||||
|
@ -25,19 +25,27 @@ package com.iluwatar.acyclicvisitor;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.groups.Tuple.tuple;
|
||||
import static uk.org.lidalia.slf4jext.Level.INFO;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import uk.org.lidalia.slf4jtest.TestLogger;
|
||||
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor;
|
||||
import com.iluwatar.acyclicvisitor.Hayes;
|
||||
import com.iluwatar.acyclicvisitor.HayesVisitor;
|
||||
import com.iluwatar.acyclicvisitor.Zoom;
|
||||
import com.iluwatar.acyclicvisitor.ZoomVisitor;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
/**
|
||||
* ConfigureForUnixVisitor test class
|
||||
*/
|
||||
public class ConfigureForUnixVisitorTest {
|
||||
|
||||
private static final TestLogger LOGGER = TestLoggerFactory.getTestLogger(ConfigureForUnixVisitor.class);
|
||||
TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForUnixVisitor.class);
|
||||
|
||||
@AfterEach
|
||||
public void clearLoggers() {
|
||||
@ -51,7 +59,7 @@ public class ConfigureForUnixVisitorTest {
|
||||
|
||||
conUnix.visit(zoom);
|
||||
|
||||
assertThat(LOGGER.getLoggingEvents()).extracting("level", "message").contains(
|
||||
assertThat(logger.getLoggingEvents()).extracting("level", "message").contains(
|
||||
tuple(INFO, zoom + " used with Unix configurator."));
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>adapter</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -53,6 +53,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
@ -85,4 +90,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -53,6 +53,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -53,6 +53,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
@ -76,4 +81,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
@ -31,7 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
*/
|
||||
public class InventoryControllerTest {
|
||||
@Test
|
||||
public void testGetProductInventories() {
|
||||
public void testGetProductInventories() throws Exception {
|
||||
InventoryController inventoryController = new InventoryController();
|
||||
|
||||
int numberOfInventories = inventoryController.getProductInventories();
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>aggregator-microservices</artifactId>
|
||||
|
@ -43,7 +43,7 @@ A remote services represented as a singleton.
|
||||
public class RemoteService implements RemoteServiceInterface {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
|
||||
private static RemoteService service = null;
|
||||
private static RemoteService service = null;2
|
||||
|
||||
static synchronized RemoteService getRemoteService() {
|
||||
if (service == null) {
|
||||
|
@ -29,15 +29,20 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ambassador</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
package com.iluwatar.ambassador;
|
||||
|
||||
import com.iluwatar.ambassador.util.RandomProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -32,10 +31,9 @@ import static java.lang.Thread.sleep;
|
||||
* A remote legacy application represented by a Singleton implementation.
|
||||
*/
|
||||
public class RemoteService implements RemoteServiceInterface {
|
||||
static final int THRESHOLD = 200;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
|
||||
private static RemoteService service = null;
|
||||
private final RandomProvider randomProvider;
|
||||
|
||||
static synchronized RemoteService getRemoteService() {
|
||||
if (service == null) {
|
||||
@ -44,33 +42,24 @@ public class RemoteService implements RemoteServiceInterface {
|
||||
return service;
|
||||
}
|
||||
|
||||
private RemoteService() {
|
||||
this(Math::random);
|
||||
}
|
||||
private RemoteService() {}
|
||||
|
||||
/**
|
||||
* This constuctor is used for testing purposes only.
|
||||
*/
|
||||
RemoteService(RandomProvider randomProvider) {
|
||||
this.randomProvider = randomProvider;
|
||||
}
|
||||
/**
|
||||
* Remote function takes a value and multiplies it by 10 taking a random amount of time.
|
||||
* Will sometimes return -1. This imitates connectivity issues a client might have to account for.
|
||||
* @param value integer value to be multiplied.
|
||||
* @return if waitTime is less than {@link RemoteService#THRESHOLD}, it returns value * 10,
|
||||
* otherwise {@link RemoteServiceInterface#FAILURE}.
|
||||
* @return if waitTime is more than 200ms, it returns value * 10, otherwise -1.
|
||||
*/
|
||||
@Override
|
||||
public long doRemoteFunction(int value) {
|
||||
|
||||
long waitTime = (long) Math.floor(randomProvider.random() * 1000);
|
||||
long waitTime = (long) Math.floor(Math.random() * 1000);
|
||||
|
||||
try {
|
||||
sleep(waitTime);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Thread sleep state interrupted", e);
|
||||
}
|
||||
return waitTime <= THRESHOLD ? value * 10 : FAILURE;
|
||||
return waitTime >= 200 ? value * 10 : -1;
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ package com.iluwatar.ambassador;
|
||||
* Interface shared by ({@link RemoteService}) and ({@link ServiceAmbassador}).
|
||||
*/
|
||||
interface RemoteServiceInterface {
|
||||
int FAILURE = -1;
|
||||
|
||||
|
||||
long doRemoteFunction(int value) throws Exception;
|
||||
}
|
||||
|
@ -59,15 +59,15 @@ public class ServiceAmbassador implements RemoteServiceInterface {
|
||||
private long safeCall(int value) {
|
||||
|
||||
int retries = 0;
|
||||
long result = FAILURE;
|
||||
long result = -1;
|
||||
|
||||
for (int i = 0; i < RETRIES; i++) {
|
||||
|
||||
if (retries >= RETRIES) {
|
||||
return FAILURE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((result = checkLatency(value)) == FAILURE) {
|
||||
if ((result = checkLatency(value)) == -1) {
|
||||
LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
|
||||
retries++;
|
||||
try {
|
||||
|
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.ambassador.util;
|
||||
|
||||
/**
|
||||
* An interface for randomness. Useful for testing purposes.
|
||||
*/
|
||||
public interface RandomProvider {
|
||||
double random();
|
||||
}
|
@ -24,8 +24,6 @@ package com.iluwatar.ambassador;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for {@link Client}
|
||||
*/
|
||||
@ -37,6 +35,6 @@ public class ClientTest {
|
||||
Client client = new Client();
|
||||
long result = client.useService(10);
|
||||
|
||||
assertTrue(result == 100 || result == RemoteService.FAILURE);
|
||||
assert result == 100 || result == -1;
|
||||
}
|
||||
}
|
||||
|
@ -22,43 +22,16 @@
|
||||
*/
|
||||
package com.iluwatar.ambassador;
|
||||
|
||||
import com.iluwatar.ambassador.util.RandomProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for {@link RemoteService}
|
||||
*/
|
||||
public class RemoteServiceTest {
|
||||
|
||||
@Test
|
||||
public void testFailedCall() {
|
||||
RemoteService remoteService = new RemoteService(
|
||||
new StaticRandomProvider(0.21));
|
||||
long result = remoteService.doRemoteFunction(10);
|
||||
assertEquals(RemoteServiceInterface.FAILURE, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulCall() {
|
||||
RemoteService remoteService = new RemoteService(
|
||||
new StaticRandomProvider(0.2));
|
||||
long result = remoteService.doRemoteFunction(10);
|
||||
assertEquals(100, result);
|
||||
}
|
||||
|
||||
private class StaticRandomProvider implements RandomProvider {
|
||||
private double value;
|
||||
|
||||
StaticRandomProvider(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double random() {
|
||||
return value;
|
||||
}
|
||||
public void test() {
|
||||
long result = RemoteService.getRemoteService().doRemoteFunction(10);
|
||||
assert result == 100 || result == -1;
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,6 @@ package com.iluwatar.ambassador;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for {@link ServiceAmbassador}
|
||||
*/
|
||||
@ -34,6 +32,6 @@ public class ServiceAmbassadorTest {
|
||||
@Test
|
||||
public void test() {
|
||||
long result = new ServiceAmbassador().doRemoteFunction(10);
|
||||
assertTrue(result == 100 || result == RemoteServiceInterface.FAILURE);
|
||||
assert result == 100 || result == -1;
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>api-gateway-service</artifactId>
|
||||
@ -48,14 +48,15 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
@ -66,6 +67,10 @@
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -84,4 +89,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -53,6 +53,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
@ -76,4 +81,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
|
@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<artifactId>api-gateway</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -53,6 +53,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
@ -76,4 +81,4 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>async-method-invocation</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -29,12 +29,17 @@
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>balking</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
@ -43,4 +48,4 @@
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
</project>
|
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.balking;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* An interface to simulate delay while executing some work.
|
||||
*/
|
||||
public interface DelayProvider {
|
||||
void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
|
||||
}
|
@ -25,38 +25,17 @@ package com.iluwatar.balking;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Washing machine class
|
||||
*/
|
||||
public class WashingMachine {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
|
||||
private final DelayProvider delayProvider;
|
||||
|
||||
private WashingMachineState washingMachineState;
|
||||
|
||||
/**
|
||||
* Creates a new instance of WashingMachine
|
||||
*/
|
||||
public WashingMachine() {
|
||||
this((interval, timeUnit, task) -> {
|
||||
try {
|
||||
Thread.sleep(timeUnit.toMillis(interval));
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
task.run();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of WashingMachine using provided delayProvider. This constructor is used only for
|
||||
* unit testing purposes.
|
||||
*/
|
||||
public WashingMachine(DelayProvider delayProvider) {
|
||||
this.delayProvider = delayProvider;
|
||||
this.washingMachineState = WashingMachineState.ENABLED;
|
||||
washingMachineState = WashingMachineState.ENABLED;
|
||||
}
|
||||
|
||||
public WashingMachineState getWashingMachineState() {
|
||||
@ -77,8 +56,12 @@ public class WashingMachine {
|
||||
washingMachineState = WashingMachineState.WASHING;
|
||||
}
|
||||
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
|
||||
|
||||
this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
endOfWashing();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,8 +22,11 @@
|
||||
*/
|
||||
package com.iluwatar.balking;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@ -33,39 +36,32 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
*/
|
||||
public class WashingMachineTest {
|
||||
|
||||
private FakeDelayProvider fakeDelayProvider = new FakeDelayProvider();
|
||||
private volatile WashingMachineState machineStateGlobal;
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
public void wash() {
|
||||
WashingMachine washingMachine = new WashingMachine(fakeDelayProvider);
|
||||
|
||||
washingMachine.wash();
|
||||
washingMachine.wash();
|
||||
|
||||
WashingMachineState machineStateGlobal = washingMachine.getWashingMachineState();
|
||||
|
||||
fakeDelayProvider.task.run();
|
||||
|
||||
// washing machine remains in washing state
|
||||
public void wash() throws Exception {
|
||||
WashingMachine washingMachine = new WashingMachine();
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(2);
|
||||
executorService.execute(washingMachine::wash);
|
||||
executorService.execute(() -> {
|
||||
washingMachine.wash();
|
||||
machineStateGlobal = washingMachine.getWashingMachineState();
|
||||
});
|
||||
executorService.shutdown();
|
||||
try {
|
||||
executorService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ie) {
|
||||
ie.printStackTrace();
|
||||
}
|
||||
assertEquals(WashingMachineState.WASHING, machineStateGlobal);
|
||||
|
||||
// washing machine goes back to enabled state
|
||||
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endOfWashing() {
|
||||
public void endOfWashing() throws Exception {
|
||||
WashingMachine washingMachine = new WashingMachine();
|
||||
washingMachine.wash();
|
||||
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
|
||||
}
|
||||
|
||||
private class FakeDelayProvider implements DelayProvider {
|
||||
private Runnable task;
|
||||
|
||||
@Override
|
||||
public void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task) {
|
||||
this.task = task;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bridge</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -37,7 +37,7 @@ public class HammerTest extends WeaponTest {
|
||||
* underlying weapon implementation.
|
||||
*/
|
||||
@Test
|
||||
public void testHammer() {
|
||||
public void testHammer() throws Exception {
|
||||
final Hammer hammer = spy(new Hammer(mock(FlyingEnchantment.class)));
|
||||
testBasicWeaponActions(hammer);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public class SwordTest extends WeaponTest {
|
||||
* underlying weapon implementation.
|
||||
*/
|
||||
@Test
|
||||
public void testSword() {
|
||||
public void testSword() throws Exception {
|
||||
final Sword sword = spy(new Sword(mock(FlyingEnchantment.class)));
|
||||
testBasicWeaponActions(sword);
|
||||
}
|
||||
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>builder</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -30,10 +30,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>business-delegate</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Bytecode
|
||||
folder: bytecode
|
||||
permalink: /patterns/bytecode/
|
||||
categories: Behavioral
|
||||
tags:
|
||||
- Java
|
||||
- Difficulty-Beginner
|
||||
---
|
||||
|
||||
## Intent
|
||||
Allows to encode behaviour as instructions for virtual machine.
|
||||
|
||||
## Applicability
|
||||
Use the Bytecode pattern when you have a lot of behavior you need to define and your
|
||||
game’s implementation language isn’t a good fit because:
|
||||
|
||||
* it’s too low-level, making it tedious or error-prone to program in.
|
||||
* iterating on it takes too long due to slow compile times or other tooling issues.
|
||||
* it has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Game programming patterns](http://gameprogrammingpatterns.com/bytecode.html)
|
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<class-diagram version="1.2.3" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
||||
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
||||
<class id="1" language="java" name="com.iluwatar.bytecode.VirtualMachine" project="bytecode"
|
||||
file="/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="455" y="173"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="2" language="java" name="com.iluwatar.bytecode.App" project="bytecode"
|
||||
file="/bytecode/src/main/java/com/iluwatar/bytecode/App.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="148" y="110"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<class id="3" language="java" name="com.iluwatar.bytecode.Wizard" project="bytecode"
|
||||
file="/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="148" y="416"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<association id="4">
|
||||
<end type="SOURCE" refId="1" navigable="false" variant="ASSOCIATION">
|
||||
<attribute id="5" name="wizards">
|
||||
<position height="18" width="48" x="296" y="291"/>
|
||||
</attribute>
|
||||
<multiplicity id="6" minimum="0" maximum="2147483647">
|
||||
<position height="0" width="0" x="-327" y="-27"/>
|
||||
</multiplicity>
|
||||
</end>
|
||||
<end type="TARGET" refId="3" navigable="true" variant="ASSOCIATION"/>
|
||||
<display labels="true" multiplicity="true"/>
|
||||
</association>
|
||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</classifier-display>
|
||||
<association-display labels="true" multiplicity="true"/>
|
||||
</class-diagram>
|
@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
The MIT License
|
||||
Copyright (c) 2019 Ilkka Seppälä
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.21.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>bytecode</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,79 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import com.iluwatar.bytecode.util.InstructionConverterUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The intention of Bytecode pattern is to give behavior the flexibility of data by encoding it as instructions
|
||||
* for a virtual machine.
|
||||
* An instruction set defines the low-level operations that can be performed. A series of instructions is encoded as
|
||||
* a sequence of bytes. A virtual machine executes these instructions one at a time,
|
||||
* using a stack for intermediate values. By combining instructions, complex high-level behavior can be defined.
|
||||
*
|
||||
* This pattern should be used when there is a need to define high number of behaviours and implementation engine
|
||||
* is not a good choice because
|
||||
* It is too lowe level
|
||||
* Iterating on it takes too long due to slow compile times or other tooling issues.
|
||||
* It has too much trust. If you want to ensure the behavior being defined can’t break the game,
|
||||
* you need to sandbox it from the rest of the codebase.
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Main app method
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
|
||||
Wizard wizard = new Wizard();
|
||||
wizard.setHealth(45);
|
||||
wizard.setAgility(7);
|
||||
wizard.setWisdom(11);
|
||||
vm.getWizards()[0] = wizard;
|
||||
|
||||
interpretInstruction("LITERAL 0", vm);
|
||||
interpretInstruction( "LITERAL 0", vm);
|
||||
interpretInstruction( "GET_HEALTH", vm);
|
||||
interpretInstruction( "LITERAL 0", vm);
|
||||
interpretInstruction( "GET_AGILITY", vm);
|
||||
interpretInstruction( "LITERAL 0", vm);
|
||||
interpretInstruction( "GET_WISDOM ", vm);
|
||||
interpretInstruction( "ADD", vm);
|
||||
interpretInstruction( "LITERAL 2", vm);
|
||||
interpretInstruction( "DIVIDE", vm);
|
||||
interpretInstruction( "ADD", vm);
|
||||
interpretInstruction( "SET_HEALTH", vm);
|
||||
}
|
||||
|
||||
private static void interpretInstruction(String instruction, VirtualMachine vm) {
|
||||
InstructionConverterUtil converter = new InstructionConverterUtil();
|
||||
vm.execute(converter.convertToByteCode(instruction));
|
||||
LOGGER.info(instruction + String.format("%" + (12 - instruction.length()) + "s", "" ) + vm.getStack());
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
/**
|
||||
* Representation of instructions understandable by virtual machine
|
||||
*/
|
||||
public enum Instruction {
|
||||
|
||||
LITERAL(1),
|
||||
SET_HEALTH(2),
|
||||
SET_WISDOM (3),
|
||||
SET_AGILITY(4),
|
||||
PLAY_SOUND(5),
|
||||
SPAWN_PARTICLES(6),
|
||||
GET_HEALTH(7),
|
||||
GET_AGILITY(8),
|
||||
GET_WISDOM(9),
|
||||
ADD(10),
|
||||
DIVIDE (11);
|
||||
|
||||
private int value;
|
||||
|
||||
Instruction(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts integer value to Instruction
|
||||
* @param value value of instruction
|
||||
* @return representation of the instruction
|
||||
*/
|
||||
public static Instruction getInstruction(int value) {
|
||||
for (int i = 0; i < Instruction.values().length; i++) {
|
||||
if (Instruction.values()[i].getIntValue() == value) {
|
||||
return Instruction.values()[i];
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid instruction value");
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Implementation of virtual machine
|
||||
*/
|
||||
public class VirtualMachine {
|
||||
|
||||
private Stack<Integer> stack = new Stack();
|
||||
|
||||
private Wizard[] wizards = new Wizard[2];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public VirtualMachine() {
|
||||
for (int i = 0; i < wizards.length; i++) {
|
||||
wizards[i] = new Wizard();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes provided bytecode
|
||||
* @param bytecode to execute
|
||||
*/
|
||||
public void execute(int[] bytecode) {
|
||||
for (int i = 0; i < bytecode.length; i++) {
|
||||
Instruction instruction = Instruction.getInstruction(bytecode[i]);
|
||||
int wizard;
|
||||
int amount;
|
||||
switch (instruction) {
|
||||
case LITERAL:
|
||||
// Read the next byte from the bytecode.
|
||||
int value = bytecode[++i];
|
||||
stack.push(value);
|
||||
break;
|
||||
case SET_AGILITY:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setAgility(wizard, amount);
|
||||
break;
|
||||
case SET_WISDOM:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setWisdom(wizard, amount);
|
||||
break;
|
||||
case SET_HEALTH:
|
||||
amount = stack.pop();
|
||||
wizard = stack.pop();
|
||||
setHealth(wizard, amount);
|
||||
break;
|
||||
case GET_HEALTH:
|
||||
wizard = stack.pop();
|
||||
stack.push(getHealth(wizard));
|
||||
break;
|
||||
case GET_AGILITY:
|
||||
wizard = stack.pop();
|
||||
stack.push(getAgility(wizard));
|
||||
break;
|
||||
case GET_WISDOM:
|
||||
wizard = stack.pop();
|
||||
stack.push(getWisdom(wizard));
|
||||
break;
|
||||
case ADD:
|
||||
int a = stack.pop();
|
||||
int b = stack.pop();
|
||||
stack.push(a + b);
|
||||
break;
|
||||
case DIVIDE:
|
||||
a = stack.pop();
|
||||
b = stack.pop();
|
||||
stack.push(b / a);
|
||||
break;
|
||||
case PLAY_SOUND:
|
||||
wizard = stack.pop();
|
||||
getWizards()[wizard].playSound();
|
||||
break;
|
||||
case SPAWN_PARTICLES:
|
||||
wizard = stack.pop();
|
||||
getWizards()[wizard].spawnParticles();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid instruction value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Stack<Integer> getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void setHealth(int wizard, int amount) {
|
||||
wizards[wizard].setHealth(amount);
|
||||
}
|
||||
|
||||
public void setWisdom(int wizard, int amount) {
|
||||
wizards[wizard].setWisdom(amount);
|
||||
}
|
||||
|
||||
public void setAgility(int wizard, int amount) {
|
||||
wizards[wizard].setAgility(amount);
|
||||
}
|
||||
|
||||
public int getHealth(int wizard) {
|
||||
return wizards[wizard].getHealth();
|
||||
}
|
||||
|
||||
public int getWisdom(int wizard) {
|
||||
return wizards[wizard].getWisdom();
|
||||
}
|
||||
|
||||
public int getAgility(int wizard) {
|
||||
return wizards[wizard].getAgility();
|
||||
}
|
||||
|
||||
public Wizard[] getWizards() {
|
||||
return wizards;
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class represent game objects which properties can be changed by instructions interpreted by virtual machine
|
||||
*/
|
||||
public class Wizard {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
|
||||
|
||||
private int health;
|
||||
|
||||
private int agility;
|
||||
private int wisdom;
|
||||
|
||||
private int numberOfPlayedSounds;
|
||||
private int numberOfSpawnedParticles;
|
||||
|
||||
public int getHealth() {
|
||||
return health;
|
||||
}
|
||||
|
||||
public void setHealth(int health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
public int getAgility() {
|
||||
return agility;
|
||||
}
|
||||
|
||||
public void setAgility(int agility) {
|
||||
this.agility = agility;
|
||||
}
|
||||
|
||||
public int getWisdom() {
|
||||
return wisdom;
|
||||
}
|
||||
|
||||
public void setWisdom(int wisdom) {
|
||||
this.wisdom = wisdom;
|
||||
}
|
||||
|
||||
public void playSound() {
|
||||
LOGGER.info("Playing sound");
|
||||
numberOfPlayedSounds++;
|
||||
}
|
||||
|
||||
public void spawnParticles() {
|
||||
LOGGER.info("Spawning particles");
|
||||
numberOfSpawnedParticles++;
|
||||
}
|
||||
|
||||
public int getNumberOfPlayedSounds() {
|
||||
return numberOfPlayedSounds;
|
||||
}
|
||||
|
||||
public int getNumberOfSpawnedParticles() {
|
||||
return numberOfSpawnedParticles;
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode.util;
|
||||
|
||||
import com.iluwatar.bytecode.Instruction;
|
||||
|
||||
/**
|
||||
* Utility class used for instruction validation and conversion
|
||||
*/
|
||||
public class InstructionConverterUtil {
|
||||
/**
|
||||
* Converts instructions represented as String
|
||||
*
|
||||
* @param instructions to convert
|
||||
* @return array of int representing bytecode
|
||||
*/
|
||||
public static int[] convertToByteCode(String instructions) {
|
||||
if (instructions == null || instructions.trim().length() == 0) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
String[] splitedInstructions = instructions.trim().split(" ");
|
||||
int[] bytecode = new int[splitedInstructions.length];
|
||||
for (int i = 0; i < splitedInstructions.length; i++) {
|
||||
if (isValidInstruction(splitedInstructions[i])) {
|
||||
bytecode[i] = Instruction.valueOf(splitedInstructions[i]).getIntValue();
|
||||
} else if (isValidInt(splitedInstructions[i])) {
|
||||
bytecode[i] = Integer.valueOf(splitedInstructions[i]);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid instruction or number: " + splitedInstructions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
private static boolean isValidInstruction(String instruction) {
|
||||
try {
|
||||
Instruction.valueOf(instruction);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidInt(String value) {
|
||||
try {
|
||||
Integer.parseInt(value);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Application test
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.iluwatar.bytecode.Instruction.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Test for {@Link VirtualMachine}
|
||||
*/
|
||||
public class VirtualMachineTest {
|
||||
|
||||
@Test
|
||||
public void testLiteral() {
|
||||
int[] bytecode = new int[2];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = 10;
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(1, vm.getStack().size());
|
||||
assertEquals(Integer.valueOf(10), vm.getStack().pop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetHealth() {
|
||||
int wizardNumber = 0;
|
||||
int[] bytecode = new int[5];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = wizardNumber;
|
||||
bytecode[2] = LITERAL.getIntValue();
|
||||
bytecode[3] = 50; // health amount
|
||||
bytecode[4] = SET_HEALTH.getIntValue();
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(50, vm.getWizards()[wizardNumber].getHealth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAgility() {
|
||||
int wizardNumber = 0;
|
||||
int[] bytecode = new int[5];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = wizardNumber;
|
||||
bytecode[2] = LITERAL.getIntValue();
|
||||
bytecode[3] = 50; // agility amount
|
||||
bytecode[4] = SET_AGILITY.getIntValue();
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(50, vm.getWizards()[wizardNumber].getAgility());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetWisdom() {
|
||||
int wizardNumber = 0;
|
||||
int[] bytecode = new int[5];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = wizardNumber;
|
||||
bytecode[2] = LITERAL.getIntValue();
|
||||
bytecode[3] = 50; // wisdom amount
|
||||
bytecode[4] = SET_WISDOM.getIntValue();
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(50, vm.getWizards()[wizardNumber].getWisdom());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetHealth() {
|
||||
int wizardNumber = 0;
|
||||
int[] bytecode = new int[8];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = wizardNumber;
|
||||
bytecode[2] = LITERAL.getIntValue();
|
||||
bytecode[3] = 50; // health amount
|
||||
bytecode[4] = SET_HEALTH.getIntValue();
|
||||
bytecode[5] = LITERAL.getIntValue();;
|
||||
bytecode[6] = wizardNumber;
|
||||
bytecode[7] = GET_HEALTH.getIntValue();
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(Integer.valueOf(50), vm.getStack().pop());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlaySound() {
|
||||
int wizardNumber = 0;
|
||||
int[] bytecode = new int[3];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = wizardNumber;
|
||||
bytecode[2] = PLAY_SOUND.getIntValue();
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(0, vm.getStack().size());
|
||||
assertEquals(1, vm.getWizards()[0].getNumberOfPlayedSounds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpawnParticles() {
|
||||
int wizardNumber = 0;
|
||||
int[] bytecode = new int[3];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = wizardNumber;
|
||||
bytecode[2] = SPAWN_PARTICLES.getIntValue();
|
||||
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
vm.execute(bytecode);
|
||||
|
||||
assertEquals(0, vm.getStack().size());
|
||||
assertEquals(1, vm.getWizards()[0].getNumberOfSpawnedParticles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidInstruction() {
|
||||
int[] bytecode = new int[1];
|
||||
bytecode[0] = 999;
|
||||
VirtualMachine vm = new VirtualMachine();
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> vm.execute(bytecode));
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.bytecode.util;
|
||||
|
||||
import com.iluwatar.bytecode.Instruction;
|
||||
import com.iluwatar.bytecode.util.InstructionConverterUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for {@Link InstructionConverterUtil}
|
||||
*/
|
||||
public class InstructionConverterUtilTest {
|
||||
@Test
|
||||
public void testEmptyInstruction() {
|
||||
String instruction = "";
|
||||
|
||||
int[] bytecode = InstructionConverterUtil.convertToByteCode(instruction);
|
||||
|
||||
Assertions.assertEquals(0, bytecode.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstructions() {
|
||||
String instructions =
|
||||
"LITERAL 35 SET_HEALTH SET_WISDOM SET_AGILITY PLAY_SOUND SPAWN_PARTICLES GET_HEALTH ADD DIVIDE";
|
||||
|
||||
int[] bytecode = InstructionConverterUtil.convertToByteCode(instructions);
|
||||
|
||||
Assertions.assertEquals(10, bytecode.length);
|
||||
Assertions.assertEquals(Instruction.LITERAL.getIntValue(), bytecode[0]);
|
||||
Assertions.assertEquals(35, bytecode[1]);
|
||||
Assertions.assertEquals(Instruction.SET_HEALTH.getIntValue(), bytecode[2]);
|
||||
Assertions.assertEquals(Instruction.SET_WISDOM.getIntValue(), bytecode[3]);
|
||||
Assertions.assertEquals(Instruction.SET_AGILITY.getIntValue(), bytecode[4]);
|
||||
Assertions.assertEquals(Instruction.PLAY_SOUND.getIntValue(), bytecode[5]);
|
||||
Assertions.assertEquals(Instruction.SPAWN_PARTICLES.getIntValue(), bytecode[6]);
|
||||
Assertions.assertEquals(Instruction.GET_HEALTH.getIntValue(), bytecode[7]);
|
||||
Assertions.assertEquals(Instruction.ADD.getIntValue(), bytecode[8]);
|
||||
Assertions.assertEquals(Instruction.DIVIDE.getIntValue(), bytecode[9]);
|
||||
}
|
||||
|
||||
}
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>caching</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -28,7 +28,6 @@ import java.util.Map;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
import com.iluwatar.caching.constants.CachingConstants;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.client.FindIterable;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
@ -91,12 +90,12 @@ public final class DbManager {
|
||||
}
|
||||
}
|
||||
FindIterable<Document> iterable =
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).find(new Document(CachingConstants.USER_ID, userId));
|
||||
db.getCollection("user_accounts").find(new Document("userID", userId));
|
||||
if (iterable == null) {
|
||||
return null;
|
||||
}
|
||||
Document doc = iterable.first();
|
||||
return new UserAccount(userId, doc.getString(CachingConstants.USER_NAME), doc.getString(CachingConstants.ADD_INFO));
|
||||
return new UserAccount(userId, doc.getString("userName"), doc.getString("additionalInfo"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,9 +113,9 @@ public final class DbManager {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).insertOne(
|
||||
new Document(CachingConstants.USER_ID ,userAccount.getUserId()).append(CachingConstants.USER_NAME,
|
||||
userAccount.getUserName()).append(CachingConstants.ADD_INFO, userAccount.getAdditionalInfo()));
|
||||
db.getCollection("user_accounts").insertOne(
|
||||
new Document("userID", userAccount.getUserId()).append("userName",
|
||||
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,10 +133,10 @@ public final class DbManager {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).updateOne(
|
||||
new Document(CachingConstants.USER_ID, userAccount.getUserId()),
|
||||
new Document("$set", new Document(CachingConstants.USER_NAME, userAccount.getUserName())
|
||||
.append(CachingConstants.ADD_INFO, userAccount.getAdditionalInfo())));
|
||||
db.getCollection("user_accounts").updateOne(
|
||||
new Document("userID", userAccount.getUserId()),
|
||||
new Document("$set", new Document("userName", userAccount.getUserName()).append(
|
||||
"additionalInfo", userAccount.getAdditionalInfo())));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,12 +155,10 @@ public final class DbManager {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
db.getCollection(CachingConstants.USER_ACCOUNT).updateOne(
|
||||
new Document(CachingConstants.USER_ID, userAccount.getUserId()),
|
||||
new Document("$set",
|
||||
new Document(CachingConstants.USER_ID, userAccount.getUserId())
|
||||
.append(CachingConstants.USER_NAME, userAccount.getUserName()).append(CachingConstants.ADD_INFO,
|
||||
userAccount.getAdditionalInfo())),
|
||||
db.getCollection("user_accounts").updateOne(
|
||||
new Document("userID", userAccount.getUserId()),
|
||||
new Document("$set", new Document("userID", userAccount.getUserId()).append("userName",
|
||||
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())),
|
||||
new UpdateOptions().upsert(true));
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package com.iluwatar.caching.constants;
|
||||
|
||||
/**
|
||||
*
|
||||
* Constant class for defining constants
|
||||
*
|
||||
*/
|
||||
public class CachingConstants {
|
||||
|
||||
public static final String USER_ACCOUNT = "user_accounts";
|
||||
public static final String USER_ID = "userID";
|
||||
public static final String USER_NAME = "userName";
|
||||
public static final String ADD_INFO = "additionalInfo";
|
||||
|
||||
}
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>callback</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -41,7 +41,12 @@ public class App {
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Task task = new SimpleTask();
|
||||
Callback callback = () -> LOGGER.info("I'm done now.");
|
||||
Callback callback = new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
LOGGER.info("I'm done now.");
|
||||
}
|
||||
};
|
||||
task.executeWith(callback);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,29 @@ public class CallbackTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Callback callback = new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
callingCount++;
|
||||
}
|
||||
};
|
||||
|
||||
Task task = new SimpleTask();
|
||||
|
||||
assertEquals(new Integer(0), callingCount, "Initial calling count of 0");
|
||||
|
||||
task.executeWith(callback);
|
||||
|
||||
assertEquals(new Integer(1), callingCount, "Callback called once");
|
||||
|
||||
task.executeWith(callback);
|
||||
|
||||
assertEquals(new Integer(2), callingCount, "Callback called twice");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithLambdasExample() {
|
||||
Callback callback = () -> callingCount++;
|
||||
|
||||
Task task = new SimpleTask();
|
||||
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>chain</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -35,7 +35,7 @@ public class OrcCommander extends RequestHandler {
|
||||
|
||||
@Override
|
||||
public void handleRequest(Request req) {
|
||||
if (RequestType.DEFEND_CASTLE == req.getRequestType()) {
|
||||
if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) {
|
||||
printHandling(req);
|
||||
req.markHandled();
|
||||
} else {
|
||||
|
@ -35,7 +35,7 @@ public class OrcOfficer extends RequestHandler {
|
||||
|
||||
@Override
|
||||
public void handleRequest(Request req) {
|
||||
if (RequestType.TORTURE_PRISONER == req.getRequestType()) {
|
||||
if (req.getRequestType().equals(RequestType.TORTURE_PRISONER)) {
|
||||
printHandling(req);
|
||||
req.markHandled();
|
||||
} else {
|
||||
|
@ -35,7 +35,7 @@ public class OrcSoldier extends RequestHandler {
|
||||
|
||||
@Override
|
||||
public void handleRequest(Request req) {
|
||||
if (RequestType.COLLECT_TAX == req.getRequestType()) {
|
||||
if (req.getRequestType().equals(RequestType.COLLECT_TAX)) {
|
||||
printHandling(req);
|
||||
req.markHandled();
|
||||
} else {
|
||||
|
@ -43,7 +43,7 @@ public class OrcKingTest {
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testMakeRequest() {
|
||||
public void testMakeRequest() throws Exception {
|
||||
final OrcKing king = new OrcKing();
|
||||
|
||||
for (final Request request : REQUESTS) {
|
||||
|
@ -27,14 +27,19 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collection-pipeline</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
@ -26,10 +26,10 @@ package com.iluwatar.collectionpipeline;
|
||||
* A Car class that has the properties of make, model, year and category.
|
||||
*/
|
||||
public class Car {
|
||||
private final String make;
|
||||
private final String model;
|
||||
private final int year;
|
||||
private final Category category;
|
||||
private String make;
|
||||
private String model;
|
||||
private int year;
|
||||
private Category category;
|
||||
|
||||
/**
|
||||
* Constructor to create an instance of car.
|
||||
|
@ -43,7 +43,6 @@ Use the Command pattern when you want to
|
||||
## Real world examples
|
||||
|
||||
* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
|
||||
* [org.junit.runners.model.Statement](https://github.com/junit-team/junit4/blob/master/src/main/java/org/junit/runners/model/Statement.java)
|
||||
* [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
|
||||
* [javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html)
|
||||
|
||||
|
@ -234,7 +234,7 @@ Use the Command pattern when you want to:
|
||||
* Source code http://java-design-patterns.com/patterns/command/
|
||||
|
||||
</textarea>
|
||||
<script src="https://remarkjs.com/downloads/remark-latest.min.js">
|
||||
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
|
||||
</script>
|
||||
<script>
|
||||
var slideshow = remark.create();
|
||||
|
@ -29,10 +29,15 @@
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
<version>1.21.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>command</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
|
@ -1,24 +0,0 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Commander
|
||||
folder: commander
|
||||
permalink: /patterns/commander/
|
||||
categories:
|
||||
tags:
|
||||
- Java
|
||||
- Difficulty-Intermediate
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
> Used to handle all problems that can be encountered when doing distributed transactions.
|
||||
|
||||
## Applicability
|
||||
This pattern can be used when we need to make commits into 2 (or more) databases to complete transaction, which cannot be done atomically and can thereby create problems.
|
||||
|
||||
## Explanation
|
||||
Handling distributed transactions can be tricky, but if we choose to not handle it carefully, there could be unwanted consequences. Say, we have an e-commerce website which has a Payment microservice and a Shipping microservice. If the shipping is available currently but payment service is not up, or vice versa, how would we deal with it after having already received the order from the user?
|
||||
We need a mechanism in place which can handle these kinds of situations. We have to direct the order to either one of the services (in this example, shipping) and then add the order into the database of the other service (in this example, payment), since two databses cannot be updated atomically. If currently unable to do it, there should be a queue where this request can be queued, and there has to be a mechanism which allows for a failure in the queueing as well. All this needs to be done by constant retries while ensuring idempotence (even if the request is made several times, the change should only be applied once) by a commander class, to reach a state of eventual consistency.
|
||||
|
||||
## Credits
|
||||
* [https://www.grahamlea.com/2016/08/distributed-transactions-microservices-icebergs/]
|
@ -1,21 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.21.0</version>
|
||||
</parent>
|
||||
<artifactId>commander</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -1,18 +0,0 @@
|
||||
#Define root logger options
|
||||
log4j.rootLogger=TRACE, file, console
|
||||
|
||||
#Define console appender
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
logrj.appender.console.Target=System.out
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd} %d{HH:mm:ss} %5p[%t] %m%n
|
||||
|
||||
#Define rolling file appender
|
||||
log4j.appender.file=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.file.File=/log/logFile.log
|
||||
log4j.appender.file.Append=true
|
||||
log4j.appender.file.ImmediateFlush=true
|
||||
log4j.appender.file.MaxFileSize=10MB
|
||||
log4j.appender.file.MaxBackupIndex=5
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %d{HH:mm:ss} %5p[%t] %m%n
|
@ -1,96 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppEmployeeDbFailCases class looks at possible cases when Employee handle service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppEmployeeDbFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void employeeDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void employeeDbSuccessCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ItemUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppEmployeeDbFailCases aefc = new AppEmployeeDbFailCases();
|
||||
//aefc.employeeDatabaseUnavailableCase();
|
||||
aefc.employeeDbSuccessCase();
|
||||
}
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppMessagingFailCases class looks at possible cases when Messaging service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppMessagingFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void messagingDatabaseUnavailableCasePaymentSuccess() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void messagingDatabaseUnavailableCasePaymentError() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void messagingDatabaseUnavailableCasePaymentFailure() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,queueTime,queueTaskTime,
|
||||
paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void messagingSuccessCase() throws Exception {
|
||||
//done here
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppMessagingFailCases amfc = new AppMessagingFailCases();
|
||||
//amfc.messagingDatabaseUnavailableCasePaymentSuccess();
|
||||
//amfc.messagingDatabaseUnavailableCasePaymentError();
|
||||
//amfc.messagingDatabaseUnavailableCasePaymentFailure();
|
||||
amfc.messagingSuccessCase();
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.PaymentDetailsErrorException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppPaymentFailCases class looks at possible cases when Payment service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppPaymentFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void paymentNotPossibleCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new PaymentDetailsErrorException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void paymentDatabaseUnavailableCase() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void paymentSuccessCase() throws Exception {
|
||||
//goes to message after 2 retries maybe - rest is successful for now
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppPaymentFailCases apfc = new AppPaymentFailCases();
|
||||
//apfc.paymentNotPossibleCase();
|
||||
//apfc.paymentDatabaseUnavailableCase();
|
||||
apfc.paymentSuccessCase();
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppQueueFailCases class looks at possible cases when Queue Database is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppQueueFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void queuePaymentTaskDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void queueMessageTaskDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void queueEmployeeDbTaskDatabaseUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ItemUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void queueSuccessCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase(new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppQueueFailCases aqfc = new AppQueueFailCases();
|
||||
//aqfc.queuePaymentTaskDatabaseUnavailableCase();
|
||||
//aqfc.queueMessageTaskDatabaseUnavailableCase();
|
||||
//aqfc.queueEmployeeDbTaskDatabaseUnavailableCase();
|
||||
aqfc.queueSuccessCase();
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.employeehandle.EmployeeDatabase;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ShippingNotPossibleException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingDatabase;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.paymentservice.PaymentDatabase;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.shippingservice.ShippingDatabase;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
|
||||
/**
|
||||
* AppShippingFailCases class looks at possible cases when Shipping service is
|
||||
* available/unavailable.
|
||||
*/
|
||||
|
||||
public class AppShippingFailCases {
|
||||
final int numOfRetries = 3;
|
||||
final long retryDuration = 30000;
|
||||
final long queueTime = 240000; //4 mins
|
||||
final long queueTaskTime = 60000; //1 min
|
||||
final long paymentTime = 120000; //2 mins
|
||||
final long messageTime = 150000; //2.5 mins
|
||||
final long employeeTime = 240000; //4 mins
|
||||
|
||||
void itemUnavailableCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ItemUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void shippingNotPossibleCase() throws Exception {
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new ShippingNotPossibleException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void shippingDatabaseUnavailableCase() throws Exception {
|
||||
//rest is successful
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException(), new DatabaseUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
void shippingSuccessCase() throws Exception {
|
||||
//goes to payment after 2 retries maybe - rest is successful for now
|
||||
PaymentService ps = new PaymentService(new PaymentDatabase(), new DatabaseUnavailableException());
|
||||
ShippingService ss = new ShippingService(new ShippingDatabase(), new DatabaseUnavailableException(),
|
||||
new DatabaseUnavailableException());
|
||||
MessagingService ms = new MessagingService(new MessagingDatabase(), new DatabaseUnavailableException());
|
||||
EmployeeHandle eh = new EmployeeHandle(new EmployeeDatabase());
|
||||
QueueDatabase qdb = new QueueDatabase();
|
||||
Commander c = new Commander(eh,ps,ss,ms,qdb,numOfRetries,retryDuration,
|
||||
queueTime,queueTaskTime,paymentTime,messageTime,employeeTime);
|
||||
User user = new User("Jim", "ABCD");
|
||||
Order order = new Order(user, "book", 10f);
|
||||
c.placeOrder(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AppShippingFailCases asfc = new AppShippingFailCases();
|
||||
//asfc.itemUnavailableCase();
|
||||
//asfc.shippingNotPossibleCase();
|
||||
//asfc.shippingDatabaseUnavailableCase();
|
||||
asfc.shippingSuccessCase();
|
||||
}
|
||||
}
|
@ -1,613 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import org.apache.log4j.Logger;
|
||||
import com.iluwatar.commander.employeehandle.EmployeeHandle;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.ItemUnavailableException;
|
||||
import com.iluwatar.commander.exceptions.PaymentDetailsErrorException;
|
||||
import com.iluwatar.commander.exceptions.ShippingNotPossibleException;
|
||||
import com.iluwatar.commander.messagingservice.MessagingService;
|
||||
import com.iluwatar.commander.Order.MessageSent;
|
||||
import com.iluwatar.commander.Order.PaymentStatus;
|
||||
import com.iluwatar.commander.paymentservice.PaymentService;
|
||||
import com.iluwatar.commander.queue.QueueDatabase;
|
||||
import com.iluwatar.commander.queue.QueueTask;
|
||||
import com.iluwatar.commander.queue.QueueTask.TaskType;
|
||||
import com.iluwatar.commander.shippingservice.ShippingService;
|
||||
|
||||
/**
|
||||
*<p>Commander pattern is used to handle all issues that can come up while making a
|
||||
* distributed transaction. The idea is to have a commander, which coordinates the
|
||||
* execution of all instructions and ensures proper completion using retries and
|
||||
* taking care of idempotence. By queueing instructions while they haven't been done,
|
||||
* we can ensure a state of 'eventual consistency'.</p>
|
||||
* <p>In our example, we have an e-commerce application. When the user places an order,
|
||||
* the shipping service is intimated first. If the service does not respond for some
|
||||
* reason, the order is not placed. If response is received, the commander then calls
|
||||
* for the payment service to be intimated. If this fails, the shipping still takes
|
||||
* place (order converted to COD) and the item is queued. If the queue is also found
|
||||
* to be unavailable, the payment is noted to be not done and this is added to an
|
||||
* employee database. Three types of messages are sent to the user - one, if payment
|
||||
* succeeds; two, if payment fails definitively; and three, if payment fails in the
|
||||
* first attempt. If the message is not sent, this is also queued and is added to employee
|
||||
* db. We also have a time limit for each instruction to be completed, after which, the
|
||||
* instruction is not executed, thereby ensuring that resources are not held for too long.
|
||||
* In the rare occasion in which everything fails, an individual would have to step in to
|
||||
* figure out how to solve the issue.</p>
|
||||
* <p>We have abstract classes {@link Database} and {@link Service} which are extended
|
||||
* by all the databases and services. Each service has a database to be updated, and
|
||||
* receives request from an outside user (the {@link Commander} class here). There are
|
||||
* 5 microservices - {@link ShippingService}, {@link PaymentService}, {@link MessagingService},
|
||||
* {@link EmployeeHandle} and a {@link QueueDatabase}. We use retries to execute any
|
||||
* instruction using {@link Retry} class, and idempotence is ensured by going through some
|
||||
* checks before making requests to services and making change in {@link Order} class fields
|
||||
* if request succeeds or definitively fails. There are 5 classes -
|
||||
* {@link AppShippingFailCases}, {@link AppPaymentFailCases}, {@link AppMessagingFailCases},
|
||||
* {@link AppQueueFailCases} and {@link AppEmployeeDbFailCases}, which look at the different
|
||||
* scenarios that may be encountered during the placing of an order.</p>
|
||||
*/
|
||||
|
||||
public class Commander {
|
||||
|
||||
private final QueueDatabase queue;
|
||||
private final EmployeeHandle employeeDb;
|
||||
private final PaymentService paymentService;
|
||||
private final ShippingService shippingService;
|
||||
private final MessagingService messagingService;
|
||||
private int queueItems = 0; //keeping track here only so don't need access to queue db to get this
|
||||
private final int numOfRetries;
|
||||
private final long retryDuration;
|
||||
private final long queueTime;
|
||||
private final long queueTaskTime;
|
||||
private final long paymentTime;
|
||||
private final long messageTime;
|
||||
private final long employeeTime;
|
||||
private boolean finalSiteMsgShown;
|
||||
static final Logger LOG = Logger.getLogger(Commander.class);
|
||||
//we could also have another db where it stores all orders
|
||||
|
||||
Commander(EmployeeHandle empDb, PaymentService pService, ShippingService sService,
|
||||
MessagingService mService, QueueDatabase qdb, int numOfRetries, long retryDuration,
|
||||
long queueTime, long queueTaskTime, long paymentTime, long messageTime, long employeeTime) {
|
||||
this.paymentService = pService;
|
||||
this.shippingService = sService;
|
||||
this.messagingService = mService;
|
||||
this.employeeDb = empDb;
|
||||
this.queue = qdb;
|
||||
this.numOfRetries = numOfRetries;
|
||||
this.retryDuration = retryDuration;
|
||||
this.queueTime = queueTime;
|
||||
this.queueTaskTime = queueTaskTime;
|
||||
this.paymentTime = paymentTime;
|
||||
this.messageTime = messageTime;
|
||||
this.employeeTime = employeeTime;
|
||||
this.finalSiteMsgShown = false;
|
||||
}
|
||||
|
||||
void placeOrder(Order order) throws Exception {
|
||||
sendShippingRequest(order);
|
||||
}
|
||||
|
||||
private void sendShippingRequest(Order order) throws Exception {
|
||||
ArrayList<Exception> list = shippingService.exceptionsList;
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to shipping service, trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating shipping request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
String transactionId = shippingService.receiveRequest(order.item, order.user.address);
|
||||
//could save this transaction id in a db too
|
||||
LOG.info("Order " + order.id + ": Shipping placed successfully, transaction id: " + transactionId);
|
||||
System.out.println("Order has been placed and will be shipped to you. Please wait while we make your"
|
||||
+ " payment... ");
|
||||
sendPaymentRequest(order);
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
if (ShippingNotPossibleException.class.isAssignableFrom(err.getClass())) {
|
||||
System.out.println("Shipping is currently not possible to your address. We are working on the problem "
|
||||
+ "and will get back to you asap.");
|
||||
finalSiteMsgShown = true;
|
||||
LOG.info("Order " + order.id + ": Shipping not possible to address, trying to add problem to employee db..");
|
||||
employeeHandleIssue(o);
|
||||
} else if (ItemUnavailableException.class.isAssignableFrom(err.getClass())) {
|
||||
System.out.println("This item is currently unavailable. We will inform you as soon as the item becomes "
|
||||
+ "available again.");
|
||||
finalSiteMsgShown = true;
|
||||
LOG.info("Order " + order.id + ": Item " + order.item + " unavailable, trying to add problem to employee "
|
||||
+ "handle..");
|
||||
employeeHandleIssue(o);
|
||||
} else {
|
||||
System.out.println("Sorry, there was a problem in creating your order. Please try later.");
|
||||
LOG.error("Order " + order.id + ": Shipping service unavailable, order not placed..");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
r.perform(list, order);
|
||||
}
|
||||
|
||||
private void sendPaymentRequest(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.paymentTime) {
|
||||
if (order.paid.equals(PaymentStatus.Trying)) {
|
||||
order.paid = PaymentStatus.NotDone;
|
||||
sendPaymentFailureMessage(order);
|
||||
LOG.error("Order " + order.id + ": Payment time for order over, failed and returning..");
|
||||
} //if succeeded or failed, would have been dequeued, no attempt to make payment
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = paymentService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to payment service, trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating payment request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (order.paid.equals(PaymentStatus.Trying)) {
|
||||
String transactionId = paymentService.receiveRequest(order.price);
|
||||
order.paid = PaymentStatus.Done;
|
||||
LOG.info("Order " + order.id + ": Payment successful, transaction Id: " + transactionId);
|
||||
if (!finalSiteMsgShown) {
|
||||
System.out.println("Payment made successfully, thank you for shopping with us!!");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
sendSuccessMessage(order);
|
||||
return;
|
||||
}
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
if (PaymentDetailsErrorException.class.isAssignableFrom(err.getClass())) {
|
||||
if (!finalSiteMsgShown) {
|
||||
System.out.println("There was an error in payment. Your account/card details may have been incorrect. "
|
||||
+ "Meanwhile, your order has been converted to COD and will be shipped.");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
LOG.error("Order " + order.id + ": Payment details incorrect, failed..");
|
||||
o.paid = PaymentStatus.NotDone;
|
||||
sendPaymentFailureMessage(o);
|
||||
} else {
|
||||
try {
|
||||
if (o.messageSent.equals(MessageSent.NoneSent)) {
|
||||
if (!finalSiteMsgShown) {
|
||||
System.out.println("There was an error in payment. We are on it, and will get back to you "
|
||||
+ "asap. Don't worry, your order has been placed and will be shipped.");
|
||||
finalSiteMsgShown = true;
|
||||
}
|
||||
LOG.warn("Order " + order.id + ": Payment error, going to queue..");
|
||||
sendPaymentPossibleErrorMsg(o);
|
||||
}
|
||||
if (o.paid.equals(PaymentStatus.Trying) && System.currentTimeMillis() - o.createdTime < paymentTime) {
|
||||
QueueTask qt = new QueueTask(o, TaskType.Payment,-1);
|
||||
updateQueue(qt);
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void updateQueue(QueueTask qt) throws InterruptedException {
|
||||
if (System.currentTimeMillis() - qt.order.createdTime >= this.queueTime) {
|
||||
//since payment time is lesser than queuetime it would have already failed..additional check not needed
|
||||
LOG.trace("Order " + qt.order.id + ": Queue time for order over, failed..");
|
||||
return;
|
||||
} else if ((qt.taskType.equals(TaskType.Payment) && !qt.order.paid.equals(PaymentStatus.Trying))
|
||||
|| (qt.taskType.equals(TaskType.Messaging) && ((qt.messageType == 1
|
||||
&& !qt.order.messageSent.equals(MessageSent.NoneSent))
|
||||
|| qt.order.messageSent.equals(MessageSent.PaymentFail)
|
||||
|| qt.order.messageSent.equals(MessageSent.PaymentSuccessful)))
|
||||
|| (qt.taskType.equals(TaskType.EmployeeDb) && qt.order.addedToEmployeeHandle)) {
|
||||
LOG.trace("Order " + qt.order.id + ": Not queueing task since task already done..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = queue.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (list) -> {
|
||||
if (!list.isEmpty()) {
|
||||
LOG.warn("Order " + qt.order.id + ": Error in connecting to queue db, trying again..");
|
||||
throw list.remove(0);
|
||||
}
|
||||
queue.add(qt);
|
||||
queueItems++;
|
||||
LOG.info("Order " + qt.order.id + ": " + qt.getType() + " task enqueued..");
|
||||
tryDoingTasksInQueue();
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<QueueTask> handleError = (qt,err) -> {
|
||||
if (qt.taskType.equals(TaskType.Payment)) {
|
||||
qt.order.paid = PaymentStatus.NotDone;
|
||||
sendPaymentFailureMessage(qt.order);
|
||||
LOG.error("Order " + qt.order.id + ": Unable to enqueue payment task, payment failed..");
|
||||
}
|
||||
LOG.error("Order " + qt.order.id + ": Unable to enqueue task of type " + qt.getType()
|
||||
+ ", trying to add to employee handle..");
|
||||
employeeHandleIssue(qt.order);
|
||||
return;
|
||||
};
|
||||
Retry<QueueTask> r = new Retry<QueueTask>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, qt);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void tryDoingTasksInQueue() { //commander controls operations done to queue
|
||||
ArrayList<Exception> list = queue.exceptionsList;
|
||||
Thread t2 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (list) -> {
|
||||
if (!list.isEmpty()) {
|
||||
LOG.warn("Error in accessing queue db to do tasks, trying again..");
|
||||
throw list.remove(0);
|
||||
}
|
||||
doTasksInQueue();
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<QueueTask> handleError = (o,err) -> {
|
||||
return;
|
||||
};
|
||||
Retry<QueueTask> r = new Retry<QueueTask>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, null);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t2.start();
|
||||
}
|
||||
|
||||
private void tryDequeue() {
|
||||
ArrayList<Exception> list = queue.exceptionsList;
|
||||
Thread t3 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (list) -> {
|
||||
if (!list.isEmpty()) {
|
||||
LOG.warn("Error in accessing queue db to dequeue task, trying again..");
|
||||
throw list.remove(0);
|
||||
}
|
||||
queue.dequeue();
|
||||
queueItems--;
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<QueueTask> handleError = (o,err) -> {
|
||||
return;
|
||||
};
|
||||
Retry<QueueTask> r = new Retry<QueueTask>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, null);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t3.start();
|
||||
}
|
||||
|
||||
private void sendSuccessMessage(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.messageTime) {
|
||||
LOG.trace("Order " + order.id + ": Message time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = messagingService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to messaging service "
|
||||
+ "(Payment Success msg), trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating Payment Success messaging request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (!order.messageSent.equals(MessageSent.PaymentFail)
|
||||
&& !order.messageSent.equals(MessageSent.PaymentSuccessful)) {
|
||||
String requestId = messagingService.receiveRequest(2);
|
||||
order.messageSent = MessageSent.PaymentSuccessful;
|
||||
LOG.info("Order " + order.id + ": Payment Success message sent, request Id: " + requestId);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
try {
|
||||
if ((o.messageSent.equals(MessageSent.NoneSent) || o.messageSent.equals(MessageSent.PaymentTrying))
|
||||
&& System.currentTimeMillis() - o.createdTime < messageTime) {
|
||||
QueueTask qt = new QueueTask(order, TaskType.Messaging,2);
|
||||
updateQueue(qt);
|
||||
LOG.info("Order " + order.id + ": Error in sending Payment Success message, trying to "
|
||||
+ "queue task and add to employee handle..");
|
||||
employeeHandleIssue(order);
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void sendPaymentFailureMessage(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.messageTime) {
|
||||
LOG.trace("Order " + order.id + ": Message time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = messagingService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to messaging service "
|
||||
+ "(Payment Failure msg), trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating Payment Failure message request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (!order.messageSent.equals(MessageSent.PaymentFail)
|
||||
&& !order.messageSent.equals(MessageSent.PaymentSuccessful)) {
|
||||
String requestId = messagingService.receiveRequest(0);
|
||||
order.messageSent = MessageSent.PaymentFail;
|
||||
LOG.info("Order " + order.id + ": Payment Failure message sent successfully, request Id: " + requestId);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
if ((o.messageSent.equals(MessageSent.NoneSent) || o.messageSent.equals(MessageSent.PaymentTrying))
|
||||
&& System.currentTimeMillis() - o.createdTime < messageTime) {
|
||||
try {
|
||||
QueueTask qt = new QueueTask(order, TaskType.Messaging,0);
|
||||
updateQueue(qt);
|
||||
LOG.warn("Order " + order.id + ": Error in sending Payment Failure message, "
|
||||
+ "trying to queue task and add to employee handle..");
|
||||
employeeHandleIssue(o);
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void sendPaymentPossibleErrorMsg(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.messageTime) {
|
||||
LOG.trace("Message time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = messagingService.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
if (DatabaseUnavailableException.class.isAssignableFrom(l.get(0).getClass())) {
|
||||
LOG.debug("Order " + order.id + ": Error in connecting to messaging service "
|
||||
+ "(Payment Error msg), trying again..");
|
||||
} else {
|
||||
LOG.debug("Order " + order.id + ": Error in creating Payment Error messaging request..");
|
||||
}
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (order.paid.equals(PaymentStatus.Trying) && order.messageSent.equals(MessageSent.NoneSent)) {
|
||||
String requestId = messagingService.receiveRequest(1);
|
||||
order.messageSent = MessageSent.PaymentTrying;
|
||||
LOG.info("Order " + order.id + ": Payment Error message sent successfully, request Id: " + requestId);
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
try {
|
||||
if (o.messageSent.equals(MessageSent.NoneSent) && order.paid.equals(PaymentStatus.Trying)
|
||||
&& System.currentTimeMillis() - o.createdTime < messageTime) {
|
||||
QueueTask qt = new QueueTask(order,TaskType.Messaging,1);
|
||||
updateQueue(qt);
|
||||
LOG.warn("Order " + order.id + ": Error in sending Payment Error message, "
|
||||
+ "trying to queue task and add to employee handle..");
|
||||
employeeHandleIssue(o);
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void employeeHandleIssue(Order order) {
|
||||
if (System.currentTimeMillis() - order.createdTime >= this.employeeTime) {
|
||||
LOG.trace("Order " + order.id + ": Employee handle time for order over, returning..");
|
||||
return;
|
||||
}
|
||||
ArrayList<Exception> list = employeeDb.exceptionsList;
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Retry.Operation op = (l) -> {
|
||||
if (!l.isEmpty()) {
|
||||
LOG.warn("Order " + order.id + ": Error in connecting to employee handle, trying again..");
|
||||
throw l.remove(0);
|
||||
}
|
||||
if (!order.addedToEmployeeHandle) {
|
||||
employeeDb.receiveRequest(order);
|
||||
order.addedToEmployeeHandle = true;
|
||||
LOG.info("Order " + order.id + ": Added order to employee database");
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry.HandleErrorIssue<Order> handleError = (o,err) -> {
|
||||
try {
|
||||
if (!o.addedToEmployeeHandle && System.currentTimeMillis() - order.createdTime < employeeTime) {
|
||||
QueueTask qt = new QueueTask(order, TaskType.EmployeeDb,-1);
|
||||
updateQueue(qt);
|
||||
LOG.warn("Order " + order.id + ": Error in adding to employee db, trying to queue task..");
|
||||
return;
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
return;
|
||||
};
|
||||
Retry<Order> r = new Retry<Order>(op, handleError, numOfRetries, retryDuration,
|
||||
e -> DatabaseUnavailableException.class.isAssignableFrom(e.getClass()));
|
||||
try {
|
||||
r.perform(list, order);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void doTasksInQueue() throws Exception {
|
||||
if (queueItems != 0) {
|
||||
QueueTask qt = queue.peek(); //this should probably be cloned here
|
||||
//this is why we have retry for doTasksInQueue
|
||||
LOG.trace("Order " + qt.order.id + ": Started doing task of type " + qt.getType());
|
||||
if (qt.firstAttemptTime == -1) {
|
||||
qt.firstAttemptTime = System.currentTimeMillis();
|
||||
}
|
||||
if (System.currentTimeMillis() - qt.firstAttemptTime >= queueTaskTime) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This queue task of type " + qt.getType()
|
||||
+ " does not need to be done anymore (timeout), dequeue..");
|
||||
} else {
|
||||
if (qt.taskType.equals(TaskType.Payment)) {
|
||||
if (!qt.order.paid.equals(PaymentStatus.Trying)) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This payment task already done, dequeueing..");
|
||||
} else {
|
||||
sendPaymentRequest(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to payment service..");
|
||||
}
|
||||
} else if (qt.taskType.equals(TaskType.Messaging)) {
|
||||
if (qt.order.messageSent.equals(MessageSent.PaymentFail)
|
||||
|| qt.order.messageSent.equals(MessageSent.PaymentSuccessful)) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This messaging task already done, dequeue..");
|
||||
} else if ((qt.messageType == 1 && (!qt.order.messageSent.equals(MessageSent.NoneSent)
|
||||
|| !qt.order.paid.equals(PaymentStatus.Trying)))) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This messaging task does not need to be done, dequeue..");
|
||||
} else if (qt.messageType == 0) {
|
||||
sendPaymentFailureMessage(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service..");
|
||||
} else if (qt.messageType == 1) {
|
||||
sendPaymentPossibleErrorMsg(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service..");
|
||||
} else if (qt.messageType == 2) {
|
||||
sendSuccessMessage(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to messaging service..");
|
||||
}
|
||||
} else if (qt.taskType.equals(TaskType.EmployeeDb)) {
|
||||
if (qt.order.addedToEmployeeHandle) {
|
||||
tryDequeue();
|
||||
LOG.trace("Order " + qt.order.id + ": This employee handle task already done, dequeue..");
|
||||
} else {
|
||||
employeeHandleIssue(qt.order);
|
||||
LOG.debug("Order " + qt.order.id + ": Trying to connect to employee handle..");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queueItems == 0) {
|
||||
LOG.trace("Queue is empty, returning..");
|
||||
} else {
|
||||
Thread.sleep(queueTaskTime / 3);
|
||||
tryDoingTasksInQueue();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* Database abstract class is extended by all databases in our example. The add and get
|
||||
* methods are used by the respective service to add to database or get from database.
|
||||
* @param <T> T is the type of object being held by database.
|
||||
*/
|
||||
|
||||
public abstract class Database<T> {
|
||||
public abstract T add(T obj) throws DatabaseUnavailableException;
|
||||
public abstract T get(String tId) throws DatabaseUnavailableException;
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Order class holds details of the order.
|
||||
*/
|
||||
|
||||
public class Order { //can store all transactions ids also
|
||||
|
||||
enum PaymentStatus {
|
||||
NotDone, Trying, Done
|
||||
};
|
||||
|
||||
enum MessageSent {
|
||||
NoneSent, PaymentFail, PaymentTrying, PaymentSuccessful
|
||||
};
|
||||
|
||||
final User user;
|
||||
final String item;
|
||||
public final String id;
|
||||
final float price;
|
||||
final long createdTime;
|
||||
private static final String ALL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
private static final Hashtable<String, Boolean> USED_IDS = new Hashtable<String, Boolean>();
|
||||
PaymentStatus paid;
|
||||
MessageSent messageSent; //to avoid sending error msg on page and text more than once
|
||||
boolean addedToEmployeeHandle; //to avoid creating more to enqueue
|
||||
|
||||
Order(User user, String item, float price) {
|
||||
this.createdTime = System.currentTimeMillis();
|
||||
this.user = user;
|
||||
this.item = item;
|
||||
this.price = price;
|
||||
String id = createUniqueId();
|
||||
if (USED_IDS.get(id) != null) {
|
||||
while (USED_IDS.get(id)) {
|
||||
id = createUniqueId();
|
||||
}
|
||||
}
|
||||
this.id = id;
|
||||
USED_IDS.put(this.id, true);
|
||||
this.paid = PaymentStatus.Trying;
|
||||
this.messageSent = MessageSent.NoneSent;
|
||||
this.addedToEmployeeHandle = false;
|
||||
}
|
||||
|
||||
String createUniqueId() {
|
||||
StringBuilder random = new StringBuilder();
|
||||
Random rand = new Random();
|
||||
while (random.length() < 12) { // length of the random string.
|
||||
int index = (int) (rand.nextFloat() * ALL_CHARS.length());
|
||||
random.append(ALL_CHARS.charAt(index));
|
||||
}
|
||||
return random.toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Retry pattern
|
||||
* @param <T> is the type of object passed into HandleErrorIssue as a parameter.
|
||||
*/
|
||||
|
||||
public class Retry<T> {
|
||||
|
||||
/**
|
||||
* Operation Interface will define method to be implemented.
|
||||
*/
|
||||
|
||||
public interface Operation {
|
||||
void operation(ArrayList<Exception> list) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* HandleErrorIssue defines how to handle errors.
|
||||
* @param <T> is the type of object to be passed into the method as parameter.
|
||||
*/
|
||||
|
||||
public interface HandleErrorIssue<T> {
|
||||
void handleIssue(T obj, Exception e);
|
||||
}
|
||||
|
||||
private final Operation op;
|
||||
private final HandleErrorIssue<T> handleError;
|
||||
private final int maxAttempts;
|
||||
private final long maxDelay;
|
||||
private final AtomicInteger attempts;
|
||||
private final Predicate<Exception> test;
|
||||
private final ArrayList<Exception> errors;
|
||||
|
||||
Retry(Operation op, HandleErrorIssue handleError, int maxAttempts,
|
||||
long maxDelay, Predicate<Exception>... ignoreTests) {
|
||||
this.op = op;
|
||||
this.handleError = handleError;
|
||||
this.maxAttempts = maxAttempts;
|
||||
this.maxDelay = maxDelay;
|
||||
this.attempts = new AtomicInteger();
|
||||
this.test = Arrays.stream(ignoreTests).reduce(Predicate::or).orElse(e -> false);
|
||||
this.errors = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performing the operation with retries.
|
||||
* @param list is the exception list
|
||||
* @param obj is the parameter to be passed into handleIsuue method
|
||||
*/
|
||||
|
||||
public void perform(ArrayList<Exception> list, T obj) throws Exception {
|
||||
do {
|
||||
try {
|
||||
op.operation(list);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
this.errors.add(e);
|
||||
if (this.attempts.incrementAndGet() >= this.maxAttempts || !this.test.test(e)) {
|
||||
this.handleError.handleIssue(obj, e);
|
||||
return; //return here...dont go further
|
||||
}
|
||||
try {
|
||||
Random rand = new Random();
|
||||
long testDelay = (long) Math.pow(2, this.attempts.intValue()) * 1000 + rand.nextInt(1000);
|
||||
long delay = testDelay < this.maxDelay ? testDelay : maxDelay;
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException f) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Random;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* Service class is an abstract class extended by all services in this example. They
|
||||
* all have a public receiveRequest method to receive requests, which could also contain
|
||||
* details of the user other than the implementation details (though we are not doing
|
||||
* that here) and updateDb method which adds to their respective databases. There is a
|
||||
* method to generate transaction/request id for the transactions/requests, which are
|
||||
* then sent back. These could be stored by the {@link Commander} class in a separate
|
||||
* database for reference (though we are not doing that here).
|
||||
*/
|
||||
|
||||
public abstract class Service {
|
||||
|
||||
protected final Database database;
|
||||
public ArrayList<Exception> exceptionsList;
|
||||
private static final String ALL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
|
||||
private static final Hashtable<String, Boolean> USED_IDS = new Hashtable<String, Boolean>();
|
||||
|
||||
protected Service(Database db, Exception...exc) {
|
||||
this.database = db;
|
||||
this.exceptionsList = new ArrayList<Exception>(Arrays.asList(exc));
|
||||
}
|
||||
|
||||
public abstract String receiveRequest(Object...parameters) throws DatabaseUnavailableException;
|
||||
protected abstract String updateDb(Object...parameters) throws DatabaseUnavailableException;
|
||||
|
||||
protected String generateId() {
|
||||
StringBuilder random = new StringBuilder();
|
||||
Random rand = new Random();
|
||||
while (random.length() < 12) { // length of the random string.
|
||||
int index = (int) (rand.nextFloat() * ALL_CHARS.length());
|
||||
random.append(ALL_CHARS.charAt(index));
|
||||
}
|
||||
String id = random.toString();
|
||||
if (USED_IDS.get(id) != null) {
|
||||
while (USED_IDS.get(id)) {
|
||||
id = generateId();
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander;
|
||||
|
||||
/**
|
||||
* User class contains details of user who places order.
|
||||
*/
|
||||
|
||||
public class User {
|
||||
String name;
|
||||
String address;
|
||||
|
||||
User(String name, String address) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.employeehandle;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import com.iluwatar.commander.Database;
|
||||
import com.iluwatar.commander.Order;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* The Employee Database is where orders which have encountered some issue(s) are added.
|
||||
*/
|
||||
|
||||
public class EmployeeDatabase extends Database<Order> {
|
||||
private Hashtable<String, Order> data;
|
||||
|
||||
public EmployeeDatabase() {
|
||||
this.data = new Hashtable<String, Order>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order add(Order o) throws DatabaseUnavailableException {
|
||||
return data.put(o.id,o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order get(String oId) throws DatabaseUnavailableException {
|
||||
return data.get(oId);
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.employeehandle;
|
||||
|
||||
import com.iluwatar.commander.Order;
|
||||
import com.iluwatar.commander.Service;
|
||||
import com.iluwatar.commander.exceptions.DatabaseUnavailableException;
|
||||
|
||||
/**
|
||||
* The EmployeeHandle class is the middle-man between {@link Commander} and
|
||||
* {@link EmployeeDatabase}.
|
||||
*/
|
||||
|
||||
public class EmployeeHandle extends Service {
|
||||
|
||||
public EmployeeHandle(EmployeeDatabase db, Exception...exc) {
|
||||
super(db, exc);
|
||||
}
|
||||
|
||||
public String receiveRequest(Object...parameters) throws DatabaseUnavailableException {
|
||||
return updateDb((Order)parameters[0]);
|
||||
}
|
||||
|
||||
protected String updateDb(Object...parameters) throws DatabaseUnavailableException {
|
||||
Order o = (Order) parameters[0];
|
||||
if (database.get(o.id) == null) {
|
||||
database.add(o);
|
||||
return o.id; //true rcvd - change addedToEmployeeHandle to true else dont do anything
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* DatabaseUnavailableException is thrown when database is unavailable and nothing
|
||||
* can be added or retrieved.
|
||||
*/
|
||||
|
||||
public class DatabaseUnavailableException extends Exception {
|
||||
private static final long serialVersionUID = 2459603L;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* IsEmptyException is thrown when it is attempted to dequeue from an empty queue.
|
||||
*/
|
||||
|
||||
public class IsEmptyException extends Exception {
|
||||
private static final long serialVersionUID = 123546L;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* ItemUnavailableException is thrown when item is not available for shipping.
|
||||
*/
|
||||
|
||||
public class ItemUnavailableException extends Exception {
|
||||
private static final long serialVersionUID = 575940L;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* The MIT License
|
||||
* Copyright (c) 2014-2016 Ilkka Sepp<70>l<EFBFBD>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.iluwatar.commander.exceptions;
|
||||
|
||||
/**
|
||||
* PaymentDetailsErrorException is thrown when the details entered are incorrect or
|
||||
* payment cannot be made with the details given.
|
||||
*/
|
||||
|
||||
public class PaymentDetailsErrorException extends Exception {
|
||||
private static final long serialVersionUID = 867203L;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user