mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 09:17:43 +03:00
Typed ACS and transaction streams for Java codegen (#15159)
* added transactionFilter * move transactionFilter to `TransactionFilter` * fromCreatedEvent * format * added getTransaction with contract type companion * ACS using contract type companion * position * add change log CHANGELOG_BEGIN CHANGELOG_END * Ct * Ct * format * better exception * fixed test cases * added java doc and rename method to GetContracts * address Stephen's comments * address Stephen's comments * address Stephen's comments * remove unused import * format * address Stephen's comments * address Stephen's comments * Make some codegen code to be java 8 compatible; Modify IouMain to use the new getActiveContracts. to address Stephen's comments * use 1.11, no need to be java 8 compatible * revert * 11 not 1.11
This commit is contained in:
parent
a49dd9ed8c
commit
74dd242984
@ -9,8 +9,8 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<daml-codegen-java.output>${project.build.directory}/generated-sources/iou</daml-codegen-java.output>
|
||||
<ledgerhost>localhost</ledgerhost>
|
||||
<ledgerport>6865</ledgerport>
|
||||
|
@ -4,6 +4,7 @@
|
||||
package com.daml.quickstart.iou;
|
||||
|
||||
import com.daml.ledger.javaapi.data.*;
|
||||
import com.daml.ledger.rxjava.ContractUtil;
|
||||
import com.daml.ledger.rxjava.DamlLedgerClient;
|
||||
import com.daml.ledger.rxjava.LedgerClient;
|
||||
import com.daml.quickstart.model.iou.Iou;
|
||||
@ -59,14 +60,14 @@ public class IouMain {
|
||||
|
||||
client
|
||||
.getActiveContractSetClient()
|
||||
.getActiveContracts(iouFilter, true)
|
||||
.getActiveContracts(ContractUtil.of(Iou.COMPANION), Collections.singleton(party), true)
|
||||
.blockingForEach(
|
||||
response -> {
|
||||
response
|
||||
activeContracts -> {
|
||||
activeContracts
|
||||
.getOffset()
|
||||
.ifPresent(offset -> acsOffset.set(new LedgerOffset.Absolute(offset)));
|
||||
response.getCreatedEvents().stream()
|
||||
.map(Iou.Contract::fromCreatedEvent)
|
||||
activeContracts
|
||||
.getContracts()
|
||||
.forEach(
|
||||
contract -> {
|
||||
long id = idCounter.getAndIncrement();
|
||||
|
@ -3,9 +3,11 @@
|
||||
|
||||
package com.daml.ledger.rxjava;
|
||||
|
||||
import com.daml.ledger.javaapi.data.ActiveContracts;
|
||||
import com.daml.ledger.javaapi.data.GetActiveContractsResponse;
|
||||
import com.daml.ledger.javaapi.data.TransactionFilter;
|
||||
import io.reactivex.Flowable;
|
||||
import java.util.Set;
|
||||
|
||||
/** An RxJava version of {@link com.daml.ledger.api.v1.ActiveContractsServiceGrpc} */
|
||||
public interface ActiveContractsClient {
|
||||
@ -15,4 +17,31 @@ public interface ActiveContractsClient {
|
||||
|
||||
Flowable<GetActiveContractsResponse> getActiveContracts(
|
||||
TransactionFilter filter, boolean verbose, String accessToken);
|
||||
|
||||
/**
|
||||
* Get active Contracts
|
||||
*
|
||||
* @param contractUtil Utilities for specified type of contract. It can be instantiated with
|
||||
* <code>ContractTypeCompanion</code>
|
||||
* @param parties Set of parties to be included in the transaction filter.
|
||||
* @param verbose If enabled, values served over the API will contain more information than
|
||||
* strictly necessary to interpret the data.
|
||||
* @return Flowable of active contracts of type <code>Ct</code>
|
||||
*/
|
||||
<Ct> Flowable<ActiveContracts<Ct>> getActiveContracts(
|
||||
ContractUtil<Ct> contractUtil, Set<String> parties, boolean verbose);
|
||||
|
||||
/**
|
||||
* Get active Contracts
|
||||
*
|
||||
* @param contractUtil Utilities for specified type of contract. It can be instantiated with
|
||||
* <code>ContractTypeCompanion</code>
|
||||
* @param parties Set of parties to be included in the transaction filter.
|
||||
* @param verbose If enabled, values served over the API will contain more information than
|
||||
* strictly necessary to interpret the data.
|
||||
* @param accessToken Access token for authentication.
|
||||
* @return Active contracts of type <code>Ct</code>
|
||||
*/
|
||||
<Ct> Flowable<ActiveContracts<Ct>> getActiveContracts(
|
||||
ContractUtil<Ct> contractUtil, Set<String> parties, boolean verbose, String accessToken);
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.ledger.rxjava;
|
||||
|
||||
import com.daml.ledger.javaapi.data.*;
|
||||
import com.daml.ledger.javaapi.data.codegen.Contract;
|
||||
import com.daml.ledger.javaapi.data.codegen.ContractCompanion;
|
||||
import com.daml.ledger.javaapi.data.codegen.InterfaceCompanion;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This class contains utilities to decode a <code>CreatedEvent</code> and create a <code>
|
||||
* TransactionFilter</code> by provider parties It can only be instantiated with a subtype of <code>
|
||||
* ContractCompanion</code>
|
||||
*/
|
||||
public final class ContractUtil<Ct> {
|
||||
private final FromCreatedEventFunc<CreatedEvent, Ct> fromCreatedEvent;
|
||||
|
||||
private final Filter filter;
|
||||
|
||||
private ContractUtil(FromCreatedEventFunc<CreatedEvent, Ct> fromCreatedEvent, Filter filter) {
|
||||
this.fromCreatedEvent = fromCreatedEvent;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public static <Ct> ContractUtil<Ct> of(ContractCompanion<Ct, ?, ?> companion) {
|
||||
Filter filter =
|
||||
new InclusiveFilter(Collections.singleton(companion.TEMPLATE_ID), Collections.emptyMap());
|
||||
return new ContractUtil<>(companion::fromCreatedEvent, filter);
|
||||
}
|
||||
|
||||
public static <Cid, View> ContractUtil<Contract<Cid, View>> of(
|
||||
InterfaceCompanion<?, Cid, View> companion) {
|
||||
Filter filter =
|
||||
new InclusiveFilter(
|
||||
Collections.emptySet(),
|
||||
Collections.singletonMap(companion.TEMPLATE_ID, Filter.Interface.INCLUDE_VIEW));
|
||||
return new ContractUtil<>(companion::fromCreatedEvent, filter);
|
||||
}
|
||||
|
||||
public Ct toContract(CreatedEvent createdEvent) throws IllegalArgumentException {
|
||||
return fromCreatedEvent.apply(createdEvent);
|
||||
}
|
||||
|
||||
public TransactionFilter transactionFilter(Set<String> parties) {
|
||||
return transactionFilter(filter, parties);
|
||||
}
|
||||
|
||||
private static TransactionFilter transactionFilter(Filter filter, Set<String> parties) {
|
||||
Map<String, Filter> partyToFilters =
|
||||
parties.stream().collect(Collectors.toMap(Function.identity(), x -> filter));
|
||||
return new FiltersByParty(partyToFilters);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface FromCreatedEventFunc<T, R> {
|
||||
R apply(T t) throws IllegalArgumentException;
|
||||
}
|
||||
}
|
@ -3,10 +3,7 @@
|
||||
|
||||
package com.daml.ledger.rxjava;
|
||||
|
||||
import com.daml.ledger.javaapi.data.LedgerOffset;
|
||||
import com.daml.ledger.javaapi.data.Transaction;
|
||||
import com.daml.ledger.javaapi.data.TransactionFilter;
|
||||
import com.daml.ledger.javaapi.data.TransactionTree;
|
||||
import com.daml.ledger.javaapi.data.*;
|
||||
import io.reactivex.Flowable;
|
||||
import io.reactivex.Single;
|
||||
import java.util.Set;
|
||||
@ -30,6 +27,39 @@ public interface TransactionsClient {
|
||||
Flowable<Transaction> getTransactions(
|
||||
LedgerOffset begin, TransactionFilter filter, boolean verbose, String accessToken);
|
||||
|
||||
/**
|
||||
* Get contracts
|
||||
*
|
||||
* @param contractUtil Utilities for specified type of contract. It can be instantiated with
|
||||
* <code>ContractTypeCompanion</code>
|
||||
* @param begin begin offset.
|
||||
* @param parties Set of parties to be included in the transaction filter.
|
||||
* @param verbose If enabled, values served over the API will contain more information than
|
||||
* strictly necessary to interpret the data.
|
||||
* @return Flowable of contract type <code>Ct</code>
|
||||
*/
|
||||
<Ct> Flowable<Ct> getContracts(
|
||||
ContractUtil<Ct> contractUtil, LedgerOffset begin, Set<String> parties, boolean verbose);
|
||||
|
||||
/**
|
||||
* Get contracts
|
||||
*
|
||||
* @param contractUtil Utilities for specified type of contract. It can be instantiated with
|
||||
* <code>ContractTypeCompanion</code>
|
||||
* @param begin begin offset.
|
||||
* @param parties Set of parties to be included in the transaction filter.
|
||||
* @param verbose If enabled, values served over the API will contain more information than
|
||||
* strictly necessary to interpret the data.
|
||||
* @param accessToken Access token for authentication.
|
||||
* @return Flowable of contract type <code>Ct</code>
|
||||
*/
|
||||
<Ct> Flowable<Ct> getContracts(
|
||||
ContractUtil<Ct> contractUtil,
|
||||
LedgerOffset begin,
|
||||
Set<String> parties,
|
||||
boolean verbose,
|
||||
String accessToken);
|
||||
|
||||
Flowable<TransactionTree> getTransactionsTrees(
|
||||
LedgerOffset begin, LedgerOffset end, TransactionFilter filter, boolean verbose);
|
||||
|
||||
|
@ -6,15 +6,17 @@ package com.daml.ledger.rxjava.grpc;
|
||||
import com.daml.grpc.adapter.ExecutionSequencerFactory;
|
||||
import com.daml.ledger.api.v1.ActiveContractsServiceGrpc;
|
||||
import com.daml.ledger.api.v1.ActiveContractsServiceOuterClass;
|
||||
import com.daml.ledger.javaapi.data.GetActiveContractsRequest;
|
||||
import com.daml.ledger.javaapi.data.GetActiveContractsResponse;
|
||||
import com.daml.ledger.javaapi.data.TransactionFilter;
|
||||
import com.daml.ledger.javaapi.data.*;
|
||||
import com.daml.ledger.rxjava.ActiveContractsClient;
|
||||
import com.daml.ledger.rxjava.ContractUtil;
|
||||
import com.daml.ledger.rxjava.grpc.helpers.StubHelper;
|
||||
import com.daml.ledger.rxjava.util.ClientPublisherFlowable;
|
||||
import io.grpc.Channel;
|
||||
import io.reactivex.Flowable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class ActiveContractClientImpl implements ActiveContractsClient {
|
||||
@ -56,4 +58,36 @@ public class ActiveContractClientImpl implements ActiveContractsClient {
|
||||
@NonNull TransactionFilter filter, boolean verbose, @NonNull String accessToken) {
|
||||
return getActiveContracts(filter, verbose, Optional.of(accessToken));
|
||||
}
|
||||
|
||||
private <Ct> Flowable<ActiveContracts<Ct>> getActiveContracts(
|
||||
ContractUtil<Ct> contractUtil,
|
||||
Set<String> parties,
|
||||
boolean verbose,
|
||||
Optional<String> accessToken) {
|
||||
TransactionFilter filter = contractUtil.transactionFilter(parties);
|
||||
|
||||
Flowable<GetActiveContractsResponse> responses =
|
||||
getActiveContracts(filter, verbose, accessToken);
|
||||
return responses.map(
|
||||
response -> {
|
||||
List<Ct> activeContracts =
|
||||
response.getCreatedEvents().stream()
|
||||
.map(contractUtil::toContract)
|
||||
.collect(Collectors.toList());
|
||||
return new ActiveContracts<>(
|
||||
response.getOffset().orElse(""), activeContracts, response.getWorkflowId());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Ct> Flowable<ActiveContracts<Ct>> getActiveContracts(
|
||||
ContractUtil<Ct> contractUtil, Set<String> parties, boolean verbose) {
|
||||
return getActiveContracts(contractUtil, parties, verbose, Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Ct> Flowable<ActiveContracts<Ct>> getActiveContracts(
|
||||
ContractUtil<Ct> contractUtil, Set<String> parties, boolean verbose, String accessToken) {
|
||||
return getActiveContracts(contractUtil, parties, verbose, Optional.of(accessToken));
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import com.daml.grpc.adapter.ExecutionSequencerFactory;
|
||||
import com.daml.ledger.api.v1.TransactionServiceGrpc;
|
||||
import com.daml.ledger.api.v1.TransactionServiceOuterClass;
|
||||
import com.daml.ledger.javaapi.data.*;
|
||||
import com.daml.ledger.rxjava.ContractUtil;
|
||||
import com.daml.ledger.rxjava.TransactionsClient;
|
||||
import com.daml.ledger.rxjava.grpc.helpers.StubHelper;
|
||||
import com.daml.ledger.rxjava.util.ClientPublisherFlowable;
|
||||
@ -16,6 +17,7 @@ import io.reactivex.Single;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class TransactionClientImpl implements TransactionsClient {
|
||||
private final String ledgerId;
|
||||
@ -73,6 +75,40 @@ public final class TransactionClientImpl implements TransactionsClient {
|
||||
return getTransactions(begin, end, filter, verbose, Optional.of(accessToken));
|
||||
}
|
||||
|
||||
private <Ct> Flowable<Ct> getContracts(
|
||||
ContractUtil<Ct> contractUtil,
|
||||
LedgerOffset begin,
|
||||
Set<String> parties,
|
||||
boolean verbose,
|
||||
Optional<String> accessToken) {
|
||||
TransactionFilter filter = contractUtil.transactionFilter(parties);
|
||||
Flowable<Transaction> transactions = getTransactions(begin, filter, verbose, accessToken);
|
||||
Flowable<CreatedEvent> createdEvents =
|
||||
transactions.concatMapIterable(
|
||||
tx ->
|
||||
tx.getEvents().stream()
|
||||
.filter(e -> e instanceof CreatedEvent)
|
||||
.map(e -> (CreatedEvent) e)
|
||||
.collect(Collectors.toList()));
|
||||
return createdEvents.map(contractUtil::toContract);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Ct> Flowable<Ct> getContracts(
|
||||
ContractUtil<Ct> contractUtil, LedgerOffset begin, Set<String> parties, boolean verbose) {
|
||||
return getContracts(contractUtil, begin, parties, verbose, Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Ct> Flowable<Ct> getContracts(
|
||||
ContractUtil<Ct> contractUtil,
|
||||
LedgerOffset begin,
|
||||
Set<String> parties,
|
||||
boolean verbose,
|
||||
String accessToken) {
|
||||
return getContracts(contractUtil, begin, parties, verbose, Optional.of(accessToken));
|
||||
}
|
||||
|
||||
private Flowable<Transaction> getTransactions(
|
||||
LedgerOffset begin, TransactionFilter filter, boolean verbose, Optional<String> accessToken) {
|
||||
TransactionServiceOuterClass.GetTransactionsRequest request =
|
||||
|
@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.ledger.javaapi.data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public final class ActiveContracts<Ct> implements WorkflowEvent {
|
||||
|
||||
private final String offset;
|
||||
|
||||
private final List<Ct> activeContracts;
|
||||
|
||||
private final String workflowId;
|
||||
|
||||
public ActiveContracts(
|
||||
@NonNull String offset, @NonNull List<Ct> activeContracts, String workflowId) {
|
||||
this.offset = offset;
|
||||
this.activeContracts = activeContracts;
|
||||
this.workflowId = workflowId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<String> getOffset() {
|
||||
// Empty string indicates that the field is not present in the protobuf.
|
||||
return Optional.of(offset).filter(off -> !offset.equals(""));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<@NonNull Ct> getContracts() {
|
||||
return activeContracts;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getWorkflowId() {
|
||||
return workflowId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ActiveContracts{"
|
||||
+ "offset='"
|
||||
+ offset
|
||||
+ '\''
|
||||
+ ", activeContracts="
|
||||
+ activeContracts
|
||||
+ ", workflowId="
|
||||
+ workflowId
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ActiveContracts<?> that = (ActiveContracts<?>) o;
|
||||
return Objects.equals(offset, that.offset)
|
||||
&& Objects.equals(activeContracts, that.activeContracts)
|
||||
&& Objects.equals(workflowId, that.workflowId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(offset, activeContracts, workflowId);
|
||||
}
|
||||
}
|
@ -4,7 +4,13 @@
|
||||
package com.daml.ledger.javaapi.data;
|
||||
|
||||
import com.daml.ledger.api.v1.TransactionFilterOuterClass;
|
||||
import com.daml.ledger.javaapi.data.codegen.ContractCompanion;
|
||||
import com.daml.ledger.javaapi.data.codegen.ContractTypeCompanion;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class TransactionFilter {
|
||||
|
||||
@ -17,4 +23,17 @@ public abstract class TransactionFilter {
|
||||
abstract TransactionFilterOuterClass.TransactionFilter toProto();
|
||||
|
||||
public abstract Set<String> getParties();
|
||||
|
||||
public static TransactionFilter transactionFilter(
|
||||
ContractTypeCompanion<?, ?> contractCompanion, Set<String> parties) {
|
||||
Filter filter =
|
||||
(contractCompanion instanceof ContractCompanion)
|
||||
? new InclusiveFilter(Set.of(contractCompanion.TEMPLATE_ID), Collections.emptyMap())
|
||||
: new InclusiveFilter(
|
||||
Collections.emptySet(),
|
||||
Map.of(contractCompanion.TEMPLATE_ID, Filter.Interface.INCLUDE_VIEW));
|
||||
Map<String, Filter> partyToFilters =
|
||||
parties.stream().collect(Collectors.toMap(Function.identity(), x -> filter));
|
||||
return new FiltersByParty(partyToFilters);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public abstract class Contract<Id, Data> implements com.daml.ledger.javaapi.data
|
||||
}
|
||||
|
||||
// concrete 1st type param would need a self-reference type param in Contract
|
||||
protected abstract ContractCompanion<? extends Contract<Id, Data>, Id, Data> getCompanion();
|
||||
protected abstract ContractTypeCompanion<?, Data> getCompanion();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
@ -81,7 +81,7 @@ public abstract class Contract<Id, Data> implements com.daml.ledger.javaapi.data
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"%s.Contract(%s, %s, %s, %s, %s)",
|
||||
getCompanion().templateClassName,
|
||||
getCompanion().TEMPLATE_CLASS_NAME,
|
||||
this.id,
|
||||
this.data,
|
||||
this.agreementText,
|
||||
|
@ -26,8 +26,6 @@ import java.util.function.Function;
|
||||
* the template, whose instances contain only the payload.
|
||||
*/
|
||||
public abstract class ContractCompanion<Ct, Id, Data> extends ContractTypeCompanion<Data, Data> {
|
||||
final String templateClassName; // not something we want outside this package
|
||||
|
||||
protected final Function<String, Id> newContractId;
|
||||
protected final Function<DamlRecord, Data> fromValue;
|
||||
|
||||
@ -84,8 +82,7 @@ public abstract class ContractCompanion<Ct, Id, Data> extends ContractTypeCompan
|
||||
Function<String, Id> newContractId,
|
||||
Function<DamlRecord, Data> fromValue,
|
||||
List<ChoiceMetadata<Data, ?, ?>> choices) {
|
||||
super(templateId, choices);
|
||||
this.templateClassName = templateClassName;
|
||||
super(templateId, templateClassName, choices);
|
||||
this.newContractId = newContractId;
|
||||
this.fromValue = fromValue;
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ public abstract class ContractTypeCompanion<ContractType, Data> {
|
||||
/** The full template ID of the template or interface that defined this companion. */
|
||||
public final Identifier TEMPLATE_ID;
|
||||
|
||||
final String TEMPLATE_CLASS_NAME;
|
||||
|
||||
/**
|
||||
* The provides a mapping of choice name to Choice.
|
||||
*
|
||||
@ -40,8 +42,11 @@ public abstract class ContractTypeCompanion<ContractType, Data> {
|
||||
* interface in question instead.
|
||||
*/
|
||||
protected ContractTypeCompanion(
|
||||
Identifier templateId, List<ChoiceMetadata<ContractType, ?, ?>> choices) {
|
||||
Identifier templateId,
|
||||
String templateClassName,
|
||||
List<ChoiceMetadata<ContractType, ?, ?>> choices) {
|
||||
TEMPLATE_ID = templateId;
|
||||
TEMPLATE_CLASS_NAME = templateClassName;
|
||||
this.choices =
|
||||
choices.stream().collect(Collectors.toMap(choice -> choice.name, Function.identity()));
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.ledger.javaapi.data.codegen;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
final class ContractWithInterfaceView<Id, View> extends Contract<Id, View> {
|
||||
|
||||
private final ContractTypeCompanion<?, View> contractTypeCompanion;
|
||||
|
||||
ContractWithInterfaceView(
|
||||
ContractTypeCompanion<?, View> contractTypeCompanion,
|
||||
Id id,
|
||||
View interfaceView,
|
||||
Optional<String> agreementText,
|
||||
Set<String> signatories,
|
||||
Set<String> observers) {
|
||||
super(id, interfaceView, agreementText, signatories, observers);
|
||||
this.contractTypeCompanion = contractTypeCompanion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractTypeCompanion<?, View> getCompanion() {
|
||||
return contractTypeCompanion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof ContractWithInterfaceView && super.equals(object);
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ public abstract class ContractWithKey<Id, Data, Key> extends Contract<Id, Data>
|
||||
public final String toString() {
|
||||
return String.format(
|
||||
"%s.Contract(%s, %s, %s, %s, %s, %s)",
|
||||
getCompanion().templateClassName,
|
||||
getCompanion().TEMPLATE_CLASS_NAME,
|
||||
this.id,
|
||||
this.data,
|
||||
this.agreementText,
|
||||
|
@ -3,8 +3,14 @@
|
||||
|
||||
package com.daml.ledger.javaapi.data.codegen;
|
||||
|
||||
import com.daml.ledger.javaapi.data.*;
|
||||
import com.daml.ledger.javaapi.data.DamlRecord;
|
||||
import com.daml.ledger.javaapi.data.Identifier;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Metadata and utilities associated with an interface as a whole. Its subclasses serve to
|
||||
@ -14,7 +20,9 @@ import java.util.List;
|
||||
* @param <View> The {@link DamlRecord} subclass representing the interface view, as may be
|
||||
* retrieved from the ACS or transaction stream.
|
||||
*/
|
||||
public abstract class InterfaceCompanion<I, View> extends ContractTypeCompanion<I, View> {
|
||||
public abstract class InterfaceCompanion<I, Id, View> extends ContractTypeCompanion<I, View> {
|
||||
|
||||
private final Function<String, Id> newContractId;
|
||||
|
||||
public final ValueDecoder<View> valueDecoder;
|
||||
|
||||
@ -25,10 +33,54 @@ public abstract class InterfaceCompanion<I, View> extends ContractTypeCompanion<
|
||||
* INTERFACE} field on generated code for Daml interfaces instead.
|
||||
*/
|
||||
protected InterfaceCompanion(
|
||||
String templateClassName,
|
||||
Identifier templateId,
|
||||
Function<String, Id> newContractId,
|
||||
ValueDecoder<View> valueDecoder,
|
||||
List<ChoiceMetadata<I, ?, ?>> choices) {
|
||||
super(templateId, choices);
|
||||
super(templateId, templateClassName, choices);
|
||||
this.newContractId = newContractId;
|
||||
this.valueDecoder = valueDecoder;
|
||||
}
|
||||
|
||||
private Contract<Id, View> fromIdAndRecord(
|
||||
String contractId,
|
||||
Map<Identifier, DamlRecord> interfaceViews,
|
||||
Optional<String> agreementText,
|
||||
Set<String> signatories,
|
||||
Set<String> observers)
|
||||
throws IllegalArgumentException {
|
||||
Optional<DamlRecord> maybeRecord = Optional.ofNullable(interfaceViews.get(TEMPLATE_ID));
|
||||
Optional<DamlRecord> maybeFailedRecord = Optional.ofNullable(interfaceViews.get(TEMPLATE_ID));
|
||||
Id id = newContractId.apply(contractId);
|
||||
|
||||
return maybeRecord
|
||||
.map(
|
||||
record -> {
|
||||
View view = valueDecoder.decode(record);
|
||||
return new ContractWithInterfaceView<>(
|
||||
this, id, view, agreementText, signatories, observers);
|
||||
})
|
||||
.orElseThrow(
|
||||
() ->
|
||||
maybeFailedRecord
|
||||
.map(
|
||||
record ->
|
||||
new IllegalArgumentException(
|
||||
"Failed interface view for " + TEMPLATE_ID))
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
"interface view of " + TEMPLATE_ID + " not found.")));
|
||||
}
|
||||
|
||||
public final Contract<Id, View> fromCreatedEvent(CreatedEvent event)
|
||||
throws IllegalArgumentException {
|
||||
return fromIdAndRecord(
|
||||
event.getContractId(),
|
||||
event.getInterfaceViews(),
|
||||
event.getAgreementText(),
|
||||
event.getSignatories(),
|
||||
event.getObservers());
|
||||
}
|
||||
}
|
||||
|
@ -108,12 +108,10 @@ object ContractClass {
|
||||
private[this] val contractIdClassName = ClassName bestGuess "ContractId"
|
||||
|
||||
private[this] def generateGetCompanion(templateClassName: ClassName): MethodSpec = {
|
||||
val contractClassName = ClassName bestGuess "Contract"
|
||||
ClassGenUtils.generateGetCompanion(
|
||||
ParameterizedTypeName.get(
|
||||
ClassName get classOf[javaapi.data.codegen.ContractCompanion[_, _, _]],
|
||||
contractClassName,
|
||||
contractIdClassName,
|
||||
ClassName get classOf[javaapi.data.codegen.ContractTypeCompanion[_, _]],
|
||||
templateClassName,
|
||||
templateClassName,
|
||||
),
|
||||
companionFieldName,
|
||||
|
@ -106,35 +106,45 @@ object InterfaceClass extends StrictLogging {
|
||||
interfaceName: ClassName,
|
||||
choiceNames: Set[ChoiceName],
|
||||
interfaceViewTypeName: ClassName,
|
||||
): TypeSpec = TypeSpec
|
||||
.classBuilder(companionClassName)
|
||||
.superclass(
|
||||
ParameterizedTypeName
|
||||
.get(ClassName get classOf[InterfaceCompanion[_, _]], interfaceName, interfaceViewTypeName)
|
||||
)
|
||||
.addModifiers(Modifier.FINAL, Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addMethod {
|
||||
MethodSpec
|
||||
.constructorBuilder()
|
||||
// intentionally package-private
|
||||
.addStatement(
|
||||
"super($T.$N, $T.$L(), $T.of($L))",
|
||||
interfaceName,
|
||||
ClassGenUtils.templateIdFieldName,
|
||||
interfaceViewTypeName,
|
||||
"valueDecoder",
|
||||
classOf[java.util.List[_]],
|
||||
CodeBlock
|
||||
.join(
|
||||
choiceNames
|
||||
.map(choiceName => CodeBlock.of("$N", toChoiceNameField(choiceName)))
|
||||
.asJava,
|
||||
",$W",
|
||||
),
|
||||
)
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
): TypeSpec = {
|
||||
val contractIdClassName = ClassName bestGuess "ContractId"
|
||||
TypeSpec
|
||||
.classBuilder(companionClassName)
|
||||
.superclass(
|
||||
ParameterizedTypeName
|
||||
.get(
|
||||
ClassName get classOf[InterfaceCompanion[_, _, _]],
|
||||
interfaceName,
|
||||
contractIdClassName,
|
||||
interfaceViewTypeName,
|
||||
)
|
||||
)
|
||||
.addModifiers(Modifier.FINAL, Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addMethod {
|
||||
MethodSpec
|
||||
.constructorBuilder()
|
||||
// intentionally package-private
|
||||
.addStatement(
|
||||
"super($>$Z$S, $T.$N, $T::new, $T.$L(), $T.of($L))$<$Z",
|
||||
interfaceName,
|
||||
interfaceName,
|
||||
ClassGenUtils.templateIdFieldName,
|
||||
contractIdClassName,
|
||||
interfaceViewTypeName,
|
||||
"valueDecoder",
|
||||
classOf[java.util.List[_]],
|
||||
CodeBlock
|
||||
.join(
|
||||
choiceNames
|
||||
.map(choiceName => CodeBlock.of("$N", toChoiceNameField(choiceName)))
|
||||
.asJava,
|
||||
",$W",
|
||||
),
|
||||
)
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
private def generateTemplateIdField(packageId: PackageId, name: QualifiedName): FieldSpec =
|
||||
ClassGenUtils.generateTemplateIdField(
|
||||
|
Loading…
Reference in New Issue
Block a user