I have some problem with multithreaded application. I want to load the data from a CSV like file and store it in a buffer for later retrieval.
Seems like the animals list goes out of scope when the thread is finished(?), there is something about java threading I don't understand and will be grateful for assistance.
The way it's invoked:
ParseCSV parser = new ParseCSV(null);
EventQueue.invokeLater(parser);
System.err.println("printing!");
EDIT - as requested, this is the part that fails - the content of praser buffer is empty at this point. I thought that if I use new keyword in the parser, the content of animals will be persistent.
while(parser.hasNext()){
System.err.println("#");
System.err.println(parser.getNext().toString());
}
The parser class:
public class ParseCSV implements Runnable{
private String path = null;
private File file = null;
private static Logger log = LogManager.getLogger(ParseCSV.class.getName());
private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
private int pointer =0;
public ParseCSV(String path) {
animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
if(path == null){
JFileChooser jfc = new JFileChooser();
jfc.showOpenDialog(null);
file = jfc.getSelectedFile();
this.path = file.getAbsolutePath();
}
else {
this.path = path;
}
log.debug("Initialized file parser for " + this.path);
}
#Override
public void run() {
log.debug("begining file parse");
System.err.println("runnner");
try {
Scanner fileScan = new Scanner(this.file);
while(fileScan.hasNextLine()){
parseLine(fileScan.nextLine());
}
fileScan.close();
} catch (FileNotFoundException e) {
log.error("Exception occured: " + e.getMessage() + "\nstack:\n" + e.getStackTrace());
System.err.println("Exception: " + e.getMessage());
e.printStackTrace();
}
}
private void parseLine(String nextLine) {
Scanner lineScanner = new Scanner(nextLine);
lineScanner.useDelimiter("\\s\\|\\s");
if(lineScanner.hasNext()){
Animal an = new Animal(lineScanner.next(), //person
lineScanner.next(), //animal
Integer.parseInt(lineScanner.next()), //emp-number
lineScanner.next(), //date
Integer.parseInt(lineScanner.next()), //ani-number
lineScanner.next());
animals.add(an); //contract ID
System.err.println(an.toString()); //prints correct result!
}
lineScanner.close();
}
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public boolean hasNext(){
System.err.println("size of data = " + animals.size());
if(animals.size() == pointer || animals.isEmpty()) return false;
else return true;
}
public Sale getNext(){
if(animals.size() == pointer) return null;
return animals.get(pointer++);
}
}
EDIT - added comments to point out where the problem appears
You need to wait for the Parser thread to finish (currently both are happening at same time) This may be the reason that your program is not printing anything.
you can try adding some logging statements and check if the sequence is proper on not.
EventQueue#invokeLater adds a task to the event queue, so it might not be done when coming to the next line.
Use EventQueue#invokeAndWait instead, it waits for the task to finish.
There are a few problems with your code. Some of them actually leads to the problem, and some just shows that you don't really understand what you are trying to do.
private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
Why are you using volatile on this? Each thread have their own animals list, so they are just used by one thread. If your main class had a animals model that everyone added to, you would have needed to make it volatile, since multiple threads could access it.
animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
This isn't going to change anything. It might be useful if you think the method could get called multiple times and you want a fresh list each time, but it's probably just a waste.
Now onto the real problem:
When you call a thread it's because you want it to run in the background and not stop the main program execution. Then you can get back to the result at some time when it's actually finished. As people have said, if you just want a new thread without it really running in the background you could do EventQueue#invokeAndWait, but for your case this isn't the solution.
You could use the observer pattern. To do this you make an interface that has a notify method (call it parseListner or something). The parser has a list of parseListerners. When the parser finish parsing it tells all the listeners (by calling a method on the interface). So you end up with code sort of like this:
public interface ParseListner{
void fileParsed(String fileName, List<Animal> animals);
}
public class Main implements ParseListner{
public void main(){
ParseCSV parser = new ParseCSV(this);
EventQueue.invokeLater(filePath, parser);
}
public void fileParsed(String fileName, List<Animal> animals){
System.Out.Println(doneParsing);
}
}
public class ParseCSV implements Runnable{
List listners = new ArrayList<>();
public ParseCSV(String path, ParseListner caller) {
listner.add(caller)
}
#Override
public void run() {
//all the parsestuff
for(ParseListner p : listners)
p.parsedFile(fileName, animals);
}
I used a list because it's almost always useful (so you can do multiple things when it's done).
Related
How do I write in same text file from different classes in java.
One of the class call method from another class.
I do not want to open BufferedWriter in each class, so thinking if there is a cleaner way to do this ?
So essentially, I want to avoid writing the following code in each class
Path path = Paths.get("c:/output.txt");
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
writer.write("Hello World !!");
}
A good way of doing this is to create a central writing class, that maps from a file name to a reader/writer-object. For example:
public class FileHandler {
private static final Map<String, FileHandler> m_handlers = new HashMap<>();
private final String m_path;
private final BufferedWriter m_writer;
// private final BufferedReader m_reader; this one is optional, and I did not instantiate in this example.
public FileHandler (String path) {
m_path = path;
try {
m_writer = Files.newBufferedWriter(path);
} catch (Exception e) {
m_writer = null;
// some exception handling here...
}
}
public void write(String toWrite) {
if (m_writer != null) {
try {
m_writer.write(toWrite);
} catch (IOException e) {
// some more exception handling...
}
}
}
public static synchronized void write(String path, String toWrite) {
FileHandler handler = m_handlers.get(path);
if (handler == null) {
handler = new FileHandler(path);
m_handlers.put(path, toWrite);
}
handler.write(toWrite);
}
}
Be aware that this behavior does not close the file writers at any point, because you don't know who else is currently (or later on) writing. This is not a complete solution, just a strong hint in a good direction.
This is cool, because now you can "always" call FileHandler.write("c:output.txt", "Hello something!?$");. The FileHandler class could be extended (as hinted) to read files too, and to do other stuff for you, that you might need later (like buffer the content, so you don't have to read a file every time you access it).
Here's my code. I apologize for the sloppiness but essentially what it's supposed to do is simulate the backwards learning algorithm used by switches. The handleInput method takes in the src and dest MAC addresses and a port number and adds the src MAC and port# as a HashMaps into an ArrayList. The whole method is useless right now because none of the HashMaps stay in the ArrayList for some reason. Any help is much appreciated!
public class Switching {
ArrayList<HashMap> switchTable = new ArrayList<HashMap>();
public String handleInput(String srcMacAddress, int portNumber, String destMacAddress){
String output = "";
HashMap tableEntry = new HashMap();
tableEntry.put(srcMacAddress, portNumber);
for (HashMap hm : switchTable) {
if (hm.containsKey(destMacAddress)) {
output += hm.get(destMacAddress).toString();
} else {
output += "Ports flooded";
}
}
switchTable.add(tableEntry);
return output;
}
public ArrayList<HashMap> getTable(){
return switchTable;
}
public class SwitchingTests {
#Test
public void testSwitching(){
new Switching().handleInput("123456", 12, "abcdef");
ArrayList<HashMap> switchingTable = new Switching().getTable();
Assert.assertEquals(switchingTable.toString(), "[{123456=12}]");
}
}
You are creating a Switching object and call handleInput(...) on it and then proceed to create a new Switching object and get its table.
You need to get the table from the one you already created.
public class SwitchingTests {
#Test
public void testSwitching(){
Switching switching = new Switching();
switching.handleInput("123456", 12, "abcdef");
ArrayList<HashMap> switchingTable = switching.getTable();
Assert.assertEquals(switchingTable.toString(), "[{123456=12}]");
}
}
inside your handleInput method you are creating new switchTable.
what you have to do is to change your line
switchTable = new ArrayList() to switchTable = getTable();
I am trying to programm a tool, which does replicate updated files into a folder structure. This folder structure is separated into "instances", so the root folder shows those:
Test1 [Directory]
Test2 [Directory]
Test3 [Directory]
Within those directories, there are further directories and of course files. As I want to update a few files within those folders (the updated files are within another folder, where my tool has access to), I search the whole structures. The updated filenames are identical to those old, within Test1, Test2 and Test3, respectively their subfolders.
I looked up a recursive method to go through those folders and search. When my tool finds a second file within the same instance, it has to throw an error and end the for-loop.
In addition, after looking up for one update-file (patchfile), the temporary list, where I check if a duplicate exists, gets emptied. This all works fine, as in the code.
But by looking forward to the step where I want to replace the old file in the instances with the patchfile from the patchfolder, I get confused and don't know how to work.
I planned to map the place of the old (scanned) file (value in the map) and the actual patchfile (key) and just work over the elements within the map. But where do I place the put-function perfectly? The nested loops within my main-methode (iterating over the instances and iterating over the many patchfiles) in addition to the recursive method of scanning on instance, makes me confused where to put the "map.put(...)".
Here is my code so far. In addition, if you have advice in optimizing, I would be greatful to hear.
Further mentiones: My tool gets the parentfolder of the instances via an xml and JAXB and puts the list of instances, which are scanned into an ArrayList (instances -> getInstances())I iterate over.
public class Main {
public static void main(String[] args) throws SAXException, JAXBException {
XMLHandler xmlhandler = new XMLHandler();
InstanceManager manager = new InstanceManager();
PatchFileManager patchManager = new PatchFileManager(xmlhandler.getUpdateFolder());
patchManager.scanDirectoryForPatches();
ArrayList<PatchFile> patchFilesname = patchManager.getPatchFiles();
manager.setPathnameToScan(xmlhandler.getTargetFolder());
manager.scanDirectoryForInstances(manager.getPathnameToScan());
PatchManager ptchmngr = new PatchManager();
outerloop:
for (PatchFile f : patchFilesname) {
for (Instance e : manager.getInstances()) {
ptchmngr.scanInstallationForPatchFile(e.getPathname(), f);
if(ptchmngr.getPatchSearchTempChecker().size()>1){
System.out.println("loop stopped");
break outerloop;
}
}
}
....
}
}
And the actual class, where the scanning for the folders happens (getters- and setters excluded)
public class PatchManager {
private InstanceManager theInstanceManager;
private ArrayList<BackUp> backUpList = new ArrayList<BackUp>();
private ASPXManager theAspxHandler;
private ArrayList<PatchFile> patchFileList = new ArrayList<PatchFile>();
private LogManager theLogManager;
private ArrayList<String> patchSearchTempChecker = new ArrayList<String>();
private HashMap map = new HashMap();
public void copyPatch(PatchFile patchfile) {
}
public void searchFiles(PatchFile patchFile) {
}
public void createBackUp(PatchFile patchfile) {
}
public void scanInstallationForPatchFile(String searchstart, PatchFile patchfile) {
File filetoSearch = new File(searchstart);
try {
if (filetoSearch.isDirectory()) {
System.out.println("Searching directory..." + filetoSearch.getAbsolutePath());
if (filetoSearch.canRead()) {
for (File temp : filetoSearch.listFiles()) {
if (patchSearchTempChecker.size() > 1) {
throw new DoubleDefinitionException();
}
if (temp.isDirectory() && !(temp.getName().equals("Images"))) {
scanInstallationForPatchFile(temp.getAbsolutePath(), patchfile);
} else {
if (patchfile.getFilename().toLowerCase().equals(temp.getName().toLowerCase())) {
patchSearchTempChecker.add(temp.getAbsolutePath().toString());
System.out.println(patchSearchTempChecker.size());
}
}
}
}
} else {
System.out.println("Permission denied");
}
} catch (
DoubleDefinitionException ex)
{
System.out.println("File does exist multiple times within instance, proceed manually");
}
}
//Getters and Setters
//...
//
}
Can someone please check my code and determine why my pickup function's not working.
-- write missing methods for these procedures to occur
Dog bob = new Dog(5);
System.out.println(bob);
bob.walk();
bob.walk();
bob.pickUp("Tennis ball");
System.out.println(bob);
bob.drop();
bob.bark();
System.out.println(bob);
-- In my class where I've defined the pickUp method:
public Head()
{
}
public void pickUp(String object)
{
this.object = object;
System.out.println("Picked up "+object);
}
public String getObject()
{
return object;
}
public void drop()
{
System.out.println("Dropped "+object);
object = null;
}
public void bark()
{
System.out.println("WOOF!");
}
public String toString()
{
return "Head is holding "+ object;
}
}
-- The other class where I'm utilising the method:
public class Dog
{
private int position;
private Leg hind1;
private Leg hind2;
private Leg front1;
private Leg front2;
private Head head = new Head();
//Constructor for Dog class
public Dog(int position)
{
hind1 = new Leg(position-2);
hind2 = new Leg(position-2);
front1 = new Leg(position+2);
front2 = new Leg(position+2);
}
public void walk()
{
front1.step();
front2.step();
hind1.step();
hind2.step();
System.out.println("Pitter patter...");
}
public String toString()
{
return "Head is holding " + head+", Leg at "+hind1.position+", Leg at "+ hind2.position+", Leg at "+front1.position+", Leg at "+front2.position;
}
public void pickup()
{
head.pickUp(head.object);
}
public void drop()
{
head.drop();
}
public void bark()
{
head.bark();
}
PS. head is a new object I've made which belongs to the Head Class, Which is where the first code is from. I'm currently trying to get the second code working to display a picked up object that head picked up.
-EDIT : Even if I do put a string in(Eg. head.pickUp("ball");), it still displays "cannot find symbol - method.pickUp(java.lang.String)" when I try running the procedures.
EDITED (a third time!): Now that you've posted your code, I've confirmed that my answer below is correct. Tl;dr - you're trying to use head.object before it's been set. What you should be passing in to pickUp is a string that represents the name of the object you want to pick up. For example, head.pickUp("ball");
It would help if you could clarify a bit more what you mean by "not working" - however, it looks like you've got a sort of chicken-and-egg problem here:
If I'm reading this right, your code looks something like this? (Including the entire class in your comment might help)
public class Head {
String object;
public void pickUp(String object)
{
this.object = object;
System.out.println("Picked up "+object);
}
}
public class SomeOtherClass {
Head head = new Head();
public void pickup()
{
head.pickUp(head.object);
}
}
EDITED (again) for clarity - It looks like you're trying to use the pickup function (the one in SomeOtherClass) to define the object property of your head. However, by calling it with head.object, you assume that head.object is already defined. Where are you actually setting the string you want to use?
It's not really clear what you're trying to accomplish here - but you might want to try either 1) setting head.object in a constructor in your head class. or 2) calling head.pickUp with a string other than head.object (which hasn't been set yet). - Try replacing head.object with "Hello World", for starters. Or, if I've totally misunderstood your intent, perhaps give us a bit more context?
EDITED - because I realized that your pickup function wasn't in Head.
I'm new to Android and Java but do have some experience in Objective C and iPhone programming. I'm attempting to recreate an app I've already designed for the iPhone and am getting stuck on what should be a simple concept.
In my ParserHandler class I am parsing an XML from a server and putting the data into three separate ArrayList's. The parsing appears to be working fine. When I log and iterate through the ArrayList within my ParserHandler.java class it all works fine.
(List1.java class has a few string variables and I've declared it like so in the ParserHandler: private List1 theList = new List1(); )
for(int i = 0; i<dogArray.size(); i++){
theList = dogArray.get(i);
Log.i(TAG, "looping " + i + " " + theList.Name);
Log.i(TAG, "looping " + i + " " + theList.PhotoUrl);
Log.i(TAG, "looping " + i + " " + theList.Type);
}//this loops fine and has all the data
The dogArray is declared like so: public ArrayList<List1> dogArray = new ArrayList<List1>();
Now I want to access the dogArray from the class DogListView.java so in the onCreate method I attempt to do the following:
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.dog_list_view);
ParserHandler ph = new ParserHandler();
int d = ph.getNumberofDogs();
int m = ph.dogArray.size();
Log.i(TAG, "dog size is:" + d + "and:" + m);}
I've tried two different ways and both always return "0" in the log. However the correct size is always logged and all the data is there when the log comes from the ParserHandler.java class.
This is the accessor method in ParserHandler.java.
public int getNumberofDogs(){
return dogArray.size();
}
I'd prefer to access the dogArray via accessor method (as this seems to be best practice from what I've gathered) however I'm open to all suggestions.
Thanks in advance!!
EDIT 8/23/12
I ended up solving the problem by declaring my ArrayLists Static. I know this (and public) approach my not be ideal for OOP but i'm going with it. In my ParserHandler.java I declared
public static ArrayList<List1> dogArray = null;
public static ArrayList<List1> otherArray = null;
public static ArrayList<List1> catArray = null;
Then begin my SAX parser:
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
if (qName.equalsIgnoreCase("ArrayOfDataFeedAnimal")){
catArray = new ArrayList<List1>();
dogArray = new ArrayList<List1>();
otherArray = new ArrayList<List1>();
}else if(qName.equalsIgnoreCase("DataFeedAnimal")){
theList = new List1();
}
then the rest of my SAX parsing stuff happens. Lastly, from whatever class I want to access the array i simply do that in the static way by ParserHandler.dogArray.size() to get the size of the array. I can now manipulate the array any way i see fit from whatever class i need to get it.
I'm still unclear why creating an instance of the ParserHandler class hasn't worked for me with my parsed ArrayLists because when it worked fine when I tested with a simple int[].
hopefully this can help someone else in the future.
Thanks again for everyones feedback!
Cheers!
you can do it in two ways,
Create a setter/getter class
Make a public static method that returns ArrayList
First Method:
class name : myDataObject.java
private ArrayList myArrayList;
// setting the ArrayList Value
public void setArrayList ( ArrayList myArrayList )
{
this.myArrayList = myArrayList;
}
// getting the ArrayList value
public ArrayList getArrayList()
{
return myArrayList;
}
Second Method:
In ArrayList file, ( suppose class name is class A.java )
private static ArrayList myArrayList = null;
...
// assign arraylist
public static ArrayList getArrayList()
{
return myArrayList;
}
in the calling activity/class you can call it using following code,
private ArrayList newArrayList = null;
newArrayList = A.getArrayList();
You should not make the Methods static.Because that is not an OOP Design then.
There are 2 ways:
1). Either make the properties public. (Not a good practise either)
2). add getters and setters for ParserHandler class
class ParserHandler {
private List<List1> dogArray = new ArrayList<List1>();
public List<List1> getDogArray() {
return this.dogArray;
}
public void setDogArray(List<List1> dogArray) {
this.dogArray = dogArray;
}
}
Now access dogArray Like this
ph.getDogArray();
int m = ph.getDogArray().size();
Initially it will be 0 since it is an empty list. Use the setter method to set the array first
Note that in your oncreate you are doing a file operation in your ParserHandler which parses the xml file as your data. This could potentially block the UI thread if the ParserHandler is not processed in a separate thread. However if you processed in a separate thread then your int d = ph.getNumberofDogs(); may return 0 even if there are data in your xml because of race conditions between UI thread and the separate thread processing the parsing.
The best solution in my opinion is to create a listener when the parsing is done so that you are pretty sure that the processing is done before you access the size of the list.
add this in your ParserHandler class
class ParserHandler {
...... your original codes here
private OnParsingDoneListener mListener;
public void setOnParsingDoneListener (OnParsingDoneListener listener){
mListener = listener;
}
public static interface OnParsingDoneListener {
public void onParsingDone (List dogList);
}
}
make sure to call mListener.onParsingDone when youre done parsing xml data.
In Your onCreate()...
ParserHandler ph = new ParserHandler();
ph.setOnParsingDoneListener (new ParserHandler.OnParsingDoneListener(){
public void onParsingDone(List dogList){
// do whatever you want to the doglist
// at this point all parsing is done and dogList contains the data from xml
}
});