I'm quite new with Corda.
I want to do a Scheduler, is like a Todo List that check if the Task is assigned every 30 seconds.
I use the Java Template without any specific configuration, the database is H2 and the Corda version is 4.9
The State class extend ContractState, LinearState and SchedulableState
ToDoState
#BelongsToContract(ToDoContract.class)
public class TodoState implements ContractState, LinearState, SchedulableState {
private final Instant deadlineReminder;
public Party getAssignedBy() {
return assignedBy;
}
private final Party assignedBy;
public Party getAssignedTo() {
return assignedTo;
}
private final Party assignedTo;
public String getTaskDescription() {
return taskDescription;
}
private final String taskDescription;
private UniqueIdentifier linearId;
public TodoState(Party assignedBy, Party assignedTo, String taskDescription) {
this.assignedBy = assignedBy;
this.assignedTo = assignedTo;
this.taskDescription = taskDescription;
this.linearId = new UniqueIdentifier();
this.deadlineReminder = Instant.now().plusSeconds(30);
}
#ConstructorForDeserialization
public TodoState(Party assignedBy, Party assignedTo, String taskDescription, UniqueIdentifier linearId, Instant deadlineReminder) {
this.assignedBy = assignedBy;
this.assignedTo = assignedTo;
this.taskDescription = taskDescription;
this.linearId = linearId;
this.deadlineReminder = deadlineReminder;
}
public TodoState assign(Party assignedTo) {
return new TodoState(assignedBy, assignedTo, taskDescription, linearId, deadlineReminder);
}
#NotNull
#Override
public List<AbstractParty> getParticipants() {
return Arrays.asList(assignedBy, assignedTo);
}
#NotNull
#Override
public UniqueIdentifier getLinearId() {
return linearId;
}
#Nullable
#Override
public ScheduledActivity nextScheduledActivity(#NotNull StateRef thisStateRef, #NotNull FlowLogicRefFactory flowLogicRefFactory) {
System.out.println("nextScheduledActivity invoked");
System.out.println("StateRef TX is " + thisStateRef.getTxhash());
final ScheduledActivity scheduledActivity = new ScheduledActivity(flowLogicRefFactory.create(
"com.template.flows.AlarmFlow", thisStateRef
), deadlineReminder);
System.out.println("Passed");
return scheduledActivity;
}
}
The Flow
public class CreateToDoFlow {
#InitiatingFlow
#StartableByRPC
public static class CreateTodoFlowInitiator extends FlowLogic<Void> {
private final String taskDescription;
private Party me;
public CreateTodoFlowInitiator(String task) {
this.taskDescription = task;
}
#Override
#Suspendable
public Void call() throws FlowException {
this.me = getOurIdentity();
final Party notary = getServiceHub().getNetworkMapCache().getNotary(CordaX500Name.parse("O=Notary,L=London,C=GB"));
final TodoState output = new TodoState(this.me, this.me, this.taskDescription);
final TransactionBuilder builder = new TransactionBuilder(notary);
builder.addOutputState(output);
builder.addCommand(new Command.CreateToDoCommand(), me.getOwningKey());
builder.verify(getServiceHub());
final SignedTransaction ptx = getServiceHub().signInitialTransaction(builder);
subFlow(new FinalityFlow(ptx, Collections.<FlowSession>emptySet()));
System.out.println("1");
return null;
}
}
}
And the AlarmFlow called from the Scheduler, where, i guess the error come.
AlarmFlow
public class AlarmFlow {
#InitiatingFlow
#SchedulableFlow
public static class AlarmFlowInitiator extends FlowLogic<Void> {
private StateRef stateRef;
//public constructor
public AlarmFlowInitiator(StateRef stateRef) {
this.stateRef = stateRef;
}
#Override
#Suspendable
public Void call() throws FlowException {
ServiceHub sb = getServiceHub();
StateAndRef<TodoState> todoStateAndRef = sb.toStateAndRef(stateRef);
TodoState todo = todoStateAndRef.getState().getData();
sb.getVaultService().addNoteToTransaction(
stateRef.getTxhash(), "Reminder made: " + Instant.now()
);
System.out.println("DeadLine is coming up for task: " + todo.getTaskDescription());
return null;
}
}
}
when i execute the flow
flow start CreateTodoFlow task: "Pay bill"
i get the following error
[ERROR] 23:48:19+0200 [Node thread-1] vault.NodeVaultService. - Failed to record transaction states locally - the node could be now in an inconsistent state with other peers and/or the notary - hospitalising the flow {actor_id=internalShell, actor_owning_identity=O=PartyA, L=London, C=GB, actor_store_id=NODE_CONFIG, fiber-id=10000001, flow-id=5eb282b3-4b47-459d-917d-06ea0de16e6f, invocation_id=aadb5b6a-4716-4875-a18e-78a351592365, invocation_timestamp=2022-09-19T21:48:19.052Z, origin=internalShell, session_id=b78e7e1d-b91f-4c40-b42e-468e7b5f4fb0, session_timestamp=2022-09-19T21:48:18.782Z, thread-id=139, tx_id=1BBDFF4EC549457D1C8D60E30041AE97436D44778675BEB2C78E737DBFFFE124}
seems that the vault fail when is called in the Scheduled Activity method
Thanks in advance for your help
I have found the solution:
The scheduler call the AlarmFlow Class and the class is embebbed on the AlarmFlow class like that:
public class AlarmFlow {
#InitiatingFlow
#SchedulableFlow
public static class AlarmFlowInitiator extends FlowLogic<Void> {
private StateRef stateRef;
//public constructor
public AlarmFlowInitiator(StateRef stateRef) {
this.stateRef = stateRef;
}
#Override
#Suspendable
public Void call() throws FlowException {
ServiceHub sb = getServiceHub();
StateAndRef<TodoState> todoStateAndRef = sb.toStateAndRef(stateRef);
TodoState todo = todoStateAndRef.getState().getData();
sb.getVaultService().addNoteToTransaction(
stateRef.getTxhash(), "Reminder made: " + Instant.now()
);
System.out.println("DeadLine is coming up for task: " + todo.getTaskDescription());
return null;
}
}
}
If i extract the AlarmFlowInitiator class out side like that
#InitiatingFlow
#SchedulableFlow
public class AlarmFlow extends FlowLogic<Void>{
private StateRef stateRef;
//public constructor
public AlarmFlow(StateRef stateRef) {
this.stateRef = stateRef;
}
#Override
#Suspendable
public Void call() throws FlowException {
ServiceHub sb = getServiceHub();
StateAndRef<TodoState> todoStateAndRef = sb.toStateAndRef(stateRef);
TodoState todo = todoStateAndRef.getState().getData();
sb.getVaultService().addNoteToTransaction(
stateRef.getTxhash(), "Reminder made: " + Instant.now()
);
System.out.println("DeadLine is coming up for task: " + todo.getTaskDescription());
return null;
}
}
the Scheduler work properly
Related
My objectmapper not working when I use spring controller & class for requestbody inheritation .
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type", visible = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = RecipeVersion.class, name = "recipe"),
#JsonSubTypes.Type(value = DietVersion.class, name = "diet"),
})
public interface DocumentVersion {
Info getInfo();
void setInfo(Info info);
}
and also
#Data
public class DietVersion implements DocumentVersion {
private LocalizedText warnings;
private List<DietDay> days = new LinkedList<>();
private Info info = new Info();
private String getType() {
return "diet";
}
}
Ok. I have BaseController for diets and recipes
abstract public class BaseController<T extends Document<V>, V extends DocumentVersion> {
abstract protected BaseService<T, V> getService();
#PostMapping("/{docId}/version/last")
#ResponseStatus(HttpStatus.NO_CONTENT)
public void saveVersion(#PathVariable("docId") String docId, #RequestBody V version, Authentication authentication) {
getService().replaceLastVersion(docId, version, authentication);
}
}
and some realizations. example for diet
#Controller
#RequestMapping("/diet")
public class DietController extends BaseController<Diet, DietVersion> {
private final DietService dietService;
#Autowired
public DietController(DietService dietService) {
this.dietService = dietService;
}
#Override
protected DietService getService() {
return dietService;
}
#Override
public void saveVersion(String docId, DietVersion version, Authentication authentication) {
super.saveVersion(docId, version, authentication);
}
}
But when I send json with info, days, type ('diet') to '/diet/1/version/last' then I see in debug mode that my DietVersion pure clear and has no any data. Why ?
How to change settings for objectmapper ?
what if you provide all this in your DietController class.
public void saveVersion(#PathVariable("docId") String docId, #RequestBody V version, Authentication authentication){
Just wanted to make sure that whether messages are processed in correct way or not. When the message gets received at listener, it will be always processed by a new thread( defined the processor bean as prototype). is this implementation correct ? (i have Considered the listener is not thread safe, so for this reason the prototype scope of bean to process the message has been used)
(Input : TestTopic- 5 partitions - 1 consumer) or (Input : TestTopic- 5 partitions - 5 consumers)
public class EventListener {
#Autowired
private EventProcessor eventProcessor;
#KafkaListener(topics = "TestTopic", containerFactory = "kafkaListenerContainerFactory",
autoStartup = "true")
public void onMessage(
#Payload List<ConsumerRecord<String, String>> consumerRecords, Acknowledgment acknowledgment) {
eventProcessor.processAndAcknowledgeBatchMessages(consumerRecords, acknowledgment);
}
}
//event processor
#Slf4j
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
#NoArgsConstructor
#SuppressWarnings("unused")
public class EventProcessorImpl implements EventProcessor {
#Autowired
private KafkaProducerTemplate kafkaProducerTemplate;
#Autowired
private ObjectMapper localObjectMapper;
#Autowired
private Dao dao;
public void processAndAcknowledgeBatchMessages(
List<ConsumerRecord<String, String>> consumerRecords, Acknowledgment acknowledgment) {
long start = System.currentTimeMillis();
consumerRecords.forEach( consumerRecord -> {
Event event = localObjectMapper.readValue(consumerRecord.value(), Event.class);
dao.save(process(event));
});
acknowledgment.acknowledge();
}
}
No it is not correct; you should not execute on another thread; it will cause problems with committing offsets and error handling.
Also, making the EventProcessorImpl a prototype bean won't help. That just means a new instance is used each time the bean is referenced.
Since it is #Autowired it is only referenced once, during initialization. To get a new instance for each request, you would need to call getBean() on the application context each time.
It is better to make your code thread-safe.
EDIT
There are (at least) a couple of ways to deal with a not thread-safe service defined in prototype scope.
Use a ThreadLocal:
#SpringBootApplication
public class So68447863Application {
public static void main(String[] args) {
SpringApplication.run(So68447863Application.class, args);
}
private static final ThreadLocal<NotThreadSafeService> SERVICES = new ThreadLocal<>();
#Autowired
ApplicationContext context;
#KafkaListener(id = "so68447863", topics = "so68447863", concurrency = "5")
void listen(String in) {
NotThreadSafeService service = SERVICES.get();
if (service == null) {
service = this.context.getBean(NotThreadSafeService.class);
SERVICES.set(service);
}
service.process(in);
}
#EventListener
void removeService(ConsumerStoppedEvent event) {
System.out.println("Consumer stopped; removing TL");
SERVICES.remove();
}
#Bean
NewTopic topic() {
return TopicBuilder.name("so68447863").partitions(10).replicas(1).build();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
NotThreadSafeService service() {
return new NotThreadSafeService();
}
}
class NotThreadSafeService {
void process(String msg) {
System.out.println(msg + " processed by " + this);
}
}
Use a pool of instances.
#SpringBootApplication
public class So68447863Application {
public static void main(String[] args) {
SpringApplication.run(So68447863Application.class, args);
}
private static final BlockingQueue<NotThreadSafeService> SERVICES = new LinkedBlockingQueue<>();
#Autowired
ApplicationContext context;
#KafkaListener(id = "so68447863", topics = "so68447863", concurrency = "5")
void listen(String in) {
NotThreadSafeService service = SERVICES.poll();
if (service == null) {
service = this.context.getBean(NotThreadSafeService.class);
}
try {
service.process(in);
}
finally {
SERVICES.add(service);
}
}
#Bean
NewTopic topic() {
return TopicBuilder.name("so68447863").partitions(10).replicas(1).build();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
NotThreadSafeService service() {
return new NotThreadSafeService();
}
}
class NotThreadSafeService {
void process(String msg) {
System.out.println(msg + " processed by " + this);
}
}
When running a NodeDriver test that uses a QueryableState, I get an error saying "Unknown entity". I confirmed that if I remove the QueryableState code from the State, the tests run successfully.
java.util.concurrent.ExecutionException:
net.corda.core.CordaRuntimeException:
java.lang.IllegalArgumentException: Unknown entity:
com.template.states.IOUCustomSchema$PersistentIOU
Here is the implementation of the QueryableState:
#BelongsToContract(IOUContract.class)
public class IOUState implements ContractState, LinearState, QueryableState {
public final Amount<TokenType> amount;
public final Party lender;
public final Party borrower;
public final Amount<TokenType> paid;
private final UniqueIdentifier linearId;
// Private constructor used only for copying a State object
#ConstructorForDeserialization
private IOUState(Amount<TokenType> amount, Party lender, Party borrower, Amount<TokenType> paid, UniqueIdentifier linearId){
this.amount = amount;
this.lender = lender;
this.borrower = borrower;
this.paid = paid;
this.linearId = linearId;
}
public IOUState(Amount<TokenType> amount, Party lender, Party borrower) {
this(amount, lender, borrower, new Amount<>(0, amount.getToken()), new UniqueIdentifier());
}
/** omitting boiletplate */
/**
* This method will return a list of the nodes which can "use" this state in a valid transaction. In this case, the
* lender or the borrower.
*/
#Override
public List<AbstractParty> getParticipants() {
return ImmutableList.of(lender, borrower);
}
#Override
public PersistentState generateMappedObject(MappedSchema schema) {
if (schema instanceof IOUCustomSchema) {
return new IOUCustomSchema.PersistentIOU(linearId.getId(), lender.getName().toString(),
borrower.getName().toString(), amount.getQuantity());
} else{
throw new IllegalArgumentException("Unrecognised schema " + schema);
}
}
#Override
public Iterable<MappedSchema> supportedSchemas() {
return ImmutableList.of(new IOUCustomSchema());
}
}
IOUCustomSchema
public class IOUCustomSchema extends MappedSchema {
public IOUCustomSchema() {
super(IOUCustomSchema.class, 1, ImmutableList.of(PersistentState.class));
}
#Entity
#Table
public static class PersistentIOU extends PersistentState {
#Column(nullable = false)
UUID linearId;
#Column(nullable = false) String lender;
#Column(nullable = false) String borrower;
#Column(nullable = false) Long amount;
public PersistentIOU(UUID linearId, String lender, String borrower, Long amount) {
this.linearId = linearId;
this.lender = lender;
this.borrower = borrower;
this.amount = amount;
}
public PersistentIOU() {
this.linearId = null;
this.lender = null;
this.borrower = null;
this.amount = 0L;
}
public UUID getLinearId() {
return linearId;
}
public String getLender() {
return lender;
}
public String getBorrower() {
return borrower;
}
public Long getAmount() {
return amount;
}
}
}
You didn't implement the custom schema correctly; you're supposed to have at least 2 classes:
IOUCustomSchema should be just an empty class that represents the family of schemas for IOUState. See here: https://github.com/corda/samples/blob/release-V4/cordapp-example/contracts-java/src/main/java/com/example/schema/IOUSchema.java
Then you create a V1 of the schema, which is what you did but you should rename your class to IOUCustomSchemaV1; so in your code:
a. Rename class to IOUCustomSchemaV1.
b. Rename constructor to IOUCustomSchemaV1.
c. Keep super(IOUCustomSchema.class... as it is.
d. In your state also rename IOUCustomSchema to IOUCustomSchemaV1 in all occurrences.
You can see the correct implementation in the samples repo, under cordapp-example project:
Family of schemas: https://github.com/corda/samples/blob/release-V4/cordapp-example/contracts-java/src/main/java/com/example/schema/IOUSchema.java
Schema V1: https://github.com/corda/samples/blob/release-V4/cordapp-example/contracts-java/src/main/java/com/example/schema/IOUSchemaV1.java
State: https://github.com/corda/samples/blob/release-V4/cordapp-example/contracts-java/src/main/java/com/example/state/IOUState.java
It was actually just a copy and paste error. I needed to change the following line in order to get things working.
super(IOUCustomSchema.class, 1, ImmutableList.of(PersistentState.class));
I was using the generic PersistentState here instead of my custom PersistentIOU
super(IOUCustomSchema.class, 1, ImmutableList.of(PersistentIOU.class));
I am creating a flow to fetch signatures from CollectSignaturesFlow of other party and I am facing the below issue in log.
#InitiatingFlow
#StartableByRPC
public static class BGInitiator extends FlowLogic<SignedTransaction> {
private final Party manufacturer;
private final Party regulator;
private final String bgData;
public BGInitiator(Party manufacturer,Party regulator, String bgData) {
this.manufacturer = manufacturer;
this.regulator = regulator;
this.bgData = bgData;
}
private final Step GENERATING_TRANSACTION = new Step("Generating transaction based on YO.");
private final Step BUILDING_TRANSACTION = new Step("Verifying contract constraints.");
private final Step SIGNING_TRANSACTION = new Step("Signing transaction with our private key.");
private final Step GATHERING_SIGS = new Step("Gathering the counterparty's signature.") {
#Override
public ProgressTracker childProgressTracker() {
return CollectSignaturesFlow.Companion.tracker();
}
};
private final Step FINALISING_TRANSACTION = new Step("Obtaining notary signature and recording transaction.") {
#Override
public ProgressTracker childProgressTracker() {
return FinalityFlow.Companion.tracker();
}
};
private final ProgressTracker progressTracker = new ProgressTracker(
GENERATING_TRANSACTION,
BUILDING_TRANSACTION,
SIGNING_TRANSACTION,
GATHERING_SIGS,
FINALISING_TRANSACTION
);
#Override
public ProgressTracker getProgressTracker() {
return progressTracker;
}
#Suspendable
#Override
public SignedTransaction call() throws FlowException {
progressTracker.setCurrentStep(GENERATING_TRANSACTION);
Party notary = getServiceHub().getNetworkMapCache().getNotaryIdentities().get(0);
BGState bgState = new BGState(getOurIdentity(),manufacturer,regulator,bgData);
progressTracker.setCurrentStep(BUILDING_TRANSACTION);
final List<PublicKey> requiredSigners = bgState.getParticipantKeys();
final List<Party> parties = bgState.getParties();
final PublicKey me = bgState.getSeller().getOwningKey();
final TransactionBuilder tb = new TransactionBuilder(notary)
.addOutputState(bgState,BGContract.BG_CONTRACT_ID)
.addCommand(new BGContract.Commands.Send(),requiredSigners);
progressTracker.setCurrentStep(SIGNING_TRANSACTION);
final SignedTransaction ptx = getServiceHub().signInitialTransaction(tb,me);
progressTracker.setCurrentStep(GATHERING_SIGS);
FlowSession manufacturerflow = initiateFlow(manufacturer);
final SignedTransaction stx = subFlow(new CollectSignaturesFlow(ptx,ImmutableSet.of(manufacturerflow),ImmutableList.of(me),GATHERING_SIGS.childProgressTracker()));
progressTracker.setCurrentStep(FINALISING_TRANSACTION);
return subFlow(new FinalityFlow(stx,FINALISING_TRANSACTION.childProgressTracker()));
}
}
After deploying and executing, the flow stops, giving me the following error:
java.lang.IllegalArgumentException: The Initiator of CollectSignaturesFlow must pass in exactly the sessions required to sign the transaction.
at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:108) ~[corda-core-2.0.0.jar:?]
at net.corda.core.flows.CollectSignaturesFlow.call(CollectSignaturesFlow.kt:64) ~[corda-core-2.0.0.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:243) ~[corda-core-2.0.0.jar:?]
at com.example.flow.BGFlow$BGInitiator.call(BGFlow.java:107) ~[java-source-0.1.jar:?]
I believe I am passing the required flow session and I am still getting this. Any ideas on how to solve this?
Edit 1: when I replace the flowsession to multiple sessions using the code below and executing it, the flow struck and even wrote nothing in logs. I would like to know whether the following is the correct way to fetch signatures.
List<FlowSession> flowSessions = parties.stream().map(a -> initiateFlow(a)).collect(Collectors.toList());
final SignedTransaction stx = subFlow(new CollectSignaturesFlow(ptx,flowSessions,ImmutableList.of(me),GATHERING_SIGS.childProgressTracker()));
The getParties() code in BGState:
public List<Party> getParties(){
return Arrays.asList(manufacturer,regulator);
}
The BGState Definition:
public class BGState implements LinearState,QueryableState {
private final Party seller;
private final Party manufacturer;
private final Party regulator;
private final String senderToReceiverInformation;
private final UniqueIdentifier linearId;
public BGState(Party seller, Party manufacturer,Party regulator,String senderToReceiverInformation) {
this.seller = seller;
this. manufacturer= manufacturer;
this.regulator = regulator;
this.senderToReceiverInformation = senderToReceiverInformation;
this.linearId = new UniqueIdentifier();
}
public Party getSeller() {
return seller;
}
public Party getManufacturer() {
return manufacturer;
}
public Party getRegulator() {
return regulator;
}
#NotNull
#Override
public UniqueIdentifier getLinearId() {
return linearId;
}
#NotNull
#Override
public PersistentState generateMappedObject(MappedSchema schema) {
if (schema instanceof BGSchema) {
return new BGSchema.Bg760(
this.seller,
this.manufacturer,
this.regulator,
this.senderToReceiverInformation,
this.linearId
);
} else {
throw new IllegalArgumentException("Unrecognised schema $schema");
}
}
#NotNull
#Override
public Iterable<MappedSchema> supportedSchemas() {
return ImmutableList.of(new BGSchema());
}
#NotNull
#Override
public List<AbstractParty> getParticipants() {
return Arrays.asList(seller,manufacturer,regulator);
}
public List<PublicKey> getParticipantKeys(){
return getParticipants().stream().map(AbstractParty :: getOwningKey).collect(Collectors.toList());
}
public List<Party> getParties(){
return Arrays.asList(manufacturer,regulator);
}
}
The list of FlowSessions passed to CollectSignaturesFlow must correspond exactly to the transaction's required signers.
In this case, no FlowSession was passed for the regulator, who is one of the required signers.
In BGState - your case there are 3 participants so you need to pass other two parties except initiating node FlowSession also in CollectSignaturesFlow.
FlowSession manufacturerflow = initiateFlow(manufacturer);
FlowSession regulator = initiateFlow(manufacturer);
final SignedTransaction stx = subFlow(new CollectSignaturesFlow(ptx,ImmutableSet.of(manufacturerflow,regulator),ImmutableList.of(me),GATHERING_SIGS.childProgressTracker()));
How to fetch data from corda Custom tables?
my sample code is as follows :-
Api layer -- getIous() method
{
Field attributeValue=IOUSchemaV1.PersistentIOU.class.getDeclaredField("value");
CriteriaExpression currencyIndex = Builder.equal(attributeValue, "12");
QueryCriteria.VaultCustomQueryCriteria criteria = new
QueryCriteria.VaultCustomQueryCriteria(currencyIndex);
vaultStates = services.vaultQueryByCriteria(criteria,IOUState.class);
}
In ExamplePlugin I added below code for schema registration
public class ExamplePlugin extends CordaPluginRegistry implements
WebServerPluginRegistry
{
#NotNull
#Override
public Set<MappedSchema> getRequiredSchemas()
{
Set<MappedSchema> requiredSchemas = new HashSet<>();
requiredSchemas.add(new IOUSchemaV1());
return requiredSchemas;
}
}
My Schema classes are ---
public final class IOUSchema {
}
#CordaSerializable
public class IOUSchemaV1 extends MappedSchema
{
public IOUSchemaV1() {
super(IOUSchema.class, 1, ImmutableList.of(PersistentIOU.class));
}
#Entity
#Table(name = "iou_states")
public static class PersistentIOU extends PersistentState {
#Column(name = "sender_name") private final String senderName;
#Column(name = "recipient_name") private final String recipientName;
#Column(name = "value") private final int value;
public PersistentIOU(String senderName, String recipientName, int value) {
this.senderName = senderName;
this.recipientName = recipientName;
this.value = value;
}
public String getSenderName() {
return senderName;
}
public String getRecipientName() {
return recipientName;
}
public int getValue() {
return value;
}
}
}
my state has :-
public class IOUState implements LinearState, QueryableState
{
--- some code goes here and below methods as well.---
#Override
public PersistentState generateMappedObject(MappedSchema schema) {
if (schema instanceof IOUSchemaV1) {
return new IOUSchemaV1.PersistentIOU(
this.sender.getName().toString(),
this.recipient.getName().toString(),
this.iou.getValue());
} else {
throw new IllegalArgumentException("Unrecognised schema $schema");
}
}
#Override
public Iterable<MappedSchema> supportedSchemas() {
return ImmutableList.of(new IOUSchemaV1());
}
}
But all the time i am getting below exception.
Caused by: net.corda.core.node.services.VaultQueryException:
Please register the entity 'com.example.schema.IOUSchemaV1' class in your CorDapp's CordaPluginRegistry configuration (requiredSchemas attribute)
and ensure you have declared (in supportedSchemas()) and mapped (in generateMappedObject())
the schema in the associated contract state's QueryableState interface implementation.
Can anyone please help to resolve this.
Try deleting implements WebServerPluginRegistry from your plugin declaration.