BAEL 3320 JCommander (#7971)
* init jcommander * add model layer jcommander app * service scaffolding * init jcommander cli layer * wire up services and commands * splitter impl; validator impl; tests and cleanup * cleanup pom * integration tests * fix uuid validator example * optimise uuid regex; if-else to switch * review comments * fix builder formatting * change list assertion in fetch charges tests * missing minor edit * move to new module libraries-3 * rm unwanted files
This commit is contained in:
parent
f2d9829b91
commit
e16bd73565
|
@ -0,0 +1,9 @@
|
|||
## Libraries-3
|
||||
|
||||
This module contains articles about various Java libraries.
|
||||
These are small libraries that are relatively easy to use and do not require any separate module of their own.
|
||||
|
||||
The code examples related to different libraries are each in their own module.
|
||||
|
||||
Remember, for advanced libraries like [Jackson](/jackson) and [JUnit](/testing-modules) we already have separate modules. Please make sure to have a look at the existing modules in such cases.
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?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>
|
||||
<artifactId>libraries-3</artifactId>
|
||||
<name>libraries-3</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jboss-public-repository-group</id>
|
||||
<name>JBoss Public Repository Group</name>
|
||||
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>never</updatePolicy>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
<updatePolicy>daily</updatePolicy>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.beust</groupId>
|
||||
<artifactId>jcommander</artifactId>
|
||||
<version>${jcommander.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<jcommander.version>1.78</jcommander.version>
|
||||
<lombok.version>1.18.6</lombok.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
</properties>
|
||||
</project>
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.jcommander.helloworld;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
|
||||
public class HelloWorldApp {
|
||||
|
||||
/*
|
||||
* Execute:
|
||||
* mvn exec:java -Dexec.mainClass=com.baeldung.jcommander.helloworld.HelloWorldApp -q \
|
||||
* -Dexec.args="--name JavaWorld"
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
HelloWorldArgs jArgs = new HelloWorldArgs();
|
||||
JCommander helloCmd = JCommander
|
||||
.newBuilder()
|
||||
.addObject(jArgs)
|
||||
.build();
|
||||
|
||||
helloCmd.parse(args);
|
||||
System.out.println("Hello " + jArgs.getName());
|
||||
}
|
||||
}
|
||||
|
||||
class HelloWorldArgs {
|
||||
|
||||
@Parameter(
|
||||
names = "--name",
|
||||
description = "User name",
|
||||
required = true
|
||||
)
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.jcommander.usagebilling;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.cli.UsageBasedBilling;
|
||||
|
||||
public class UsageBasedBillingApp {
|
||||
|
||||
/*
|
||||
* Entry-point: invokes the cli passing the command-line args
|
||||
*
|
||||
* Invoking "Submit" sub-command:
|
||||
* mvn exec:java \
|
||||
-Dexec.mainClass=com.baeldung.jcommander.usagebilling.UsageBasedBillingApp -q \
|
||||
-Dexec.args="submit --customer cb898e7a-f2a0-46d2-9a09-531f1cee1839 --subscription subscriptionPQRMN001 --pricing-type PRE_RATED --timestamp 2019-10-03T10:58:00 --quantity 7 --price 24.56"
|
||||
*
|
||||
* Invoking "Fetch" sub-command:
|
||||
* mvn exec:java \
|
||||
-Dexec.mainClass=com.baeldung.jcommander.usagebilling.UsageBasedBillingApp -q \
|
||||
-Dexec.args="fetch --customer cb898e7a-f2a0-46d2-9a09-531f1cee1839 --subscription subscriptionPQRMN001 subscriptionPQRMN002 subscriptionPQRMN003 --itemized"
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new UsageBasedBilling().run(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.cli.splitter.ColonParameterSplitter;
|
||||
import com.baeldung.jcommander.usagebilling.cli.validator.UUIDValidator;
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesRequest;
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesResponse;
|
||||
import com.baeldung.jcommander.usagebilling.service.FetchCurrentChargesService;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.baeldung.jcommander.usagebilling.cli.UsageBasedBilling.*;
|
||||
import static com.baeldung.jcommander.usagebilling.service.FetchCurrentChargesService.getDefault;
|
||||
|
||||
@Parameters(
|
||||
commandNames = { FETCH_CMD },
|
||||
commandDescription = "Fetch charges for a customer in the current month, can be itemized or aggregated"
|
||||
)
|
||||
@Getter
|
||||
class FetchCurrentChargesCommand {
|
||||
|
||||
FetchCurrentChargesCommand() {
|
||||
}
|
||||
|
||||
private FetchCurrentChargesService service = getDefault();
|
||||
|
||||
@Parameter(names = "--help", help = true)
|
||||
private boolean help;
|
||||
|
||||
@Parameter(
|
||||
names = { "--customer", "-C" },
|
||||
description = "Id of the Customer who's using the services",
|
||||
validateWith = UUIDValidator.class,
|
||||
order = 1,
|
||||
required = true
|
||||
)
|
||||
private String customerId;
|
||||
|
||||
@Parameter(
|
||||
names = { "--subscription", "-S" },
|
||||
description = "Filter charges for specific subscription Ids, includes all subscriptions if no value is specified",
|
||||
variableArity = true,
|
||||
splitter = ColonParameterSplitter.class,
|
||||
order = 2
|
||||
)
|
||||
private List<String> subscriptionIds;
|
||||
|
||||
@Parameter(
|
||||
names = { "--itemized" },
|
||||
description = "Whether the response should contain breakdown by subscription, only aggregate values are returned by default",
|
||||
order = 3
|
||||
)
|
||||
private boolean itemized;
|
||||
|
||||
void fetch() {
|
||||
CurrentChargesRequest req = CurrentChargesRequest.builder()
|
||||
.customerId(customerId)
|
||||
.subscriptionIds(subscriptionIds)
|
||||
.itemized(itemized)
|
||||
.build();
|
||||
|
||||
CurrentChargesResponse response = service.fetch(req);
|
||||
System.out.println(response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.cli.converter.ISO8601TimestampConverter;
|
||||
import com.baeldung.jcommander.usagebilling.cli.validator.UUIDValidator;
|
||||
import com.baeldung.jcommander.usagebilling.model.UsageRequest;
|
||||
import com.baeldung.jcommander.usagebilling.model.UsageRequest.PricingType;
|
||||
import com.baeldung.jcommander.usagebilling.service.SubmitUsageService;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
import static com.baeldung.jcommander.usagebilling.cli.UsageBasedBilling.*;
|
||||
import static com.baeldung.jcommander.usagebilling.service.SubmitUsageService.getDefault;
|
||||
|
||||
@Parameters(
|
||||
commandNames = { SUBMIT_CMD },
|
||||
commandDescription = "Submit usage for a given customer and subscription, accepts one usage item"
|
||||
)
|
||||
@Getter
|
||||
class SubmitUsageCommand {
|
||||
|
||||
SubmitUsageCommand() {
|
||||
}
|
||||
|
||||
private SubmitUsageService service = getDefault();
|
||||
|
||||
@Parameter(names = "--help", help = true)
|
||||
private boolean help;
|
||||
|
||||
@Parameter(
|
||||
names = { "--customer", "-C" },
|
||||
description = "Id of the Customer who's using the services",
|
||||
validateWith = UUIDValidator.class,
|
||||
order = 1,
|
||||
required = true
|
||||
)
|
||||
private String customerId;
|
||||
|
||||
@Parameter(
|
||||
names = { "--subscription", "-S" },
|
||||
description = "Id of the Subscription that was purchased",
|
||||
order = 2,
|
||||
required = true
|
||||
)
|
||||
private String subscriptionId;
|
||||
|
||||
@Parameter(
|
||||
names = { "--pricing-type", "-P" },
|
||||
description = "Pricing type of the usage reported",
|
||||
order = 3,
|
||||
required = true
|
||||
)
|
||||
private PricingType pricingType;
|
||||
|
||||
@Parameter(
|
||||
names = { "--quantity" },
|
||||
description = "Used quantity; reported quantity is added over the billing period",
|
||||
order = 3,
|
||||
required = true
|
||||
)
|
||||
private Integer quantity;
|
||||
|
||||
@Parameter(
|
||||
names = { "--timestamp" },
|
||||
description = "Timestamp of the usage event, must lie in the current billing period",
|
||||
converter = ISO8601TimestampConverter.class,
|
||||
order = 4,
|
||||
required = true
|
||||
)
|
||||
private Instant timestamp;
|
||||
|
||||
@Parameter(
|
||||
names = { "--price" },
|
||||
description = "If PRE_RATED, unit price to be applied per unit of usage quantity reported",
|
||||
order = 5
|
||||
)
|
||||
private BigDecimal price;
|
||||
|
||||
void submit() {
|
||||
|
||||
UsageRequest req = UsageRequest.builder()
|
||||
.customerId(customerId)
|
||||
.subscriptionId(subscriptionId)
|
||||
.pricingType(pricingType)
|
||||
.quantity(quantity)
|
||||
.timestamp(timestamp)
|
||||
.price(price)
|
||||
.build();
|
||||
|
||||
String reqId = service.submit(req);
|
||||
System.out.println("Generated Request Id for reference: " + reqId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.beust.jcommander.UnixStyleUsageFormatter;
|
||||
|
||||
public class UsageBasedBilling {
|
||||
|
||||
static final String SUBMIT_CMD = "submit";
|
||||
static final String FETCH_CMD = "fetch";
|
||||
|
||||
private JCommander jCommander;
|
||||
private SubmitUsageCommand submitUsageCmd;
|
||||
private FetchCurrentChargesCommand fetchChargesCmd;
|
||||
|
||||
public UsageBasedBilling() {
|
||||
this.submitUsageCmd = new SubmitUsageCommand();
|
||||
this.fetchChargesCmd = new FetchCurrentChargesCommand();
|
||||
jCommander = JCommander.newBuilder()
|
||||
.addObject(this)
|
||||
.addCommand(submitUsageCmd)
|
||||
.addCommand(fetchChargesCmd)
|
||||
.build();
|
||||
|
||||
setUsageFormatter(SUBMIT_CMD);
|
||||
setUsageFormatter(FETCH_CMD);
|
||||
}
|
||||
|
||||
public void run(String[] args) {
|
||||
String parsedCmdStr;
|
||||
try {
|
||||
jCommander.parse(args);
|
||||
parsedCmdStr = jCommander.getParsedCommand();
|
||||
|
||||
switch (parsedCmdStr) {
|
||||
case SUBMIT_CMD:
|
||||
if (submitUsageCmd.isHelp()) {
|
||||
getSubCommandHandle(SUBMIT_CMD).usage();
|
||||
}
|
||||
System.out.println("Parsing usage request...");
|
||||
submitUsageCmd.submit();
|
||||
break;
|
||||
|
||||
case FETCH_CMD:
|
||||
if (fetchChargesCmd.isHelp()) {
|
||||
getSubCommandHandle(SUBMIT_CMD).usage();
|
||||
}
|
||||
System.out.println("Preparing fetch query...");
|
||||
fetchChargesCmd.fetch();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
System.err.println("Invalid command: " + parsedCmdStr);
|
||||
}
|
||||
} catch (ParameterException e) {
|
||||
System.err.println(e.getLocalizedMessage());
|
||||
parsedCmdStr = jCommander.getParsedCommand();
|
||||
if (parsedCmdStr != null) {
|
||||
getSubCommandHandle(parsedCmdStr).usage();
|
||||
} else {
|
||||
jCommander.usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JCommander getSubCommandHandle(String command) {
|
||||
JCommander cmd = jCommander.getCommands().get(command);
|
||||
|
||||
if (cmd == null) {
|
||||
System.err.println("Invalid command: " + command);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private void setUsageFormatter(String subCommand) {
|
||||
JCommander cmd = getSubCommandHandle(subCommand);
|
||||
cmd.setUsageFormatter(new UnixStyleUsageFormatter(cmd));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli.converter;
|
||||
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.beust.jcommander.converters.BaseConverter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
public class ISO8601TimestampConverter extends BaseConverter<Instant> {
|
||||
|
||||
private static final DateTimeFormatter TS_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss");
|
||||
|
||||
public ISO8601TimestampConverter(String optionName) {
|
||||
super(optionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant convert(String value) {
|
||||
try {
|
||||
return LocalDateTime
|
||||
.parse(value, TS_FORMATTER)
|
||||
.atOffset(ZoneOffset.UTC)
|
||||
.toInstant();
|
||||
} catch (DateTimeParseException e) {
|
||||
throw new ParameterException(getErrorString(value, format("an ISO-8601 formatted timestamp (%s)", TS_FORMATTER.toString())));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli.splitter;
|
||||
|
||||
import com.beust.jcommander.converters.IParameterSplitter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class ColonParameterSplitter implements IParameterSplitter {
|
||||
|
||||
@Override
|
||||
public List<String> split(String value) {
|
||||
return asList(value.split(":"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli.validator;
|
||||
|
||||
import com.beust.jcommander.IParameterValidator;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class UUIDValidator implements IParameterValidator {
|
||||
|
||||
private static final String UUID_REGEX =
|
||||
"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}";
|
||||
|
||||
@Override
|
||||
public void validate(String name, String value) throws ParameterException {
|
||||
if (!isValidUUID(value)) {
|
||||
throw new ParameterException(
|
||||
"String parameter " + value + " is not a valid UUID.");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidUUID(String value) {
|
||||
return Pattern
|
||||
.compile(UUID_REGEX)
|
||||
.matcher(value).matches();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.jcommander.usagebilling.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@Builder
|
||||
@Getter
|
||||
public class CurrentChargesRequest {
|
||||
|
||||
private String customerId;
|
||||
private List<String> subscriptionIds;
|
||||
private boolean itemized;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.baeldung.jcommander.usagebilling.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@Builder
|
||||
@Getter
|
||||
public class CurrentChargesResponse {
|
||||
|
||||
private String customerId;
|
||||
private BigDecimal amountDue;
|
||||
private List<LineItem> lineItems;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb
|
||||
.append("Current Month Charges: {")
|
||||
.append("\n\tcustomer: ")
|
||||
.append(this.customerId)
|
||||
.append("\n\ttotalAmountDue: ")
|
||||
.append(this.amountDue.setScale(2, RoundingMode.HALF_UP))
|
||||
.append("\n\tlineItems: [");
|
||||
|
||||
for (LineItem li : this.lineItems) {
|
||||
sb
|
||||
.append("\n\t\t{")
|
||||
.append("\n\t\t\tsubscription: ")
|
||||
.append(li.subscriptionId)
|
||||
.append("\n\t\t\tamount: ")
|
||||
.append(li.amount.setScale(2, RoundingMode.HALF_UP))
|
||||
.append("\n\t\t\tquantity: ")
|
||||
.append(li.quantity)
|
||||
.append("\n\t\t},");
|
||||
}
|
||||
|
||||
sb.append("\n\t]\n}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@Builder
|
||||
@Getter
|
||||
public static class LineItem {
|
||||
|
||||
private String subscriptionId;
|
||||
private BigDecimal amount;
|
||||
private Integer quantity;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.baeldung.jcommander.usagebilling.model;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
@Builder
|
||||
@Getter
|
||||
public class UsageRequest {
|
||||
|
||||
private String customerId;
|
||||
private String subscriptionId;
|
||||
private PricingType pricingType;
|
||||
private Integer quantity;
|
||||
private BigDecimal price;
|
||||
private Instant timestamp;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb
|
||||
.append("\nUsage: {")
|
||||
.append("\n\tcustomer: ")
|
||||
.append(this.customerId)
|
||||
.append("\n\tsubscription: ")
|
||||
.append(this.subscriptionId)
|
||||
.append("\n\tquantity: ")
|
||||
.append(this.quantity)
|
||||
.append("\n\ttimestamp: ")
|
||||
.append(this.timestamp)
|
||||
.append("\n\tpricingType: ")
|
||||
.append(this.pricingType);
|
||||
|
||||
if (PricingType.PRE_RATED == this.pricingType) {
|
||||
sb
|
||||
.append("\n\tpreRatedAt: ")
|
||||
.append(this.price);
|
||||
}
|
||||
|
||||
sb.append("\n}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public enum PricingType {
|
||||
PRE_RATED, UNRATED
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.baeldung.jcommander.usagebilling.service;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesRequest;
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesResponse;
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesResponse.LineItem;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Arrays.fill;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.concurrent.ThreadLocalRandom.current;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
class DefaultFetchCurrentChargesService implements FetchCurrentChargesService {
|
||||
|
||||
@Override
|
||||
public CurrentChargesResponse fetch(CurrentChargesRequest request) {
|
||||
List<String> subscriptions = request.getSubscriptionIds();
|
||||
|
||||
if (subscriptions == null || subscriptions.isEmpty()) {
|
||||
System.out.println("Fetching ALL charges for customer: " + request.getCustomerId());
|
||||
subscriptions = mockSubscriptions();
|
||||
|
||||
} else {
|
||||
System.out.println(format("Fetching charges for customer: %s and subscriptions: %s", request.getCustomerId(), subscriptions));
|
||||
}
|
||||
|
||||
CurrentChargesResponse charges = mockCharges(request.getCustomerId(), subscriptions, request.isItemized());
|
||||
System.out.println("Fetched charges...");
|
||||
return charges;
|
||||
}
|
||||
|
||||
private CurrentChargesResponse mockCharges(String customerId, List<String> subscriptions, boolean itemized) {
|
||||
List<LineItem> lineItems = mockLineItems(subscriptions);
|
||||
BigDecimal amountDue = lineItems
|
||||
.stream()
|
||||
.map(li -> li.getAmount())
|
||||
.reduce(new BigDecimal("0"), BigDecimal::add);
|
||||
|
||||
return CurrentChargesResponse
|
||||
.builder()
|
||||
.customerId(customerId)
|
||||
.lineItems(itemized ? lineItems : emptyList())
|
||||
.amountDue(amountDue)
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<LineItem> mockLineItems(List<String> subscriptions) {
|
||||
return subscriptions
|
||||
.stream()
|
||||
.map(subscription -> LineItem.builder()
|
||||
.subscriptionId(subscription)
|
||||
.quantity(current().nextInt(20))
|
||||
.amount(new BigDecimal(current().nextDouble(1_000)))
|
||||
.build())
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
private List<String> mockSubscriptions() {
|
||||
String[] subscriptions = new String[5];
|
||||
fill(subscriptions, UUID.randomUUID().toString());
|
||||
return asList(subscriptions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.jcommander.usagebilling.service;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.model.UsageRequest;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
class DefaultSubmitUsageService implements SubmitUsageService {
|
||||
|
||||
@Override
|
||||
public String submit(UsageRequest request) {
|
||||
System.out.println("Submitting usage..." + request);
|
||||
|
||||
System.out.println("Submitted usage successfully...");
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.jcommander.usagebilling.service;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesRequest;
|
||||
import com.baeldung.jcommander.usagebilling.model.CurrentChargesResponse;
|
||||
|
||||
public interface FetchCurrentChargesService {
|
||||
|
||||
static FetchCurrentChargesService getDefault() {
|
||||
return new DefaultFetchCurrentChargesService();
|
||||
}
|
||||
|
||||
CurrentChargesResponse fetch(CurrentChargesRequest request);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.jcommander.usagebilling.service;
|
||||
|
||||
import com.baeldung.jcommander.usagebilling.model.UsageRequest;
|
||||
|
||||
public interface SubmitUsageService {
|
||||
|
||||
static SubmitUsageService getDefault() {
|
||||
return new DefaultSubmitUsageService();
|
||||
}
|
||||
|
||||
String submit(UsageRequest request);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.jcommander.helloworld;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HelloWorldAppUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenJCommanderInvokedWithArgs_thenArgsParsed() {
|
||||
|
||||
HelloWorldArgs jArgs = new HelloWorldArgs();
|
||||
JCommander helloCmd = JCommander
|
||||
.newBuilder()
|
||||
.addObject(jArgs)
|
||||
.build();
|
||||
|
||||
// when
|
||||
String[] argv = new String[] {
|
||||
"--name", "JavaWorld"
|
||||
};
|
||||
helloCmd.parse(argv);
|
||||
|
||||
// then
|
||||
assertEquals("JavaWorld", jArgs.getName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class FetchCurrentChargesCommandUnitTest {
|
||||
|
||||
private JCommander jc = JCommander.newBuilder()
|
||||
.addObject(new FetchCurrentChargesCommand())
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void whenParsedMultipleSubscriptionsParameter_thenParameterSubscriptionsIsPopulated() {
|
||||
FetchCurrentChargesCommand cmd = (FetchCurrentChargesCommand) jc
|
||||
.getObjects()
|
||||
.get(0);
|
||||
|
||||
jc.parse(new String[] {
|
||||
"-C", "cb898e7a-f2a0-46d2-9a09-531f1cee1839",
|
||||
"-S", "subscriptionA001",
|
||||
"-S", "subscriptionA002",
|
||||
"-S", "subscriptionA003",
|
||||
});
|
||||
|
||||
assertThat(cmd.getSubscriptionIds(),
|
||||
contains("subscriptionA001", "subscriptionA002", "subscriptionA003"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenParsedSubscriptionsColonSeparatedParameter_thenParameterSubscriptionsIsPopulated() {
|
||||
FetchCurrentChargesCommand cmd = (FetchCurrentChargesCommand) jc
|
||||
.getObjects()
|
||||
.get(0);
|
||||
|
||||
jc.parse(new String[] {
|
||||
"-C", "cb898e7a-f2a0-46d2-9a09-531f1cee1839",
|
||||
"-S", "subscriptionA001:subscriptionA002:subscriptionA003",
|
||||
});
|
||||
|
||||
assertThat(cmd.getSubscriptionIds(),
|
||||
contains("subscriptionA001", "subscriptionA002", "subscriptionA003"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenParsedSubscriptionsWithVariableArity_thenParameterSubscriptionsIsPopulated() {
|
||||
FetchCurrentChargesCommand cmd = (FetchCurrentChargesCommand) jc
|
||||
.getObjects()
|
||||
.get(0);
|
||||
|
||||
jc.parse(new String[] {
|
||||
"-C", "cb898e7a-f2a0-46d2-9a09-531f1cee1839",
|
||||
"-S", "subscriptionA001", "subscriptionA002", "subscriptionA003",
|
||||
});
|
||||
|
||||
assertThat(cmd.getSubscriptionIds(),
|
||||
contains("subscriptionA001", "subscriptionA002", "subscriptionA003"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.baeldung.jcommander.usagebilling.cli;
|
||||
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SubmitUsageCommandUnitTest {
|
||||
|
||||
private JCommander jc = JCommander.newBuilder()
|
||||
.addObject(new SubmitUsageCommand())
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void whenParsedCustomerParameter_thenParameterOfTypeStringIsPopulated() {
|
||||
jc.parse(new String[] {
|
||||
"--customer", "cb898e7a-f2a0-46d2-9a09-531f1cee1839",
|
||||
"--subscription", "subscriptionPQRMN001",
|
||||
"--pricing-type", "PRE_RATED",
|
||||
"--timestamp", "2019-10-03T10:58:00",
|
||||
"--quantity", "7",
|
||||
"--price", "24.56"
|
||||
});
|
||||
|
||||
SubmitUsageCommand cmd = (SubmitUsageCommand) jc
|
||||
.getObjects()
|
||||
.get(0);
|
||||
assertEquals("cb898e7a-f2a0-46d2-9a09-531f1cee1839", cmd.getCustomerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenParsedTimestampParameter_thenParameterOfTypeInstantIsPopulated() {
|
||||
jc.parse(new String[] {
|
||||
"--customer", "cb898e7a-f2a0-46d2-9a09-531f1cee1839",
|
||||
"--subscription", "subscriptionPQRMN001",
|
||||
"--pricing-type", "PRE_RATED",
|
||||
"--timestamp", "2019-10-03T10:58:00",
|
||||
"--quantity", "7",
|
||||
"--price", "24.56"
|
||||
});
|
||||
|
||||
SubmitUsageCommand cmd = (SubmitUsageCommand) jc
|
||||
.getObjects()
|
||||
.get(0);
|
||||
assertEquals("2019-10-03T10:58:00Z", cmd
|
||||
.getTimestamp()
|
||||
.toString());
|
||||
}
|
||||
|
||||
@Test(expected = ParameterException.class)
|
||||
public void whenParsedCustomerIdNotUUID_thenParameterException() {
|
||||
jc.parse(new String[] {
|
||||
"--customer", "customer001",
|
||||
"--subscription", "subscriptionPQRMN001",
|
||||
"--pricing-type", "PRE_RATED",
|
||||
"--timestamp", "2019-10-03T10:58:00",
|
||||
"--quantity", "7",
|
||||
"--price", "24.56"
|
||||
});
|
||||
}
|
||||
}
|
2
pom.xml
2
pom.xml
|
@ -541,6 +541,7 @@
|
|||
<!-- <module>lagom</module> --> <!-- Not a maven project -->
|
||||
<module>libraries</module>
|
||||
<module>libraries-2</module>
|
||||
<module>libraries-3</module>
|
||||
<module>libraries-data</module>
|
||||
<module>libraries-data-2</module>
|
||||
<module>libraries-data-db</module>
|
||||
|
@ -1307,6 +1308,7 @@
|
|||
|
||||
<!-- <module>lagom</module> --> <!-- Not a maven project -->
|
||||
<module>libraries</module>
|
||||
<module>libraries-3</module>
|
||||
<module>libraries-data</module>
|
||||
<module>libraries-data-2</module>
|
||||
<module>libraries-data-db</module>
|
||||
|
|
Loading…
Reference in New Issue