RedBlackTree delete using insert-method (StackOverFlowError) - java

I somehow get a StackOverFlowError when testing my following method. The tests and helper functions are 100% correct. I'm trying to implement a delete-method for a BinarySearchTree using the insert-method I already implemented (and works).
Here is my code:
public void delete(TreeNode toDelete) {
TreeNode _rootTmp = _root;
RedBlackTree tree = new RedBlackTree();
if(_root == null) {
tree.insert(_root);
}
if(_rootTmp.left != _nil) {
if(!_rootTmp.left.equals(toDelete)) {
tree.insert(_rootTmp.left);
}
delete(_rootTmp.left);
}
if(_rootTmp.right != _nil) {
if(!_rootTmp.right.equals(toDelete)) {
tree.insert(_rootTmp.right);
}
delete(_rootTmp.right);
}
if(_rootTmp.left == _nil && _rootTmp.right == _nil) {
_root = tree._root;
}
}
At our RedBlackTree Class we use _nil instead of null for checking if there is another node or not.
Thanks for your help!!

Related

How do i create unit test for a client service with void methods?

I want to create a unit test for a client service.
The function of the client service is to call the webservice, get data, and update the database as scheduled.
The scheduled method return void.
How to create unit test for a
client service
schedule method
void returning methods
The client is like this:
#ApplicationScoped
public class ClientClass {
private static final Logger LOGGER = Logger.getLogger(VdsClient.class);
#Inject
Client client;
VMR vmr;
CommandService commandService;
public VdsClient(VMR vmr,
CommandService commandService) {
this.vmr = vmr;
this.commandService = commandService;
}
#Scheduled(XXX)
public void getVal() {
var monitoringStateFilter =
new VMF.vmf(true, true);
var monoResultList =
vmr.fvms(monitoringStateFilter)
.collectList();
if (monoResultList != null) {
var resultList = monoResultList.block();
if (resultList != null) {
resultList.stream()
.map(row -> row.getValue("val", val.class))
.map(vin -> this.updateEstimate(val.getValue()))
}
}
}
public Tuple2<String, Boolean> updateEstimate(String val) {
List<route> routeList;
try {
routeList = vdsClient.getval(val)
.getItem();
boolean hasDealerDestination = false;
for (Route route : routeList) {
if (vd.DestLocationType._00.value()
.equals(route.getTransportConnectionPointTyp())) {
hasDealerDestination = true;
var estimate = DateTimeUtil.convertToInstantWithOffset(route.getArrivalDate(),
route.getArrivalTime(), route.getTimezone(), DateTimeUtil.PATTERN_LONG_DATE);
if (estimate == null) {
return Tuples.of(val, false);
}
var result = this.updateVehicleEstimate(val, estimate);
return Tuples.of(val, result);
}
}
if (!hasDealerDestination) {
return Tuples.of(val, false);
} else {
return Tuples.of(val, false);
}
} catch (route e) {
return Tuples.of(val, false);
} catch (Exception e) {
return Tuples.of(val, false);
}
}
public Boolean updateVehicleEstimate(String val, Instant estimate) {
var vehicleUpdate = vu.vuc.builder()
.val(new Val(val))
.Estimate(estimate)
.build();
return (Boolean) cs.ec(vu).block();
}
A unit should only be testing that a particular unit of code is working fine. In your case, for the unit test, you should assume that the webservice will return the data and the db updation works fine. We can accomplish this through mocking the response for each of these calls.
For void returning methods, you can actually verify if the call was indeed made or not.
For example:
Mockito.verify(mockedObject, Mockito.times(1)).callWebService(mockedParameter1, mockedParameter2);
There is another way, though I personally don't prefer that:
You can declare a class variable and make sure the value updates itself whenever the scheduled method reaches the end of the code. Read that value in your test and assert on its value. If the value is updated, then your code worked fine, else NO and it's a failure.
Also, in case you want to actually make sure the webservice returned the correct response / db entry was updated, then those should be part of integration tests and not unit tests.

How to delete empty directories recursively without deleting parent folder?

Following function is used to delete empty directories inside backup folder. But problem with this method is it deletes backup folder as well if it is empty.
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
if(folder.listFiles().length == 0){
folder.delete();
}else {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if(fileEntry.listFiles().length == 0){
fileEntry.delete();
}
}
}
}
}
Assuming my folder structure is as follows,
backup
-2019
-10
-15
-2020
If I call method as deleteEmptyDirectoriesOfFolder(backup) it deletes backup folder as well. Any suggestions to fix it without including a second parameter to the method?
Your so close, just break it in two methods:
deleteEmptySubDirectoriesOfFolder-Calls current method for all subdirectories
deleteEmptyDirectoriesOfFolder-Your current method.
Here is the new method:
public static void
deleteEmptySubDirectoriesOfFolder(final File folder)
{
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if(fileEntry.listFiles().length == 0){
fileEntry.delete();
}
}
}
}
Have a wrapper class around File as below
class FileWrapper {
private File folder;
private boolean isRoot;
}
when you call deleteEmptyDirectoriesOfFolder for the first time, initialize FileWrapper as
File folder = new File("<backup_dir_path>");
FileWrapper fileWrapper = new FileWrapper(folder, true);
deleteEmptyDirectoriesOfFolder(fileWrapper);
then slightly change deleteEmptyDirectoriesOfFolder method as
public static void deleteEmptyDirectoriesOfFolder(final FileWrapper fileWrapper) {
if(fileWrapper.getFolder().listFiles().length == 0 && !fileWrapper.getIsRoot()){
fileWrapper.getFolder().delete();
}else {
for (final File fileEntry : fileWrapper.getFolder().listFiles()) {
if (fileEntry.isDirectory()) {
FileWrapper fileWrapper = new FileWrapper(fileEntry, false);
deleteEmptyDirectoriesOfFolder(fileWrapper);
if(fileEntry.listFiles().length == 0){
fileEntry.delete();
}
}
}
}
}
Actually...I'm very surprised that you don't ever get a NullPointerException. I think you should. Based on the directory structure example you provided, I interpret the tree to be:
- backup
- 2019
- 10
- 15
- 2020
As your for loop within the deleteEmptyDirectoriesOfFolder() method iterates through the folders it does a recursive call against any sub-directory determined by
fileEntry.isDirectory(). A recursive call eventually gets to the sub-directory named 15 in which case a final recursive call is made. Upon that final recursive call the condition for the if statement above the for loop
if (folder.listFiles().length == 0) {
folder.delete();
}
becomes true and ultimately the sub-directory is deleted and the recursive call is returned to the previous recursive call except now, because the folder (15) is deleted fileEntry.listFiles() becomes null hence when checking for fileEntry.listFiles() again (within the for loop under the recursive call):
deleteEmptyDirectoriesOfFolder(fileEntry);
if (fileEntry.listFiles().length == 0) { // HERE
fileEntry.delete();
}
a NullPointerException should be thrown. You want to ignore the ones that are null so, you should perhaps check to see if fileEntry.listFiles() is null before attempting to play on it, like this:
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
if (folder.listFiles().length == 0) {
folder.delete();
}
else {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if (fileEntry.listFiles() != null && fileEntry.listFiles().length == 0) {
fileEntry.delete();
}
}
}
}
}
If you don't want to also delete the backup folder if it is empty then just use the for loop (the backup directory should remain):
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if (fileEntry.listFiles() != null && fileEntry.listFiles().length == 0) {
fileEntry.delete();
}
}
}
}
Your method should now function properly.
Here is my solution after going through other answers,
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
deleteEmptyDirectoriesOfFolder(folder, true);
}
private static void deleteEmptyDirectoriesOfFolder(final File folder, boolean isRoot) {
if(!isRoot && folder.listFiles().length == 0){
folder.delete();
}else {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
File parent = fileEntry.getParentFile();
deleteEmptyDirectoriesOfFolder(fileEntry,false);
if(!isRoot && parent != null && parent.listFiles().length == 0){
parent.delete();
}
}
}
}
}

Why `break label` cannot be used inside lambda expression? Any workaround?

I am trying to implement a retry mechanism for HTTP request with a HTTPClient library. For the retry mechanism, I have a list of website to try and I will try each website for retries times. The process ends when I receive a status 200 from any of the requests.
My idea is to use a boolean requestSuccess and a label requestLabel. I will set requestSuccess = true and break the requestLabel when I receive a status 200. However, variable must be (effectively) final and break label is not available inside lambda expression.
Is there any workaround to implement such retry mechanism?
boolean requestSuccess = false;
requestLabel:
for(String site: sites) {
for(int i = 0; i < retries; i++) {
client.request(site, data, requestOptions, (err, res, content) -> {
if(err == null) {
requestSuccess = true;
break requestLabel;
} else {
log(...);
}
})
}
}
if(!requestSuccess) {
log("request failed");
}
One possible answer
Inspired by a submitted then deleted answer, I can use a wrapped-class-like solution. I think it would work, but it seems dirty?
boolean[] requestSuccess = new boolean[1];
requestLabel:
for(String site: sites) {
for(int i = 0; i < retries; i++) {
if(requestSuccess[0] == true) {
break requestLabel;
}
client.request(site, data, requestOptions, (err, res, content) -> {
if(err == null) {
requestSuccess[0] = true;
} else {
log(...);
}
})
}
}
if(!requestSuccess) {
log("request failed");
}
A lambda gets turned into it's own class under the hood. It would be as if you have two classes as far as the java interpreter is concerned.
class Main {
public void runstuff() {
labelX:
for(...) {
client.request(new Main$Foo().xyz(.....));
}
}
class Foo {
public xyz(....) {
break labelX; // There is no labelX to break to here in Foo.xyz
}
}
}

"Too many open files in system" failure while listing a recursive directory structure

I've implemented (in Java) a fairly straightforward Iterator to return the names of the files in a recursive directory structure, and after about 2300 files it failed "Too many open files in system" (the failure was actually in trying to load a class, but I assume the directory listing was the culprit).
The data structure maintained by the iterator is a Stack holding the contents of the directories that are open at each level.
The actual logic is fairly basic:
private static class DirectoryIterator implements Iterator<String> {
private Stack<File[]> directories;
private FilenameFilter filter;
private Stack<Integer> positions = new Stack<Integer>();
private boolean recurse;
private String next = null;
public DirectoryIterator(Stack<File[]> directories, boolean recurse, FilenameFilter filter) {
this.directories = directories;
this.recurse = recurse;
this.filter = filter;
positions.push(0);
advance();
}
public boolean hasNext() {
return next != null;
}
public String next() {
String s = next;
advance();
return s;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void advance() {
if (directories.isEmpty()) {
next = null;
} else {
File[] files = directories.peek();
while (positions.peek() >= files.length) {
directories.pop();
positions.pop();
if (directories.isEmpty()) {
next = null;
return;
}
files = directories.peek();
}
File nextFile = files[positions.peek()];
if (nextFile.isDirectory()) {
int p = positions.pop() + 1;
positions.push(p);
if (recurse) {
directories.push(nextFile.listFiles(filter));
positions.push(0);
advance();
} else {
advance();
}
} else {
next = nextFile.toURI().toString();
count++;
if (count % 100 == 0) {
System.err.println(count + " " + next);
}
int p = positions.pop() + 1;
positions.push(p);
}
}
}
}
I would like to understand how many "open files" this requires. Under what circumstances is this algorithm "opening" a file, and when does it get closed again?
I've seen some neat code using Java 7 or Java 8, but I'm constrained to Java 6.
When you call nextFile.listFiles(), an underlying file descriptor is opened to read the directory. There is no way to explicitly close this descriptor, so you are relying on garbage collection. As your code descends a deep tree, it is essentially collecting a stack of nextFile instances which can't be garbaged collected.
Step 1: set nextFile = null before calling advance(). This releases the object for garbage collection.
Step 2: you may need to call System.gc() after nulling nextFile to encourage quick garbage collection. Unfortunately, there is no way to force GC.
Step 3: you may need to increase the open file limit on your operating system. On Linux this may be done with ulimit(1).
If you can migrate to Java 7 or later, then DirectoryStream will solve your problem. Instead of using nextFile.listFiles(), use Files.newDirectoryStream(nextFile.toPath()) to get a DirectoryStream. You can then iterate over the stream and then close() it to release the operating system resources. Each returned path can be converted back to a file with toFile(). However you might like to refactor to use just Path instead of File.
Thanks everyone for the help and advice. I established that the problem is actually in what is being done with the files after they are returned by the iterator: the "client" code is opening the files as they are delivered, and is not tidying up properly. It's complicated by the fact that the files coming back are actually being processed in parallel.
I've also rewritten the DireectoryIterator, which I share incase anyone is interested:
private static class DirectoryIterator implements Iterator<String> {
private Stack<Iterator<File>> directories;
private FilenameFilter filter;
private boolean recurse;
private String next = null;
public DirectoryIterator(Stack<Iterator<File>> directories, boolean recurse, FilenameFilter filter) {
this.directories = directories;
this.recurse = recurse;
this.filter = filter;
advance();
}
public boolean hasNext() {
return next != null;
}
public String next() {
String s = next;
advance();
return s;
}
public void remove() {
throw new UnsupportedOperationException();
}
private void advance() {
if (directories.isEmpty()) {
next = null;
} else {
Iterator<File> files = directories.peek();
while (!files.hasNext()) {
directories.pop();
if (directories.isEmpty()) {
next = null;
return;
}
files = directories.peek();
}
File nextFile = files.next();
if (nextFile.isDirectory()) {
if (recurse) {
directories.push(Arrays.asList(nextFile.listFiles(filter)).iterator());
}
advance();
} else {
next = nextFile.toURI().toString();
}
}
}
}

Eclipse Class File Error - localPlayerList

Why localPlayerList gaves me an error? Thank You (my error is signed with localPlayerList
public OfflinePlayer findPlayer(String paramString)
{
Object localObject = this.plugin.getServer().getOfflinePlayer(paramString);
if(!((OfflinePlayer) localObject).hasPlayedBefore())
{
localObject = this.plugin.getServer().getPlayer(paramString);
}
if(localObject == null)
{
PlayerList localPlayerList = this.plugin.getPlayerList(true);
for(PlayerList.Entry localEntry : localPlayerList)
{
String str = paramString.toLowerCase();
if(localEntry.name.toLowerCase().startsWith(str))
{
localObject = this.plugin.getServer().getOfflinePlayer(localEntry.name);
break;
}
}
}
return (OfflinePlayer) localObject;
}
Judging by the PlayerList.Entry mentioned in the for loop, PlayerList probably implements java.util.Map, which means to iterate around the entries it should be called like this:
for(PlayerList.Entry localEntry : localPlayerList.entrySet())

Categories

Resources