Reactive on SSE payload on Quarkus trasmit only data field? - quarkus

My example Code :
#GET
#Path("/reactive")
#Produces(MediaType.SERVER_SENT_EVENTS)
#RestSseElementType(MediaType.APPLICATION_JSON)
public Multi<OutboundSseEvent> reactive() {
return Multi.createFrom().ticks().every(Duration.ofSeconds(1))
.onItem().transform(n -> creaMessaggioSse(n,"SseReactive"));
}
private OutboundSseEvent creaMessaggioSse(Long evt, String nome){
return sse.newEventBuilder()
.data("Evento-"+evt)
.id("Id-"+evt)
.name(nome)
.build();
}
My output is :
data:{"name":"SseReactive","comment":null,"id":"Id-0","type":"java.lang.String","genericType":"java.lang.String","mediaType":{"type":"text","subtype":"plain","parameters":{},"wildcardType":false,"wildcardSubtype":false},"mediaTypeSet":false,"data":"Evento-0","reconnectDelay":-1,"escape":false,"reconnectDelaySet":false}``
instead of
id:Id-1
event:SseStandard
data:Evento-1
That's because the code executed is (finded by debug)
PublisherResponseHandler.onNext(Object item) {
OutboundSseEventImpl event = new OutboundSseEventImpl.BuilderImpl().data(item).build();
SseUtil.send(requestContext, event)
So the event "sent" has only data.
Where am I wrong ??

Related

Mono<Object> being returned instead of Mono<ResponseEntity> when mapping (Java 8)

Trying to practice reactive coding for an API but I'm struggling to understand what I'm doing wrong when using flatMap() and map() to cast to a ResponseEntity object. The error mentions that the code is returning a Mono<Object> and cant be cast/transformed into a Mono<ResponseEntity<>>.
Public Mono<ResponseEntity<?> deleteEndpoint(String someId) {
return db.existsById(someId).flatMap(exists -> {
if (!exists) return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
else {
Mono<Boolean> deletedStuff1 = someFunct();
Mono<Boolean> deletedStuff2 = anotherFunct();
Mono<Tuple2<Boolean, Boolean>> deletedStuff = Mono.zip(deletedStuff1, deletedStuff2);
return deletedStuff.then(Mono.just(ResponseEntity.status(NO_CONTENT).build());
}
});
}
All help is appreciated
From .flatMap() you must return Publisher, not actual object
In this if statement you return ResponseEntity instead of Mono<ResponseEntity>
So, just wrap it with Mono
if (!exists) {
return Mono.just(ResponseEntity.status(HttpStatus.BAD_REQUEST).build());
} else {
// ...

Xamarin Form - Can't get return value data from Service class method into MainPage method for filtering

I'm new to Xamarin, I have an app in Xamarin-Form that it's fetching data from web api and getting user input from Entry control.
The web api service class is working fine and reaches the deserialization in the getCourses method as seen below in Code Snippet 1.
The Entry control as well is working fine until it retrieves the user input on the MainPage class, OnOkGetCourseButton method as seen below Code Snippet 2.
What I want to achieve is, inside MainPage.xaml.cs, I create a method that takes the user input data and check agaisnt the deseriaized json data (the Id specially),
if it finds the Id in deserialized List of data, then it can send the found data to another ViewPage and display them.
if It cannot find the data, it shows a dialog box.
So far, I tried to call Task<ObservableCollection> getCourses() method from the MainPage class, inside CheckCourseComplete as seen below but it giving me no value/nothing, some kind of null value.
I don't want to filter the user input against web api json response inside getCourses(),
I want to do that in a separate method to follow S-OLID (Single Responsibility Principle).
If it's not possible in a separate method, then I just need to get it worked.
Please what is the best way to achieve it?
Code Snippet 1
public class CourseService : ICourseService
{
string Base_Url = "https://www.test.com/api/TheCourse";
public async Task<ObservableCollection<Course>> getCourses()
{
try
{
string url = Base_Url;
HttpClient client = new HttpClient();
HttpResponseMessage responseMessage = await client.GetAsync(url);
if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await responseMessage.Content.ReadAsStringAsync();
var deserializedClass = JsonConvert.DeserializeObject<ObservableCollection<Course>>(result);
// I don't want to do that here, as it will violate SRP (SOLID)
return deserializedClass;
}
return null;
}
catch (Exception)
{
throw;
}
}
}
Code Snippet 2
namespace CourseMobile
{
public partial class MainPage : ContentPage
{
private string _getEntryText;
private readonly CourseViewModel orderViewModel;
public Course FetchCourse { get; set; }
public MainPage()
{
InitializeComponent();
CheckCourseComplete();
BindingContext = new CourseViewModel();
}
public string GetEntryText
{
get => _getEntryText;
set => _getEntryText = value;
}
public async void OnOkGetCourseButton(object sender, EventArgs e)
{
var inputtedCourseNumber = this.GetEntryText;
if(inputtedCourseNumber == string.Empty)
{
await DisplayAlert("", "Please enter your Course number", "OK 3");
}
else
{
CheckCourseComplete();
this.GetEntryText = inputtedCourseNumber;
await DisplayAlert("New Text", inputtedCourseNumber, "OK 2");
}
}
void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
var newText = e.NewTextValue;
this.GetEntryText = newText;
}
public async void CheckCourseComplete()
{
CourseService myCourse = new CourseService();
await myCourse.getCourses(); // It doesn't return the json data (web api data)
// I need to check user input + (web api data) here
}
}
}
getCourses is async, so you need to use await when calling it
public async void CheckCourseComplete()
{
CourseService myCourse = new CourseService();
var data = await myCourse.getCourses();
// now filter data
}

JavaFX: How to trigger TreeItem event

I have class myClass extends TreeItem<file> to be used as datamodel in a TreeTableView mostly following the example here: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TreeItem.html .
public class myTreeItem extends TreeItem<File>
private boolean isLeaf;
private boolean isFirstTimeChildren = true;
private boolean isFirstTimeLeaf = true;
#Override public ObservableList<TreeItem<File>> getChildren() {
// ... full code see link to Oracle documentation
return super.getChildren();
}
private ObservableList<TreeItem<File>> buildChildren(TreeItem<File> TreeItem) {
// ... full code see link to Oracle documentation
};
}
I have added a function to add children to this item. I have problems with the correct update of the TreeTableView. More details see in the code and comments below:
public void addChild(String name) {
itemManger.addChild(this.getValue(), name); // Generate Child
isFirstTimeChildren = true; // Ensure that buildChildren() is called, when getchildren() is called.
// getChildren(); // If I would activate this line,
// all listeners would be notified
// and the TreeTableView is updated.
// This is most likely due to the call super.getChildren();
// However I want to throw the event on my own in order
// to avoid the extra call of this.getChildren(). Here is my
// (not sufficent) try:
EventType<TreeItem.TreeModificationEvent<MLDCostumizableItem>> eventType = TreeItem.treeNotificationEvent();
TreeModificationEvent<MLDCostumizableItem> event = new TreeModificationEvent<>(eventType,this);
Event.fireEvent(this, event);
// Here I don't know how to get a value for target.
// Is there some standard target, which includes all FX components?
}
How the correctly throw this event?
Seems that I had a missunderstanding in how the triggering works in JavaFX. Now the most simple solution is:
#Override // Taken from Link
public void update(Observable observ, Object arg1) {
if (observ!=this.item)
{
LOGGER.error(new MLDConnectionException("Unexpected call of update() with observ = " + observ.toString()));
return;
}
// Build new Chidren list
try {
super.getChildren().removeIf((x) -> true); // empty list
super.getChildren().setAll(buildChildren(this));
} catch (MLDConnectionException e) {
LOGGER.error("Error when genereting children List: ", e);
}
}
public File addChild(String name) throws MLDException {
File newChild = itemManger.addChild(item, name);
update(this.item, null);
return newChild;
}

Get HttpHeaders from HttpRequestException?

I have a Web API, When the incoming request is not valid then the API sends back a HttpStatusCode.BadRequest and API would also add a CorrelationId into Response's HttpHeader. Something like below
public class ValidateRequestAttribute : ActionFilterAttribute
{
public ValidateRequestAttribute()
{
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.ModelState.IsValid == false)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.HttpContext.Response.Headers.Add("x-correlationid", "someid");
context.Result = new ContentResult()
{
Content = "bad request."
};
}
}
}
On client side im using HttpClient to access the API. I am not sure how client would retrieve HttpStatusCode and HttpHeader here. Here is my client code
public bool Process(url)
{
bool result = false;
try
{
Task.Run(async () => await _httpClient.GetStringAsync(url).ConfigureAwait(false)).Result;
}
catch (Exception ex)
{
if(ex is AggregateException)
{
var aggregateException = ex as AggregateException;
foreach(var innerException in aggregateException.InnerExceptions)
{
if (innerException is HttpRequestException)
{
var httpRequestException = innerException as HttpRequestException;
// how do i get StatusCode and HttpHeader values here??
}
}
}
}
return result;
}
I have already gone through SO post here and MSDN article here and also Stephen Cleary's article here
Even though its recommended to make async all the way down, I this case Client and API are both disconnected from each other and client is synchronous. Note that Client's Process method is synchronous method.
Like this:
public bool Process(string url)
{
var result = _httpClient.GetAsync(url).ConfigureAwait(false).GetAwaiter().GetResult();
if (result.StatusCode == HttpStatusCode.BadRequest)
{
IEnumerable<string> values;
if (result.Headers.TryGetValues("x-correlationid", out values))
{
// Should print out "someid"
Console.WriteLine(values.First());
}
}
return result.IsSuccessStatusCode;
}
Also note that doing .GetAwaiter().GetResult(); vs .Result; is recommended since it makes the code easier to work with because it does not throw an AggregateException.
If you want to read the response content as a string just do:
var content = result.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
If you want to make your code async though you should use the async/await keyword and skip the .GetAwaiter().GetResult();.

Get data already sent from handheld to wear

I have sent data from mobile to wear as
private static final String IMAGE_PATH = "/image";
private static final String IMAGE_TITLE = "imageTitle";
private static final String IMAGE_TO_SEND = "image";
PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(IMAGE_PATH);
putDataMapRequest.getDataMap().putString(IMAGE_TITLE, "hi this handheld");
PutDataRequest putDataRequest = putDataMapRequest.asPutDataRequest();
putDataRequest.setUrgent();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(#NonNull DataApi.DataItemResult dataItemResult) {
if (dataItemResult.getStatus().isSuccess()) {
} else {
}
}
});
On wear side I want to first check if data has been already sent or not. If data has been sent already then I want to use that data otherwise I want to request data for mobile:
I have done it but it always fails. My code is as follow:
Wearable.NodeApi.getLocalNode(googleApiClient).setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
#Override
public void onResult(#NonNull NodeApi.GetLocalNodeResult getLocalNodeResult) {
Uri uri = new Uri.Builder()
.scheme(PutDataRequest.WEAR_URI_SCHEME)
.path(IMAGE_PATH)
.authority(getLocalNodeResult.getNode().getId())
.build();
Wearable.DataApi.getDataItem(googleApiClient, uri).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(#NonNull DataApi.DataItemResult dataItemResult) {
if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
Log.d(TAG, "onResult: success result");
DataMap dataMap = DataMap.fromByteArray(dataItemResult.getDataItem().getData());
} else {
}
}
});
}
});
I found solution. I was checking data by getting local nodes id ,so that it was providing null data.Local Node id i-e id of my watch, Node Id must be id of node which has sent data using Data Layer Api. In my case at first my handheld sends data through the Data Layer Api and my watch checks data exist or not.If data found gets data otherwise send request to Handheld.
Wearable.NodeApi.getConnectedNodes(googleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
#Override
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
for (Node node : nodes.getNodes()) {
connectedNode = node;
}
Uri uri = new Uri.Builder()
.scheme(PutDataRequest.WEAR_URI_SCHEME)
.path(IMAGE_PATH)
.authority(connectedNode.getId()) //id which has sent data
.build();
Wearable.DataApi.getDataItem(googleApiClient, uri).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(#NonNull DataApi.DataItemResult dataItemResult) {
if (dataItemResult.getStatus().isSuccess() && dataItemResult.getDataItem() != null) {
Log.d(TAG, "onResult: successfully got previous data");
} else {
makeRequestToSendData();
Log.d(TAG, "onResult: failed to got previous data");//request handheld to get data using **Message API**
}
}
});
}
});
We have to change getLocalNode to getConnectedNodes .
Your code looks fine, is the node id non null ?
Does it fail at the getDataItem result callback ?
To get the DataMap from the DataItemResult, use this code :
DataItem dataItem = dataItemResult.getDataItem();
if (dataItem != null) {
DataMap dataMap = DataMapItem.fromDataItem(dataItem).getDataMap();
}

Resources