Getting No data when accessing SAP table with jCo(3.x)) - java

Here is my sample code.In this example has only elementary types,no structure types has to set.But in the output no data exists in the table.
When I check the records in SAP it contains multiple records for this particular id.Can someone explain this to me?
public void invokeRFC(JCoDestination destination) {
JCoFunction function=null;
try
{
JCoFunctionTemplate functionTemplate = destination.getRepository().getFunctionTemplate("RFC_METHOD");
if (functionTemplate != null) {
function = functionTemplate.getFunction();
}
if (function == null)
throw new RuntimeException("Not found in SAP.");
//to fill elementary types and structures
configureImportParameters(function,"xxx", "abc");
//to fill table type parameters
configureTableParameters(function, "tblName",1,"100");
function.execute(destination);
} catch (JCoException e)
{
e.printStackTrace();
}
}
public void configureTableParameters(JCoFunction function, String table_name, int index, String id) {
JCoTable table = function.getTableParameterList().getTable("table_name");
table.appendRow();
table.setRow(index);
table.setValue("Partner", "100");
}
private void exportTable(JCoFunction jCoFunction, String tblName) {
JCoTable resultTable = jCoFunction.getTableParameterList().getTable(tblName);
int value = resultTable.getNumRows();
System.out.println(value);
}
private void configureImportParameters(JCoFunction function, String param1, String param2) {
JCoParameterList parameterList =
function.getImportParameterList();
parameterList.setValue("field1", param1);
parameterList.setValue("field2", param2);
}
UPDATED the code.

multiple problem can cause this.
if you setting "" or " " to fields. (when you set values better set if those has some values
if it says partner does not exist and if you sure its exist this mean your data does not pass properly. add debug points to where you set the data and make sure you pass correct name and correct values.
also you do not need to add(index) you can just table.appendRow(); // but this will not impact on your case
also when you setValue make sure its int filed. (normally not) in your given example its int
eg:
private void configureTableParameters(JCoParameterList tableParameters){
JCoTable jCoTable=tableParameters.getTable(key);
jCoTable.appendRow();
if(value!=null)
jCoTable.setValue(fieldKey,String.valueOf(value));
}
this is just psuda code and will not work

Test your ABAP remote function module with an SAP GUI via transaction code SE37 first.
If this test is successful and you get a different result if called from JCo with using the same parameter values, then I recommend to study SAP note 206068 for possible reasons.
Also check your method configureTableParameters. I guess, index shall be a field index and not a row count. Your implementation will create far too many unnecessary rows. I assume you wanted to call table.appendRow(); instead of table.appendRows(index);. Moreover, you maybe intended to fill the first field in the row with the value "100", for which you would have to pass the index value 0 instead of 1 in this case.

Related

How To Put If Statement Inside Transaction Firebase Firestore

When the user clicks a button it's going to check if the Document in Firestore is exists or not, if it is, then just update (increase) some value, and if it isn't create a new document with the new value.
I could just do the normal documentRef.get(), and documentRef.set(), but when I tested it with 2 user press the button at the same time. Its just put the new value of one of them. and so I used transaction.
In this transaction, first I get the documentsnapshot, and I get the value.
and then I put if statement to check if the document is exist, the first statement which is document is exist is working fine, but when I deleted the document, the else statement didn't do anything.
Is it even possible to use if statement inside Firebase Firestore transaction?
Map<String, Object> newDocumentSet = new HashMap<>();
newDocumentSet.put("sold", 1);
newDocumentSet.put("price", myProductPrice);
mDb.runTransaction(new Transaction.Function<Void>() {
#Nullable
#Override
public Void apply(#NonNull Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot myDocumentSnapshot = transaction.get(myDocumentRef);
long newAddSold = myDocumentSnapshot.getLong("sold") + 1;
long newAddPrice = myDocumentSnapshot.getLong("price") + myProductPrice;
if(myDocumentSnapshot.exists()){
transaction.update(myDocumentRef, "sold", newAddSold);
transaction.update(myDocumentRef, "price", newAddPrice);
}else {
transaction.set(myDocumentRef, newDocumentSet);
}
return null;
}
});
I don't know what's happening, it didn't show any error, please tell me if I made some mistake or there is another way of doing this.
or there is another way of doing this..
Yes there is, even a simpler one which in fact is more efficient than a transaction because it does not require a round trip between the client and Firebase servers. Assuming that the mDb points to the correct document, to increment the sold property by 1, please use the following line of code:
mDb.update("sold", FieldValue.increment(1));
All you need is to return a Map<String, dynamic> value from the runTransaction function and inside the run transaction make sure you return a map value like
if (a) {
return "value":true
} else {
return "value":false
}
Then in the return statement of your function assign mapDynamic["value"];. Then you will now which part of your code was executed. mapDynamic is just a variable name.

Get a string list of values from a generic object

So I have an Object that comes in that can be any of 100 different specific objects, with different elements inside it, from other objects, lists, sequences, primitives etc.
I want to strip the values in a depth first fashion to make a string of simple values with a delimiter between them. I have mapped the fields and stored them elsewhere using recursion/reflection that only happens once a new Object type comes in for the first time.
An example of how I'm storing the data in the database for a few simple example objects:
Object A layout table: Timestamp = 12345 Fields = Length|Width|Depth
Object B layout table: Timestamp = 12345 Fields = Height|Weight|Name
Object A layout table: Timestamp = 12350 Fields = Length|Width|Depth|Label
Object A sample: Timestamp = 12348 Values = 5|7|2
Object A sample: Timestamp = 12349 Values = 4|3|1
Object B sample: Timestamp = 12346 Values = 75|185|Steve Irwin
Object A sample: Timestamp = 12352 Values = 7|2|8|HelloWorld
Below is my current solution. I'm seeking improvements or alternatives to the design to accomplish the goal stated above.
Currently I get the object in and translate it to JSON using gson.toJson(); From that, I cycle through the JSON to get values using the code below. Issue is, this code is very CPU intensive on the low end CPU I am developing for due to the fact that there are many samples coming in per second. Overall purpose of the application is a data recorder that records real time samples into a SQLite database. I have also attempted to store the unmodified JSON into a SQLite BLOB column, but this is terribly inefficient with regards to DB size. Is there a better/more efficient method for getting values out of an object?
I don't have an issue storing the field mapping since it only needs to be done once, but the value stripping needs to be done for every sample. I know you can do it via reflection as well, but that is also processing heavy. Anyone have a better method?
public static List<String> stripValuesFromJson(JsonElement json)
{
// Static array list that will have the values added to it. This will
// be the return object
List<String> dataList = new ArrayList<String>();
// Iterate through the JSONElement and start parsing out values
for (Entry<String, JsonElement> entry : ((JsonObject) json).entrySet())
{
// Call the recursive processor that will parse out items based on their individual type: primitive, array, seq etc
dataList.addAll(dataParser(entry.getValue()));
}
return dataList;
}
/**
* The actual data processor that parses out individual values and deals with every possible type of data that can come in.
*
* #param json - The json object being recursed through
* #return - return the list of values
*/
public static List<String> dataParser(JsonElement json)
{
List<String> dataList = new ArrayList<String>();
// Deal with primitives
if (json instanceof JsonPrimitive)
{
// Deal with items that come up as true/false.
if (json.getAsString().equals("false"))
{
dataList.add("0");
} else if (json.getAsString().equals("true"))
{
dataList.add("1");
} else
{
dataList.add(json.getAsString());
}
// Send through recursion to get the primitives or objects out of this object
} else if (json instanceof JsonObject)
{
dataList.addAll(stripValuesFromJson(json));
} else if (json instanceof JsonArray)
{
// Send through recursion for each element in this array/sequence
for (JsonElement a : (JsonArray) json)
{
dataList.addAll(dataParser(a));
}
} else if (json instanceof JsonNull)
{
dataList.add(null);
} else
{
errorLog.error("Unknown JSON type: " + json.getClass());
}
return dataList;
}
One thing you could try out is writing your own JSON parser which simply emits values. I have more experience in JavaCC so I'd take one of existing JSON grammars and modify it so that it only outputs values. This should not be too complicated.
Take for example the booleanValue production from the mentioned grammar:
Boolean booleanValue(): {
Boolean b;
}{
(
(
<TRUE>
{ b = Boolean.TRUE; }
) | (
<FALSE>
{ b = Boolean.FALSE; }
)
)
{ return b; }
}
Basically you will need to replace returning the boolean value with appending "1" or "0" to the target list.
ANTLR is another option.

JHDF5 - How to avoid dataset being overwritten

I am using JHDF5 to log a collection of values to a hdf5 file. I am currently using two ArrayLists to do this, one with the values and one with the names of the values.
ArrayList<String> valueList = new ArrayList<String>();
ArrayList<String> nameList = new ArrayList<String>();
valueList.add("Value1");
valueList.add("Value2");
nameList.add("Name1");
nameList.add("Name2");
IHDF5Writer writer = HDF5Factory.configure("My_Log").keepDataSetsIfTheyExist().writer();
HDF5CompoundType<List<?>> type = writer.compound().getInferredType("", nameList, valueList);
writer.compound().write("log1", type, valueList);
writer.close();
This will log the values in the correct way to the file My_Log and in the dataset "log1". However, this example always overwrites the previous log of the values in the dataset "log1". I want to be able to log to the same dataset everytime, adding the latest log to the next line/index of the dataset. For example, if I were to change the value of "Name2" to "Value3" and log the values, and then change "Name1" to "Value4" and "Name2" to "Value5" and log the values, the dataset should look like this:
I thought the keepDataSetsIfTheyExist() option to would prevent the dataset to be overwritten, but apparently it doesn't work that way.
Something similar to what I want can be achieved in some cases with writer.compound().writeArrayBlock(), and specify by what index the array block shall be written. However, this solution doesn't seem to be compatible with my current code, where I have to use lists for handling my data.
Is there some option to achieve this that I have overlooked, or can't this be done with JHDF5?
I don't think that will work. It is not quite clear to me, but I believe the getInferredType() you are using is creating a data set with 2 name -> value entries. So it is effectively creating an object inside the hdf5. The best solution I could come up with was to read the previous values add them to the valueList before outputting:
ArrayList<String> valueList = new ArrayList<>();
valueList.add("Value1");
valueList.add("Value2");
try (IHDF5Reader reader = HDF5Factory.configure("My_Log.h5").reader()) {
String[] previous = reader.string().readArray("log1");
for (int i = 0; i < previous.length; i++) {
valueList.add(i, previous[i]);
}
} catch (HDF5FileNotFoundException ex) {
// Nothing to do here.
}
MDArray<String> values = new MDArray<>(String.class, new long[]{valueList.size()});
for (int i = 0; i < valueList.size(); i++) {
values.set(valueList.get(i), i);
}
try (IHDF5Writer writer = HDF5Factory.configure("My_Log.h5").writer()) {
writer.string().writeMDArray("log1", values);
}
If you call this code a second time with "Value3" and "Value4" instead, you will get 4 values. This sort of solution might become unpleasant if you start to have hierarchies of datasets however.
To solve your issue, you need to define the dataset log1 as extendible so that it can store an unknown number of log entries (that are generated over time) and write these using a point or hyperslab selection (otherwise, the dataset will be overwritten).
If you are not bound to a specific technology to handle HDF5 files, you may wish to give a look at HDFql which is an high-level language to manage HDF5 files easily. A possible solution for your use-case using HDFql (in Java) is:
public class Example
{
public Class Log
{
String name1;
String name2;
}
public boolean doSomething(Log log)
{
log.name1 = "Value1";
log.name2 = "Value2";
return true;
}
public static void main(String args[])
{
// declare variables
Log log = new Log();
int variableNumber;
// create an HDF5 file named 'My_Log.h5' and use (i.e. open) it
HDFql.execute("CREATE AND USE FILE My_Log.h5");
// create an extendible HDF5 dataset named 'log1' of data type compound
HDFql.execute("CREATE DATASET log1 AS COMPOUND(name1 AS VARCHAR, name2 AS VARCHAR)(0 TO UNLIMITED)");
// register variable 'log' for subsequent usage (by HDFql)
variableNumber = HDFql.variableRegister(log);
// call function 'doSomething' that does something and populates variable 'log' with an entry
while(doSomething(log))
{
// alter (i.e. extend) dataset 'log1' to +1 (i.e. add a new row)
HDFql.execute("ALTER DIMENSION log1 TO +1");
// insert (i.e. write) data stored in variable 'log' into dataset 'log1' using a point selection
HDFql.execute("INSERT INTO log1(-1) VALUES FROM MEMORY " + variableNumber);
}
}
}

Returning a null array string in java

I am having a java class where I am executing a query and assigning the query result to an string array, finally return the array.
Everything works fine. But I want to return "no data" if the db values are empty (not the whole array). what can I do for this?
Code:
query="select `t1`,`t2`,`t3` from test";
PreparedStatement pre = conn.prepareStatement(query);
ResultSet res = pre.executeQuery();
String val[][] = new String[res.getRow()][3];
while (res.next()) {
val[i][0] = res.getString(1);
val[i][1] = res.getString(2);
val[i][2] = res.getString(3);
i++;
}
res.close();
conn.close();
pre.close();
return (val);
(Where I want the val[1][1] to be "No Data" if res.getString(2) is null).
No Data seems to be a value you display more than a logical value.
So you should decide of a special value and display it in a special way. We usually call this a sentry value.
This value could be null or a string that can't be in your db. (maybe it doesn't apply here as everything is often possible in a db).
Also note that it could be attractive to use an exception instead of this special value but it is actually a very poor use of exceptions, mostly for performance issues and hence it is a design to avoid if possible except if this value can lead to problems for your clients classes.
try this way
val[i][0] = (res.getString(1)!=null & !res.getString(1).equals(""))?res.getString(1).equals(""):"No Data";
val[i][1] = (res.getString(1)!=null & !res.getString(2).equals(""))?res.getString(3).equals(""):"No Data";
val[i][2] = (res.getString(1)!=null & !res.getString(3).equals(""))?res.getString(3).equals(""):"No Data";
use the only one "&" what happen when you check the condition with && first it will check for the first i.e. rs.getString(1)!=null if this is null or not it will check for the another condition i.e. rs.getString(1).equal("") so if you check and it will null then in second condition it will cause the error for NullPointerException.
while if you use only one & then it will check first condition if that was true then only it go for check the another condition otherwise not.
Add small helper methods like this:
public static String getValue(String value) {
return getValue(value, "No Data");
}
public static String getValue(String value, String default) {
return value == null ? default : value;
}
Use it like this:
val[i][0] = getValue(res.getString(1)); // standard
val[i][0] = getValue(res.getString(1), "NULL"); // with custom default message

Abstract table model

I face a problem in using AbstractTableModel, i use linked list as a container for data , and i fetch records from table from db then i put it in linked list in table model then i male jable.setModel(model). THE PROBLEM i face that the last record i fetch from table from db is repeated n times since n is the number of records in database.
and when i make model.getIndextOF(anAppointmentDate); each time return 0 , so i think it each time the object in inserted in the same place ? i may be wrong , but that what i think
public class appointmentModel extends AbstractTableModel {
List<appointmentDate> patientAppointment;
public appointmentModel() {
patientAppointment = new LinkedList<appointmentDate>(); // linked list
}
public int getRowCount() {
return patientAppointment.size();
}
public int getColumnCount() {
return 2;
}
public String getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return patientAppointment.get(rowIndex).getDateOFAppointment();
} else if (columnIndex == 1) {
return patientAppointment.get(rowIndex).getTimeOfAppointment();
} else {
return "Not found";
}
}
public String getColumnName(int column) {
if (column == 0) {
return "date";
} else if (column == 1) {
return "time";
} else {
return "not found";
}
}
public void insertRecord(appointmentDate anAppointmentDate)
{
list.add(anAppointmentDate);
fireTableRowsInserted(list.size()-1, list.size()-1);
System.out.println(list.indexOf(anAppointmentDate)); // each time it prints 0
}
//////////
here where i use the model
while (resultSet.next()) {
N_Date= resultSet.getDate("appointDate");
anAppointment.setDateOFAppointment(N_Date);
N_time = resultSet.getString("appointTime");
anAppointment.setTimeOfAppointment(N_time);
tableModel.insertRecord(anAppointment);
}
jTable.setModel(tableModel);
The output i have is the last record repeated in all table records ,plz help!
You are using the same reference to an AppointmentDate object, and change only its internal state.
Thus everytime you add the same object to the list. So with the last loop iteration you set all objects inside the list to have the data of the last row.
To fix this, instantiate a new AppointmentDate() on each loop iteration:
while (resultSet.next()) {
AppointmentDate anAppointment = new AppontmentDate();
// the rest is the same
}
Note also that the class name should start with an upper-case letter - i.e. AppointmentDate, not appointmentDate.
Found the problem!
You don't show quite enough code around "where you use the model" but it looks like you are re-using the same object for each insert. You've got this object, you set its attributes from what comes out of the DB, and then you stash it in the list.
Well guess what: It's the same object every time, so it's bound to have the same value every time! If you want different values in your list, you'll need to use distinct objects. Don't worry, this is a common enough beginner's mistake.
A sensible way to do this would be to construct a new appointmentDate for every DB record. You may want to initialize the data right in the constructor.
Finally, note that if appointmentDate is a class name, it should (by convention) begin with an uppercase letter!
Finally (some more): LinkedList is efficient at inserts, but performs horribly at retrieval, i.e. the get(n) thing. I'd expect there to be a lot more scrolling and displaying from your list than inserting, so I'd use the List implementation that's much better performing here: ArrayList. It works the same, is only marginally slower at inserts and much faster at retrieval. But that's just additional information for you. Performance isn't so important for a small project like this.

Categories

Resources