Why is String [] giving different length and splitting the given string? - java

I have sample strings like:
Data Management_Commercial IMS (Information Management System)
Data Management_Non-structured Data Management (Text Documents, Paper Forms, etc.)
I am passing the strings from the jsp page via input-move-boxes. So in the jsp page I have:
List<KeyValuePair> leftDataManagementList = new ArrayList<KeyValuePair>();
List<KeyValuePair> rightDataManagementList = new ArrayList<KeyValuePair>();
rightDataManagementList.add(new KeyValuePair(attribute.getAttributeListName()+"_"+attribute.getAttributeListValue(), attribute.getAttributeListValue()));
leftDataManagementList.add(new KeyValuePair(attributeMaster.getAttributeListName()+"_"+attributeMaster.getAttributeListValue(), attributeMaster.getAttributeListValue()));
The input-move-box in this case is
<liferay-ui:input-move-boxes
leftBoxName="availabledm"
leftTitle="Data Management Available"
leftList="<%=leftDataManagementList %>"
rightBoxName="selecteddm"
rightTitle="Data Management Selected"
rightList="<%= rightDataManagementList%>"
/>
In java class these are retrieved in String[] selecteddm variable.
String[] selecteddm = ParamUtil.getParameterValues(request, "selecteddm");
But I am passing one string at a time.
So when I store the first string Data Management_Commercial IMS (Information Management System) in the variable. I get the expected results.
System.out.println("Length:" +selecteddm.length);//Length:1
System.out.println(Arrays.toString(selecteddm));//[Data Management_Commercial IMS (Information Management System)]
int count = 0;
for(String str:selecteddm){
System.out.println(str);//Data Management_Commercial IMS (Information Management System)
System.out.println(count++);//0
}
Now I get the problem with the second string Data Management_Non-structured Data Management (Text Documents, Paper Forms, etc.), as it is splitting into separate strings after comma. In this case,
System.out.println("Length:" +selecteddm.length);//Length:3
//This print seems fine
System.out.println(Arrays.toString(selecteddm));//[Data Management_Non-structured Data Management (Text Documents, Paper Forms, etc.)]
int count = 0;
for(String str:selecteddm){
System.out.println(str);
System.out.println(count++);
}
The loop in this case prints:
Data Management_Non-structured Data Management (Text Documents
0
Paper Forms
1
etc.)
2
Why is this exactly happening? As a result str.split("_")[1] on the string in second case generates ArrayIndexOutOfBoundsException. How can I avoid this and make it work like the string in the first case?
Has it to do with this bug?
https://issues.liferay.com/browse/LPS-42949

EDIT: after reading update disclosing use of Liferay
The root of the problem is that you are passing the display labels from the form instead of a key to identify them. You should pass form selections by key instead, like this:
List<User> userList = ...
List leftList = new ArrayList();
List rightList = new ArrayList();
for (int k = 0; k < userList.size(); k++) {
User user = (User) userList.get(k);
leftList.add(new KeyValuePair(String.valueOf(user.getUserId()), user.getScreenName()));
}
The second argument of the KeyValuePair is displayed to the user, the first argument is the key which is sent as part of a single, comma separated request parameter (containing all keys of selected items). You are supposed to identify the selection based on the keys, not the display labels.
ParamUtil.getParameterValues is ultimately splitting the value by ",". This explains the behavior your are seeing.
BTW: that bug LPS-42949 seems fixed in the latest Liferay version. In any case it is not the cause of your problems.

Related

Is there a way to select specific characters from a TextView variable?

I am using AWS IoT to read and publish some information from a microelectronic's sensors. I am able to get the json file in the app as a big wall of text, but it is not very readable. I am using TextView as I don't want the user to be able to change the information. My problem is that I can't find a way to remove the parts that are not necessary to the user.
I am new to app creation, so I am trying to do this as simply as possible. I have my xml ready to receive the information; I just need the info in a variable that I can pass to it. I have tried implementing a character array, but haven't been able to get past the fact that I can't edit the text view.
tvLastMessage = (TextView) findViewById(R.id.tvLastMessage);
This is currently the block of text that I am receiving. It looks like this:
{"sensors":[{"name":"steamTemp","data":"181.39","state":1,
{"name":"waterTemp","data":"-713.15","state":0,
{"name":"waterFlow","data":"0.00","state":3,
{"name":"dieselFlow","data":"0.00","state":2,
{"name":"manualResetLevel","data":"1","state":0,
{"name":"waterFeederLevel","data":"1","state":0,
{"name":"autoResetPressure","data":"1","state":0,
{"name":"manualResetPressure","data":"1","state":0},
{"name":"tempLimit","data":"1","state":0,
{"name":"heatEff","data":"0.00","state":2}]}
The text does not look as formatted as this, but it is more understandable and readable to represent it this way. It normally does not have the new lines, so it will just naturally go to one as it runs out of room.
I am hoping that I can get it to simply show the numbers associated with each "name" and "data" as I have those hard-coded into my xml since they don't change. Just getting those numbers into different variables would be ideal, so I can simply reference the variable in my xml file. However, if there is a better way to do this, I am happy to take suggestions!
Try using a loop to find each instance of "name", "data", and "state", and get the values between them.
Assuming input is a string:
String string = "{\"sensors\":[{\"name\":\"steamTemp\",\"data\":\"181.39\",\"state\":1,\n{\"name\":\"waterTemp\",\"data\":\"-713.15\",\"state\":0,\n{\"name\":\"waterFlow\",\"data\":\"0.00\",\"state\":3,\n{\"name\":\"dieselFlow\",\"data\":\"0.00\",\"state\":2,\n{\"name\":\"manualResetLevel\",\"data\":\"1\",\"state\":0,\n{\"name\":\"waterFeederLevel\",\"data\":\"1\",\"state\":0,\n{\"name\":\"autoResetPressure\",\"data\":\"1\",\"state\":0,\n{\"name\":\"manualResetPressure\",\"data\":\"1\",\"state\":0},\n{\"name\":\"tempLimit\",\"data\":\"1\",\"state\":0,\n{\"name\":\"heatEff\",\"data\":\"0.00\",\"state\":2}]}";
Map<String, Double> map = new HashMap<>();
int index0 = 0, index1, index2;
while (true) {
// Get indices
index0 = string.indexOf("name", index0);
index1 = string.indexOf("data", index0);
index2 = string.indexOf("state", index1);
// If "name", "data", or "state" was not found
if (index0 == -1 || index1 == -1 || index2 == -1)
break;
// Get the data from the string and put it into the map
String key = string.substring(index0 + 7, index1 - 3);
Double value = Double.parseDouble(string.substring(index1 + 7, index2 - 3));
map.put(key, value);
// Update index
index0 = index2;
}
System.out.println(map);
Output:
{waterFlow=0.0, manualResetLevel=1.0, waterFeederLevel=1.0, manualResetPressure=1.0, waterTemp=-713.15, autoResetPressure=1.0, tempLimit=1.0, dieselFlow=0.0, heatEff=0.0, steamTemp=181.39}

Ektorp CouchDb: Query for pattern with multiple contains

I want to query multiple candidates for a search string which could look like "My sear foo".
Now I want to look for documents which have a field that contains one (or more) of the entered strings (seen as splitted by whitespaces).
I found some code which allows me to do a search by pattern:
#View(name = "find_by_serial_pattern", map = "function(doc) { var i; if(doc.serialNumber) { for(i=0; i < doc.serialNumber.length; i+=1) { emit(doc.serialNumber.slice(i), doc);}}}")
public List<DeviceEntityCouch> findBySerialPattern(String serialNumber) {
String trim = serialNumber.trim();
if (StringUtils.isEmpty(trim)) {
return new ArrayList<>();
}
ViewQuery viewQuery = createQuery("find_by_serial_pattern").startKey(trim).endKey(trim + "\u9999");
return db.queryView(viewQuery, DeviceEntityCouch.class);
}
which works quite nice for looking just for one pattern. But how do I have to modify my code to get a multiple contains on doc.serialNumber?
EDIT:
This is the current workaround, but there must be a better way i guess.
Also there is only an OR logic. So an entry fits term1 or term2 to be in the list.
#View(name = "find_by_serial_pattern", map = "function(doc) { var i; if(doc.serialNumber) { for(i=0; i < doc.serialNumber.length; i+=1) { emit(doc.serialNumber.slice(i), doc);}}}")
public List<DeviceEntityCouch> findBySerialPattern(String serialNumber) {
String trim = serialNumber.trim();
if (StringUtils.isEmpty(trim)) {
return new ArrayList<>();
}
String[] split = trim.split(" ");
List<DeviceEntityCouch> list = new ArrayList<>();
for (String s : split) {
ViewQuery viewQuery = createQuery("find_by_serial_pattern").startKey(s).endKey(s + "\u9999");
list.addAll(db.queryView(viewQuery, DeviceEntityCouch.class));
}
return list;
}
Looks like you are implementing a full text search here. That's not going to be very efficient in CouchDB (I guess same applies to other databases).
Correct me if I am wrong but from looking at your code looks like you are trying to search a list of serial numbers for a pattern. CouchDB (or any other database) is quite efficient if you can somehow index the data you will be searching for.
Otherwise you must fetch every single record and perform a string comparison on it.
The only way I can think of to optimize this in CouchDB would be the something like the following (with assumptions):
Your serial numbers are not very long (say 20 chars?)
You force the search to be always 5 characters
Generate view that emits every single 5 char long substring from your serial number - more or less this (could be optimized and not sure if I got the in):
...
for (var i = 0; doc.serialNo.length > 5 && i < doc.serialNo.length - 5; i++) {
emit([doc.serialNo.substring(i, i + 5), doc._id]);
}
...
Use _count reduce function
Now the following url:
http://localhost:5984/test/_design/serial/_view/complex-key?startkey=["01234"]&endkey=["01234",{}]&group=true
Will return a list of documents with a hit count for a key of 01234.
If you don't group and set the reduce option to be false, you will get a list of all matches, including duplicates if a single doc has multiple hits.
Refer to http://ryankirkman.com/2011/03/30/advanced-filtering-with-couchdb-views.html for the information about complex keys lookups.
I am not sure how efficient couchdb is in terms of updating that view. It depends on how many records you will have and how many new entries appear between view is being queried (I understand couchdb rebuilds the view's b-tree on demand).
I have generated a view like that that splits doc ids into 5 char long keys. Out of over 1K docs it generated over 30K results - id being 32 char long, simple maths really: (serialNo.length - searchablekey.length + 1) * docscount).
Generating the view took a while but the lookups where fast.
You could generate keys of multiple lengths, etc. All comes down to your records count vs speed of lookups.

Java: showing the output of a separate for loop as an extra column shown in a console

Bit of context...
In my project I have one embedded for loop that outputs data whereby for each category show the item and within each item show its property so in reality the output I generated is 3 columns of data in the console (headings: Category/Item/Property) The for loop to show this data looks like this (Variables are set earlier on in the method):
for... (picks up each category)
for...(picks up items in category)
for (String propertyName : item.getPropertyNames()) {
out.println(category.getName() + "\t"
+ itemDesc.getName() + "\tProperty:"
+ propertyName);
}
}
}
The purpose of the project is to provide a more dynamic documentation of the properties of set components in the system. (The /t making it possible to separate them in to individual columns on a console and even in a file in say an excel spreadsheet should I choose to set the file on the printstream (Also at the start of this method.))
The Problem
Now for the problem, after the for loops specified above I have generated another for loop separate from the data but shows the list of all the functions and operators involved in the components:
//Outside the previous for loops
for (Function function : Functions.allFunctions) {
out.println(function.getSignature());
}
What I want is to set this list as the 4th column but the positioning of the for loop and the way it is set leaves it fixed on the first column with the categories. I cant add it after property names as the functions are more generic to everything in the lists and there maybe repetitions of the functions which I am trying to avoid. Is there a way to set it as the forth column? Having trouble finding the sufficient research that specifies what I am looking for here. Hope this makes sense.
One solution, if the total amount of output is small enough to fit in memory, is to simply save all the data into an ArrayList of String, and output it all at the very end.
List<String> myList = new ArrayList<String>();
for... (picks up each category)
for...(picks up items in category)
for (String propertyName : item.getPropertyNames()) {
myList.add(category.getName() + "\t"
+ itemDesc.getName() + "\tProperty:"
+ propertyName);
}
}
}
int i = 0;
// Here we assume that the total lines output by the previous set of loops is
// equal to the total output by this loop.
for (Function function : Functions.allFunctions) {
out.println(myList.get(i) + "\t" + function.getSignature());
i++;
}

Protobuf in java : Uid.Lists from Accumulo Values go in but they don't come out

I am attempting to write and read Uids from Accumulo Value (key,Value) into Uid.List using protobuf.
Specifically:
org.apache.accumulo.examples.wikisearch.protobuf.Uid;import org.apache.accumulo.examples.wikisearch.protobuf.Uid.List.Builder
I use the following code to write Uid.List where I declare UidListCount as #of uids in List Cseq:
Builder uidBuilder = Uid.List.newBuilder();
uidBuilder.setIGNORE(false);
for String entry : seq){
uidBuilder.addUID(entry);
}
Uid.List uidList = uidBuilder.build();
Value newAccumuloValue = new Value(uidList.toByteArray());
This seems to work fine.
When I Try to read the Uid.List out of accumulo value,where value is a protobuf Uid.List, its a no-go:
byte[] byteVal = value.getBytes; //retrieving Accumulo Value containing Uid.List
Uid.List uids= Uid.List.parseFrom(byteVal);
while (counter <= counter){
String uidStr = uids.getUID(counter).toString();
system.out.println(uidStr);
}
I keep getting "tag errors"
I would really like to understand how to read out what goes in.
Thanks!
I would suggest changing the second bit of code to something along the lines of:
byte[] byteVal = value.getBytes;
Uid.List uids= Uid.List.parseFrom(byteVal);
int count = uids.getUIDCount();
for (int i = 0; i< count; i++){
String uidStr = uids.getUID(i).toString();
system.out.println(uidStr);
}
This code does work as long as the UIDs in your list are properly cleaned before the list is built by protobuf. If you have characters within the data (such as unicode nulls) that are used by protobuf as part of the list format then, when parsing the data back out, it is going to break because data characters will be recognized as format characters that don't properly match the data schema. I would start by taking a look at your data and ensuring that it meets data quality and cleanliness standards for what you are trying to achieve.

Java ADF stored value from data control doesn't display until next run

Basically I've got a JSF page with a number of components, including an ADF table populated with a List of data returned from a getData() method in my data control class.
Above the table I'm trying to display some calculated values from the data displayed - but the field values are not being displayed correctly.
(I'm using JDev 11.1.1.5)
The data control class is called RecentDeals and the getData() method returns a List of Deal objects that includes a number of fields (dates, values, names, etc).
The RecentDeals class also contains private variables to store the calculated (average) values to be displayed above the table (eg. avgSize, avgTerm, avgRent, etc).
In the same getData() method, after iterating through the List of Deals to perform required calculations (and storing the respective values along the way), the variables are updated with the calculated averages before returning the List of Deal objects that populates the table.
Below is an excerpt of the code for reference:
public class RecentDealsDC {
private Double avgSize;
private Double avgTerm;
private Double avgRent;
...
public RecentDealsDC() {
super();
avgSize = 0.0;
avgTerm = 0.0;
avgRent = 0.0;
...
}
public List<DealDTO> getData(List<String> businessUnits){
List<TransactionDTO> transactions = new ArrayList<TransactionDTO>();
List<DealDTO> deals = new ArrayList<DealDTO>();
TransactionSessionBean transBean = lookupTransactionSessionBean();
Double size = 0.0;
Double term = 0.0;
Double totalBaseRent = 0.0;
...
Integer recordCount = 0;
if (businessUnits != null && !businessUnits.isEmpty()){
transactions = transBean.getDealsData(SystemUtil.getCurrentUser(), businessUnits);
recordCount = transactions.size();
if( recordCount > 0 ){
for (int i=0; i < recordCount; i++){
TransactionDTO transObj = new TransactionDTO();
DealDTO dealObj = new DealDTO();
transObj = transactions.get(i);
// process transaction, execute logic, store deal values
size = size + transObj.getRentableArea();
term = term + transObj.getLeaseTerm();
totalBaseRent = totalBaseRent + (transObj.getRentableArea() * transObj.getBaseRent());
...
deals.add(dealObj);
}
}
avgSize = size / recordCount;
avgTerm = term / recordCount;
avgRent = totalBaseRent / size;
...
}
return deals;
}
}
When I run my JSF page it correctly displays the data from the List of Deal objects but the calculated fields just display zero.
When the user selects the next "criteria" to populate the table (from a dropdown list in the header), the calculated fields are then updated with the previous stored values.
So in other words the header fields are showing the averages pertaining to the previous set of data and the cycle seems to continue for each subsequent user selection - so the user is forced to select another value to get the averages needed, which is obviously not acceptable.
I have confirmed in debug mode that the calculations are being executed correctly and the correct values are stored in the private variables before the List is returned.
Not sure what I'm missing here but I'm thinking I need to somehow "refresh" the outputText components to display the expected values right away.
That is what I'm researching but at something of a loss right now.
Any suggestions/direction/ideas would be really appreciated.
EDIT: It looks like the outputText fields also update when I collapse and re-expand the panelBox they are contained inside. So I'm wondering if there's some way for me to manually perform that same update...
Thanks,
Karim
The solution I came to is as follows:
Revised the DC class getData method to return a new DTO that contained the original List resultset and the 4 variables I needed to display.
Then I bound the resultset and variables from below the returned DTO to the same respective components (resultset in ADF table, variables in 4 outputText fields in header above resultset table).
Then I added a Refresh="IfNeeded" property to the Iterator for the attribute bindings.
Now my outputText fields refresh as expected at the same time as the resultSet changes!
Karim

Categories

Resources