Browse Source

Fast!

master
Pascal Widdershoven 7 years ago
commit
b59fddeb02

+ 3
- 0
.gitignore View File

@@ -0,0 +1,3 @@
*.iml
.idea/
target/

+ 37
- 0
pom.xml View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>

<groupId>co.wuunder</groupId>
<artifactId>rule-engine</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.3</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 19
- 0
src/main/java/co/wuunder/rule_engine/Address.java View File

@@ -0,0 +1,19 @@
package co.wuunder.rule_engine;

public class Address {
public final String country;
public final String business;

public Address(String country, String business) {
this.country = country;
this.business = business;
}

public String type() {
if(this.business == null || this.business.isEmpty()) {
return "consumer";
} else {
return "business";
}
}
}

+ 21
- 0
src/main/java/co/wuunder/rule_engine/RandomRules.java View File

@@ -0,0 +1,21 @@
package co.wuunder.rule_engine;

import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.toList;

public class RandomRules {
private static final Random random = new Random(System.currentTimeMillis());

public static List<RateRule> randomRules(int numberOfRules) {
return IntStream.range(0, numberOfRules)
.mapToObj(RandomRules::randomRule)
.collect(toList());
}

private static RateRule randomRule(int _n) {
return new RateRule(random.nextInt(), random.nextInt(), random.nextInt(), random.nextInt() % 2 == 0, random.nextInt(), "NL", "consumer", "NL", "consumer");
}
}

+ 62
- 0
src/main/java/co/wuunder/rule_engine/RateRule.java View File

@@ -0,0 +1,62 @@
package co.wuunder.rule_engine;

public class RateRule {
public final int minWeight;
public final int maxWeight;
public final int maxLengthHeightWidth;
public final boolean isReturn;
public final int maxDimension;
public final String pickupCountry;
public final String pickupAddressType;
public final String deliveryCountry;
public final String deliveryAddressType;

public RateRule(int minWeight, int maxWeight, int maxLengthHeightWidth, boolean isReturn,
int maxDimension, String pickupCountry, String pickupAddressType, String deliveryCountry,
String deliveryAddressType) {
this.minWeight = minWeight;
this.maxWeight = maxWeight;
this.maxLengthHeightWidth = maxLengthHeightWidth;
this.isReturn = isReturn;
this.maxDimension = maxDimension;
this.pickupCountry = pickupCountry;
this.pickupAddressType = pickupAddressType;
this.deliveryCountry = deliveryCountry;
this.deliveryAddressType = deliveryAddressType;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

RateRule rateRule = (RateRule) o;

if (minWeight != rateRule.minWeight) return false;
if (maxWeight != rateRule.maxWeight) return false;
if (maxLengthHeightWidth != rateRule.maxLengthHeightWidth) return false;
if (isReturn != rateRule.isReturn) return false;
if (maxDimension != rateRule.maxDimension) return false;
if (pickupCountry != null ? !pickupCountry.equals(rateRule.pickupCountry) : rateRule.pickupCountry != null)
return false;
if (pickupAddressType != null ? !pickupAddressType.equals(rateRule.pickupAddressType) : rateRule.pickupAddressType != null)
return false;
if (deliveryCountry != null ? !deliveryCountry.equals(rateRule.deliveryCountry) : rateRule.deliveryCountry != null)
return false;
return deliveryAddressType != null ? deliveryAddressType.equals(rateRule.deliveryAddressType) : rateRule.deliveryAddressType == null;
}

@Override
public int hashCode() {
int result = minWeight;
result = 31 * result + maxWeight;
result = 31 * result + maxLengthHeightWidth;
result = 31 * result + (isReturn ? 1 : 0);
result = 31 * result + maxDimension;
result = 31 * result + (pickupCountry != null ? pickupCountry.hashCode() : 0);
result = 31 * result + (pickupAddressType != null ? pickupAddressType.hashCode() : 0);
result = 31 * result + (deliveryCountry != null ? deliveryCountry.hashCode() : 0);
result = 31 * result + (deliveryAddressType != null ? deliveryAddressType.hashCode() : 0);
return result;
}
}

+ 37
- 0
src/main/java/co/wuunder/rule_engine/RuleEngine.java View File

@@ -0,0 +1,37 @@
package co.wuunder.rule_engine;

import java.util.Arrays;
import java.util.List;
import java.util.function.BiPredicate;

import static java.util.stream.Collectors.toList;

public class RuleEngine {

private final List<RateRule> rules;
private final List<BiPredicate<Shipment, RateRule>> functions;

public RuleEngine(List<RateRule> rules) {
this.rules = rules;
this.functions = Arrays.asList(
Rules::matchesHeight,
Rules::matchesLength,
Rules::matchesWeight,
Rules::matchesWidth,
Rules::matchesReturn,
Rules::matchesDimensions,
Rules::matchesPickupCountry,
Rules::matchesPickupAddressType,
Rules::matchesDeliveryCountry,
Rules::matchesDeliveryAddressType
);
}

public List<RateRule> generateRules(Shipment shipment) {
return rules.stream().filter(rule -> matchesRule(shipment, rule)).collect(toList());
}

private boolean matchesRule(Shipment shipment, RateRule rateRule) {
return functions.stream().allMatch(f -> f.test(shipment, rateRule));
}
}

+ 44
- 0
src/main/java/co/wuunder/rule_engine/Rules.java View File

@@ -0,0 +1,44 @@
package co.wuunder.rule_engine;

public class Rules {

public static boolean matchesWeight(Shipment shipment, RateRule rateRule) {
return shipment.weight >= rateRule.minWeight && shipment.weight <= rateRule.maxWeight;
}

public static boolean matchesLength(Shipment shipment, RateRule rateRule) {
return shipment.length < rateRule.maxLengthHeightWidth;
}

public static boolean matchesWidth(Shipment shipment, RateRule rateRule) {
return shipment.width < rateRule.maxLengthHeightWidth;
}

public static boolean matchesHeight(Shipment shipment, RateRule rateRule) {
return shipment.height < rateRule.maxLengthHeightWidth;
}

public static boolean matchesDimensions(Shipment shipment, RateRule rateRule) {
return shipment.dimensions() <= rateRule.maxDimension;
}

public static boolean matchesPickupCountry(Shipment shipment, RateRule rateRule) {
return shipment.pickupCountry().equals(rateRule.pickupCountry);
}

public static boolean matchesPickupAddressType(Shipment shipment, RateRule rateRule) {
return shipment.pickupAddressType().equals(rateRule.pickupAddressType);
}

public static boolean matchesDeliveryCountry(Shipment shipment, RateRule rateRule) {
return shipment.deliveryCountry().equals(rateRule.deliveryCountry);
}

public static boolean matchesDeliveryAddressType(Shipment shipment, RateRule rateRule) {
return shipment.deliveryAddressType().equals(rateRule.deliveryAddressType);
}

public static boolean matchesReturn(Shipment shipment, RateRule rateRule) {
return shipment.isReturn == rateRule.isReturn;
}
}

+ 53
- 0
src/main/java/co/wuunder/rule_engine/Shipment.java View File

@@ -0,0 +1,53 @@
package co.wuunder.rule_engine;

public class Shipment {
public final int weight;
public final int width;
public final int height;
public final int length;
public final boolean isReturn;
public final boolean dropoff;
public final Address pickupAddress;
public final Address deliveryAddress;

public Shipment(int weight, int width, int height, int length, boolean isReturn, boolean dropoff,
Address pickupAddress, Address deliveryAddress) {
this.weight = weight;
this.width = width;
this.height = height;
this.length = length;
this.isReturn = isReturn;
this.dropoff = dropoff;
this.pickupAddress = pickupAddress;
this.deliveryAddress = deliveryAddress;
}

public String deliveryCountry() {
return this.deliveryAddress.country;
}

public String deliveryAddressType() {
if(this.dropoff) {
return "parcelshop";
}

return this.deliveryAddress.type();
}

public String pickupCountry() {
return this.pickupAddress.country;
}

public String pickupAddressType() {
if(this.dropoff) {
return "parcelshop";
}

return this.pickupAddress.type();
}

public int dimensions() {
double dimensions = (2.0 * this.weight) + (2 * this.height) + this.length;
return (int)Math.ceil(dimensions);
}
}

+ 34
- 0
src/test/java/PerfTest.java View File

@@ -0,0 +1,34 @@
import co.wuunder.rule_engine.Address;
import co.wuunder.rule_engine.RuleEngine;
import co.wuunder.rule_engine.Shipment;
import org.junit.jupiter.api.Test;

import java.util.Random;

import static co.wuunder.rule_engine.RandomRules.*;

public class PerfTest {
private final RuleEngine ruleEngine = new RuleEngine(randomRules(100_000));

@Test
public void perf() {
long start = System.currentTimeMillis();
int numberOfShipments = 50;

for(int i = 0 ; i < numberOfShipments; i++) {
ruleEngine.generateRules(randomShipment());
}

long end = System.currentTimeMillis();

System.out.println((end - start) / numberOfShipments);
}

private Shipment randomShipment() {
Random random = new Random(System.currentTimeMillis());
Address pickupAddress = new Address("NL", "");
Address deliveryAddress = new Address("NL", "");

return new Shipment(random.nextInt(), random.nextInt(), random.nextInt(), random.nextInt(), random.nextInt() % 2 == 0, random.nextInt() % 2 == 0, pickupAddress, deliveryAddress);
}
}

Loading…
Cancel
Save