I'm using eclipse jetty as a web container and the application is served in windows environment.The client and server consumes javax.websocket for communication.Client will simply send a source zip from linux environment to windows environment and after building the source in windows environment, output zip will be sent back to linux environment.
On every successful build, the output executable will be created under Release directory. For example:
D:\Build\26-09-2020\foo\Release\donate.exe
And then the file will be moved to output directory and eventually the contents of the output directory will be sent back to client. Below is an example of output directory structure.
D:\build\26-09-2020\foo\wintask_output
Everything worked fine without any issues but when i tried to delete the build directory (i.e)
D:\build\26-09-2020
The contents were removed but the directory structure resides in the machine until restarting jetty server. Below is the sample error thrown by windows on deleting build directory.
Below is the code used for moving donate.exe from release directory to output directory:
private boolean moveFileOrDirectory(String src, String target) {
Path source = Paths.get(src);
Path destination = Paths.get(target);
Boolean isMoved = false;
int relay = 0;
if (Files.notExists(source)) {
logger.info("source directory '" + source + "' doesn't exist, ignoring move action");
return true;
}
while (!isMoved && relay < 20) {
try {
Files.move(source, destination, StandardCopyOption.REPLACE_EXISTING);
isMoved = true;
break;
} catch (Exception e) {
logger.trace(
":: This exception will be taken as granted beecause windows/antivirus may held the files while renaming :: Exception",
e);
}
relay++;
}
if (!isMoved) {
logger.trace("Cannot move directories using java attempting to move as native command");
String CommandLine = "-noprofile" + " " + "-nologo" + " " + "-noninteractive" + " " + "-Command" + " "
+ "Rename-Item" + " " + io.surroundWithDoubleQuotes(source.toString()) + " "
+ io.surroundWithDoubleQuotes(destination.toString());
io.executeNativeCommand(Constants.POWER_SHELL_EXECUTABLE, CommandLine, this.WorkDirectory,
this.WorkDirectory + pathSep + "renameFolder.txt", false);
}
if (Files.exists(destination)) {
logger.trace("Directory/File renamed from '" + source + "' to '"+destination+"'.");
isMoved = true;
}
return isMoved;
}
And even i tried to to remove the old directory in my cron job(ScheduledExecutorService) and below is the exception:
27 Sep 2020 20:00:27 TRACE com.integ.utils.FileIO.forceDeleteDirectory() @402 - Exception while deleting directory D:\Build\26-09-2020
java.io.IOException: Unable to delete file: D:\Build\26-09-2020
at org.apache.commons.io.FileUtils.forceDelete(FileUtils.java:1338) ~[commons-io-2.7.jar:2.7]
at com.integ.utils.FileIO.forceDeleteDirectory(FileIO.java:398) [JettyStandAloneServer.jar:?]
at com.integ.scheduledjobs.server.ScheduledTasks.deleteOneDayOlderDirectories(ScheduledTasks.java:31) [JettyStandAloneServer.jar:?]
at com.integ.scheduledjobs.server.ScheduledTasks.run(ScheduledTasks.java:50) [JettyStandAloneServer.jar:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) [?:?]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: java.nio.file.AccessDeniedException: D:\Build\26-09-2020\foo
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:89) ~[?:?]
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103) ~[?:?]
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108) ~[?:?]
at sun.nio.fs.WindowsDirectoryStream.<init>(WindowsDirectoryStream.java:86) ~[?:?]
at sun.nio.fs.WindowsFileSystemProvider.newDirectoryStream(WindowsFileSystemProvider.java:523) ~[?:?]
at java.nio.file.Files.newDirectoryStream(Files.java:471) ~[?:?]
at java.nio.file.FileTreeWalker.visit(FileTreeWalker.java:300) ~[?:?]
at java.nio.file.FileTreeWalker.next(FileTreeWalker.java:373) ~[?:?]
at java.nio.file.Files.walkFileTree(Files.java:2760) ~[?:?]
at java.nio.file.Files.walkFileTree(Files.java:2796) ~[?:?]
at org.apache.commons.io.file.PathUtils.visitFileTree(PathUtils.java:535) ~[commons-io-2.7.jar:2.7]
at org.apache.commons.io.file.PathUtils.deleteDirectory(PathUtils.java:265) ~[commons-io-2.7.jar:2.7]
at org.apache.commons.io.file.PathUtils.delete(PathUtils.java:254) ~[commons-io-2.7.jar:2.7]
at org.apache.commons.io.FileUtils.forceDelete(FileUtils.java:1336) ~[commons-io-2.7.jar:2.7]
... 9 more
Below is the main program for jetty server start-up and as well as websocket integration:
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import javax.websocket.Decoder;
import javax.websocket.Encoder;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
import org.glassfish.jersey.servlet.ServletContainer;
import com.integ.commons.Constants;
import com.integ.jetty.filters.TokenFilter;
import com.integ.scheduledjobs.server.Cron;
import static javax.servlet.DispatcherType.REQUEST;
public class Initservice
{
private static final Logger logger = LogManager.getLogger(Initservice.class.getName());
public static Server createServer(int port)
{
Server server = new Server(port);
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath("/");
servletContextHandler.addServlet(DefaultServlet.class, "/");
servletContextHandler.addFilter(TokenFilter.class, "/*", EnumSet.of(REQUEST));
ServletHolder servletHolder = servletContextHandler.addServlet(ServletContainer.class, "/api/*");
server.setHandler(servletContextHandler);
servletHolder.setInitOrder(0);
servletHolder.setInitParameter(
"jersey.config.server.provider.packages",
"com.integ.rest"
);
try
{
// Initialize javax.websocket layer
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(servletContextHandler);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.setDefaultMaxBinaryMessageBufferSize(65565555);
wscontainer.setDefaultMaxTextMessageBufferSize(65565555);
wscontainer.setDefaultMaxSessionIdleTimeout(0);
ServerEndpointConfig config = ServerEndpointConfig.Builder.create(WsServer.class, "/events").build();
wscontainer.addEndpoint(config);
}
catch (Throwable t)
{
t.printStackTrace(System.err);
}
return server;
}
public static void main(String[] args) throws Exception
{
int port = Constants.Port;
Server server = createServer(port);
Cron scheduledjobs = new Cron();
try {
scheduledjobs.startScheduledServices();
server.start();
server.join();
} catch(Exception ex) {
logger.error("Error While starting jetty server");
logger.log(Level.ERROR, ex.getMessage(), ex);
} finally {
server.stop();
server.destroy();
logger.fatal("Server destroyed..");
}
}
}
Java version - OpenJDK Runtime Environment Zulu11.41+23-CA (build 11.0.8+10-LTS) & Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Windows version - 2019 server (10.0.17763 Build 17763)
The issue persists on directories/files where move action is performed using
Files.move(Path source,Path target,CopyOption... options)throws IOException
UPDATE: The error is occurring only on windows environment,the same setup works fine in Linux. Is this anomaly is because of jvm ? because as soon as i shut down the jvm, the directory can be deleted from file explorer without any issues.
Any help is appreciated :-)