Problems with asynchronous methods - java

I'm working with Flex 4 invoking webservices from JVM 1.6
I'm trying to make asynchronous calls to java to populate three comboboxes that will display country, states and cities, these three are related (master-slave relationship) but sometimes the calls are not met, or they are not completed, and I think this is because they are asynchronous, how can I be sure that I'm making the call to fill the next combobox when the master combobox (country) is filled?
protected function comboCountry_changeHandler(idCombo:String):void
{
selectedComboCountry= idCombo;
var countryId:String;
if(selectedComboCountry == comboCountry.id){
countryId = String(comboCountry.selectedItem.countryId);
}else if(selectedCombocountry == combocountrySuc.id){
countryId = String(comboCountrySuc.selectedItem.countryId);
}
obtainStatesResult.token = wsfacturas.obtainStates(countryId);
}
protected function obtainStatesResult_resultHandler(event:ResultEvent):void
{
var StateListVo:ArrayCollection = obtainStatesResult.token.result as ArrayCollection;
if(selectedComboCountry == "comboCountrySuc"){
StateListsSuc.removeAll();
CityListsSuc.removeAll();
for (var d:int = 0; d < StateListVo.length; d++){
var estSuc:State = StateListVo[d];
StateListsSuc.addItem(estSuc);
}
comboStateSuc.dataProvider = StateListsSuc;
}
else if(selectedCombocountry == "combocountry"){
StateListsEmp.removeAll();
CityListsEmp.removeAll();
for (var i:int = 0; i < StateListVo.length; i++){
var estEmp:State = StateListVo[i];
StateListsEmp.addItem(estEmp);
}
comboState.dataProvider = StateListsEmp;
} else {
for (var f:int = 0; f < StateListVo.length; f++){
var est:State = StateListVo[f];
StateListsSuc.addItem(est);
StateListsEmp.addItem(est);
}
comboState.dataProvider = StateListsEmp;
comboStateSuc.dataProvider = StateListsSuc;
}
}

Wouldn't it mean that you probably need to load the country and wait for change event on the country combobox to update state and so on? If you do that, you dont have to worry about asynchronicity of your requests? Otherwise, you might be able to use DataProviders and they might provide Event:Complete..
I am not sure though, I definitely am not an expert.. :)

You might want to give slightly more details in your question. But I am just playing with whatever details you have provided.
1_ First asynchronous calls never caused me any problem with dynamic data binding. Sometimes
a SOAP call can take reasonable amount of time, in that case, make sure to show a busy cursor till the web service call returns.
2_Combobox has always had problem with dynamic data binding. You can create a custom combobox that extends a combobox and override the setValue method Or Else you have to iterate over the dataProvider of the combobox and look for a match in the data field and then sets the combo box to that item.
So in summary, the problem mostly have to do with binding of the new data to the rendered combobox not asynchronous calls or any latency.

Related

How to add key and value dynamically and call the procedure in java (Oracle ADF)

ViewObject VO = getViewObjectFromAMImpl("EOView2", "AppModuleDataControl");
Row[] selectedRows = VO.getFilteredRows("tSelect", true);
int counter = 0;
ADFContext adfCtx = ADFContext.getCurrent();
SecurityContext secCntx = adfCtx.getSecurityContext();
String _user = secCntx.getUserName();
//Date vDate = getMinDate();
java.sql.Timestamp startDate = null;
for (Row r : selectedRows) {
startDate = (java.sql.Timestamp) r.getAttribute("StartDate");
if ("E".equals(r.getAttribute("SrcType"))) {
r.setAttribute("Type","S");
r.setAttribute("UpdatedBy", new Date());
r.setAttribute("LastUpdateDate", new Date());
counter++;
}
}
System.out.println("printing count"+counter);
if (counter == 0) {
JSFUtils.addFacesErrorMessage((String) JSFUtils.resolveExpression("No records Approved."));
} else {
Commit();
JSFUtils.addFacesInformationMessage((String) JSFUtils.resolveExpression(" records Approved successfully."));
AdfFacesContext.getCurrentInstance().addPartialTarget(hearderTableBind);
}
approvePopup.cancel();
From the above code i will get the selected rows with key and value pair. I want to add those rows ( Key and Value) to a list and i need to call the procedure. Could you please tell me which is the best possible way to achive this.
I want to call the procedure with key and value pair( Multiple values will come)
You should read the doc at
https://docs.oracle.com/en/middleware/developer-tools/adf/12.2.1.4/develop/extending-business-components-functionality1.html#GUID-B93C7B79-73C9-4434-B12E-A7E23479969A
However, I fail to understand why you need to call a pl/sql procedure at all.
You should be able to do everything in ADF or call a procedure directly without iterating over the data just to set some values.
It's not a good idea to change values in ADF, then call a procedure and assume that the framework somehow knows the changes. The procedure runs in the DB in a different transaction. ADF doesn't know about changes done in the function. The function doesn't know about the changes done in ADF until you post them to the DB.

modify underlying result/value of async object

I am using Kotlin in a webserver app and I have a line of code as follows:
.onComplete { jsonResult: AsyncResult<JsonObject>? ->
Now what I want to do is change the underlying JsonObject wrapped in the AsyncResult, so that it is going to be reflected further downstream.
var res: JsonObject? = jsonResult?.result()
if (res != null) {
if (res.getInteger("files_uploaded") > 0) {
res.put("URL", "Some URL")
}
}
I was then imagining to update the underlying JSON object in the result but not sure how to do that.
please take note that single quotes are missing and ` appear as \` because the code formatting. I tried to leave what seemed least confusing...
You should be able to make changes in the conditional statement
if (res !=null) {
res being the JsonObject:
console.log(res);
would show you what's in there. You may need to use
let resXmodifiedX = JSON.parse(res);
One approach is to write a function and pass res to that function which you can do if it is in the console.log(res).
Some notes on what's below:
place the function somewhere consistent maybe at the bottom of the file...
objects often have multiple levels res.person.name, res.contact.email, or whatever...
use multiple for loops:
let level = res[key]; for(child in level) {
you don't need to do this if you know exactly what object attributes you need to update.
you can set the value directly but you always want to test for it before trying to set it to avoid errors that stop execution.
let toBe = toBe =>`${toBe}`;
let update = (res)?toBe(update(res)):toBe('not Found');
This option is really only if you know for sure that data will be there and you can't proceed without it. Which is not uncommon but also not how JSON is designed to be used.
The code below is a concise way to make some simple changes but may not be an ideal solution. To use it xModify(res) replaces console.log(res) above.
function xModify(x) {
let resXmodifiedX = JSON.parse(x);
let res = resXmodifiedX;
for (key in res) {
res[key] = key=='name'? \`My change ${res[key]}\`: key=='other'? \`My Change ${res[key]}\`:res[key];
resXmodifiedX = JSON.stringify(res);
return resXmodifiedX;
}
That will update res.name and res.other otherwise res[key] is unchanged. If you do not need to parse res change let res = xModifiedx; to let res = x; remove the first line and change the last two lines to return res;
function xModify(x) {
let res = x;
for (key in res) {
res[key] = key=='name'? \`My change ${res[key]}\`: key=='other'? \`My Change ${res[key]}\`:res[key];
return res;
}
If your data is numeric which is not generally the case in a web server response scenario this is a terrible approach. Because it is probably a string I used the template variable as a way to easily add a complex pattern in place of a string. My change ${res[key]} not a real world example. Any valid JS code can go in the ${ } (template variable). I've been defaulting to the first pattern more and more.
let me = (bestCase)?`${'the best version'} of myself`:`${'someone'} I'm ok with`;

Creating managed RealmList outside RealmObject

In my app, I have a method that accepts an ArrayList of ID's and returns a RealmList of Machines belonging to these IDs.
public RealmList<Machine> getMachinesById(ArrayList<Long> machineIds) {
RealmList<Machine> machines = new RealmList<Machine>();
for (int i = 0; i < machineIds.size(); i++){
Machine m = getMachineById(machineIds.get(i));
if (m != null) {
machines.add(m);
}
}
return machines;
}
The getMachineById() function just finds the correct machine for a specific id.
I want to filter this output some more, however, when I try to get the RealmQuery by doing .where(), I get an Exception telling me I should put this RealmList in 'managed mode'.
Caused by: io.realm.exceptions.RealmException: This method is only available in managed mode
at io.realm.RealmList.where(RealmList.java:425)
I'm aware that I get this error because this list is standalone, and not managed by Realm.
It is probably important to add that this function will be called quite a lot, since it is triggered every time some list in my app refreshes. This would mean that (if possible) every time I'm creating a new managed RealmList.
My questions:
Is there any way to let this RealmList be managed by Realm?
If this is possible, is it a problem that this function is being called pretty often
Is there any other (preferred) way to achieve this (List of IDs > RealmResults/RealmQuery)
Is there any way to let this RealmList be managed by Realm?
Yes. There is. But the point of having RealmList is it should be a field of an RealmObjects. eg.:
public class Factory {
RealmList<Machine> machineList;
// setter & getters
}
Factory factory = new Factory();
RealmList<Machine> machineList = new RealmList<>();
// Add something to the list
factory.setMachines(machineList);
realm.beginTransaction();
Factory managedFactory = realm.copyToRealmOrUpdate(factory);
realm.commitTransaction();
Managed means it has be persisted Realm.
If this is possible, is it a problem that this function is being called pretty often
Depends, if you don't need to persist them again, see answer 3.
Is there any other (preferred) way to achieve this (List of IDs > RealmResults/RealmQuery)
In your case, maybe you can use ReaulResults instead? eg.:
RealmQuery<Machine> query = realm.where(Machine.class);
for (int i = 0; i < machineIds.size(); i++){
if (i != 0) query = query.or();
query = query.equalTo("id", machineIds.get(i));
}
RealmResults<Machine> machines = query.findAll();

Invoke Methods Dynamically on Java

At work, we have to generate a report for our client that changes its parameters several times during the week.
This report is generated from a single table on our database.
For example, imagine a table that has 100 columns and I have to generate a report with only 5 columns today, but tomorrow I have to generate with 95 of them.
With this in mind, I created a TO class with all the columns of the specified table and my query returns all columns (SELECT * FROM TABLE).
What I'm trying to create is a dynamic form to generate the report.
I first thought on create a simple frame with a list of the columns listed as check boxes and the user would select the columns that he wants (of course with a button to Select All and another to Deselect All).
As all of the columns have the same name as the attributes of the TO class, I developed the following code (I have Google this):
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
Is this the better way to do what I need to?
Thanks in advance.
Obs.: the getters of the TO class have the pattern "getAttribute_Name".
Note: This question is different from the one where the user is asking HOW to invoke some method given a certain name. I know how to do that. What I'm asking is if this is the better way to solve the problem I described.
My Java is a little more limited, but I believe that's about as good as you're going to get using reflection.
Class<?> c = Test.class;
for (String attribute : listOfAttributes) {
auxText += String.valueOf(c.getMethod("get" + attribute).invoke(this, null));
}
But since this sounds like it's from potentially untrusted data, I would advise using a HashMap in this case, with each method explicitly referenced. First of all, it explicitly states what methods can be dynamically called. Second, it's more type safe, and compile-time errors are way better than runtime errors. Third, it is likely faster, since it avoids reflection altogether. Something to the effect of this:
private static final HashMap<String, Supplier<Object>> methods = new HashMap<>();
// Initialize all the methods.
static {
methods.set("Foo", Test::getFoo);
methods.set("Bar", Test::getBar);
// etc.
}
private String invokeGetter(String name) {
if (methods.containsKey(name)) {
return String.valueOf(methods.get(name).get());
} else {
throw new NoSuchMethodException();
}
}
It might sound like a major DRY violation to do so, but the repetition at least makes sure you don't wind up with unrelated getters accidentally called.
Class c = Test.class;
for(int i = 0; i < listOfAttributes.length; i++)
{
auxText += String.valueOf( c.getMethod( "get" + listOfAttributes[i]).invoke( this, null ) );
}
You can do this somewhat more elegantly via Java Beans, the Introspector, and PropertyDescriptor, but it's a little more long-winded:
Map<String, Method> methods = new HashMap<>();
Class c = this.getClass(); // surely?
for (PropertyDescriptor pd : Introspector.getBeanInfo(c).getPropertyDescriptors())
{
map.put(pd.getName(), pd.getReadMethod();
}
//
for (int i = 0; i < listOfAttributes.length; i++)
{
Method m = methods.get(listOfAttributes[i]);
if (m == null)
continue;
auxText += String.valueOf(m.invoke(this, null));
}

SmartGWT - Update ListGridRecord dynamically

I am using SmartGWT and I have a ListGrid populated with an array of ListGridRecords using the setData() call. I am trying to update a progress property of a single record (on a timer for testing) and have it update in the browser. I have tried various combinations of draw(), redraw(), markForRedraw() etc. to no avail.
I also tried overriding the updateRecordComponent() method in my table class, but it only gets called when the records are first created (after createRecordComponent()).
I should note that I do NOT want to accomplish this by binding to a DataSource. I just want to be able to update the attribute on the client-side.
ArrayList<SegmentSortRecord> mRecords;
mRecords.add(new SegmentSortRecord("03312010_M001_S004"));
mRecords.add(new SegmentSortRecord("03312010_M001_S005"));
mRecords.add(new SegmentSortRecord("03312010_M001_S006"));
mRecords.add(new SegmentSortRecord("03312010_M001_S007"));
SegmentSortRecord[] records = new SegmentSortRecord[mRecords.size()];
mRecords.toArray(records);
mSortProgressTable.setData(records);
.
.
.
mTestTimer = new Timer()
{
public void run()
{
mTestPercent += 5;
if (mTestPercent <= 100)
{
mSortProgressTable.getRecord(2).setAttribute(Constants.PROGRESS_COL_NAME, mTestPercent);
//mSortProgressTable.markForRedraw();
//mSortProgressTable.redraw();
}
else
{
mTestPercent = 0;
}
}
};
...
#Override
protected Canvas createRecordComponent(final ListGridRecord aRecord, Integer aColumn)
{
String fieldName = getFieldName(aColumn);
// Want to override the behavior for rendering the "progress" field
if (fieldName.equals(Constants.PROGRESS_COL_NAME))
{
Progressbar bar = new Progressbar();
bar.setBreadth(10);
bar.setLength(100);
// The JavaScript record object contains attributes that we can
// access via 'getAttribute' functions.
bar.setPercentDone(aRecord.getAttributeAsInt(Constants.PROGRESS_COL_NAME));
return bar;
}
Thanks in advance for any help.
I solved the dynamic update with:
grid.getRecord(i).setAttribute(name, value);
grid.refreshRow(i);
resp.
grid.refreshCell(i, j);
ListGrid has an updateData method, where you can pass a record. Have you tried it?
a blunt and not very high-performance way is simply setting your records array again with setData or setRecords
grid.setData(recordArr);
I use that in my app, but only because all records are updated anyway.
BTW: you could set up a clientside datasource
dataSource.setClientOnly(true);
dataSource.setTestData(...);

Categories

Resources