Put into map after recursive directory-scan - java

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
//...
//
}

Related

Share limited amount of resources between different threads

I write selenium tests and make it parallel via testng.
There are some tests which should use resource, and that resource cant be used in tests, while it using in another test.
So to make it clear let me describe in other words, I have 10 resources, and when some test start working with one of them, only 9 another resources should be available in another tests. If all 10 resources are busy, and another test attempts to get it, it should wait until one of test will finish execution and free it's resource.
Im trying to create provider which will control desired behaviour but it looks like I get deadlocks, because it hangs out some times at synchronized method call.
My plan is provider have 2 methods get() and remove()
get() called in test method to get resource
remove() called in method annotated with #AfterMethod annotation and this method is default method of specific interface which should be implemented in class, containing resource usage
Here is provider class:
public class ResourceProvider {
private static final Logger logger = LogManager.getLogger();
private static List<Resource> freeResources;
private static Map<String, List<Resource>> resourcesInUse;
static {
freeResources = new ArrayList<>();
//here is resource initialization to fill freeResources list
resourcesInUse = new HashMap<>();
}
public static synchronized Resource get() {
String testName = Thread.currentThread().getStackTrace()[2].getClassName()
+ "." + Thread.currentThread().getStackTrace()[2].getMethodName();
Resource resource = null;
logger.info(String.format("Attempt to get resource for %s test", testName));
for (int i = 0; i < 240; i++) {
if (freeResources.isEmpty()) {
try {
Thread.sleep(5_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
resource = freeResources.get(0);
if (resourcesInUse.containsKey(testName)) {
resourcesInUse.get(testName).add(resource);
} else {
List<Resource> resources = new ArrayList<>();
resources.add(resource);
resourcesInUse.put(testName, resources);
}
freeResources.remove(resource);
break;
}
}
if (resource == null) {
throw new RuntimeException(String.format("There is no free resource for '%s' in 20 minutes", testName));
}
logger.info(String.format("Resource %s used in %s", resource, testName));
return resource;
}
public static synchronized boolean remove(ITestResult result) {
String testName = result.getMethod().getTestClass().getName() + "." + result.getMethod().getMethodName();
return remove(testName);
}
public static synchronized boolean remove(String testName) {
boolean isTestUseResource = resourcesInUse.containsKey(testName);
if (isTestUseResource) {
logger.info(String.format("Removing %s resources, used in %s", resourcesInUse.get(testName), testName));
freeResources.addAll(resourcesInUse.get(testName));
resourcesInUse.remove(testName);
}
return isTestUseResource;
}
Interface:
public interface RemoveResource {
#AfterMethod
default void removeResource(ITestResult result) {
ResourceProvider.remove(result);
}
But this code doesnt work good, it hangs out at remove() call sometimes.
May you help me to understand why I get hangs out and how to resolve it?

how to use a list in another class?

I want to create a list, add blocks to it and then use it in a BlockBreakEvent to check if the block is in the list and cancel the event if it's not. But I can't seem to create and add things in it any other way than in the actual event itself (which looks to me like it would create issues). The only thing that is working for me is creating the list in the event and adding blocks to it one by one which looks really messy compared to: creating the list in a separate class and just checking the list with if(Listname.contains(block)) does anyone know how I can achieve this? Whether its dependency injection, or whatever else. I just can't figure out how to put it to use.
Here's what I've tried and is currently working for me, but I believe it's theoretically incorrect:
public class Event implements Listener {
#EventHandler
public void onBreak(BlockBreakEvent e) {
List<Material> allowedblocks = new ArrayList<Material>();
allowedblocks.add(Material.STONE);
//repeat this 10-50 times for whatever item
Player p = e.getPlayer();
Material block = e.getBlock().getType();
if(allowedblocks.contains(block)){
p.sendMessage("Invalid block. Break cancelled");
e.setCancelled(true);
}else{
p.sendMessage("Valid Block");
}
}
}
You can make allowedBlocks List a class field and fill it with elements inside of the constructor.
public class YourClass {
private List<Material> allowedBlocks = new ArrayList<>();
public YourClass() {
allowedBlocks.add(Material.STONE);
//repeat this 10-50 times for whatever item
}
#EventHandler
public void onBreak(BlockBreakEvent e) {
Player p = e.getPlayer();
Material block = e.getBlock().getType();
if(allowedBlocks.contains(block)){
p.sendMessage("Valid Block");
} else {
p.sendMessage("Invalid block. Break cancelled");
e.setCancelled(true);
}
}
}
Another approach would be to make the list static and fill it with values inside of a static block. I would not recommend making the list static if you are planning to change its values, but if your allowed blocks are going to remain the same, it may be a good idea to even go further and make it public, so you can access it from anywhere without an instance of YourClass
public class YourClass {
public static final List<Material> allowedBlocks;
static {
List<Materials> list = new ArrayList<>();
list.add(Material.STONE);
//repeat this 10-50 times for whatever item
//use an unmodifiable list,
//so you do not accidentally change its content later
allowedBlocks = Collections.unmodifiableList(list);
}
#EventHandler
public void onBreak(BlockBreakEvent e) {
Player p = e.getPlayer();
Material block = e.getBlock().getType();
if(allowedBlocks.contains(block)){
p.sendMessage("Valid Block");
} else {
p.sendMessage("Invalid block. Break cancelled");
e.setCancelled(true);
}
}
}
In the first case, there will be a list of allowedBlocks per instance of YourClass, which means, that every time you call new YourClass() a new List will be created and filled. In the second case, there will be only one list which will be created and populated on class loading (at the very beginning of the program) start up.
P.S. I would rather use a Set instead of a List here, considering you are using contains very often.
Since you are using an enum to store your Material types, you can simply call the static .values() method through Material.
Ex:
#EventHandler
public void onBreak(BlockBreakEvent e) {
Player p = e.getPlayer();
Material block = e.getBlock().getType();
if(List.of(Material.values()).contains(block)){
p.sendMessage("Invalid block. Break cancelled");
e.setCancelled(true);
}else{
p.sendMessage("Valid Block");
}
}
}
If you need to be able to customize what values are in the List you can use the singleton pattern to access that information globally.
The instance can be accessed statically from anywhere in the application:
import java.util.List;
public class BlockController {
public static BlockController instance = new BlockController();
private List<Material> allowedBlocks;
public BlockController() {
this.allowedBlocks = new ArrayList<>();
}
public void addAllowedBlock(Material mat) {
this.allowedBlocks.add(mat);
}
public void removeAllowedBlock(Material mat) {
this.allowedBlocks.remove(mat);
}
public boolean containsBlock(Material mat) {
return this.allowedBlocks.contains(mat);
}
public void clear() {
this.allowedBlocks.clear();
}
/**
* You can add more functionality here...
* This class can be accessed anywhere in the application
*
* use:
*
* BlockController controller = BlockController.instance;
* controller.containsBlock(Material.BLOCK);
*/
}
One approach to creating the list in a separate class is to use a static initializer block:
public class MyClass {
public static final List<Material> ALLOWED_MATERIALS = new ArrayList<>();
static {
ALLOWED_MATERIALS.add( Material.STONE );
}
public static List<Material> getAllowedMaterials() {
return Collections.unmodifiableList( ALLOWED_MATERIALS );
}
...
}
Try to create the List in a static context. This way the list is the same for all instances:
public class MyClass {
public static List<Material> allowedblocks = new ArrayList<Material>();
#EventHandler
public void onBreak(BlockBreakEvent e) {
allowedblocks.add(Material.STONE);
...
Then you can call the List from everywhere like this (e.g. if statement):
if(MyClass.allowedblocks.contains(block))
Your problem seems similar to this question, maybe this answer helps too: .

Adding custom class objects to list showing ambiguity

This is a sample test code I wrote to ensure what I know is right
class Form {
List<Sample> samples;
List<Sample> sampleList;
public List<Sample> getSamples() {
return samples;
}
public void setSamples(List<Sample> samples) {
this.samples = samples;
}
public List<Sample> getSampleList() {
return sampleList;
}
public void setSampleList(List<Sample> sampleList) {
this.sampleList = sampleList;
}
void setInitialData() {
this.samples = new ArrayList<Sample>();
this.sampleList = new ArrayList<Sample>();
}
}
class Sample {
}
public class ListAddingAmbiguity {
public static void main(String[] args) {
Form form = new Form();
form.setInitialData();
Sample sample = new Sample();
form.getSamples().add(sample);
form.getSampleList().add(sample);
System.out.println(form.getSamples().size());
System.out.println(form.getSampleList().size());
}
}
The output coming is
1
1
And it is correct, samples and sampleList are two different references pointing to two different memory locations, so adding to samples won't change the size of sampleList.
But in my project code it is different, this is my Form class
public class InvoiceForm extends BaseActionForm {
private List<ProductTO> products;
private List<ProductTO> productList;
// getters and setters
}
This is the code in my Action class
private void setProductsToInvoice(InvoiceForm invoiceForm) throws Exception {
if(invoiceForm.getProducts() != null && !invoiceForm.getProducts().isEmpty()){
ProductTO productTO = new ProductTO();//ProductEntryHandler.getInstance().prepareProductsForInvoice();
invoiceForm.getProducts().add(productTO);
invoiceForm.getProductList().add(productTO);
}else {
List<ProductTO> productTOs = new ArrayList<ProductTO>();
productTOs.add(ProductEntryHandler.getInstance().prepareProductsForInvoice());
invoiceForm.setProducts(productTOs);
invoiceForm.setProductList(productTOs);
}
}
Both the products and productList are having a size of 1 initially, so in the above code if block will execute. The commented portion is the earlier code. Even if it is the new code ProductTO productTO = new ProductTO(); or the old code ProductTO productTO = ProductEntryHandler.getInstance().prepareProductsForInvoice(); the problem is the same.
Like I said when execution comes to the method both the lists are having a size of 1. When the line invoiceForm.getProducts().add(productTO); is executed the size of products and productList size becomes 2, which is in conflict with my test code. Now when the nest line invoiceForm.getProductList().add(productTO); is executed both the list size is becoming 3. I don't know why its happening, can anybody help?
The following code else case in setProductsToInvoice set both products and productList to the same list:
List<ProductTO> productTOs = new ArrayList<ProductTO>();
productTOs.add(ProductEntryHandler.getInstance().prepareProductsForInvoice());
invoiceForm.setProducts(productTOs);
invoiceForm.setProductList(productTOs);
The correct way, or at least the less incorrect way, is something like this:
ProductTO newProd =
ProductEntryHandler.getInstance().prepareProductsForInvoice());
invoiceForm.setProducts(new ArrayList<ProductTO>());
invoiceForm.getProducts().add(newProd);
invoiceForm.setProductList(new ArrayList<ProductTO>());
invoiceForm.getProductList().add(newProd);
I'd suggest an investigation to determine why there are two lists apparently being maintained in parallel in the first place. At first glance, it has a bit of a smell to it...

field goes out of scope java

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).

Sencha: Iterating a list store of a custom BaseModel subclass

I just started playing with Sencha's Ext GWT yesterday and I've hit a wall. I combined methods from their JSON loaded grid and their editable grid. As a test data set I'm using a list of Stargate Atlantis episodes hence the SGAEpisode which is defined as:
public class SGAEpisode extends BaseModel {
public SGAEpisode() {
}
public SGAEpisode(String season, String episode) {
set("season",season);
set("episode",episode);
}
public void setSeason(String season) {
set("season",season);
}
public String getSeason(){
return get("season");
}
public void setEpisode(String name) {
set("episode",name);
}
public String getEpisode() {
return get("episode");
}
public String toString() {
return "Season: " + get("season") + " episode: " + get("episode");
}
}
the onModuleLoad() starts off with...
ModelType type = new ModelType();
type.setRoot("seasons");
type.addField("Season","season");
type.addField("Episode","episode");
String path = GWT.getHostPageBaseURL() + "senchaapp/sgaepisodes";
final RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,path);
final MVProxy<String> proxy = new SProxy<String>(builder);
JsonLoadResultReader<ListLoadResult<SGAEpisode>> reader = new JsonLoadResultReader<ListLoadResult<SGAEpisode>>(type);
final BaseListLoader<ListLoadResult<SGAEpisode>> loader = new BaseListLoader<ListLoadResult<SGAEpisode>>(proxy,reader);
final ListStore<SGAEpisode> episodes = new ListStore<SGAEpisode>(loader);
so loader.load() works great, populating a grid, I can edit fields, but I don't see commitChanges() doing anything and I can't iterate over the ListStore "episodes" to gather changed or added values. Oh, and SProxy is just a DataProxy subclass to allow me to specify the season's JSON I'm loading into the grid.
If I try either
for(SGAEpisode episode : episodes) {
save(episode);
}
or
for(int i = 0; i < episodes.getCount(); i++) {
save(episodes.getAt(i));
}
I get an exception with the message "com.extjs.gxt.ui.client.data.BaseModel cannot be cast to com.mvsc.sencha.shared.SGAEpisode" Any idea what I'm doing wrong? Everything up to that point was defined/populated with SGAEpisodes.....
Addendum
Ok, so if I try
List<Record> modified = episodes.getModifiedRecords();
for(Record r : modified) {
ModelData md = r.getModel();
save(md.get("season"),md.get("episode"));
}
I can iterate, and get the modified values, but what's the point of having a ModelData subclass if I have to use the base class like this. Which makes me think I don't in fact have to..... little help?
Addendum 2 I tried subclassing BaseModelData instead with no success.
I know its an older post, I had the same issue. This is how I fixed it.
try iterating through the models in listStore.
for(SGAEpisode episode : episodes.getModels()) {
save(episode);
}

Categories