When the code is ran the nested loop causes it to create occasional duplicate entries to the system, i have spent a while looking through this but still cant find what is causing this, would greatly appreciate any help?
for(int i = 0; i < subWorkItemElement.getChildNodes().getLength(); i++) {
Boolean test = false;
WorkItemCommon existingChild = null;
String summary = null;
if(subWorkItemElement.getChildNodes().item(i).getNodeName().equals("workitem")) {
// We know it's a work item - but is it in the existing list?
Element childWorkItem = (Element) subWorkItemElement.getChildNodes().item(i);
for(int j = 0; j < subWorkItemElement.getChildNodes().getLength(); j++) {
if(childWorkItem.getChildNodes().item(j) instanceof Element) {
if(((Element)childWorkItem.getChildNodes().item(j)).getNodeName().equals("details")) {
summary = ((Element) childWorkItem.getChildNodes().item(j)).getElementsByTagName("summary")
.item(0).getTextContent();
for(String k : userInfoHashMap.keySet()) {
summary = summary.replace("${" + k + "}", userInfoHashMap.get(k));
}
if(childHashTable.containsKey(summary)) {
test = true;
existingChild = childHashTable.get(summary);
IWorkItem workItem = existingChild.getWorkItem();
System.out.println("INFO: The task with summary \"" + summary + "\" already exists. Skipping creation.");
System.out.println("this task is work item: " + workItem.getId());
//either check the tasks in the xml for updated details and then modify the existing workitem
//or just modify the work item without checking for updates
makeChildTask(childWorkItem, existingChild, childHashTable, userInfoHashMap, workItemHashMap, rtc, false);
break;
}
}
}
}
if(!test) {
System.out.println("INFO: The task with summary " + summary + " does not currently exist. Creating.");
makeChildTask(childWorkItem, thisItem, childHashTable, userInfoHashMap, workItemHashMap, rtc, true);
} else makeFromExistingChildTask(childWorkItem, existingChild, userInfoHashMap, workItemHashMap, rtc);
}
}
You are possibly (not sure what makeChildTask() does) changing an XML structure while iterating through the children list. While not necessarily incorrect, this can mean you get entries inserted while you process the list. Since you call the subWorkItemElement.getChildNodes().getLength() each time instead of cache'ing it, this might result in the length changing in between the loop iterations.
Related
This is an excerpt from my project:
import javafx.util.Pair;
import org.w3c.dom.*;
private Pair<Element, Integer> findBestAlbumElement(Element recording) {
Pair<Element, Integer> best = new Pair<>(null, Integer.MIN_VALUE);
NodeList list = recording.getElementsByTagName("release");
for (int i = 0; i < list.getLength(); i++) {
System.out.println((best.getKey() == null ? "null" : best.getKey().getTextContent()) + "; " + best.getValue());
Element album = (Element) list.item(i);
int mark = getAlbumAndYearMark(recording, album);
if (mark > best.getValue()) best = new Pair<>(album, mark);
System.out.println((best.getKey() == null ? "null" : best.getKey().getTextContent()) + "; " + best.getValue());
}
return best;
}
and I'm running into a strange problem in this piece of code. The variable best resets between loop iterations, as seen in the beginning of the printout to console:
null; -2147483648
Live USABootlegAlbumLive1990DE1990GermanyGermanyDE212CD2T.N.T255240; 6
null; -2147483648
...
The first line is the first System.out.println(), the second line is the second one (where the variable best is properly set as expected) and the third line is the first one again (where the variable best seemingly just resets of its own accord).
I've tried to replicate the problem with the following code:
Pair<String, Integer> best = new Pair<>("", Integer.MIN_VALUE);
String[] strings = {"asdf", "fdsa", "dsaf"};
int[] marks = {1, 5, 3};
for (int i = 0; i < strings.length; i++) {
System.out.println(best.getKey() + " " + best.getValue());
if (marks[i] > best.getValue()) best = new Pair<>(strings[i], marks[i]);
System.out.println(best.getKey() + " " + best.getValue());
}
which replaces the NodeList with a String array, but this code works as expected.
My problem is, I don't even know how to approach this issue. I don't know how to debug this further or even reproduce the problem in a smaller example, as I don't know how to create a valid NodeList (since it's an interface, so I can't just new NodeList).
I'm also at a bit of a loss, as it looks to me like the bug appears in a place where it shouldn't even be possible, since the only code that is supposed to execute between the two println calls is i++ (not altering or even accessing best in any way). Am I wrong about this?
Does anyone have any idea what could be going on, or even how I would get closer to pinpointing the issue?
EDIT
As per request, here's getAlbumAndYearMark, which uses the jaudiotagger library (apologies for the ugly long lined code, this is a fairly old project).
private Tag tag;
private int getAlbumAndYearMark(Element recording, Element album) {
int mark = 0;
if (album == null) return tag.hasField(FieldKey.YEAR) ? getYearMark(album) : 0;
if (contains(album.getElementsByTagName("primary-type"), "Album")) mark += 2;
else if (!contains(album.getElementsByTagName("secondary-type"), "Album")) return Integer.MIN_VALUE;
Node title = album.getElementsByTagName("title").item(0);
if (title != null && tag.hasField(FieldKey.ALBUM)) mark += title.getTextContent().equals(tag.getFirst(FieldKey.ALBUM)) ? 7 : -4;
Node date = album.getElementsByTagName("date").item(0);
if (date != null && tag.hasField(FieldKey.YEAR)) mark += date.getTextContent().equals(tag.getFirst(FieldKey.YEAR).trim()) ? 3 : -3;
Node track = album.getElementsByTagName("number").item(0);
if (track != null && tag.hasField(FieldKey.TRACK)) mark += track.getTextContent().equals(tag.getFirst(FieldKey.TRACK).trim()) ? 3 : -1;
return mark;
}
private int getYearMark(Element element) {
NodeList dates = element.getElementsByTagName("date");
for (int i = 0; i < dates.getLength(); i++)
if (dates.item(i).getTextContent().substring(0, 4).equals(tag.getFirst(FieldKey.YEAR))) return 7;
return -7;
}
private static boolean contains(NodeList list, String string) {
for (int i = 0; i < list.getLength(); i++)
if (list.item(i).getTextContent().trim().equalsIgnoreCase(string)) return true;
return false;
}
but I don't believe this method is the problem, as I still have the same issue if I replace int mark = getAlbumYearMark(recording, album); with int mark = (int) (Math.random() * 10);
Here's a (heavily trimmed) example XML file, printed directly from the program:
<?xml version="1.0" encoding="UTF-8"?><metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#" xmlns:ext="http://musicbrainz.org/ns/ext#-2.0" created="2018-02-16T02:07:28.816Z">
<recording-list count="72" offset="0">
<recording ext:score="100" id="6e702972-00c2-4725-b3e5-60e85ef0de25">
<title>T.N.T</title>
<artist-credit>
<name-credit>
<artist id="66c662b6-6e2f-4930-8610-912e24c63ed1">
<name>AC/DC</name>
</artist>
</name-credit>
</artist-credit>
<release-list>
<release id="ddaa5690-df97-4bb2-b93d-396fe5fb49d5">
<title>Live USA</title>
<release-group id="6b1ace64-bf92-3c42-8a1f-aea6fa08edec" type="Live">
<primary-type>Album</primary-type>
<secondary-type-list>
<secondary-type>Live</secondary-type>
</secondary-type-list>
</release-group>
<date>1990</date>
<country>DE</country>
<release-event-list>
<release-event>
<date>1990</date>
<area id="85752fda-13c4-31a3-bee5-0e5cb1f51dad">
<name>Germany</name>
<sort-name>Germany</sort-name>
<iso-3166-1-code-list>
<iso-3166-1-code>DE</iso-3166-1-code>
</iso-3166-1-code-list>
</area>
</release-event>
</release-event-list>
<medium-list>
<track-count>21</track-count>
<medium>
<position>2</position>
<format>CD</format>
<track-list count="11" offset="1">
<track id="caadf3b8-4a44-34c6-b9dc-c9870c5d9bc0">
<number>2</number>
</track>
</track-list>
</medium>
</medium-list>
</release>
</release-list>
</recording>
</recording-list>
</metadata>
You can see an untrimmed example by querying the musicbrainz database directly, for example this query.
It's not an answer (yet). I'm trying with next xml:
<root>
<release-list>
<release id="ddaa5690-df97-4bb2-b93d-396fe5fb49d5">
<title>Live USA</title>
<date>1990</date>
<country>DE</country>
</release>
<release id="qqqa5690-df97-4bb2-b93d-396fe5fb49d5">
<title>German collections</title>
<date>1991</date>
<country>DE</country>
</release>
</release-list>
<release-list>
<release id="zzza5690-df97-4bb2-b93d-396fe5fb49d5">
<title>Just USA</title>
<date>1995</date>
<country>US</country>
</release>
</release-list>
<release-list>
<release id="aaaa5690-df97-4bb2-b93d-396fe5fb49d5">
<title>Anoother USA</title>
<primary-type>Album</primary-type>
<date>1999</date>
<country>RUS</country>
</release>
</release-list>
And I have no issues. Could you please try with this xml?
Also I'm using both incremental mark like return mockMark++; and array-based mark like
private int getAlbumAndYearMark(Element recording, Element album) {
int[] arr = {1,0,5,7,3,6,8,9,10};
return arr[mockMark++];
}
I need to get all items in the list, but my script shows only the first item. Please refer to the verifyDisplay assertion in for loop, where I want to show all items in the list. Thanks for the help.
My script:
List<WebElement> groups = driver.findElements(By
.xpath(".//*[#id='competitiveCategoryTemp']/option"));
verifyDisplay("'" + competitive_categories_id_with_space + "'" + "===> The newly added Competitive Category is listed",
By.xpath(".//*[#id='competitiveCategoryTemp']/option"));
boolean sortedGroups = false;
for (int i = 0; i < groups.size() - 1; i++) {
verifyDisplay("'" + groups.get(i).getText() + "'" + "\n"+
"Other Competitive Categories are available and names are SORTED",
By.xpath(".//*[#id='competitiveCategoryTemp']/option"));
if (groups.get(i).getText()
.compareToIgnoreCase(groups.get(i + 1).getText()) > 0) {
sortedGroups = true;
break;
}
sortedGroups = true;
}
if (sortedGroups) {
System.out.println("The Competitive Category names are SORTED");
} else
System.out.println("The Competitive Category names are UN-SORTED");
}
if (groups.get(i).getText()
.compareToIgnoreCase(groups.get(i + 1).getText()) > 0) {
sortedGroups = true;
break;
}
If this condition is met, it breaks out of the for loop, and thus does not proceed forward to the second element. Could that be the problem?
WebDriver has Select class to control dropdown objects. Your approach will also work. But this way it will look neat and you can reuse the existing methods.
Import this lib.
import org.openqa.selenium.support.ui.Select;
Then,
Select dropdown = new Select(driver.findElement(By.id("competitiveCategoryTemp")));
dropdown.getOptions() // will return all the options - it is a List<WebElement>
//To use
for(WebElement option: dropdown.getOptions()){
System.out.println(option.getText());
}
dropdown.getAllSelectedOptions() // will return the default selected options - it is a List<WebElement>
I am getting the following error.
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element
(Session info: chrome=39.0.2171.95)
From the looks of the error message it says that it couldnt find such element.
So i added a wait until the element appears.
The funny thing is that the error occurs on the line driver.findElement which means that the wait was able to find the element.
The question is obviously why is selenium not able to find the element.
At first i thought it was because of using a variable in the string
driver.findElement(By.id("_ctl0_ContentPlaceHolder1_eoiSectionSummary_individualRepeater__ctl0_sectionRepeater__ct" + i + "_isCompleteLabel")).getText();
So i tried to store the string somewhere and then findElement with it.
As you see in the code below i have tried using print to verify that the string is the same as the one in the web. And they do match.
Im currently out of ideas now. Please help. Please let me know if you need any other information
public int verifyCompletion() {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("_ctl0_ContentPlaceHolder1_eoiSectionSummary_individualRepeater__ctl0_sectionRepeater__ctl0_isCompleteLabel")));
int uncompletedCounter = 0;
for (int i = 10; i < 20; i++) {
String text = "_ctl0_ContentPlaceHolder1_eoiSectionSummary_individualRepeater__ctl0_sectionRepeater__ct" + i + "_isCompleteLabel";
driver.findElement(By.id(text)).getText();
System.out.println(text);
boolean sectionCompleted =text.equalsIgnoreCase("Yes");
if (!sectionCompleted) {
uncompletedCounter++;
}
}
return uncompletedCounter;
}
I see a small bug in your selector. You are not parameterizing the selector correctly. I am not sure if it a very efficient way to handle this scenario though.
String selector = "_ctl" + i + "_ContentPlaceHolder1_eoiSectionSummary_individualRepeater__ctl" + i + "_sectionRepeater__ctl" + i + "_isCompleteLabel";
Edit: more precise code should look like this:
public int verifyCompletion() {
int uncompletedCounter = 0;
for (int i = 0; i < 10; i++) {
String selector = "_ctl" + i + "_ContentPlaceHolder1_eoiSectionSummary_individualRepeater__ctl" + i + "_sectionRepeater__ctl" + i + "_isCompleteLabel";
(new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.id(selector)));
String elementText = driver.findElement(By.id(selector)).getText();
System.out.println(selector);
System.out.println(elementText);
boolean sectionCompleted =text.equalsIgnoreCase("Yes");
if (!sectionCompleted) {
uncompletedCounter++;
}
}
return uncompletedCounter;
}
I'm trying to implement an expandable listview with data from a remote server. I've already have the JSON part covered. My sample has three value sets returned (confirmed by checking logcat on the original JSON response). My problem now is while dividing the JSON return into header and child datas, the first value set is skipped. My code is as follows:
int lisDataHeaderCounter = 0;
String searchKey;
for (int i = 0; i < components.length(); i++) {
List<String> component_value = new ArrayList<String>();
searchKey = main_components.get(i);
if (!listDataHeader.contains(searchKey)) {
listDataHeader.add(searchKey);
Iterator<Map.Entry<String, String>> entries = sub_components.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
Log.d("getValue() ", "+ " + entry.getValue());
if (searchKey == entry.getKey())
component_value.add(entry.getValue());
}
listDataChild.put(listDataHeader.get(lisDataHeaderCounter), component_value);
lisDataHeaderCounter++;
}
}
I've also tried the code below and it still has the same result.
for (Map.Entry<String, String> entry : sub_components.entrySet()) {
if (searchKey == entry.getKey())
component_value.add(entry.getValue());
}
Here is a sample of the JSON response that is being process by the above codes:
[{"activity_code":"1","activity_name":"Midterm Exam"},
{"activity_code":"1","activity_name":"Final Exam"},
{"activity_code":"2","activity_name":"Project"}]
With the current codes, in the for loop, the first value of searchKey is '1'. When I placed a Log.d(); in the while loop to check what the first value is read, I found that it is "Final Exam" and not "Midterm Exam". Is there a way for me to get the value of the first data set before it goes into the while loop?
Here is a workaround I've made to ensure that the first value would be included to the sub_components. But I guess it doesn't look neat. If anyone has a better solution, please feel free to share.
for (int i = 0; i < components.length(); i++) {
JSONObject c = components.getJSONObject(i);
String formula_code = c.getString(TAG_FORMULA_CODE);
String component_name = c.getString(TAG_ACTIVITY_NAME);
main_components.add(formula_code);
sub_components.put(formula_code, component_name);
if (!listDataHeader.contains(formula_code))
listDataHeader.add(formula_code);
if (i == 0) {
component_value.add(component_name);
}
}
for (int i = 0; i < listDataHeader.size(); i++) {
for (Map.Entry<String, String> entry : sub_components.entrySet()) {
if (listDataHeader.get(i) == entry.getKey())
component_value.add(entry.getValue());
}
listDataChild.put(listDataHeader.get(i), component_value);
component_value = new ArrayList<String>();
}
I can't see any off by one error on the two, but perhaps it's the searchKey == entry.getKey(), that might have to be searchKey.equals(entry.getKey()), but I would need to see more code to know for sure.
I try hard to find the problem in this Java code, but I can't find it - can you help me?
I hope the code I provide is enough, but I will post more if necessary.
Further I apologize, I didn't make a minimal example.
game.getGroupPlayers().list();
MoverThread[] playerThread = game.getPlayers();
System.out.println(playerThread.length);
for (int i = 0; i < playerThread.length; i++) {
try {
System.out.println(i + " -> " +playerThread[i].toString());
returnString += playerThread[i].toString() + "\n";
} catch(NullPointerException e) {
System.out.println("Problem at i = " + i);
e.printStackTrace();
}
game.getGroupPlayers().list();
}
sometimes gives me the following output:
java.lang.ThreadGroup[name=Players,maxpri=10]
Player-0: 113
Player-1: 277
Player-2: 0
3
0 -> Player-0: 113
1 -> Player-1: 277
Problem at i = 2
java.lang.NullPointerException
at Referee.goalFound(Referee.java:70)
at DebugTestReferee.goalFound(DebugTestReferee.java:42)
at Player.checkGoal(Player.java:61)
at Player.run(Player.java:94)
at java.lang.Thread.run(Thread.java:636)
java.lang.ThreadGroup[name=Players,maxpri=10]
Player-0: 113
Player-1: 277
Player-2: 0
[edit]
here's the source of getPlayers()
/*
* post returns the games players as an array
*/
public MoverThread[] getPlayers() {
synchronized(movers) {
MoverThread[] playerList = new MoverThread[players.activeCount()];
players.enumerate(playerList);
return playerList;
}
}
[edit]
here's how players is generated
private ThreadGroup movers;
private ThreadGroup players;
private ThreadGroup ghosts;
private Observer observer;
/*
* constructor
*/
public Game(Maze maze, Referee referee) {
this.maze = maze;
this.referee = referee;
threadList = new ArrayList<MoverThread>();
movers = new ThreadGroup("Movers");
players = new ThreadGroup(movers, "Players");
ghosts = new ThreadGroup(movers, "Ghosts");
observer = null;
}
[edit]
Here's how I call the method that generates the problem:
/*
* post checks if the players thread was interrupted - if not if hostfield pretends to be a goal the game gets stopped and referee is called to perform "goal-found-actions"
*/
private void checkGoal() {
if (!getThread().isInterrupted()) {
synchronized(getGame().getMovers()) {
if (!getThread().isInterrupted()) {
if (getHostField().isGoal()) {
Field goal = getHostField();
getGame().getReferee().goalFound(this, goal);
getGame().setGameOver();
}
}
}
}
}
and here's the whole goalFound()
/*
* post action to be performed if a player finds a goal
* print some information
*/
public void goalFound(Player player, Field at) {
//FIXME get the Bug!!!
String returnString = "Game over - player " + player.getName() + " found a goal on (" + at.getPos()[0] + ", " + at.getPos()[1] + ")!\n";
game.getGroupPlayers().list();
MoverThread[] playerThread = game.getPlayers();
System.out.println(playerThread.length);
for (int i = 0; i < playerThread.length; i++) {
try {
System.out.println(i + " -> " +playerThread[i].toString());
returnString += playerThread[i].toString() + "\n";
} catch(NullPointerException e) {
System.out.println("Problem at i = " + i);
e.printStackTrace();
}
}
game.getGroupPlayers().list();
returnString += game.mazeString();
System.out.println(returnString);
}
There isn't a nice way of enumerating the Threads of a ThreadGroup. It's a well known terrible design.
Between calling ThreadGroup.activeCount and ThreadGroup.enumerate(Thread[]), threads may have started or died. The best you can do is add a fudge factor the activeCount when allocating the array. If the returned value matches the array length, then you may have missed some and should repeat with a larger array size (probably a factor larger, rather than just adding a constant). When successful, you will need to trim your array appropriately (or treat it as such).
game.getPlayers(); is returning MoverThread[] with length 3, but the third one is null.
I found a solution - or maybe more a workaround...
Beside using ThreadGroups I store my threads in an ArrayList aswell (maybe a Vector would be even better, but I'm fine with the ArrayList).
I don't know why, but when I try to call all Threads in the ThreadGroup it often happens that some Threads are left out. However, with the ArrayList it works fine.
Would be interesting why ThreadGroups don't work as supposed and what we need them for in this case.