How to Correctly Mock a WebSocket session? - java

I have created a simple websocket application using springBoot. I am new to Mockito and I am trying to unit test the behaviour of following class with mockito and junit.
#Component
public class TextHandler extends TextWebSocketHandler {
WebSocketSession session;
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws InterruptedException, IOException {
// send message
if (session.isOpen()) {
try {
session.sendMessage(new TextMessage("Hello from the websocket"));
} finally {
session.close();
}
} else {
System.out.println("no open session available");
}
}
I created a stub for the session under test package as follows.
#Component
public class WebSocketSessionStub implements WebSocketSession{
#Override
public String getId() {
return "SESSION1";
}
#Override
public URI getUri() {
// TODO Auto-generated method stub
return null;
}
#Override
public HttpHeaders getHandshakeHeaders() {
// TODO Auto-generated method stub
return null;
}
#Override
public Map<String, Object> getAttributes() {
// TODO Auto-generated method stub
return null;
}
#Override
public Principal getPrincipal() {
// TODO Auto-generated method stub
return null;
}
#Override
public InetSocketAddress getLocalAddress() {
// TODO Auto-generated method stub
return null;
}
#Override
public InetSocketAddress getRemoteAddress() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getAcceptedProtocol() {
// TODO Auto-generated method stub
return null;
}
#Override
public void setTextMessageSizeLimit(int messageSizeLimit) {
// TODO Auto-generated method stub
}
#Override
public int getTextMessageSizeLimit() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void setBinaryMessageSizeLimit(int messageSizeLimit) {
// TODO Auto-generated method stub
}
#Override
public int getBinaryMessageSizeLimit() {
// TODO Auto-generated method stub
return 0;
}
#Override
public List<WebSocketExtension> getExtensions() {
// TODO Auto-generated method stub
return null;
}
#Override
public void sendMessage(WebSocketMessage<?> message) throws IOException {
// TODO Auto-generated method stub
}
#Override
public boolean isOpen() {
System.out.println("isOpen");
return true;
}
#Override
public void close() throws IOException {
// TODO Auto-generated method stub
}
#Override
public void close(CloseStatus status) throws IOException {
// TODO Auto-generated method stub
}
}
Following is my unit test class.
#RunWith(SpringRunner.class)
#SpringBootTest
public class TextHandlerTest {
#Autowired
TextHandler textHandler;
#Mock
WebSocketSessionStub ws;
#Mock
WebSocketMessage<TextMessage> webSocketMessage;
TextMessage textMsg = new TextMessage("Test Message".getBytes());
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
textHandler.handleMessage(ws, textMsg);
}
#Test
public void verifyCallToIsOpenConnection() throws Exception {
verify(ws, times(1)).isOpen();
System.out.println("isOpen " + ws.isOpen());
}
}
Above test passes, however isOpen evaluates to false. Therefore I cannot verify the sendMessage method call. How can I rectify it?

You can mock WebSocketSession and inject it into TextHandler#handleTextMessage.
/*
* You don't need spring context while mocking.
* Hence No need to have spring runner.
*/
#RunWith(MockitoJunitRunner.class)
public class TextHandlerTest {
#Test
public void verifyCallToIsOpenConnection() {
WebSocketSession session = mock(WebSocketSession.class);
TextMessage textMsg = new TextMessage("Test Message".getBytes());
when(session.isOpen()).thenReturn(true);
TextHandler textHandler = new TextHandler();
// Pass the mocked session object here
textHandler. handleTextMessage(session, textMsg);
// Now you can verify if session.sendMessage() was called or not
verify(session, times(1)).sendMessage(textMsg);
}
}

Related

Observer with RxJava/Quarkus

I started a Quarkus project, which (in part) shall watch for file changes on a text-file, read the added line(s) and then sends the added line(s) through a websocket connection to a client.
For watching the file changes and reading those I created the following class:
public class McServerService {
private String directory;
private List<String> currentLog;
private Observable<List<String>> observableLog;
private Thread logObserverThread;
public McServerService (String directory) {
this.currentLog = new ArrayList<String>();
this.observableLog = Observable.fromCallable(() -> this.currentLog);
this.directory = directory;
}
public void startWatching () {
this.logObserverThread = new Thread(new LogObserverThreadImpl(this.directory));
this.logObserverThread.start();
}
public void subscribeToLog (Observer<? super List<String>> observer) {
this.observableLog.subscribe(observer);
}
private class LogObserverThreadImpl implements Runnable {
BufferedReader br;
WatchService watchService;
private LogObserverThreadImpl (String directory) {
try {
this.br = new BufferedReader(new java.io.FileReader(directory + "\\" + "latest.log"));
String nextLine;
while ((nextLine = this.br.readLine()) != null) {
McServerService.this.currentLog.add(nextLine);
System.out.println(nextLine);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run() {
Path path = Paths.get(directory);
try {
System.out.println("entered try");
this.watchService = FileSystems.getDefault().newWatchService();
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey key;
while ((key = this.watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
if (event.context().toString().equals("latest.log")) {
String line = this.br.readLine();
McServerService.this.currentLog.add(line);
System.out.println(line);
}
}
key.reset();
}
System.out.println("after while");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Now the websocket would be handled by this class:
#ServerEndpoint("/test")
#ApplicationScoped
public class McServerWebSocket {
Map<String, Session> sessions = new ConcurrentHashMap<>();
McServerService mss = new McServerService("D:\\Spiele\\Minecraft");
#OnOpen
public void onOpen(Session session, #PathParam("name") String name) {
sessions.put(name, session);
}
#OnClose
public void onClose(Session session, #PathParam("name") String name) {
sessions.remove(name);
}
#OnError
public void onError(Session session, #PathParam("name") String name, Throwable throwable) {
sessions.remove(name);
}
#OnMessage
public void onMessage(String message, #PathParam("name") String name) {
Session c_session = sessions.get(name);
c_session.getAsyncRemote().sendObject("insert");
}
private class ConsoleLogObserverImpl implements Observer<List<String>>{
private ConsoleLogObserverImpl () {
}
#Override
public void onSubscribe(#NonNull Disposable d) {
// TODO Auto-generated method stub
System.out.println("subscribed");
}
#Override
public void onNext(#NonNull List<String> t) {
System.out.println(t.toString());
}
#Override
public void onError(#NonNull Throwable e) {
// TODO Auto-generated method stub
}
#Override
public void onComplete() {
// TODO Auto-generated method stub
System.out.println("finished");
}
}
}
I didnt implement the websocket yet, because my problem lies with observing the changes of
private List<String> currentLog; in the McServerServive class.
Unfortunately I deleted the main method in McServerWebSocket, that I used to test this, but that main method would essentially just create an instance of McServerWebSocket and then call the startWatching() method of its McServerService mss = new McServerService("D:\\Spiele\\Minecraft"); and its
public void subscribeToLog (Observer<? super List<String>> observer) {
this.observableLog.subscribe(observer);
}
method with the inner class:
private class ConsoleLogObserverImpl implements Observer<List<String>>
But the behaviour was not as I would have exspected. The output was:
subscribed
[]
finished
The observable was imediately terminating. Did I do something wrong when creating the Observable or did I completly misunderstand the usage RxJava?
How can I create an Observable class field and an Observer that triggers an action when the Observable is changed with RxJava/some Quarkus extension?

How to implement a custom DataStoreFactory for use with Google APIs using OAuth2?

I'm trying to implement a custom DataStoreFactory as mentioned in the docs here so that I can authenticate with Google APIs and store my access/refresh tokens in my database, but I can't find any documentation or examples of a custom implementation e.g.
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new MyCustomDatastoreFactory() )
.setAccessType("offline")
.build();
If I implement the DataStoreFactory interface, it gives me one method to implement:
import java.io.IOException;
import java.io.Serializable;
import com.google.api.client.util.store.DataStore;
import com.google.api.client.util.store.DataStoreFactory;
public class MyCustomDatastoreFactory implements DataStoreFactory {
#Override
public <V extends Serializable> DataStore<V> getDataStore(String arg0) throws IOException {
...
}
}
The DataStore object has several methods that need to be implemented, but I'm not sure where and how exactly I need to use this to retrieve and store my credentials:
new DataStore<Serializable>() {
#Override
public DataStore<Serializable> clear() throws IOException {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean containsKey(String arg0) throws IOException {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean containsValue(Serializable arg0) throws IOException {
// TODO Auto-generated method stub
return false;
}
#Override
public DataStore<Serializable> delete(String arg0) throws IOException {
// TODO Auto-generated method stub
return null;
}
#Override
public Serializable get(String arg0) throws IOException {
// TODO Auto-generated method stub
return null;
}
#Override
public DataStoreFactory getDataStoreFactory() {
// TODO Auto-generated method stub
return null;
}
#Override
public String getId() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean isEmpty() throws IOException {
// TODO Auto-generated method stub
return false;
}
#Override
public Set<String> keySet() throws IOException {
// TODO Auto-generated method stub
return null;
}
#Override
public DataStore<Serializable> set(String arg0, Serializable arg1) throws IOException {
// TODO Auto-generated method stub
return null;
}
#Override
public int size() throws IOException {
// TODO Auto-generated method stub
return 0;
}
#Override
public Collection<Serializable> values() throws IOException {
// TODO Auto-generated method stub
return null;
}
};
There is also DataStoreCredentialRefreshListener class, but do I need to implement that and associate it with my DataStoreFactory or DataStore so that it will automatically update my DB with new tokens?

ZuulFallbackProvider not getting invoked

I am trying to have a fallback if Zuul does not find a service. I have the a ZuulSever with the below code:
#SpringBootApplication
#EnableZuulProxy
#EnableDiscoveryClient
public class ZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServerApplication.class, args);
}
#Bean
public ZuulFallbackProvider fallBackProvider() {
return new ZuulFallbackProvider() {
#Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
#Override
public HttpHeaders getHeaders() {
return null;
}
#Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("Hello".getBytes());
}
#Override
public String getStatusText() throws IOException {
// TODO Auto-generated method stub
return "Service Down";
}
#Override
public HttpStatus getStatusCode() throws IOException {
// TODO Auto-generated method stub
return HttpStatus.OK;
}
#Override
public int getRawStatusCode() throws IOException {
// TODO Auto-generated method stub
return 200;
}
#Override
public void close() {
// TODO Auto-generated method stub
}
};
}
#Override
public String getRoute() {
// TODO Auto-generated method stub
return "*";
}
};
}
}
When the service in my route is up and running, I am able to get the output. But when I bring down the service in the route, I expected the fallback to kick in. But I still see an error message instead of the fallback message. Why is the fallback not invoked? I am using Dalston Release version.
If you configure Zuul to directly connect to an URL for your route, it will use SimpleHostRoutingFilter, which will (almost) always return a 500 in case of an error. Any FallbackProviders will not kick in.
I used a custom SimpleHostRoutingFilter instead:
public class CustomErrorHostRoutingFilter extends SimpleHostRoutingFilter {
public CustomErrorHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties properties, ApacheHttpClientConnectionManagerFactory connectionManagerFactory, ApacheHttpClientFactory httpClientFactory) {
super(helper, properties, connectionManagerFactory, httpClientFactory);
}
#Override
protected ZuulException handleException(Exception ex) {
if (ex instanceof ConnectTimeoutException) {
return new ZuulException(ex, "Downstream timeout", HttpServletResponse.SC_GATEWAY_TIMEOUT, ex.getMessage());
}
if (ex instanceof IOException) {
return new ZuulException(ex, "Downstream I/O error", HttpServletResponse.SC_SERVICE_UNAVAILABLE, ex.getMessage());
}
return super.handleException(ex);
}
}
Some kind of configuration class is required as well:
#Configuration
#EnableZuulProxy
public class ZuulConfiguration {
#Bean
public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper,
ZuulProperties zuulProperties,
ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
ApacheHttpClientFactory httpClientFactory) {
return new CustomErrorHostRoutingFilter(helper, zuulProperties, connectionManagerFactory, httpClientFactory);
}
}

Creating Markers and Problems in Eclipse Plugin

I have been doing a fair amount of research but am having a hard time understanding the relation between IProblem and IMarker. I have been able to create problems and add markers but the two do not seem to be connected. Are problems and markers independent? At first I was thinking that if I add problems to ReconcileContext the markers would appear automatically but that does not appear to be the case. Does anyone know if I am doing something wrong?
SecureCompilationParticipant.java:
public class SecureCompilationParticipant extends CompilationParticipant {
public boolean isActive(IJavaProject project) {
return true;
}
#Override
public void reconcile(ReconcileContext context) {
// Call Parent
super.reconcile(context);
// Used in expression loop
int start, end, line;
String fileName;
// Check to see if content has changed
IJavaElementDelta elementDelta = context.getDelta();
IJavaElement element = elementDelta.getElement();
if((elementDelta.getFlags() & IJavaElementDelta.F_CONTENT) != 0) {
System.out.printf("The content of %s has changed%n",
element.getElementName());
try {
CompilationUnit compilation = context.getAST8();
NodeVisitor visitor = new NodeVisitor();
compilation.accept(visitor);
// Iterate through expressions
for (ExpressionStatement expressionStatement : visitor.getExpressionStatements()) {
start = expressionStatement.getStartPosition();
end = start + expressionStatement.getLength();
line = compilation.getLineNumber(start - 1);
fileName = element.getElementName();
System.out.printf("Expression: %s%n", expressionStatement.getExpression().toString());
CategorizedProblem[] problems = new CategorizedProblem[0];
ArrayList<CategorizedProblem> problemList = new ArrayList<CategorizedProblem>();
// Put problems
SecureCodingProblem problem = new SecureCodingProblem(fileName);
problem.setSourceStart(start);
problem.setSourceEnd(end);
problem.setSourceLineNumber(line);
problemList.add(problem);
context.putProblems(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, problemList.toArray(problems));
// Create marker
IResource resource = element.getUnderlyingResource();
IMarker marker = resource.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.MESSAGE, "This is a test marker");
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
marker.setAttribute(IMarker.LINE_NUMBER, line);
marker.setAttribute(IMarker.LOCATION, String.format("Line %d", line));
}
} catch (JavaModelException e) {
// From CompilationUnit compilation = context.getAST8();
e.printStackTrace();
} catch (CoreException e) {
// From IMarker marker = resource.createMarker(IMarker.PROBLEM);
e.printStackTrace();
}
}
}
}
SecureCodingProblem.java:
public class SecureCodingProblem extends CategorizedProblem {
private int m_sourceStart;
private int m_sourceEnd;
private int m_sourceLineNumber;
private char[] m_fileName;
public SecureCodingProblem(String fileName) {
m_fileName = fileName.toCharArray();
}
#Override
public String[] getArguments() {
// TODO Auto-generated method stub
return null;
}
#Override
public int getID() {
// TODO Auto-generated method stub
return 0;
}
#Override
public String getMessage() {
// TODO Auto-generated method stub
return "This is a problem";
}
#Override
public char[] getOriginatingFileName() {
// TODO Auto-generated method stub
return m_fileName;
}
#Override
public int getSourceEnd() {
// TODO Auto-generated method stub
return m_sourceEnd;
}
#Override
public int getSourceLineNumber() {
// TODO Auto-generated method stub
return m_sourceLineNumber;
}
#Override
public int getSourceStart() {
// TODO Auto-generated method stub
return m_sourceStart;
}
#Override
public boolean isError() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isWarning() {
// TODO Auto-generated method stub
return true;
}
#Override
public void setSourceEnd(int sourceEnd) {
m_sourceEnd = sourceEnd;
}
#Override
public void setSourceLineNumber(int lineNumber) {
m_sourceLineNumber = lineNumber;
}
#Override
public void setSourceStart(int sourceStart) {
m_sourceStart = sourceStart;
}
#Override
public int getCategoryID() {
// TODO Auto-generated method stub
return CategorizedProblem.CAT_CODE_STYLE;
}
#Override
public String getMarkerType() {
// TODO Auto-generated method stub
return IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER;
}
}
IProblem is specific to the Java Development Tools whereas IMarker can be used for any file in the workspace.
The JavaDoc for IProblem says:
Note: the compiler produces IProblems internally, which are turned
into markers by the JavaBuilder so as to persist problem descriptions.
This explains why there is no API allowing to reach IProblem detected
when compiling. However, the Java problem markers carry equivalent
information to IProblem, in particular their ID (attribute "id") is
set to one of the IDs defined on this interface.

java read file from network device

Can someone help me to find a tutorial or sample java code to
read a file from any machine which is in the same network
The simplest way to do this would be to read it using regular file paths.
On Windows:
new File("\\\\server\\path\\to\\file.txt")
// (double-backslashes required for backslashes in path)
On Unix:
First mount the share using Samba (SMB, NFS or whatever other protocol) to some location like /mnt/network. Then you can use:
new File("/mnt/network/path/to/file.txt")
Once you have the File object you can use FileInputStream, FileReader or whatever else you want to read the file in.
Edit for comments response. If you are using an Applet, you probably want to pull the file from a web server. You can use the built in java.net.URL class but I would recommend this if you have to do more than just simple stuff: http://hc.apache.org/httpclient-3.x/index.html
Example (from the Commons HTTP Site):
// Create an instance of HttpClient.
HttpClient client = new HttpClient();
// Create a method instance.
GetMethod method = new GetMethod(url);
try {
// Execute the method.
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + method.getStatusLine());
}
// Read the response body.
byte[] responseBody = method.getResponseBody();
// Deal with the response.
// Use caution: ensure correct character encoding and is not binary data
System.out.println(new String(responseBody));
} catch (HttpException e) {
System.err.println("Fatal protocol violation: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("Fatal transport error: " + e.getMessage());
e.printStackTrace();
} finally {
// Release the connection.
method.releaseConnection();
}
}
}
This is not that simple! To use Server Client Aplications you need a Network API.
I have 1 by DeBukkit and an extended version. If you would to send Files I will suggest my one (Server Client Extended .jar) becazse there is an Option to send Files (FilePacket.java).
This are the links to the libs: All Libs
Code for Server for Client Server Extended:
public class TestServer extends Server {
public TestServer() {
super(29898, true, true,true);
registerMethod("bt", new FileReciver() {
#Override
public void onCompleteRecive(FileInfo data) {
System.out.println("Completely recived : "+data);
Path p = Paths.get(data.getName());
try {
Files.createFile(p);
Files.write(p, data.getContent());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* #see com.bebukkit.niton.network.packets.buffer.BufferedPacketReciver#run(com.bebukkit.niton.network.packets.Packet, java.net.Socket)
*/
#Override
public void run(Packet<? extends Serializable> msg, Socket socket) {
super.run(msg, socket);
sendMessage(new Packet<Boolean>("", null), socket);
}
});
}
#Override
public void preStart()
{
registerMethod("msg", new ReciveMethod() {
#Override
public void run(Packet<? extends Serializable> msg, Socket socket) {
broadcastMessage(msg);
}
});
}
#Override
public void onWrongDataPacketException(ClassNotFoundException e) {
// TODO Auto-generated method stub
}
#Override
public void onReceivePacketError(IOException e) {
// TODO Auto-generated method stub
}
#Override
public void onPacketReckognized(ServerSocket socket) {
// TODO Auto-generated method stub
}
#Override
public void onPacketSendException(Exception e, Packet<? extends Serializable> message, Socket socket2) {
// TODO Auto-generated method stub
}
#Override
public void onSendPacketToNotConnectedClient(Packet<? extends Serializable> message, Socket socket2) {
// TODO Auto-generated method stub
}
#Override
public void onBrodcast(Packet<? extends Serializable> pack) {
// TODO Auto-generated method stub
}
#Override
public void onServerStartError(IOException e) {
// TODO Auto-generated method stub
}
#Override
public void onServerStop() {
// TODO Auto-generated method stub
}
}
Code for Client:
package com.bebukkit.niton.network.test;
import java.io.IOException;
import java.io.Serializable;
import java.net.Socket;
import java.util.Scanner;
import com.bebukkit.niton.network.Client;
import com.bebukkit.niton.network.packets.Packet;
import com.bebukkit.niton.network.packets.ReciveMethod;
public class TestClient extends Client {
public TestClient() {
super("localhost", 29898, 5000, false,true);
registerMethod("msg", new ReciveMethod() {
#Override
public void run(Packet<? extends Serializable> msg, Socket socket) {
System.out.println(msg.getData());
}
});
registerMethod("replay", new ReciveMethod() {
#Override
public void run(Packet<? extends Serializable> msg, Socket socket) {
System.out.println("REREplay");
}
});
}
#Override
public void onSocketClosingFail() {
// TODO Auto-generated method stub
}
#Override
public void onLoginPacketSendingFailed(IOException ex) {
// TODO Auto-generated method stub
}
#Override
public void onConnectionError(IOException ex) {
// TODO Auto-generated method stub
}
#Override
public void onMessageReciveError(Exception ex) {
// TODO Auto-generated method stub
}
#Override
public void onPacketSendError(Exception ex, Packet<? extends Serializable> pack) {
// TODO Auto-generated method stub
}
#Override
public void start() {
super.start();
}
}
You need a seperated Server + Client Starter:
package com.bebukkit.niton.network.test;
public class ServerStarter {
public static void main(String[] args) {
new TestServer();
}
}
Client:
package com.bebukkit.niton.network.test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import javax.swing.JFileChooser;
import com.bebukkit.niton.network.packets.Packet;
import com.bebukkit.niton.network.packets.buffer.BufferedPacket;
import com.bebukkit.niton.network.packets.file.FileInfo;
import com.bebukkit.niton.network.packets.file.FilePacket;
public class ClientStarter {
public static void main(String[] args) throws IOException {
TestClient tc = new TestClient();
tc.start();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JFileChooser c = new JFileChooser("Choose a file to upload");
c.setFileSelectionMode(JFileChooser.FILES_ONLY);
c.showDialog(null,"Upload");
File f = c.getSelectedFile();
try {
tc.sendMessage(new FilePacket("file", f));
tc.sendMessage(new Packet<String>("replay","test"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
If your file path in a different pc (i.e. Network devices) but connected to the same LAN, then you can easily access it by using these 2 steps.
Step 1: you need to map the network drive (i.e. your desired folder) into a physical drive, for example:
In Windows, \\10.221.222.6/some/path/of/images path mapped into a Drive like Z:\ or Y:\
Step 2:
String externalSharedFilePath = "file:Z:/images/";
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**").addResourceLocations(externalSharedFilePath);
}
Try the following URL for a tutorial http://www.roseindia.net/java/beginners/construct_file_name_path.shtml
I think the best way is to use java.net.URL to open a InputSteam, because you can generalize it to files, that are not necessarily on the same network.

Categories