How to use WebSockets with Play Framework? - java

I have downloaded Play Framework from GitHub and compiled it. Now I want to use WebSockets and made a JavaScript client and a WebSocket controller similar to the one on Using WebSockets, but it doesn't work. I can open the WebSocket, but the controller doesn't receive any message I send to it. And I can't close the WebSocket with ws.close();, but if I update my webpage in the browser, the WebSocket is closed on the server.
How can I receive and send WebSocket messages using Play Framework?
Here is my Play Framework WebSocketController:
public class TestSocket extends WebSocketController {
public static void hello(String name) {
while(inbound.isOpen()) {
WebSocketEvent evt = await(inbound.nextEvent());
if(evt instanceof WebSocketFrame) {
WebSocketFrame frame = (WebSocketFrame)evt;
System.out.println("received: " + frame.getTextData());
if(!frame.isBinary()) {
if(frame.getTextData().equals("quit")) {
outbound.send("Bye!");
disconnect();
} else {
outbound.send("Echo: %s", frame.getTextData());
}
}
} else if(evt instanceof WebSocketClose) {
System.out.println("socket closed");
}
}
}
}
Here is my JavaScript client:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>WebSocket test</title>
<style>
.message {background: lightgray;}
</style>
<script>
window.onload = function() {
document.getElementById('sendbutton')
.addEventListener('click', sendMessage, false);
document.getElementById('connectbutton')
.addEventListener('click', connect, false);
document.getElementById('disconnectbutton')
.addEventListener('click', disconnect, false);
}
function writeStatus(message) {
var html = document.createElement("div");
html.setAttribute('class', 'message');
html.innerHTML = message;
document.getElementById("status").appendChild(html);
}
function connect() {
ws = new WebSocket("ws://localhost:9000/ws?name=TestUser");
ws.onopen = function(evt) {
writeStatus("connected");
}
ws.onclose = function(evt) {
writeStatus("disconnected");
}
ws.onmessage = function(evt) {
writeStatus("response: " + evt.data);
}
ws.onerror = function(evt) {
writeStatus("error: " + evt.data);
}
}
function disconnect() {
ws.close();
}
function sendMessage() {
ws.send(document.getElementById('messagefield').value);
}
</script>
</head>
<body>
<h1>WebSocket test</h1>
<button id="connectbutton">Connect</button>
<button id="disconnectbutton">Disconnect</button><br>
<input type="text" id="messagefield"/><button id="sendbutton">Send</button>
<div id="status"></div>
</body>
</html>

I have taken your code and run it on Chrome 14 and 15 and Firefox 7, with the latest version of Play from the Master Branch, and it seems to work mostly. I can
connect
send message
The changes I made where
define ws at a global scope, so put var ws = null just before the window.onload function.
for Firefox, I had to use MozWebSocket instead of WebSocket, so you may need to put an if statement to check based on browser.
change frame.getTextData() to frame.textData
frame.isBinary() to frame.isBinary
The second two bullets I had to do to get the code to compile?!

I had problems with the above code on Chrome 20 and Play 1.2.4
Upgraded to Play 1.2.5 and works like a charm!!

Related

How to delete items without reload or refresh page in ionic 4?

I have list of notification, user can select list of notification and delete.
Delete process working fine but I have to reload page every time user delete item, I couldn't view the changes once user delete elements.
I have trying Angular detect changes but it doesn't work.
It looks like there is something prevent Angular functions from work.
My .ts page
async changeView(){
if(this.dataselect!=undefined){
if(this.dataselect!=""){
const alert = await this.alertCtrl.create({
message: this.removenoti,
buttons: [
{
text: "Cancel",
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}, {
text: "Remove",
handler: () => {
const SigninData = JSON.parse(localStorage.getItem("signindata"));
this.userData.id = SigninData.mem_id;
this.userData.token = SigninData.token;
this.userData.noti_id = this.dataselect;
console.log(this.userData.noti_id);
this.providersservices.postData(this.userData, "deletenoti2").subscribe((result) =>{
this.zone.runOutsideAngular(() => {
this.presentToast(this.removesuccess);
// executing inside NgZone
this.zone.run(() => {
this.dataselect="";
this.edit=false;
this.SelAll = false;
for(var i in this.items)
{
this.checkItems[this.items[i].id]=false;
}
});
console.log(result);
let loading_time = 2000;
setTimeout( () => {
this.ngOnInit();
}, loading_time);
// window.location.assign('/');
});
}, (err) => {
console.log(JSON.stringify(err));
this.presentToast("Please connect your device to internet!");
});
}
}
]
});
await alert.present();
} else {
this.presentToast(this.noitems);
}
} else {
this.presentToast(this.noitems);
}
}
My html code
<ion-content style="--padding-top:6em">
<ion-fab *ngIf="exist=='true'" class="header_tab">
<button ion-fab *ngIf="edit" class="cancelremove" style="right: 45px;" (click)="changeView()">
<ion-icon name="trash-outline"></ion-icon>
</button>
</ion-fab>
<div *ngIf="exist=='true'">
<ion-grid *ngFor="let item of items" class="list" >
<ion-row class="textin" *ngIf="item.nstatus!=1" [style.background-color]="hexColor2">
<ion-checkbox *ngIf="edit" [checked]="allSelected" [(ngModel)]="checkItems[item.id]" (ionChange)="DeSelect();DeSelectall(item.id)"></ion-checkbox>
<ion-label style="width: 100%;max-height: 4em;">
<ion-col col-12 (click)="view(item.id, item.nsubject, item.ndetail, item.ncompany, item.nphoto)">
<ion-row class="condate">
<ion-col col-7 style="padding-left:0;">
<div *ngIf="item.nid!=0">
<p class="titlenote">{{ item.ncompany}}</p>
</div>
<div *ngIf="item.nid==0">
<p class="titlenote">Tagy</p>
</div>
</ion-col>
<ion-col col-5>
<p class="date">{{ item.ndate| date:'dd/MM/yyyy hh:mm' }}</p>
</ion-col>
</ion-row>
<ion-row>
<ion-col col-12>
<p class="detailnote">{{ item.nsubject }}</p>
</ion-col>
</ion-row>
</ion-col>
</ion-label>
</ion-row>
</ion-grid>
</div>
In angular, you can use Observables and Behavior Subjects.
You can create them like this in the .ts file
activityLoaded$ = new BehaviorSubject(false);
this.activityLoaded$.next(true);
and use them with the async pipe in the html
*ngIf="(activityLoaded$ | async) === false"
As it is async, it will update itself everytime a new value will be pushed with .next method.
I'm sorry I don't have the time to perfectly adapt my answer to your question but now you at least know and can learn more about it.
Here is a 1st link on the subject:
https://angular.io/guide/observables
I remember seeing this kind of issue when I worked with Ionic for my mobile project. After fetching data from an API, to re-render the UI, we had to execute the code within NgZone for angular to call change detection. So try this inside your handler: () function:
this.providersservices.postData(this.userData, "deletenoti2").subscribe((result) => {
this.presentToast(this.removesuccess);
// executing inside NgZone
this.zone.run(() => {
this.dataselect="";
this.edit=false;
this.SelAll = false;
for(var i in this.items) {
this.checkItems[this.items[i].id]=false;
}
});
console.log(result);
}
As I do not have full visibility of your component's code, above code is my best assumption what should execute inside NgZone, based on the code sample you have provided.
Of course, to use NgZone, you have to import it and declare in the constructor:
constructor(
...
...
private zone: NgZone
) {}
Hope this helps!
You can try using the ChangeDetectorRef to ask angular to detect any changes.
example:
import { ChangeDetectorRef } from '#angular/core';
constructor(private cdr: ChangeDetectorRef) {}
deleteItem() {
this.cdr.markForCheck();
this.cdr.detectChanges();
}

Android paytm payment gateway response

I have implemented Paytm payment system and everything is working fine with a web intent on top of my intent, money is deducted from customer's acc and its getting added on my account but after the transaction gets complete it gets stuck on a white page saying 'Redirect to app' which i believe i should write the code to redirect back to my app but i don't know how to do that because i couldn't find a onTransactionSucess() event or anything similar to that i also tried onTransactionResponse but still no response. I checked all the paytm documentation and tried contacting paytm support but couldn't find a way.
Hope you have added 'CALLBACK_URL' which is requied to verify the checksum.
As mentioned in paytm documentation
CALLBACK_URL - Security parameter to avoid tampering. Generated using
server side checksum utility provided by Paytm. Merchant has to ensure
that this always gets generated on server. Utilities to generate
checksumhash is available here .
Hope this should do the magic.
I hope you have added this variable to your code -
PaytmPGService service;
If you are using it than you can get all the payment related methods like this :
service.startPaymentTransaction(this, true,
true, new PaytmPaymentTransactionCallback() {
#Override
public void onTransactionResponse(Bundle inResponse) {
System.out.println("===== onTransactionResponse " + inResponse.toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Objects.equals(inResponse.getString("STATUS"), "TXN_SUCCESS")) {
// Payment Success
} else if (!inResponse.getBoolean("STATUS")) {
// Payment Failed
}
}
}
#Override
public void networkNotAvailable() {
// network error
}
#Override
public void clientAuthenticationFailed(String inErrorMessage) {
// AuthenticationFailed
}
#Override
public void someUIErrorOccurred(String inErrorMessage) {
// UI Error
}
#Override
public void onErrorLoadingWebPage(int iniErrorCode, String inErrorMessage, String inFailingUrl) {
// Web page loading error
}
#Override
public void onBackPressedCancelTransaction() {
// on cancelling transaction
}
#Override
public void onTransactionCancel(String inErrorMessage, Bundle inResponse) {
// maybe same as onBackPressedCancelTransaction()
}
});
I hope this will help you.
Change default callbackurl to suppose, 'http://yourdomain (ip address if checking on localhost)/pgResponse.php';.
Add following code to pgResponse.php
<?php
session_start();
header("Pragma: no-cache");
header("Cache-Control: no-cache");
header("Expires: 0");
// following files need to be included
require_once("./lib/config_paytm.php");
require_once("./lib/encdec_paytm.php");
$paytmChecksum = "";
$paramList = array();
$isValidChecksum = "FALSE";
$paramList = $_POST;
$return_array= $_POST;
$checkSum = getChecksumFromArray($paramList,PAYTM_MERCHANT_KEY);//generate new checksum
$paytmChecksum = isset($_POST["CHECKSUMHASH"]) ? $_POST["CHECKSUMHASH"] : ""; //Sent by Paytm pg
//Verify all parameters received from Paytm pg to your application. Like MID received from paytm pg is same as your applicationís MID, TXN_AMOUNT and ORDER_ID are same as what was sent by you to Paytm PG for initiating transaction etc.
$isValidChecksum = verifychecksum_e($paramList, PAYTM_MERCHANT_KEY, $paytmChecksum); //will return TRUE or FALSE string.
$return_array["IS_CHECKSUM_VALID"] = $isValidChecksum ? "Y" : "N";
unset($return_array["CHECKSUMHASH"]);
$mid = $_POST['MID'];
$orderid = $_POST['ORDERID'];
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => 'https://securegw-stage.paytm.in/order/status?JsonData={"MID":"'.$mid.'","ORDERID":"'.$orderid.'","CHECKSUMHASH":"'.$checkSum.'"}',
CURLOPT_USERAGENT => 'Make Request'
));
$resp = curl_exec($curl);
$status= json_decode($resp)->STATUS;
//do something in your database
$encoded_json = htmlentities(json_encode($return_array));
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-I">
<title>Paytm</title>
<script type="text/javascript">
function response(){
return document.getElementById('response').value;
}
</script>
</head>
<body>
Redirecting back to the app.....</br>
<form name="frm" method="post">
<input type="hidden" id="response" name="responseField" value='<?php echo $encoded_json?>'>
</form>
</body>
</html>
In android studio:
public void onTransactionResponse(Bundle inResponse) {
Log.d("Create Response", inResponse.toString());
String response = inResponse.getString("RESPMSG");
if (response.equals("Txn Successful.")) {
Toast.makeText(Bag.this,"Payment done",Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(Bag.this,response,Toast.LENGTH_LONG).show();
}
}

Child Process Fork-what do I write on the client to bring the results back to the client? How can I display these on localhost:3000?

I have written code to upload an excel file and execute a java application using Meteor. When I execute the Java application with child process, the results go into the command prompt. (I am using child process spawn.) I want the results to go onto localhost:3000/Applications. (I have created Applications with iron router. It is a separate page from the file upload page.) I have tried child process fork but I don't know how to call the results to the client. I assume that I have to call the fork results in the client code, like through a template. I can not find anything on this. Do I need a pipe? Do I need to use something different? I can give a little more detail. When the Java application executes, it is supposed to read the excel file. In order to make this happen, I used an on click method after the file is uploaded to grab the file, using (session.set and session.get) and called a meteor method that executes the child process. At this point, the method executes and sends the file name and the java application to the command prompt. I need the results to pop up on my localhost and not the command prompt. I am very close to finishing the application and have done extensive research, but because I am new to programming, I am having trouble putting the pieces together. Thank you Thank you! I appreciate you taking the time to read this!
Server Javascript Code:
Router.configure({
layoutTemplate: 'main'
});
YourFileCollection = new FS.Collection("yourFileCollection", {
stores: [new FS.Store.FileSystem("yourFileCollection", {path: "~/meteor_uploads"})]
});
YourFileCollection.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc) {
return true;
},
remove: function (userId, doc) {
return true;
},
download: function (userId, doc) {
return true;
}
});
Meteor.methods({
'kickoffJar': function(selectedFile){
console.log("kickoffJar");
console.log(selectedFile);
var child = require('child_process').spawn("Java", ['- jar','C:/\Users/\caitl/\HelloWorld.jar'],);
child.stdout.on('data', function(data) {
console.log('stdout: ' + data);
//Here is where the output goes
});
child.stderr.on('data', function(data) {
console.log('stdout: ' + data);
//Here is where the error output goes
});
child.on('close', function(code) {
console.log('closing code: ' + code);
//Here you can get the exit code of the script
});
}
});
Router.route('/', {
name: 'fileList',
template: 'fileList'
});
Client Javascript Code:
Router.configure({
layoutTemplate: 'main'
});
YourFileCollection = new FS.Collection("yourFileCollection", {
stores: [new FS.Store.FileSystem("yourFileCollection", {path: "~/meteor_uploads"})]
});
YourFileCollection.allow({
insert: function (userId, doc) {
return true;
},
update: function (userId, doc) {
return true;
},
remove: function (userId, doc) {
return true;
},
download: function (userId, doc) {
return true;
}
});
if (Meteor.isClient) {
Meteor.subscribe("fileUploads");
Template.fileList.helpers({
theFiles: function () {
return YourFileCollection.find();
}
});
Template.fileList.events({
'click #deleteFileButton ': function (event) {
console.log("deleteFile button ", this);
YourFileCollection.remove({_id: this._id});
},
'click #validateFileButton ': function (event){
Session.set('selectedFile', ({_id: this._id}));
Session.get('selectedFile');
var selectedFile = Session.get('selectedFile')
Meteor.call ('kickoffJar', selectedFile, function (error, result) {
if(error){
alert('Error');
}else{
Router.go('/Application');
}
});
},
'click #openFileButton ': function (event){
Router.go('/Application');
},
'change .your-upload-class': function (event, template) {
console.log("uploading...")
FS.Utility.eachFile(event, function (file) {
console.log("each file...");
var yourFile = new FS.File(file);
YourFileCollection.insert(yourFile, function (err, fileObj) {
console.log("callback for the insert, err: ", err);
if (!err) {
console.log("inserted without error");
}
else {
console.log("there was an error", err);
}
});
});
}
});
}
if (Meteor.isServer) {
Meteor.publish("fileUploads", function () {
console.log("publishing fileUploads");
return YourFileCollection.find();
});
}
Router.route('/Application');
Router.route('/', {
name: 'fileList',
template: 'fileList'
});
Client HTML
Application
{{> yield}}
Home
<template name="fileList">
<br/>Testing file upload below<br/><br/>
<input class="your-upload-class" type="file">
<br/><br/>
<table border="1">
<tbody>
{{#each theFiles}}
<tr>
<td>{{uploadedAt}}</td><td>{{original.name}}</td>
<td>link</td><td>{{#if isUploaded}}uploaded{{else}}uploading...{{/if}}</td>
<td><button id="deleteFileButton">delete</button></td>
<td><button id="validateFileButton">validate</button></td>
<td><button id="openFileButton">Open</button></td>
</tr>
{{/each}}
</tbody>
</table>
</template>
<template name="Application">
<h2>Application</h2>
</template>

Understanding Server-sent Events

I'm trying to update an HTML5 table in real-time with some data from the database. Here is my code:
HTML page:
<script type="text/javascript">
//check for browser support
if(typeof(EventSource)!=="undefined") {
//create an object, passing it the name and location of the server side script
var eSource = new EventSource("[some address]/api/sse");
//detect message receipt
eSource.onmessage = function(event) {
//write the received data to the page
document.getElementById("placeholder").innerHTML=table;
};
}
else {
[erro message]
}
</script>
And my Java Restful service:
#Path("/sse")
public class SSEResource {
#Context
private UriInfo context;
public SSEResource() {
}
#GET
#Produces(SseFeature.SERVER_SENT_EVENTS)
public String getServerSentEvents() throws Exception {
SomeObject o = new SomeObject();
final String myString = o.someQuery().getEntity().toString();
return "data: " + myString + "\n\n";
}
}
This someQuery() method queries from database and returns what I want to put on my table. Everythings looks great. But I want to know if it's right or wrong, because if I put some log on someQuery() method, I see that every 3 seconds the query is executed. This may cause heavy duty, right? Is this normal or is my code wrong?

Showing specific error in JSP with Ajax

I'm trying to show in my App different errors when a user is already logged in and when the user wrote their username/password wrong. I have tried many ways but none of them is working. I don't know what else to try or if it's even possible. I don't know if I'm close to the solution either.
What I'm trying to do is:
Set the errorMessage in the request;
Set the SC_INTERNAL_SERVER_ERROR in the response so the AJAX function enters in ** and the HTML in the paramether is the one in the JSP with the specific Message.
Action
public class LogUser extends Action {
#Override
public void execute() throws Exception {
...
String pageToGo = this.tryLogUser(username, password);
request.getRequestDispatcher(pageToGo).forward(request, response);
}
private String tryLogUser(String username, String password) throws Exception {
String pageToGo = "page/userHome";
...
if(canLog) {
...
try {
...
Server.getInstance().logIn(user); // Throws an Exception if the User is already logged in.
...
} catch (ServerException e) {
this.setErrorMessage("That user is already logged in.");
pageToGo = "page/error.jsp";
}
} else {
this.setErrorMessage("User and/or Password are incorrect.");
pageToGo = "page/error.jsp";
}
return pageToGo;
}
private void setErrorMessage(String message) {
request.setAttribute("errorMessage", message);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
JSP
<div class="alert alert-danger"> ${ requestScope.errorMessage } </div>
AJAX
function showUserHome() {
$.post( "${ sessionScope.ServletUrl }", $( "form#logForm" ).serialize() )
.done(function( html ) {
$( "div#toolbar" ).load("page/userToolbar.jsp");
$( "div#content" ).html( html );
})
.fail(function( html ) {
$( "#result" ).html( html );
});
}
Edit:
While trying to Debug it from the browser, it gets in the $.post and after that step, it jumps to the end of the function, skipping .done and .fail and the page remains the same. I'm not getting any error in the RAD Console or the Browser Console other than the SC_INTERNAL_SERVER_ERROR that I setted on the Action.
Calling setErrorPage method won't change your pageToGo local variable and thus always the same view is used. Change it to something like:
pageToGo = setErrorPage("That user is already logged in.");
(or even consider rename it to getErrorPage)

Categories

Resources