I have the unenviable task of editing a 2000 line javascript file inorder to maintain and add some new feature to a web app written in JSP, Json-RPC, jQuery and Java. I do not possess any deeper knowledge of jQuery and Json-RPC except basic Javascript knowledge and the original developer is not there anymore.
There is a JS function which accepts a few params, and calls a Json-RPC and here I am getting the error
arg 1 could not unmarshal
Can someone please tell me what this error means?
Here is my code
function distributeQuantityNew(pReportId, pDecimalPlaces, pRun) {
try {
alert('distributeQuantityNew: ' + pReportId + ', ' + pDecimalPlaces + ', ' + pRun);
var fieldValue = $("#distribution_quantity_" + pReportId).val();
if (fieldValue.length == 0) {
showErrorDialog(resourceBundleMap["error.no.distribution.quantity"]);
return;
} else {
$("#distribution_quantity_" + pReportId).val("");
}
var affectedRowIds = [];
var rows = $("#tableBody_" + pReportId + " tr:visible").has("input[type=text]").filter(function(index) {
var voucherType = this.cells[getVoucherColumnIndex()].innerHTML;
if ((voucherType == 'TRANSFER_CS') || (voucherType == 'PAYOUT_CS') || (voucherType == 'SOURCE_BON') || (voucherType == 'PAYOUT_BON')) {
return false;
}
affectedRowIds.push(parseInt(this.id.split("_")[3]));
return true;
}
);
var affectedReportRows = $.extend(true, {}, foreignReportMap[pReportId]);
$.each(affectedReportRows.map, function(i, row) {
if ($.inArray(row.partnerReportBillNr, affectedRowIds) == -1) {
delete affectedReportRows.map["row_" + row.partnerReportBillNr];
}
});
var report = getLoadedReportByRunId(pReportId);
var productType = report.partnerProductType;
SessionManager.extend();
var resultRows = jsonrpc.foreignReportObject.distributeQuantity(affectedReportRows, fieldValue, pDecimalPlaces, pRun);
alert('back after RPC');
$.each(resultRows.map, function(i, row) {
foreignReportMap[pReportId].map["row_" + row.partnerReportBillNr] = row;
updateForeignReportRow(row, true, productType);
});
updateSummaryRow(pReportId);
toggleApproveAllLink(pReportId);
sortForeignReportTable(pReportId, true);
} catch (e) {
handleError("Failed to distribute quantity: ", e);
}
}
I have peppered it with alerts so that I know whether RPC call was succesful, but I get the error arg 1 could not unmarshal before that from the catch block. Thanks for any hints
OK, got it solved. The first parameter to the remote function is expecting a list of Map<String, SomeBO>. SomeBO is a bean with several BigDecimals. I had another JS function which had set the values passed into the Map. This function was setting a BigNumber where I had a setter of String only. I wish the error I had gotten back from JSON unmarshaller was a bit more descriptive...Below is the code where I added .toString() to solve the issue
foreignReportMap[pReportId].map["row_" + pRowId].clientQuantity = clientQuantity.toString();
foreignReportMap[pReportId].map["row_" + pRowId].totalClientQuantity = totalClientQuantity.toString();
Related
I have a Selenium test suite that is running Selenium integration tests against a number of web applications, some that are written in Angular 2+, and some that are written in AngularJS.
We use a custom ExpectedCondition with WebDriverWait that we use to make test cases wait until AngularJS apps have finished loading, in order to avoid waiting an arbitrary amount of time:
private static ExpectedCondition<Boolean> angularIsFinished() {
return new ExpectedCondition<Boolean>() {
public Boolean apply(final WebDriver driver) {
Object result = null;
while(result == null || result.toString().equals("undefined")) {
result = ((JavascriptExecutor)driver).executeScript("return typeof angular;");
try {
Thread.sleep(200L);
} catch (final InterruptedException ex) {
logger.error("Error while trying to sleep", ex);
}
}
final String script = " var el = document.querySelector(\"body\");\n" +
" var callback = arguments[arguments.length - 1];\n" +
" angular.element(el).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);";
((JavascriptExecutor)driver).executeAsyncScript(script);
return true;
}
public String toString() {
return "Wait for AngularJS";
}
};
}
However, return typeof angular; will always return undefined for an Angular 2+ app. Is there a similar way to AngularJS's notifyWhenNoOutstandingRequests that you can use to determine when an Angular 2+ app has finished loading?
This question mentions using NgZone as a possible solution, but how would you get a handle on that via a script executed via JavascriptExecutor?
You can check it by calling e.g. document.querySelector('app-root')? or arbitrary component selector...
Or what about calling document.readyState? It should have result 'complete' after fully loaded wep page and it doesn't matter if web page is based on angular.
Thanks to #Ardesco's answer, I was able to do something similar to what Protractor does, using the window.getAllAngularTestabilities function. Here is the script that I run to determine if the Angular 2+ page loads:
var testability = window.getAllAngularTestabilities()[0];
var callback = arguments[arguments.length - 1];
testability.whenStable(callback);
And here is what the complete ExpectedCondition looks like that works for both AngularJS and Angular 2+:
private static ExpectedCondition<Boolean> angularIsFinished() {
return new ExpectedCondition<Boolean>() {
public Boolean apply(final WebDriver driver) {
Object result = null;
boolean isAngular2Plus = false;
while(result == null || result.toString().equals("undefined")) {
result = ((JavascriptExecutor)driver).executeScript("return typeof angular;");
if (result == null || result.toString().equals("undefined")) {
result = ((JavascriptExecutor)driver).executeScript("return typeof window.getAngularTestability;");
if (result != null && !result.toString().equals("undefined")) {
isAngular2Plus = true;
}
}
try {
Thread.sleep(200L);
} catch (final InterruptedException ex) {
logger.error("Error while trying to sleep", ex);
}
}
final String script;
if (isAngular2Plus) {
script =" var testability = window.getAllAngularTestabilities()[0];\n" +
" var callback = arguments[arguments.length - 1];\n" +
" testability.whenStable(callback);";
} else {
script =" var el = document.querySelector(\"body\");\n" +
" var callback = arguments[arguments.length - 1];\n" +
" angular.element(el).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);";
}
((JavascriptExecutor) driver).executeAsyncScript(script);
return true;
}
public String toString() {
return "Wait for AngularJS";
}
};
}
Looking at the Protractor code I have come up with two possible solutions:
First of all we have an option where we find a list of testability's, then add a callback to all of them, and then wait for one of them to flag the site as testable (This does mean that your script will continue after any one testability has become testable, it will not wait for all of them to become testable).
private static ExpectedCondition angular2IsTestable() {
return (ExpectedCondition<Boolean>) driver -> {
JavascriptExecutor jsexec = ((JavascriptExecutor) driver);
Object result = jsexec.executeAsyncScript("window.seleniumCallback = arguments[arguments.length -1];\n" +
"if (window.getAllAngularTestabilities()) {\n" +
" window.getAllAngularTestabilities().forEach(function (testability) {\n" +
" testability.whenStable(window.seleniumCallback(true))\n" +
" }\n" +
" );\n" +
"} else {\n" +
" window.seleniumCallback(false)\n" +
"}"
);
return Boolean.parseBoolean(result.toString());
};
}
The second option is to specifically check an angular root elements testability state:
private static ExpectedCondition angular2ElementIsTestable(final WebElement element) {
return (ExpectedCondition<Boolean>) driver -> {
JavascriptExecutor jsexec = ((JavascriptExecutor) driver);
Object result = jsexec.executeAsyncScript(
"window.seleniumCallback = arguments[arguments.length -1];\n" +
"var element = arguments[0];\n" +
"if (window.getAngularTestability && window.getAngularTestability(element)) {\n" +
" window.getAngularTestability(element).whenStable(window.seleniumCallback(true));\n" +
"} else {\n" +
" window.seleniumCallback(false)\n" +
"}"
, element);
return Boolean.parseBoolean(result.toString());
};
}
The second option is more targeted and therefore more reliable if you want to test a specific area of the site.
A third option would be to write something a bit more complicated that tracks the state of all testability's and then only fires a true callback when all of them have become true. I don't have an implementation for this yet.
So I have a program that basically allows two users two chat back and forth and do other things via websocket with javascript and java server endpoints. When one of the users presses a button I have a listener that fires off a message to the other user which invokes a function. During this function I want to be able to call an AJAX POST with JQuery to update my database but this is causing a java.util.concurrent.TimeoutException. Any idea why this occurs? I imagine it has something to do with the fact that the websocket connection doesn't stay open long enough for the ajax call to go through.
So I've done the research and I've seen that websocket and AJAX are not exactly something that should be mixed (I think). However I can't seem to figure out an alternative even to update my database. There is a lot of code for this so I will try and only post the important parts.
Here is the part of the code for when the button is pressed (it is an agree button so both users must have pressed it hence the '**' and '--' characters).
fAgree.addEventListener("click", function() {
// selects this button
if (aStr == "**" && (yStr == "**" || oStr == "**")) {
if (fStr == "--") {
fStr = "*-";
//redirect to another page
} else if (fStr == "-*") {
fStr = "**";
if(secondTransaction == false) {
var firstCoordUpload = document.getElementById("yourPos").innerHTML;
var secondCoordUpload = document.getElementById("othersPos").innerHTML;
var firstLatUpload = parseFloat(firstCoordUpload.split(",")[0]);
var firstLonUpload = parseFloat(firstCoordUpload.split(",")[1]);
$.ajax({
url: "../../309/T11/setSaleData/" + getURLParameter("saleID") + "/" + firstLatUpload + "/" + firstLonUpload + "/" + firstCoordUpload + "/" + secondCoordUpload + "/" + secondSeller,
type: "POST",
headers: {
"Authorization" : getCredentials(),
},
success: function (result) {
window.location.href = '../../frontEnd/profilePage/index.html?username='+ getUsername();
console.log(result);
},
error: function (dc, status, err) {
console.log(err);
console.log(status);
}
});
}
}
agreeBut.socket.send("a,f");
htmlChange(fStr, fStar);
}
});
Here is the part of the code that is called at the end of the code above (the agreeBut.socket.send()).
agreeBut.socket.onmessage = function(message) {
// check [0]: a for agree buttons,
// m for map,
// l of location buttons,
// t for trade
var mess = message.data.split(",");
if (mess[0] == "a") {
// second a shows the agree button was pressed, changes aStr
// accordingly and displays
if (mess[1] == "a") {
if (aStr == "--") {
aStr = "-*";
} else if (aStr == "*-") {
aStr = "**";
}
htmlChange(aStr, aStar);
// shows the final agree button has been pressed, changes fStr
// accordingly and displays
} else if (mess[1] == "f") {
if (fStr == "--") {
fStr = "-*";
//redirect
} else if (fStr == "*-") {
fStr = "**";
alert("on this");
if(secondTransaction == true) {
alert("doing it");
var firstCoordUpload = document.getElementById("yourPos").innerHTML;
var secondCoordUpload = document.getElementById("othersPos").innerHTML;
var firstLatUpload = parseFloat(firstCoordUpload.split(",")[0]);
var firstLonUpload = parseFloat(firstCoordUpload.split(",")[1]);
$.ajax({
url: "../../309/T11/setSaleData/" + getURLParameter("saleID") + "/" + firstLatUpload + "/" + firstLonUpload + "/" + firstCoordUpload + "/" + secondCoordUpload + "/" + secondSeller,
type: "POST",
headers: {
"Authorization" : getCredentials(),
},
success: function (result) {
console.log(result);
alert("Got it");
window.location.href = '../../frontEnd/profilePage/index.html?username='+ getUsername();
},
error: function (dc, status, err) {
console.log(err);
console.log(status);
}
});
}
//window.location.href = '../../frontEnd/profilePage/index.html?username='+ getUsername();
}
htmlChange(fStr, fStar);
}
}
};
It turns out I was getting this problem because of the timeout that was set on my java ServerEndpoint. In the class I used the setMaxIdleTimeout(0) function on the session variable to have no idle timeout. This seemed to solve my problem (however I feel like this is really just a workaround for poor websocket and ajax implementation on my end).
I'm working on an Android app "native written in java"
and I'm getting a response from a server the response is a javascript function
I need to use this function to do some calculations inside my native java code.
any ideas how to do so.
sample response :
function logic_1(surveyString, responseValuesString) {
var survey = eval(surveyString);
var responseValues = eval(responseValuesString);
var target = new Object();
if (isChosen(128133225, responseValues)) {
target.id = 2;
}
if (! target.id) {
target.id = 2;
}
return target;
}
I've previously used Rhino successfully to execute JavaScript code on Android:
http://www.mozilla.org/rhino/
Here's an example of how to return values from a complex type:
String strFunction =
"function add(x,y){ " +
"return { " +
"id:x+y " +
"}; " +
"}";
Context context = Context.enter();
ScriptableObject scope = context.initStandardObjects();
context.evaluateString(scope, strFunction, "test", 1, null);
Function functionAdd = (Function)scope.get("add");
NativeObject untypedResult = (NativeObject)functionAdd.call(context, scope, scope, new Object[] { 1, 2 });
double id = (Double)untypedResult.get("id", untypedResult);
The important part is the last two lines, where we call the JavaScript function, treat the result as a NativeObject, and then retrieve the value of the 'id' property from that object.
Maybe you just need to use a JavaScript auto executing function like this:
(function(x, y){
var result;
result = x + y; // do some calculations
return result;
})(1 , 2); // you can set your parameters from Java
and 1, 2 are just two parameters from Java
I have a project as follows: Several photos are taken from a mobile, the photos are saved in a web system, which in turn displays the photos on google earth that is inside it. I've read many articles but all of them were using fetchKml, one good article that i've read was using php, but using fetchKml. I dont know if its possible using parseKml instead. Anyway, I'm not sure how to do this with the kml, so it looks tike this:
My Class KMLGenerator()
public static String getKMLFromObra (List<Obra> obraFotos) {
StringBuffer sb = new StringBuffer();
sb.append("<?xml version='1.0' encoding='UTF-8'?>");
sb.append("<kml xmlns='http://www.opengis.net/kml/2.2' " +
"xmlns:gx='http://www.google.com/kml/ext/2.2' " +
"xmlns:kml='http://www.opengis.net/kml/2.2' " +
"xmlns:atom='http://www.w3.org/2005/Atom'> ");
if (obraFotos != null && obraFotos.size() > 0) {
for (Obra o : obraFotos) {
for (Local local : o.getLocais()) {
sb.append("<Document>");
sb.append("<name>" + local.getName() + "</name>");
sb.append("<Style id='defaultStyles'>");
sb.append("<IconStyle>");
sb.append("<scale>1.1</scale>");
sb.append("<Icon>");
sb.append("<href>" + "http://localhost:8080/ConstruMobilFoto/lib/img/fotoIcon.png" + "</href>");
sb.append("</Icon>");
sb.append("</IconStyle>");
sb.append("</Style>");
sb.append("<Placemark>");
sb.append("<name>" + "Foto" + "</name>");
sb.append("<styleUrl>" + "#defaultStyles"+ "</styleUrl>");
sb.append("<altitudeMode>" + "relativeToGround" + "</altitudeMode>");
sb.append("<Point>");
sb.append("<altitudeMode>relativeToGround</altitudeMode>");
sb.append("<coordinates>" + local.getLongitude() + "," + local.getLatitude() + "," + 50</coordinates>");
sb.append("</Point>");
sb.append("<Link>");
sb.append("<href>" + local.getFotos() + "</href>");
sb.append("</Link>");
sb.append("</Placemark>");
sb.append("</Document>");
sb.append("</kml>");
return sb.toString();
}
}
}
return null;
}
I have a dwr function in my jsp that invokes this method, got its String results and make the parse like this:
Class PainelEarth()
#SuppressWarnings("static-access")
public String geraFotosObra (int idObra) throws Exception {
try {
List<Obra> obraFotos = obraBusiness.getObraLatLong(new Obra(idObra));
return new KMLGenerator().getKMLFromObra(obraFotos);
} catch (Exception e) {
log.error(e.getLocalizedMessage(), e);
return null;
}
}
and in my jsp page
function initCB(instance) {
// other codes
showPics(ge);
}
function showPics(ge) {
PainelEarthAjax.geraFotosObra({
callback : function(kmlString) {
var kmlObject = ge.parseKml(kmlString);
ge.getFeatures().appendChild(kmlObject);
}
});
return null;
}
Any help will be welcome!!
In your code if you look at the signature of the method geraFotosObra you can see it takes a single int parameter idObra.
public String geraFotosObra (int idObra) throws Exception { ...
Yet when you call the method in your jsp you are passing an an object literal containing a callback function.
PainelEarthAjax.geraFotosObra({
callback : function(kmlString) { ...
As it is I don't see how the kml is generated, unless perhaps geraFotosObra is an overloaded method? Also even if it was generated, as is, I don't see how the callback function that you pass in place of an id is ever called - why for example would kmlString be the result of the call to geraFotosObra?
// How is this called, what sets kmlString!?
callback : function(kmlString) {
var kmlObject = ge.parseKml(kmlString);
ge.getFeatures().appendChild(kmlObject);
}
All in all the code you posted is a wee bit confusing, so sorry if I have missed something...I think you have possibly copy and pasted some code from a fetchKml example and the asynchronous callbacks used with that method have confused you slightly.
Anyhow, based on what you have posted, you should be passing an int id to the geraFotosObra method, getting the string result and then parsing it in the plug-in.
Something like the following makes sense. Replace the showPics function with the following.
function showPics(ge) {
var kmlString = PainelEarthAjax.geraFotosObra(1); // or something?
var kmlObject = ge.parseKml(kmlString);
ge.getFeatures().appendChild(kmlObject);
}
I need to convert a variable from JavaScript into a Java variable. I'm asking users for their e-mail ids with a Block-UI popup through Test Box. If the field is neither null nor empty, the e-mail id should be sent to a session variable so that it can be accessed anywhere in the project.
Here's my code:
function sbtEmail(){
var email = document.getElementById("EmailId").value;
if (email == null || email == ""){
alert("Enter your contact Email address to continue...!");
document.getElementById("EmailId").focus();
} else {
<%session.setAttribute("quoteEmail",email);%>
window.location.href = "demo2.jsp";
}
}
It doesn't work. What am I doing wrong?
You can not set a variable in the session (which resides on the server alone!) directly from JavaScript. You have to pass them to your server in some kind of request, and then the server can set it in the session.
Solved : using Ajax will solve the Problem.
<script type="text/javascript" src="../ajax.js"></script>
<script type="text/javascript">
function sbtEmail(){
var email = document.getElementById("anonymousEmailId").value;
if (email==null||email==""){
alert("Enter your contact Email address to continue...!");
document.getElementById("anonymousEmailId").focus();
}else{
enqueue("demo1.jsp?Id="+email,ajaxReplay);
}
}
function ajaxReplay(){
window.location.href="demo.jsp";
}
</script>
In demo1.jsp : set value for session variable
String Email = request.getParameter("Id");
session.setAttribute("sessEmail",Email);
Use this Ajax file:----> eval(function(p, a, c, k, e, r) { e = function(c) { return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^/, String)) { while (c--) r[e(c)] = k[c] || e(c); k = [function(e) { return r[e] } ]; e = function() { return '\\w+' }; c = 1 }; while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); return p } ('d 7;f n(a,b,c){6(!7)7=j s;6(!7.n(a,b,c))g l;6(!7.k)7.o();g h}f s(){3.5=j t();3.8=9;3.k;3.m=h;3.n=f(a,b,c){u(d i=0;i<3.5.p;i++)6(3.5[i][0]==a&&3.5[i][1]==b&&3.5[i][2]==c)g l;6(3.8==9){3.k=l;3.m=h;3.8=0}v{++3.8}3.5[3.8]=j t();3.5[3.8][0]=a;3.5[3.8][1]=b;3.5[3.8][2]=c;6(3.k&&c)w(c);g h};3.o=f(){6(3.8==9||3.5.p==0)g;3.k=h;6(3.m){d r=q();d a;6(r){u(d i=0;i<3.5.p;i++){6(3.5[i][2])w(3.5[i][2])}}3.m=l}3.x(3.5[0][0],3.5[0][1])};3.x=f(a,b){d r=q();6(r){r.E("F",a,h);r.G=f(){6(r.H==4){6(b)b(r.I);7.5.J(0,1);7.8>0?--7.8:7.8=9;6(7.8==9){7.k=l;7.m=h;g}v{7.o()}}};r.K(9)}}}f q(){d A=9;y{A=j z("L.B")}C(e){y{A=j z("M.B")}C(N){A=9}}6(!A&&O D!="P"){A=j D()}g A}', 52, 52, '|||this||queue|if|g_q|position|null||||var||function|return|true||new|isProcessing|false|callPreFunctions|enqueue|process|length|getXMLHTTP||ajaxQueue|Array|for|else|eval|getAjaxQueueResult|try|ActiveXObject||XMLHTTP|catch|XMLHttpRequest|open|GET|onreadystatechange|readyState|responseText|splice|send|Msxml2|Microsoft|oc|typeof|undefined'.split('|'), 0, {}))