ZuulFallbackProvider not getting invoked - java

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);
}
}

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 call spring boot MessageMapping using okhttp3 Websocket

I have created a spring boot Messaging endpoint and need to create an android chat app and am wondering how I can manage to call those endpoints using okttp Websocket client which does not seem to have a way to add api endpoints like this javascript code.
And here is my spring boot endpoints
#Configuration
#EnableWebSocketMessageBroker
public class WebMessageConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker( "/user");
config.setApplicationDestinationPrefixes("/app");
config.setUserDestinationPrefix("/user");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/ws")
.withSockJS()
.setAllowedOrigins("*");
}
}
And here is my OkHttp client code
public class StompWs {
private String SERVER_PATH="ws://mydomain.com:8443/MyContex/ws";
public static void main(String[] args) {
try {
new StompWs().run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private WebSocket webSocket;
public void run() throws Exception {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(SERVER_PATH).build();
webSocket = client.newWebSocket(request, new SocketListener());
}
private String getData()
{
MessageModel message=new MessageModel();
message.setMessage("Hello");
message.setRecipientId("1");
message.setSenderId("2");
return new Gson().toJson(message);
}
private class SocketListener extends WebSocketListener {
#Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
try {
webSocket.send(getData());
/**I need equivalent of this
stompClient.subscribe(
"/user/1/queue/messages",// I need java code to do this
onMessageReceived
*/
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("succesfully connected:"+response.toString());//this message execute well
}
#Override
public void onMessage(WebSocket webSocket, String text) {
super.onMessage(webSocket, text);
System.out.println("on message:"+text);
}
#Override
public void onFailure(WebSocket webSocket, Throwable t,
Response response) {
// TODO Auto-generated method stub
super.onFailure(webSocket, t, response);
System.out.println("on message:"+t.toString());
}
}
}

How to Correctly Mock a WebSocket session?

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);
}
}

Spring-data-solr data import handler call

I'm using spring-data-solr and have data import handler(DIH) in solr. How can I call DIH by repository or SolrTemplate, or some else?
I'd recommend a Custom Respository using SolrCallback to execute desired request.
#Override
public SolrResponse dataImport(final String command) {
return solrTemplate.execute(new SolrCallback<SolrResponse>() {
#Override
public SolrResponse doInSolr(SolrServer solrServer) throws SolrServerException, IOException {
return new SolrRequest(METHOD.GET, "/dataimport?command=" + command) {
//..skipped some methods to shorten
#Override
public SolrResponse process(SolrServer server) throws SolrServerException, IOException {
SolrResponseBase response = new SolrResponseBase();
response.setResponse(server.request(this));
return response;
}
}.process(solrServer);
}
});
}
If someone else is struggling to get the DIH working in the current version (Solr 8.11) - this is what worked for me (be sure to adapt the core name):
solrTemplate.execute(new SolrCallback<SolrResponse>() {
#Override
public SolrResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException {
SolrRequest<SolrResponse> solrRequest = new SolrRequest<>(SolrRequest.METHOD.GET, "/<core_name>/dataimport?command=full-import&commit=true&clean=true") {
#Override
public SolrParams getParams() {
return null;
}
#Override
protected SolrResponse createResponse(SolrClient solrClient) {
SolrResponseBase response = new SolrResponseBase();
try {
response.setResponse(solrClient.request(this));
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
return response;
}
};
solrRequest.setResponseParser(new DelegationTokenResponse.JsonMapResponseParser());
return solrRequest.process(solrClient);
}
});

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