My application periodically adds Strings to a List using a Thread. I want to add those strings to a ComboBox as soon as they get added to the List. Is there anyway to bind a ComboBox to a List?
My Code:
static final int max = 20;
List<String> ips = new ArrayList<String>();
public void getIP() throws UnknownHostException {
Task task = new Task<Void>() {
#Override
public Void call() throws UnknownHostException {
InetAddress localhost = InetAddress.getLocalHost();
byte[] ip = localhost.getAddress();
for (int i = 10; i <= max; i++) {
if (isCancelled()) {
break;
}
try {
ip[3] = (byte) i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(100)) {
//============================== Populating List ===============//
ips.add(address.getHostName());
}
} catch (Exception e) {
System.err.println(e);
}
updateProgress(i, max);
}
return null;
}
};
//============================== Bind ComboBox to List Code here ===============//
indicator.progressProperty().bind(task.progressProperty());
new Thread(task).start();
}
No there is no way to bind a simple list, since it's not observable. Even with a ObservableList, there would be the problem of the updates coming from a different thread.
You could however use a synchronized list and use the value property to pass the current size, which would allow you to add the items via listener.
Example
This uses a ListView instead of a ComboBox, since the results are visible without user interaction, but you could also use targetList = comboBox.getItems().
#Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
List<String> targetList = listView.getItems();
final List<String> ips = Collections.synchronizedList(new ArrayList<>());
Task<Integer> task = new Task<Integer>() {
#Override
protected Integer call() throws Exception {
Random random = new Random();
int size;
for (size = 0; size < 100; size++) {
ips.add(Integer.toString(size));
updateValue(size);
Thread.sleep(random.nextInt(500));
}
return size;
}
};
task.valueProperty().addListener((observable, oldValue, newValue) -> {
// add values not yet in the target list.
for (int i = targetList.size(), newSize = newValue; i < newSize; i++) {
targetList.add(ips.get(i));
}
});
new Thread(task).start();
Scene scene = new Scene(listView);
primaryStage.setScene(scene);
primaryStage.show();
}
It would be a bit simpler though to simply post the updates on the ui thread using Platform.runLater though:
ips = comboBox.getItems();
Task task = new Task<Void>() {
#Override
public Void call() throws UnknownHostException {
InetAddress localhost = InetAddress.getLocalHost();
byte[] ip = localhost.getAddress();
for (int i = 10; i <= max; i++) {
if (isCancelled()) {
break;
}
try {
ip[3] = (byte) i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(100)) {
//============================== Populating List ===============//
final String hostName = address.getHostName();
// do update on application thread
Platform.runLater(() -> ips.add(hostName));
}
} catch (Exception e) {
System.err.println(e);
}
updateProgress(i, max);
}
return null;
}
};
i suggest you to do the following:
change
List<String> ips = new ArrayList<String>();
to
final ObservableList<String> ips = FXCollections.observableArrayList();
change:
Task task = new Task<Void>()
to
Task<ObservableList<String> task = new Task<>(){
#Override
public ObservableList<String> call() throws UnknownHostException {
...
return ips;
}
};
comboBox.itemsProperty().bind(task.valueProperty());
Related
The test app:
static void Main(string[] args)
{
String connectionString = "DSN=DotNetUltraLightDSII; UID=user; PWD=pass";
String query = "select * from person";
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
connection.Open();
for (Int32 trial = 1; trial <= 100000; trial++)
{
if (0 == trial % 1000)
{
Console.WriteLine("Executing trial #{0:#,0}", trial);
GC.Collect();
}
using (OdbcCommand command = new OdbcCommand(query, connection))
{
using (OdbcDataReader reader = command.ExecuteReader())
{
do
{
while (reader.Read())
{
for (Int32 colIndex = 0; colIndex < reader.FieldCount; colIndex++)
{
Object x = reader[colIndex];
IDisposable d = x as IDisposable;
if (null != d)
{
d.Dispose();
}
d = null;
x = null;
}
}
} while (reader.NextResult());
reader.Close();
}
}
}
connection.Close();
}
Memory usage
Heap Snapshot Comparison
The memory usage just goes up over time. It seems like there are strong handles to the ULPersonTable but I cannot tell what exactly these strong handles are or where they are coming from. We are storing the instances of that type inside gcroot, but they seem to be destroyed. If someone could shed some light on this issue, that would be appreciated.
Regards
Ended up finding the problem. It was a pointer which wasn't being deleted properly.
I have a text file called highscore.txt and I know the format of the data going into the file which works in the following way:
Username:score
I then need to search through the whole file to see where the new score needs to be added such that the file is in order of score from largest to smallest
List<string> tempoaryList = new List<string>();
List<int> valueList = new List<int>();
string lineValues = "";
using (StreamReader sr = new StreamReader(finalPath))
{
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
tempoaryList.Add(lineValues);
int data = Convert.ToInt32(lineValues.Substring(lineValues.LastIndexOf(':') + 1));
valueList.Add(data);
}
}
valueList.Sort();
for(int i =0; i > valueList.Count; i++)
{
if(valueList[i] <= playerScore)
{
tempoaryList.Insert(i - 1, playerScore.ToString());
}
}
using (StreamWriter sw = new StreamWriter(finalPath, false))
{
for (int i = 0; i < tempoaryList.Count; i++)
{
sw.WriteLine(tempoaryList[i]);
Debug.Log(tempoaryList[i]);
}
}
The above just simply doesn't change the text file and leaves it as it was found, any ideas of what I am doing wrong?
You should change your code to this:
ScoreList.cs
using UnityEngine;
using System;
using System.IO;
using System.Collections.Generic;
public class ScoreList : MonoBehaviour {
private void Start() {
GameOver.GameOverEvent += UpdateScoreBoardFile;
}
private void UpdateScoreBoardFile(string playerName, int playerScore) {
string lineValues;
string finalPath = "[ScoreBoard File Location]";
List<string> tempoaryList = new List<string>();
List<int> valueList = new List<int>();
bool isScoreLowest = true;
using (StreamReader sr = new StreamReader(finalPath)) {
while (sr.EndOfStream == false) {
lineValues = sr.ReadLine();
tempoaryList.Add(lineValues);
int data = Convert.ToInt32(lineValues.Substring(lineValues.LastIndexOf(':') + 1));
valueList.Add(data);
}
}
if (tempoaryList != null) {
for (int i = 0; i < valueList.Count; i++) {
if (valueList[i] <= playerScore) {
tempoaryList.Insert(i, playerName + ":" + playerScore.ToString());
isScoreLowest = false;
break;
}
}
}
if (isScoreLowest) {
tempoaryList.Add(playerName + ":" + playerScore.ToString());
}
using (StreamWriter sw = new StreamWriter(finalPath, false)) {
for (int i = 0; i < tempoaryList.Count; i++) {
sw.WriteLine(tempoaryList[i]);
Debug.Log(tempoaryList[i]);
}
}
}
}
GameOver.cs (or wherever you manage the game over condition):
using UnityEngine;
using System;
public class GameOver : MonoBehaviour {
public static event Action<string, int> GameOverEvent;
string playerName;
int finalScore;
private void GameOver() {
//Do other stuff when the game is over
GameOverEvent(playerName, finalScore);
}
}
Explanation of the changes:
isScoreLowest is needed to Add the new lowest score at the end of the list, since the for loop won't add it by itself.
The if (tempoaryList != null) check is done to skip the for loop when the scoreboard is empty.
And you saved yourself from doing a Sort, which is always a good thing. :)
Hopefully someone can help me with this issue. I'm trying to couple an IEnumerator with my object pooling script to instantiate enemies in waves. But I can't get them to instantiate without immediately destroying themselves 2 or 3 times and then instantiating one wave of enemies and never spawning again. Can anyone help me see where I'm going wrong here?
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SpawnMaster : MonoBehaviour {
public int enemyCount = 4;
public float spawnWait=0.5f;
public float startWait=1;
public float waveWait=3;
public Transform[] spawnPoints;
private int currentWave = 0;
private int waveCount = 10;
private IEnumerator spawnWaves;
private IEnumerator goHorde;
bool isSpawning = false;
void Update()
{
if(!isSpawning)
{
isSpawning = true;
StartCoroutine(SpawnWaves(currentWave));
}
}
IEnumerator SpawnWaves (int currentWave)
{
Debug.Log("Spawning " + currentWave + "currentWave");
for (int i = 0; i < waveCount; i++)
{
StartCoroutine(GoHorde());
}
currentWave += 1;
yield return new WaitForSeconds (waveWait);
//We've spawned, so start another spawn
isSpawning = false;
}
IEnumerator GoHorde()
{
GameObject beetle01 = BeetlePool.current.GetPooledObject();
if(beetle01 == null)
yield return null;
// Only pick a new spawn point once per wave
int spawnPointIndex = Random.Range (0, spawnPoints.Length);
for (int j = 0; j < enemyCount; j++)
{
beetle01.transform.position = spawnPoints[spawnPointIndex].position;
beetle01.transform.rotation = spawnPoints[spawnPointIndex].rotation;
beetle01.SetActive(true);
yield return new WaitForSeconds (spawnWait);
}
}
}
I would change:
if(!isSpawning)
to:
if(isSpawning != true)
Or:
if(isSpawning == false)
Also if you are going to have multiple waves of enemies that are being instantiated and destroyed. You should look into object pooling to save memory.
I used the filter to fix the XSS. But when i scan my codes using fortify software, the number of XSS issues didn't change. Did i miss something? or Fortify cannot recognize the filter? Here are my filter codes:
public final class RequestWrapper extends HttpServletRequestWrapper {
public RequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values==null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private String cleanXSS(String value) {
System.out.println("filter : " + value);
//System.out.println("afterfilter : " + (isNotEmptyOrNull(value) ? StringEscapeUtils.escapeHtml4(value) : value));
//return isNotEmptyOrNull(value) ? StringEscapeUtils.escapeHtml4(value) : value;
if(isNotEmptyOrNull(value)){
value = value.replaceAll("<", "<").replaceAll(">", ">");
value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");
value = value.replaceAll("'", "'");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
}
System.out.println("afterfilter : " +value);
return value;
}
public static boolean isNotEmptyOrNull(String string) {
if (string != null && !"".equals(string.trim())) {
return true;
}
return false;
}
}
The problem here is that Fortify doesn't have a rule for your cleanXSS method. What you will have to do is to write a custom rule, specifically a "data flow cleanse rule". This will let fortify know that any data that enters and then returned from this method will be safe from XSS.
However after looking at you XSS filter, I have to inform you that it's incomplete and will not take in to account all possible XSS vectors. I recommend that you use OWASP ESAPI's XSS filter. Fortify already has a rules for ESAPI.
I have two Lists with the same content. The first one had added three items and removed one again. The second one had added only the remaining two items. Then I converted both to byte array, but the byte array are not equal. They differ in one byte.
Is there a way to have two "equal" lists with equal byte arrays independent of performed operations?
I need this for saving the list to a text file with a RSA signature included. But I can't have a valide signature if the list in memory, with operations performed on it in the past, is not equal to the new generated list from the content of the text file.
In my Application i use dictionaries instead of lists, but it's the same behaviour.
Here is my test code:
static void Main(string[] args)
{
List<string> one = new List<string>();
one.Add("hallo");
one.Add("hallo1");
one.Remove("hallo1");
one.Add("hallo1");
byte[] test = Program.ObjectToByteArray(one);
Console.WriteLine(test.Length);
List<string> two = new List<string>();
two.Add("hallo");
two.Add("hallo1");
byte[] test1 = Program.ObjectToByteArray(two);
Console.WriteLine(test1.Length);
bool areEqual = false;
int count = 0;
if (test.Length == test1.Length)
{
areEqual = true;
for (int i = 0; i < test.Length; i++)
{
if (test[i] != test1[i])
{
areEqual = false;
count++;
}
}
}
Console.WriteLine("Are they equal?: " + areEqual.ToString() + ": " + count.ToString());
Console.ReadLine();
}
private static byte[] ObjectToByteArray(Object obj)
{
if (obj == null)
return null;
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
Edit:
In my application i will have a class like this:
[Serializable]
class MetaDataModel
{
private Dictionary<string, string> readers;
private Dictionary<string, string> writers;
public bool IsDirty { get; set; }
public string PublicReaderKey { get; set; }
public string CipherPrivateReaderKey { get; set; }
public Dictionary<string, string> Readers
{
get
{
if (this.readers == null)
this.readers = new Dictionary<string, string>();
return this.readers;
}
set
{
this.readers = value;
}
}
public string PublicWriterKey { get; set; }
public string CipherPrivateWriterKey { get; set; }
public Dictionary<string, string> Writers
{
get
{
if (this.writers == null)
this.writers = new Dictionary<string, string>();
return this.writers;
}
set
{
this.writers = value;
}
}
public byte[] Signature { get; set; }
}
And want it use like this:
MetaDataModel metaData = new MetaDataModel()
//filling the properties here
metaData.Signature = RSASignatureGenerator.HashAndSignData(this.ObjectToByteArray(metaData), this.rsaKeyPair[0]);