I am fiddling around with JBOSS's Web Services, and I have created the following:
http://127.0.0.1:8080/IM/TestService?wsdl
Now I need to access Web Methods from that Web Service from JavaScript.
Say I have a web method named foo in TestService, how do I make an ajax call to it?
I tried accessing the method via http://127.0.0.1:8080/IM/TestService/foo, but I'm getting an HTTP Status 404.
I wrote the following JavaScript that will allow me to call the Web Methods from the JBoss Web Service.
Dependencies
jQuery
XML Objectifier
jQuery Soap Client (depends on jQuery and XML Objectifier)
var WS = function (url, ns, nsName) {
return function (method, parameters, callback) {
var i, j, para, soapBody = new SOAPObject(method), sr, response;
soapBody.ns = {
name: nsName,
uri: ns
};
if (typeof parameters === "function") {
callback = parameters;
} else if (parameters && parameters.length) {
for (i = 0, j = parameters.length; i < j; ++i) {
para = parameters[i];
soapBody.appendChild(new SOAPObject(para.name)).val(para.value);
}
}
sr = new SOAPRequest(method, soapBody);
SOAPClient.Proxy = url;
SOAPClient.SendRequest(sr, function (r) {
response = r.Body[0][method + "Response"][0]["return"][0]["Text"];
if (callback) {
callback.call(sr, response);
}
});
}
};
Usage
var ws = WS("http://127.0.0.1:8080/IM/TestService", "http://wservices/", "ns2");
ws("foo", [{name: "name", value:"dreas"}], function (r) {
console.log(r);
});
Disclaimer: This is still very much untested, so it can still blow up your computer
Related
Question: It is possible to request data in gRPC similar with a http request with params?
Details: I work on a maven java project with gRPC. Below is a simplified code of my .proto file.
syntax = "proto3";
service BookService{
rpc getBooks(Empty) returns (stream Book);
/* Other functions */
}
message Book {
int32 id = 1;
string title = 2;
int32 total_pages = 3;
string publisher = 4;
string authors = 5;
}
message Empty {
/* EMPTY */
}
On JavaFX Client I receive the data ( a list of books ) and print it in a ListView (image of GUI below)
As you can see, I show only the title, but when I request the data, I receive all information.
Now I did something like this:
stub.getBooks(BookOuterClass.Empty.newBuilder().build(), new StreamObserver<BookOuterClass.Book>() {
#Override
/* Receive the stream of data from the server */
public void onNext(BookOuterClass.Book currentBook) {
publishProgress(currentBook.getTitle().toString(), loadingBooksCounter);
loadingBooksCounter++;
}
#Override
public void onError(Throwable throwable) {
System.out.println("Error : " + throwable.getMessage());
}
#Override
public void onCompleted() {
controller.getBooksListViewLoadingBar().setVisible(false);
}
});
Obs: publishProgress - show the data dynamically as I receive it in ListView and load a progress bar below it.
What I want to try:
GetBooks with a message request like this:
message Params {
bool with_id = 1;
bool with_title = 2;
bool with_total_pages = 3;
bool with_publisher = 4;
bool with_authors = 5;
}
Two problems:
All values will be false by default.
The response is still an object with all that fields, let's say I request with field with_title set true, now I got a Book with all fields (id, title, total_pages etc.), but only the title does not have a default value.
Make multiple Book messages with different fields.
That are called by different rpc fucntions, ex:
service BookService {
rpc getBookTitles(Empty) returns (stream BookTitle);
rpc getBookIdTitles(Empty) returns (stream BookIdTitle);
}
Problems:
For each new combination of fields another function, and most probably another message too.
Make a Params message request and a Book message response which can be any Book message:
import "google/protobuf/any.proto";
service BookService {
rpc getBooks(Params) returns (stream Book);
}
message Book {
google.protobuf.Any book_type = 1;
}
message BookTitle {
string title = 1;
}
message BookIdTitle {
int32 id = 1;
string title = 2;
}
Still I have a lot of messages...
So the option 3 is somewhere between opt. 1 and opt. 2.
This makes me really curious.There is a button which sends a simple post request by ajax on a jsp page,and I use a RESTFUL method to handle this request,but that method will be executed twice or three times.This will only happen on CentOS 7.3,on my laptop I use windows10, multi-thread will not happen.I have searched on Google but nothing helpful
has been found.Here are the codes:
asset.jsp:
<button class="btn btn-default btn-sm" title="allDoMi">
<i class="fa fa-arrow-down">allDoMi</i>
</button>
$("button[title='allDoMi']").click(function () {
var dataparam = "version=1";
if (!confirm('confirm all DoMi?'))
return;
//ajax request
$.ajax({
contentType: "application/json",
url: serviceurl.baseurl + "/asset/doMiAction",
data: dataparam,
beforeSend: function () {
//do nothing
},
error: function () {
//do nothing
},
success: function (info) {
//do nothing
}
});
});
Asset.java
#Service
#Path("/asset")
public class AssetRest {
#Path("/doMiAction")
#POST
#Produces({ MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML })
public RestfulResult doMiAction(#FormParam("version") String
version) {
logger.info("doMiAction method began....");
//package data for duMiSyncDtos,here only for test
List<DuMiSyncDto> duMiSyncDtos =new List<>();
//this url is for http simulation using HttpURLConnection
final String dumiUrl = "http://someip/someurl";
final Map<String, List<DuMiSyncDto>> map;
//only continue when list is not empty
if (!duMiSyncDtos.isEmpty()) {
//this method used for sync data in a certain order
map = groupList(duMiSyncDtos);
SortedSet<String> ss = new TreeSet<>(map.keySet());
final Iterator<String> iter = ss.iterator();
final ScheduledExecutorService ticker = Executors.newSingleThreadScheduledExecutor();
logger.info("NEW A SINGLETHREADSCHEDULEDEXECUTOR");
//retrieve data from a .property file,I set it 20000,therefore the job will be executed in every 20 seconds
final int DELAY = NumberUtils.toInt(WebUtils.getConfigValue("dumi.delay"));
ticker.scheduleWithFixedDelay(new Runnable() {
private int count;
public void run() {
logger.info("BEGIN RUN METHOD:"+System.identityHashCode(AssetRest.this));
if(iter.hasNext()) {
try {
List<DuMiSyncDto> value = map.get(iter.next());
//this method used for simulating a httprequest using HttpURLConnection to invoke a remote service to get the result info which forms in a JSON string format
String resultmsg = getDuMiReturnMessage(dumiUrl,value);
if(resultmsg!=null && !resultmsg.contains("\"code\":\"0000\"")) {
logger.info("Return code is "+resultmsg+",the sync work will be terminated.");
ticker.shutdown();
return;
}
//this method used for showing some useful infomation on the console using log4j
showSyncInfomation(value);
//this method used for count how many items have been synchronized successfully
int currentcount = getSyncCount(resultmsg);
count += currentcount ;
logger.info("current sync data:"+currentcount+",summing data"+count+"");
} catch (Exception e) {
logger.error("method[doMiAction]...executing schedule:",e);
}
} else {
ticker.shutdown();
}
}
}, 0, DELAY, TimeUnit.MILLISECONDS);
}
}
After I click the button,all the log info will be shown on Putty console for two or three times,yet I have clicked that button for only ONCE!I have tested for several times,it will happen,but in windows on my laptop,this will not happen at all.Here is a detail might be help:previously the implementation for timed execution is not like this,it has been written like :
for(DuMiSyncDto dto:duMiSyncDtoList){
//do the business code
Thread.sleep(20000);
}
Because there is database synchronization from the remote service,I need to control the interval time not too soon between every two operations:execute in every 20 seconds and 100 data at a time.In this situation,the multi-thread problem occurs,I thought it may be the for loop which aroused so I change the way using a JDK API instead but issues were still there.So WHY all of these?
---------------------------first edit------------------------------------------
private int getSyncCount(String resultmsg) {
int count = 0;
JSONObject obj = JSONObject.fromObject(resultmsg);
String message = obj.getString("message");
if(!WebUtils.isEmpty(message)) {
String[] arr = message.split(" ");
if(arr!=null && arr.length>1) {
count += Integer.parseInt(arr[1].trim());
}
}
logger.info("currentThreadName:"+Thread.currentThread().getName());
return count;
}
Notice in this method,I log the current thread name,and it shows :
...
currentThreadName:pool-1-thread-1
currentThreadName:pool-2-thread-1
currentThreadName:pool-3-thread-1
...
when there are 3 threads.
I am developing a platform based on the micro services architecture (JAX-RS) and a nodeJS API.
I have a problem adding an object to the database, because it always marks null by spring boot.
*Here is my REST controller code (JAX-RS):
#RequestMapping(value="/Add")
public Actifs AjouterActifs( #RequestBody Actifs act){
return Actif.saveT(act);
}
*Here the code node API to add the object "Actifs":
app.post("/act/add",function (req,res) {
var addActif = JSON.stringify(req.body);
console.log("params: "+addActif);
try {
http.get(url+"/Add",+addActif, function (response) { //problem is here "addActif is null"
var dataJson ='';
response.on('data',function(data){
dataJson += data;
});
response.on('end',function(){
try
{
var addAct = JSON.parse(dataJson);
}
catch(err) {
console.log('erreur de retourner l\'actif -->', +err);
}
res.json(addAct);
});
});
}
catch(e) {
console.log("erreur d'ajouter les info d'actif -->", +e);
}
});
*Postman:
I get this error:
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing:
How to avoid a null object passing from node JS to the JAX-RS service ?
thank you for helping me,
You are sending the actif to be added as a query parameter
http.get(url+"/Add?act="+addActif, function (response) {
...
}
But your SpringMVC Endpoint expects to find the Actif object in the request body
#RequestMapping(value="/Add")
public Actifs AjouterActifs( #RequestBody(required=false) Actifs act) {
...
}
Option 1: Use #RequestParameter("act") Actifs act and register an editor to parse the object from the query parameter string (see this question).
Option 2: Actually send the Actif json as the request body, e.g. by performing a POST request to url + "/Add" instead of a GET. You will have to use http.request to implement that.
Furthermore I would suggest to use #RequestBody (without required=false). That ensures that the parameter must be non-null and lets the application fail fast if that is not the case.
I solved the problem by changing the code like this
app.post("/act/add",function (req,res) {
var addActif = JSON.parse(req.body); //parse object
console.log("params: "+addActif);
try {
http.get(url+"/Add",addActif, function (response) { // delete '+'
var dataJson ='';
response.on('data',function(data){
dataJson += data;
});
response.on('end',function(){
try
{
var addAct = JSON.parse(dataJson);
}
catch(err) {
console.log('erreur de retourner l\'actif -->', +err);
}
res.json(addAct);
});
});
}
catch(e) {
console.log("erreur d'ajouter les info d'actif -->", +e);
}
});
I'm trying to call a JavaEE 6 rest service from an Angular factory and I am running into issues.
The java rest service was created by someone else and I'm trying to work off of it and I'm not super-well versed in JavaEE yet, so if you need more info, I'll chip in where I can.
#Path("bills")
public class BillResource {
#EJB
#Resource
private BillableEventBean billableEventBean;
private final BillableEventMapper billableEventMapper = new BillableEventMapper();
BillService implementation not working
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("query")
public List<BillableEventDuplicate> listBillableEvents(BillableEventQueryFilter queryFilter) {
List<BillableEvent> ejbRet = billableEventBean.listBillableEvents(queryFilter.getUserID(),
queryFilter.getBillingTeamID(), queryFilter.getBillStatus(), null);
List<BillableEventDuplicate> ret = billableEventMapper.toBillableEventDuplicateList(ejbRet);
return ret;
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("{billableEventI}")
public BillableEventDuplicate getBillableEvent(#PathParam("billableEventI") String id) {
BillableEvent ejbRet = billableEventBean.getBillableEvent(id);
BillableEventDuplicate ret = billableEventMapper.toBillableEventDuplicate(ejbRet);
return ret;
}
}
My angular factory for the service looks like this:
'use strict';
var aumBills = angular.module('appBills', ['ngResource']);
appBills.factory('Bills', ['$resource',
function($resource)
{
return $resource('/ua_appcore/api/v1/bills/:billNumber',
{
billNumber:'#billNumber'
},
{
getList: {method: 'POST', params: {'userID':'ABC123'}, url: '/ua_appcore/api/v1/bills/query/'}
});
}]);
The factory in invoked from the controller thusly:
'use strict';
angular.module('app.bills', ['ngRoute','appBills'])
.config(['$routeProvider', function($routeProvider)
{
$routeProvider.
when('/bills',
{
templateUrl: 'bills/bill-list.html',
controller: 'BillListCtrl'
}).
when('/bills/:billId',
{
templateUrl: 'bills/bill-detail.html',
controller: 'BillDetailCtrl'
}).
when('/billsearch',
{
templateUrl: 'bills/bill-search.html',
controller: 'BillSearchCtrl'
});
}])
.controller('BillListCtrl', ['$scope', '$http', '$routeParams', 'Bills',
function($scope, $http, $routeParams, Bills)
{
Bills.getList({},{}).$promise.then(function(billList)
{
$scope.billList = billList;
});
}])
.controller('BillDetailCtrl', ['$scope', '$http', '$routeParams', 'Bills',
function($scope, $http, $routeParams, Bills)
{
Bills.get({},{billNumber: $routeParams.billNumber }).$promise.then(function(bill)
{
$scope.bill = bill;
});
}]);
In my understanding, I needed to create a custom action in the factory to make use of the URL option since there is a POST to get a list of bills back using the same root call. The problem I'm having is that I can't seem to be able to feed any parameters into the queryFilter object even with the Consumes annotation. Am I doing something fundamentally wrong?
First of all you can use chrome plugin Postman to check if your rest service is working correctly if true there is problem with your angular $resource. In my opinion there is missing header "Content-Type=application/json" in your request. I've never use angular in that way you can try to create service like that (this tutorial should be also helpful)
app.service("billsService", function ($resource) {
var bills = $resource("/ua_appcore/api/v1/bills/query");
this.getBills = function () {
var billsResource = new bills();
billsResource.sampleVar = 'value'; // here you can place your vars
return billsResource.$save();
}
});
So, it turns out that it was an infrastructure issue the entire time. We had been deploying to a Websphere Liberty server, and it does not contain the entire WebProfile that JavaEE 6 needs to recognize the rest services. Their may be some work-arounds for it, but the quickest short-term solution is to run a full Websphere server for deployments.
Thanks for the help!
I am using jquery Ajax to send my parameters to backend in java and return value is of JSON type. My application has different categories which uses the same jsp. If i open a single category in one tab everything is working fine. But when i open different categories in different tabs, the last opened tab/category only sends parameters to the back end, the first opened tabs triggers the ajax call, but the parameters passed are not available in the back end. PFB the code snippet of the AJAX call made,
function addThings(things) {
$(document).ready(function() {
var parameters = {
_method : 'put'
};
for ( var i = 0; i < things.length; i++) {
if (parameters[things[i][0]] != null) {
parameters[things[i][0]] = parseInt(parameters[things[i][0]])
+ parseInt(things[i][1]);
} else {
parameters[things[i][0]] = things[i][1];
}
}
$.ajax({
type : "POST",
url : "addThings.do",
async : false,
data : parameters,
datType : "json",
failure : function(data) {
ShowFatalError();
},
success : function(response) {
var resp =$.getJSON(response);
if (resp == null) {
ShowFatalError();
} else {
if (response.exceptionsOccured) {
ShowFatalError();
}
CurrentJSON = response;
CountDisplay(CurrentJSON);
return (CurrentJSON);
}
}
});
});
return CurrentJSON;
}
The above function is triggered on a button click.
Please help me out in this.