CORDA: Invoke custom query on all parties involved in transaction - java

I have multiple questions on Corda:
Can we predefine the h2 configuration to pick in build.gradle file?
I have a transaction in my corda network where i want to validate something based on custom fields the validation has to happen based on query that needs to be fired on all 3 parties sender, receiver, notary how can i fetch the session of all 3 nodes? i am able to pull the session of sender using getServiceHub().jdbcSession()
What will be the most suggested way to query a notary for custom fields? Can it be done using creating a sub-flow if yes then how?
we have validating and non validating notaries, where do we actually validate using notary? Where do we write the validation code?
how can we enable autosuggest in intellij for java api of corda?

You can set the h2Port option in deployNodes:
node {
name "O=PartyA,L=London,C=GB"
advertisedServices = []
p2pPort 10005
rpcPort 10006
webPort 10007
h2Port 10008
cordapps = ["net.corda:corda-finance:$corda_release_version"]
rpcUsers = [[ user: "user1", "password": "test", "permissions": []]]
}
Is that the kind of configuration you needed?
Each node's database is private by design, and cannot be queried from another node. Instead, you need to communicate with the other nodes as part of your flow in a way that causes them to initiate a response flow on their end where they query their own databases and send the results back. Something like:
public class CollectDBDataFlow {
#InitiatingFlow
#StartableByRPC
public static class Initiator extends FlowLogic<List<Object>> {
Party counterparty;
public Initiator(Party counterparty) {
this.counterparty = counterparty;
}
#Suspendable
#Override public List<Object> call() {
// TODO: Implement queryMyDatabase to perform querying.
Object myDBData = queryMyDatabase();
FlowSession counterpartySession = initiateFlow(counterparty);
Object theirDBData = counterpartySession.receive(Object.class);
return ImmutableList.of(myDBData, theirDBData);
}
}
#InitiatedBy(Initiator.class)
public static class Responder extends FlowLogic<Void> {
private FlowSession counterpartySession;
public Responder(FlowSession counterpartySession) {
this.counterpartySession = counterpartySession;
}
#Suspendable
#Override
public Void call() {
// TODO: Implement queryMyDatabase to perform querying.
Object myDBData = queryMyDatabase();
counterpartySession.send(myDBData);
return null;
}
}
}
The role of the notary isn't to be queried for data, but to prevent double-spends. You could technically do it using the method described in (2) above, but it wouldn't be advised. What are you trying to achieve?
The validation logic is written into the platform. See https://github.com/corda/corda/blob/release-V1/node/src/main/kotlin/net/corda/node/services/transactions/ValidatingNotaryFlow.kt.
The auto-complete should appear automatically, just like any other library.

Related

How to make a custom controller in Java Spring?

I want to make a telegram bot using Java and Spring. I want to create my own controller, similar to RestController, which allows me to make my own mapping (like GetMapping), only for the chat command, respectively. As an argument, I want to be able to receive a message from an update (which has already been parsed, removing the command, because it is already specified in the mapping), userID, chatID, and so on. That is, I need some kind of middle layer that will convert an update to these arguments that I want.
Does Spring allow you to do this? If not, is it possible to at least get the update as an argument?
I know there is a HandleInterceptor, but it uses HttpRequest which is not exactly what I need. Maybe I could extend it make a wrapper somehow?
Possible implementation of what I want is something like this:
#TelegramController
public class ListController {
private final ListService listService;
private final SendMessageService sendMessageService;
public ListController(ListService listService, SendMessageService sendMessageService) {
this.listService = listService;
this.sendMessageService = sendMessageService;
}
#CommandMapping("/addlist")
public TalkState addList(String message, User user) {
listService.addList(message, user.getId());
return TalkState.CONTINUE;
}
#CallbackQueryMapping
public TalkState addList(#RequestParam("inline_message_id") String inlineMessageId, #RequestParam("data") String data) {
listService.addList(message, userId);
sendMessageService.send("Your data: " + data);
return TalkState.STOP;
}
}

LazyList is not defined in ZUL Page

I'm trying to pass data from DAO with flexbile search query trough to the zul page using de the widgetModel. But when I print the widgetModel.orders it says...
(index):93 Uncaught ReferenceError: LazyList is not defined
at window.onload ((index):93)
zul page
window.onload = function () {
const myChart = new Chart(
document.getElementById('myChart'),
config
);
const test = [[${widgetModel.orders}]];
console.log(test);
};
controller class
public class customGraphController extends DefaultWidgetController {
private static final long serialVersionUID = 7954736389190109887L;
#WireVariable
private transient customGraphService customGraphService;
#Override
public void preInitialize(Component comp) {
super.preInitialize(comp);
WidgetModel model = getWidgetInstanceManager().getModel();
model.put("orders", customGraphService.getAllOrders());
}
}
service class
public class customGraphService {
#Autowired
private OrdersDataDao ordersDataDao;
public List<OrderModel> getAllOrders() {
return ordersDataDao.getAllOrders();
}
}
dao class
public class OrdersDataDao {
#Resource
private FlexibleSearchService flexibleSearchService;
public List<OrderModel> getAllOrders() {
final String stringQuery = "select {o.pk} from {order as o}";
final FlexibleSearchQuery query = new FlexibleSearchQuery(stringQuery);
final SearchResult<OrderModel> result = flexibleSearchService.search(query);
if (null != result.getResult()) {
return result.getResult();
} else {
return null;
}
}
}
Does someone knows a solution?
window.onLoad is always too early to manipulate ZK widgets. The onLoad callback will trigger once the initial document has been loaded, but that document itself will load ZK libaries, initialize the client engine, etc.
If you need to do something "after libraries have been loaded", you can use zk.afterload. This hook is good if you need to modify a framework function before the widgets actually use it.
However, this is still before widget instantiation by the client engine, so if your goal is to access a widget, it is still too early.
If you want to do something to a widget after that widget has been added to the page an initialized, what you actually need is a client-side onBind listener.
You can set that listener in zul or in java, but the simplest way to do that is like this: https://zkfiddle.org/sample/1v9phuk/1-Another-new-ZK-fiddle
Lastly, if you are going to use ZK's client-side API to access / modify content at client-side, I'd recommend looking into the ZK client-side selectors. Way easier than trying to manually lookup elements by ID, and way more robust in the long run.
document.getElementById('myChart') will only work if you have a dom element with the actual ID "myChart", which is not how ZK works (not with default UUID generator anyway).
Instead, you can select a widget by it's ZK ID.
Assuming you have <charts id="myChart" /> in your zul, you can get the ZK widget directly as argument to the onBind listener, or you can get it with the ZK selector:
zk.$("$myChart"), and from there you can get the DOM node: zk.$("$myChart").$n()
Make sure you know what is client-side (JavaScript), and what is Server side.
(Lastly)^2, keep in mind that in a ZK architecture, the server is the source of the state, and the client only update the state by sending client commands back to the server.
If you use JS to modify the client-side state, you can create desynchronization between the server-side state and the client-side state, so proceed with caution.
I found a solution, I used GSON to stringify the list and than pass it to the zul page :-)
private Object convertAllOrderModelsToJSON() {
//get all the models
List list = customGraphService.getAllOrdersModels();
//convert models to JSON
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(list);
return json;
}

aggregate not found in the event store

I am trying to add data using CQRS framework AXON. But while hitting the API(used to add an order). I am getting the below error:-
Command 'com.cqrs.order.commands.CreateOrderCommand' resulted in org.axonframework.modelling.command.AggregateNotFoundException(The aggregate was not found in the event store)
But i already have an Aggregate in my code(OrderAggregate.Java).
The Full code can be found at - https://github.com/iftekharkhan09/OrderManagementSystem
API to add Order - http://localhost:8080/confirmOrder
Request Body:-
{
"studentName":"Sunny Khan"
}
Can anyone please tell me where am i doing wrong?
Any help is appreciated!
For other readers, let me share the Aggregate you've created in your repository:
#Aggregate
public class OrderAggregate {
public OrderAggregate(OrderRepositoryData orderRepositoryData) {
this.orderRepositoryData = orderRepositoryData;
}
#AggregateIdentifier
private Integer orderId;
private OrderRepositoryData orderRepositoryData;
#CommandHandler
public void handle(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
#EventSourcingHandler
public void on(OrderCreatedEvent event) {
this.orderId=event.getOrderId();
Order order=new Order("Order New");
orderRepositoryData.save(order);
}
protected OrderAggregate() {
// Required by Axon to build a default Aggregate prior to Event Sourcing
}
}
There are several things you can remove entirely from this Aggregate, which are:
The OrderRepositoryData
The OrderAggregate constructor which sets the OrderRepositoryData
The manually saving of an Order in the #EventSourcingHandler annotated function
What you're doing here is mixing the Command Model's concern of making decisions with creating a queryable Order for the Query Model. It would be better to remove this logic entirely from an Aggregate (the Command Model in your example) and move this to an Event Handling Component.
This is however not the culprit for the AggregateNotFoundException you're receiving.
What you've missed is to make the CreateOrderCommand command handler a constructor.
The CreateOrderCommand will create an Order, as it's name already suggests.
Hence, it should be handled by a constructor rather than a regular method.
So, instead of this:
#CommandHandler
public *void* handle(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
You should be doing this:
#CommandHandler
public OrderAggregate(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
Hope this helps you out #Sunny!
aggregate not found in the event store
The main reason for this exception is, When the axon is trying to save the aggregate it should create the aggragate first.
#CommandHandler
public OrderAggregate(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
Also in this way ur
private OrderRepositoryData orderRepositoryData;
won't be initialized, so autowired the orderRepositoryData also.
#Autowired
private OrderRepositoryData orderRepositoryData;
For the successive events you should use same OrderId ,else also it will throw
handleThrowable(java.lang.Throwable,org.springframework.web.context.request.WebRequest)
org.axonframework.modelling.command.AggregateNotFoundException: The aggregate was not found in the event store
at org.axonframework.eventsourcing.EventSourcingRepository.doLoadWithLock(EventSourcingRepository.java:122)

accessing child constant in parent class in java

OK, so I have an interesting problem. I am using java/maven/spring-boot/cassandra... and I am trying to create a dynamic instantiation of the Mapper setup they use.
I.E.
//Users.java
import com.datastax.driver.mapping.annotations.Table;
#Table(keyspace="mykeyspace", name="users")
public class Users {
#PartitionKey
public UUID id;
//...
}
Now, in order to use this I would have to explicitly say ...
Users user = (DB).mapper(Users.class);
obviously replacing (DB) with my db class.
Which is a great model, but I am running into the problem of code repetition. My Cassandra database has 2 keyspaces, both keyspaces have the exact same tables with the exact same columns in the tables, (this is not my choice, this is an absolute must have according to my company). So when I need to access one or the other based on a form submission it becomes a mess of duplicated code, example:
//myWebController.java
import ...;
#RestController
public class MyRestController {
#RequestMapping(value="/orders", method=RequestMethod.POST)
public string getOrders(...) {
if(Objects.equals(client, "first_client_name") {
//do all the things to get first keyspace objects like....
FirstClientUsers users = (db).Mapper(FirstClientUsers.class);
//...
} else if(Objects.equals(client, "second_client_name") {
SecondClientUsers users = (db).Mapper(SecondClientUsers.class);
//....
}
return "";
}
I have been trying to use methods like...
Class cls = Class.forName(STRING_INPUT_VARIABLE_HERE);
and that works ok for base classes but when trying to use the Accessor stuff it no longer works because Accessors have to be interfaces, so when you do Class cls, it is no longer an interface.
I am trying to find any other solution on how to dynamically have this work and not have to have duplicate code for every possible client. Each client will have it's own namespace in Cassandra, with the exact same tables as all other ones.
I cannot change the database model, this is a must according to the company.
With PHP this is extremely simple since it doesn't care about typecasting as much, I can easily do...
function getData($name) {
$className = $name . 'Accessor';
$class = new $className();
}
and poof I have a dynamic class, but the problem I am running into is the Type specification where I have to explicitly say...
FirstClientUsers users = new FirstClientUsers();
//or even
FirstClientUsers users = Class.forName("FirstClientUsers");
I hope this is making sense, I can't imagine that I am the first person to have this problem, but I can't find any solutions online. So I am really hoping that someone knows how I can get this accomplished without duplicating the exact same logic for every single keyspace we have. It makes the code not maintainable and unnecessarily long.
Thank you in advance for any help you can offer.
Do not specify the keyspace in your model classes, and instead, use the so-called "session per keyspace" pattern.
Your model class would look like this (note that the keyspace is left undefined):
#Table(name = "users")
public class Users {
#PartitionKey
public UUID id;
//...
}
Your initialization code would have something like this:
Map<String, Mapper<Users>> mappers = new ConcurrentHashMap<String, Mapper<Users>>();
Cluster cluster = ...;
Session firstClientSession = cluster.connect("keyspace_first_client");
Session secondClientSession = cluster.connect("keyspace_second_client");
MappingManager firstClientManager = new MappingManager(firstClientSession);
MappingManager secondClientManager = new MappingManager(secondClientSession);
mappers.put("first_client", firstClientManager.mapper(Users.class));
mappers.put("second_client", secondClientManager.mapper(Users.class));
// etc. for all clients
You would then store the mappers object and make it available through dependency injection to other components in your application.
Finally, your REST service would look like this:
import ...
#RestController
public class MyRestController {
#javax.inject.Inject
private Map<String, Mapper<Users>> mappers;
#RequestMapping(value = "/orders", method = RequestMethod.POST)
public string getOrders(...) {
Mapper<Users> usersMapper = getUsersMapperForClient(client);
// process the request with the right client's mapper
}
private Mapper<Users> getUsersMapperForClient(String client) {
if (mappers.containsKey(client))
return mappers.get(client);
throw new RuntimeException("Unknown client: " + client);
}
}
Note how the mappers object is injected.
Small nit: I would name your class User in the singular instead of Users (in the plural).

Implement IExtensibleDataObject by default on Proxy

Whiel generating proxy class by using SVCUTIL.exe or By Adding service reference from VS, it inherits the IExtensibleDataObject to the data contract classes by default.
WCF data contract
[DataContract]
public class Employee
{
[DataMember(Order = 1)]
public string Id { get; set; }
}
WCF Servcie
public class Service1 : IService1
{
public Employee GetEmployeeById(Employee employee)
{
return employee;
}
}
Proxy Class generated by adding service reference from VS and Employee composite class in client side inherits IExtensibleDataObject interface by default even though i haven;'t implement this in service end.
Client side Employee Class
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Employee", Namespace="http://schemas.datacontract.org/2004/07/WcfService1")]
[System.SerializableAttribute()]
public partial class Employee : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string IdField;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Id {
get {
return this.IdField;
}
set {
if ((object.ReferenceEquals(this.IdField, value) != true)) {
this.IdField = value;
this.RaisePropertyChanged("Id");
}
}
}
Now the question is, While generating proxy from some other client (For ex: Java), will they implement IExtensibleDataObject interface by default?
No, because IExtensibleDataObject is an interface from .Net Framework.
The service will run even without it. It provides a way to store extra data, that is not present in the contract:
The IExtensibleDataObject interface provides a single property that
sets or returns a structure used to store data that is external to a
data contract. The extra data is stored in an instance of the
ExtensionDataObject class and accessed through the ExtensionData
property. In a roundtrip operation where data is received, processed,
and sent back, the extra data is sent back to the original sender
intact. This is useful to store data received from future versions of
the contract. If you do not implement the interface, any extra data is
ignored and discarded during a roundtrip operation.
You can read more here: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iextensibledataobject%28v=vs.100%29.aspx
Hope it helps

Categories