Spring WebFlux consumer to sink - java

Here is a simple spring boot application:
#SpringBootApplication
#RestController
public class ReactiveApplication {
static Flux<String> fluxString;
static volatile Queue<String> queue = new ConcurrentLinkedQueueProxy();
private static class ConcurrentLinkedQueueProxy extends ConcurrentLinkedQueue<String> {
private static final long serialVersionUID = 1L;
#Override
public boolean add(String e) {
synchronized (this) {
notify();
}
return super.add(e);
}
#Override
public String poll() {
synchronized (this) {
if(isEmpty()) {
try {
wait();
} catch (InterruptedException ex) {}
}
}
return super.peek() == null ? "" : super.poll();
}
}
static Consumer<String> consumer = str -> queue.add(str);
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(ReactiveApplication.class, args);
}
static {
for(int i = 0; i < 10; i++)
queue.add("testData " + i + " ");
}
#GetMapping(value = "/", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<String> home() {
Scheduler sch = Schedulers.newParallel("parallel-sch", 1);
List<String> list = new ArrayList<>(queue);
queue.removeAll(queue);
fluxString = Flux.<String>create(sink -> {
sink.onRequest(n -> {
for(int i = 0; i < n; i++) {
sink.next(queue.poll());
}
}).onCancel(() -> sch.dispose());
}).log().subscribeOn(sch).mergeWith(Flux.<String>fromIterable(list));
return fluxString;
}
#GetMapping("/add")
public String add( #RequestParam String s) {
consumer.accept(s);
return s;
}
}
So basically this application creates a String stream. Visiting / will grab all the string present queue and then merge anything that is added from /add resource(ignore the "Safe Methods Must be Idempotent" thing).
What I feel is strange is that when I move public static void main(...) to line 1, the application starts to misbehave and adding new values to /add doesn't have any effect. I think there must be something interesting going on that is making application misbehave. Any explaination?

I ended up using this which works great:
#SpringBootApplication
#RestController
public class ReactiveApplication {
private static BlockingQueue<String> queue = new ArrayBlockingQueue<>(1000);
private static Consumer<String> consumer = str -> {
try { queue.put(str); }
catch (InterruptedException e) {}
};
static {
for (int i = 0; i < 10; i++) queue.add("testData " + i + " ");
}
public static void main(String[] args) {
SpringApplication.run(ReactiveApplication.class, args);
}
#GetMapping(value = "/", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<String> home() {
final Scheduler sch = Schedulers.newSingle("async-flux");
return Flux.<String>generate(sink -> {
try { sink.next(queue.take()); }
catch (InterruptedException e) { }
}).log().subscribeOn(sch);
}
#GetMapping("/add")
public String add(#RequestParam String s) {
consumer.accept(s);
return s;
}
}

Related

How can I use the Observer Pattern for file monitoring with threads?

I am trying to implement the observer pattern to a game i have made. When a villain is created in the battle-zone file using threads, I would like to use the observer pattern to create a hero using threads and add it to the same file. The villians and heroes are created using the factory method pattern. I am unsure of where to go with regards to linking my HeroCreationMain class to the observer pattern classes.
Villian Creation
public class VillianCreationMain {
private static Villian villian;
public static void main(String[] args, int userInput) throws IOException {
String fileName = null;
Random randomVillian = new Random();
int amountOfVillians = userInput;
if (amountOfVillians < 7) {
for (int x = 0; x < amountOfVillians; x++) {
int randomGenerator = randomVillian.nextInt(6);
for (int i = 0; i < 5; i++) {
if (randomGenerator == 0 ) {
setVillian(new FlyingVillian());
}
else if (randomGenerator == 1) {
setVillian(new StrongVillian());
}
else if (randomGenerator == 2) {
setVillian(new FastVillian());
}
else if (randomGenerator == 3) {
setVillian(new SmartVillian());
}
else if (randomGenerator == 4) {
setVillian(new FireVillian());
}
else if (randomGenerator == 5) {
setVillian(new IceVillian());
}
try {
writeToFile(getVillian(), i, fileName);
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
VillianThreads t1 = new VillianThreads(VillianCreationMain.getVillian());
t1.start();
}
}
else {
System.out.println("Please enter a value of less than 7");
}
}
public static void writeToFile(Villian villian, int amountOfVillians, String fileName) throws IOException {
for(int x = 0; x < amountOfVillians; x++) {
// String parsedInt = Integer.toString(x);
fileName = "battle-zone.ser";
FileOutputStream file = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(file);
oos.writeObject(villian);
file.close();
oos.close();
}
}
public static Villian getVillian() {
return villian;
}
public static void setVillian(Villian villian) {
VillianCreationMain.villian = villian;
}
}
Hero Creation
public class HeroCreationMain {
private static Hero hero = null;
public static void main(String[] Hero) {
EnemyStatus enemyStatus = new EnemyStatus();
VillianObserver observer1 = new VillianObserver(enemyStatus);
}
public static void readFile() throws IOException, ClassNotFoundException {
#SuppressWarnings("resource")
ObjectInputStream ois = new ObjectInputStream (new FileInputStream("battle-zone.ser"));
Villian targetVillian = (Villian) ois.readObject();
System.out.println(targetVillian + " is being attacked by a hero!");
}
public static Hero getHero() {
return hero;
}
public static void setHero(Hero hero) {
HeroCreationMain.hero = hero;
}
}
Observer
public interface Observer {
public void update(boolean enemyPresent);
}
public interface Subject {
public void register(Observer o);
public void unregister(Observer o);
public void notifyObserver();
}
Observable
public class VillianObserver implements Observer {
private boolean enemyPresent;
private static int heroIDTracker;
private int heroID;
private Subject villianObserver;
public VillianObserver(Subject villianObserver) {
this.villianObserver = villianObserver;
this.heroID = ++heroIDTracker;
System.out.println("New Observer " + this.heroID);
villianObserver.register(this);
}
#Override
public void update(boolean enemyPresent) {
this.enemyPresent = enemyPresent;
printResult();
}
public void printResult() {
System.out.println(heroID + " " + enemyPresent);
}
}
Enemy Status
import java.util.ArrayList;
public class EnemyStatus implements Subject {
private ArrayList<Observer> observers;
private boolean enemyPresent;
public EnemyStatus() {
// Creates an ArrayList to hold all observers
observers = new ArrayList<Observer>();
}
#Override
public void register(Observer newObserver) {
observers.add(newObserver);
}
#Override
public void unregister(Observer deleteObserver) {
// Get the index of the observer to delete
int heroIndex = observers.indexOf(deleteObserver);
// Print out message (Have to increment index to match
System.out.println("Observer " + (heroIndex+1) + " deleted");
// Removes observer from the ArrayList
observers.remove(heroIndex);
}
#Override
public void notifyObserver() {
for(Observer observer : observers) {
observer.update(enemyPresent);
}
}
public void setEnemyStatus(boolean enemyPresent) {
this.enemyPresent = enemyPresent;
notifyObserver();
}
}
JNotify is the Java library to observe file changes on the file system.
One piece of advice: Object(Input/Output)Streams are easy when you're just getting started but they lead you down a path of ruin. Objects get so easily BadVersion'ed. Object files are also relatively hard to inspect using a text editor. I'd advise you to try using a different data format (like JSON) instead.

Not getting result : working with completableFuture

I suppose to get the response from two API and then only move forward. To achieve this tried to use completableFuture but ending up in getting NullPointerException, when fetching response from 'result' object.
Infact, completeableFuture basically not have data.
Not able to debug the thread working directly.
public APIResult execute() throws InterruptedException, ExecutionException {
CompletableFuture<TaskChair> completableFutureChair = CompletableFuture.supplyAsync(()->new TaskChair(),executorChair);
CompletableFuture<TaskBottle> completableFutureBottle = CompletableFuture.supplyAsync(()->new TaskBottle(),executorChair);
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(completableFutureChair, completableFutureBottle);
combinedFuture.get();
TaskChair taskChair = completableFutureChair.get();
TaskBottle taskBottle = completableFutureBottle.get();
List<Chair> chairs = taskChair.getChairs();
List<Bottle> bottles = taskBottle.getBottles();
APIResult result = new APIResult(chairs, bottles);
return result;
}
class TaskChair implements Callable<List<Chair>>{
List<Chair> chairs;
public List<Chair> getChairs() {
return chairs;
}
public void setChairs(List<Chair> chairs) {
this.chairs = chairs;
}
#Override
public List<Chair> call() throws Exception {
chairs = new RestAPI().getChairs();
return chairs;
}
}
public static void main(String[] args) {
RestService service = new RestService();
APIResult result = null;
try {
result = service.execute();
} catch (InterruptedException | ExecutionException e) { }
System.out.println("Chair API Status -> ");
for(Chair chair:result.getChairs()) {
System.out.println(" id : "+chair.getId()+" name : "+ chair.getName());
}
}

How to use return value from ExecutorService

I am running a for loop under ExecutorService (which sends emails)
If any of the return type is fail , i need to return return resposne as "Fail"
or else i need to return return resposne as "Success"
But i couldn't able to return value in this case
I tried as this way
import java.text.ParseException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) throws ParseException {
String response = getDataCal();
System.out.println(response);
}
public static String getDataCal() {
ExecutorService emailExecutor = Executors.newSingleThreadExecutor();
emailExecutor.execute(new Runnable() {
#Override
public void run() {
try {
for(int i=0;i<2;i++)
{
String sss = getMYInfo(i);
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
return sss;
}
public static String getMYInfo(int i)
{
String somevav = "success";//Sometimes it returns fail or success
if(i==0)
{
somevav ="success";
}
else
{
somevav ="fail";
}
return somevav;
}
}
Call your getMYInfo(i) in Callable<String>, submit this callable to executor, then wait for competition of Future<String>.
private static ExecutorService emailExecutor = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
getData();
}
private static void getData() {
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 2; i++) {
final Future<String> future = emailExecutor.submit(new MyInfoCallable(i));
futures.add(future);
}
for (Future<String> f : futures) {
try {
System.out.println(f.get());
} catch (InterruptedException | ExecutionException ex) {
}
}
}
public static String getMYInfo(int i) {
String somevav = "success";
if (i == 0) {
somevav = "success";
} else {
somevav = "fail";
}
return somevav;
}
private static class MyInfoCallable implements Callable<String> {
int i;
public MyInfoCallable(int i) {
this.i = i;
}
#Override
public String call() throws Exception {
return getMYInfo(i);
}
}
It seems that you want to wait for the completion of the task that you've submitted (why use an ExecutorService?)
You can do that by submitting a Callable<T>, the submit method will then return a Future<T>. You can then get() to wait for completion and obtain the result.

WorkStealingPool exits unexpectedly

I submitted some Runnables to an ExecutorService. Inside these Runnables, wait() and notify() are called. The code works with newFixedThreadPool as the ExecutorService. With newWorkStealingPool, the process exits unexpectedly without any error message.
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
// For regular expressions
import java.util.regex.Matcher;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import java.util.*;
import java.util.concurrent.*;
public class TestPipeline {
public static void main(String[] args) {
runAsThreads();
}
private static void runAsThreads() {
final BlockingQueue<String> urls = new OneItemQueue<String>();
final BlockingQueue<Webpage> pages = new OneItemQueue<Webpage>();
final BlockingQueue<Link> refPairs = new OneItemQueue<Link>();
final BlockingQueue<Link> uniqRefPairs = new OneItemQueue<Link>();
final ExecutorService executor = Executors.newWorkStealingPool(6);
// final ExecutorService executor = Executors.newFixedThreadPool(6);
executor.submit(new UrlProducer(urls));
executor.submit(new PageGetter(urls, pages));
executor.submit(new LinkScanner(pages,refPairs));
executor.submit(new Uniquifier<Link>(refPairs,uniqRefPairs));
executor.submit(new LinkPrinter(uniqRefPairs));
}
}
class UrlProducer implements Runnable {
private final BlockingQueue<String> output;
public UrlProducer(BlockingQueue<String> output) {
this.output = output;
}
public void run() {
System.out.println("in producer");
for (int i=0; i<urls.length; i++)
output.put(urls[i]);
}
private static final String[] urls =
{ "http://www.itu.dk", "http://www.di.ku.dk", "http://www.miele.de",
"http://www.microsoft.com", "http://www.cnn.com", "http://www.dr.dk",
"http://www.vg.no", "http://www.tv2.dk", "http://www.google.com",
"http://www.ing.dk", "http://www.dtu.dk", "http://www.bbc.co.uk"
};
}
class PageGetter implements Runnable {
private final BlockingQueue<String> input;
private final BlockingQueue<Webpage> output;
public PageGetter(BlockingQueue<String> input, BlockingQueue<Webpage> output) {
this.input = input;
this.output = output;
}
public void run() {
while (true) {
System.out.println("in pagegetter");
String url = input.take();
// System.out.println("PageGetter: " + url);
try {
String contents = getPage(url, 200);
output.put(new Webpage(url, contents));
} catch (IOException exn) { System.out.println(exn); }
}
}
public static String getPage(String url, int maxLines) throws IOException {
// This will close the streams after use (JLS 8 para 14.20.3):
try (BufferedReader in
= new BufferedReader(new InputStreamReader(new URL(url).openStream()))) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<maxLines; i++) {
String inputLine = in.readLine();
if (inputLine == null)
break;
else
sb.append(inputLine).append("\n");
}
return sb.toString();
}
}
}
class Uniquifier<T> implements Runnable{
private final Set<T> set = new HashSet<T>();
private final BlockingQueue<T> input;
private final BlockingQueue<T> output;
public Uniquifier(BlockingQueue<T> input, BlockingQueue<T> output){
this.input = input;
this.output = output;
}
public void run(){
while(true){
System.out.println("in uniquifier");
T item = input.take();
if(!set.contains(item)){
set.add(item);
output.put(item);
}
}
}
}
class LinkScanner implements Runnable {
private final BlockingQueue<Webpage> input;
private final BlockingQueue<Link> output;
public LinkScanner(BlockingQueue<Webpage> input,
BlockingQueue<Link> output) {
this.input = input;
this.output = output;
}
private final static Pattern urlPattern
= Pattern.compile("a href=\"(\\p{Graph}*)\"");
public void run() {
while (true) {
System.out.println("in link scanner");
Webpage page = input.take();
// System.out.println("LinkScanner: " + page.url);
// Extract links from the page's <a href="..."> anchors
Matcher urlMatcher = urlPattern.matcher(page.contents);
while (urlMatcher.find()) {
String link = urlMatcher.group(1);
output.put(new Link(page.url, link));
}
}
}
}
class LinkPrinter implements Runnable {
private final BlockingQueue<Link> input;
public LinkPrinter(BlockingQueue<Link> input) {
this.input = input;
}
public void run() {
while (true) {
System.out.println("in link printer");
Link link = input.take();
// System.out.println("LinkPrinter: " + link.from);
System.out.printf("%s links to %s%n", link.from, link.to);
}
}
}
class Webpage {
public final String url, contents;
public Webpage(String url, String contents) {
this.url = url;
this.contents = contents;
}
}
class Link {
public final String from, to;
public Link(String from, String to) {
this.from = from;
this.to = to;
}
// Override hashCode and equals so can be used in HashSet<Link>
public int hashCode() {
return (from == null ? 0 : from.hashCode()) * 37
+ (to == null ? 0 : to.hashCode());
}
public boolean equals(Object obj) {
Link that = obj instanceof Link ? (Link)obj : null;
return that != null
&& (from == null ? that.from == null : from.equals(that.from))
&& (to == null ? that.to == null : to.equals(that.to));
}
}
// Different from java.util.concurrent.BlockingQueue: Allows null
// items, and methods do not throw InterruptedException.
interface BlockingQueue<T> {
void put(T item);
T take();
}
class OneItemQueue<T> implements BlockingQueue<T> {
private T item;
private boolean full = false;
public void put(T item) {
synchronized (this) {
while (full) {
try { this.wait(); }
catch (InterruptedException exn) { }
}
full = true;
this.item = item;
this.notifyAll();
}
}
public T take() {
synchronized (this) {
while (!full) {
try { this.wait(); }
catch (InterruptedException exn) { }
}
full = false;
this.notifyAll();
return item;
}
}
}
Because the Pool is allocating threads dynamically, there are no threads alive after runAsThreads exits because that's the end of the main thread. There needs to be at least on thread running to keep the application alive. Adding a call to awaitTermination is needed. It's not needed for the fixed pool because that will always have active threads until it is explicitly shut down as noted in the JavaDocs.

notifyAll() method is not working in my code

I am trying to implement Bully Algorithm in Java using threads.
Here is the code which I have written.
package newbully;
public class NewBully {
public static void main(String[] args) {
int total_processes = 4;
Thread1[] t = new Thread1[total_processes];
for (int i = 0; i < total_processes; i++) {
t[i] = new Thread1(new Process(i+1, i+1), total_processes);
}
try {
Election.initialElection(t);
} catch (Exception e) {
System.out.println("Possibly you are using null references in array");
}
for (int i = 0; i < total_processes; i++) {
new Thread(t[i]).start();
}
}
}
package newbully;
public class Election {
private static boolean pingFlag = false;
private static boolean electionFlag = false;
private static boolean messageFlag = false;
public static boolean isMessageFlag() {
return messageFlag;
}
public static void setMessageFlag(boolean messageFlag) {
Election.messageFlag = messageFlag;
}
public static boolean isPingFlag() {
return pingFlag;
}
public static void setPingFlag(boolean pingFlag) {
Election.pingFlag = pingFlag;
}
public static boolean isElectionFlag() {
return electionFlag;
}
public static void setElectionFlag(boolean electionFlag) {
Election.electionFlag = electionFlag;
}
public static void initialElection(Thread1[] t) {
Process temp = new Process(-1, -1);
for (int i = 0; i < t.length; i++) {
if (temp.getPriority() < t[i].getProcess().getPriority()) {
temp = t[i].getProcess();
}
}
t[temp.pid - 1].getProcess().CoOrdinatorFlag = true;
}
}
package newbully;
public class Process {
int pid;
boolean downflag,CoOrdinatorFlag;
public boolean isCoOrdinatorFlag() {
return CoOrdinatorFlag;
}
public void setCoOrdinatorFlag(boolean isCoOrdinator) {
this.CoOrdinatorFlag = isCoOrdinator;
}
int priority;
public boolean isDownflag() {
return downflag;
}
public void setDownflag(boolean downflag) {
this.downflag = downflag;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public Process() {
}
public Process(int pid, int priority) {
this.pid = pid;
this.downflag = false;
this.priority = priority;
this.CoOrdinatorFlag = false;
}
}
package newbully;
import java.util.*;
import java.io.*;
import java.net.*;
public class Thread1 implements Runnable {
private Process process;
private int total_processes;
ServerSocket[] sock;
Random r;
public Process getProcess() {
return process;
}
public void setProcess(Process process) {
this.process = process;
}
public Thread1(Process process, int total_processes) {
this.process = process;
this.total_processes = total_processes;
this.r = new Random();
this.sock = new ServerSocket[total_processes];
}
private void recovery() {
}
synchronized private void pingCoOrdinator() {
try {
if (Election.isPingFlag()) {
wait();
}
if (!Election.isElectionFlag()) {
Election.setPingFlag(true);
System.out.println("Process[" + this.process.getPid() + "]: Are you alive?");
Socket outgoing = new Socket(InetAddress.getLocalHost(), 12345);
outgoing.close();
Election.setPingFlag(false);
notifyAll();
}
} catch (Exception ex) {
//Initiate Election
System.out.println("process[" + this.process.getPid() + "]: -> Co-Ordinator is down\nInitiating Election");
Election.setElectionFlag(true);
Election.setPingFlag(false);
notifyAll();
}
}
synchronized private void executeJob() {
int temp = r.nextInt(20);
for (int i = 0; i <= temp; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Error Executing Thread:" + process.getPid());
System.out.println(e.getMessage());
}
}
}
synchronized private boolean sendMessage() {
boolean response = false;
int i = 0;
try {
if (Election.isMessageFlag()) {
wait();
}
Election.setMessageFlag(true);
for (i = this.process.getPid() + 1; i <= this.total_processes; i++) {
try {
Socket electionMessage = new Socket(InetAddress.getLocalHost(), 10000 + i);
System.out.println("Process[" + this.process.getPid() + "] -> Process[" + i + "] responded to election message successfully");
electionMessage.close();
response = true;
} catch (Exception ex) {
System.out.println("Process[" + this.process.getPid() + "] -> Process[" + i + "] did not respond to election message");
}
}
Election.setMessageFlag(false);
notifyAll();
} catch (Exception ex1) {
System.out.println(ex1.getMessage());
}
return response;
}
synchronized private void serve() {
try {
//service counter
ServerSocket s = new ServerSocket(12345);
for (int counter = 0; counter <= 10; counter++) {
Socket incoming = s.accept();
System.out.println("Process[" + this.process.getPid() + "]:Yes");
Scanner scan = new Scanner(incoming.getInputStream());
PrintWriter out = new PrintWriter(incoming.getOutputStream(), true);
if (scan.hasNextLine()) {
if (scan.nextLine().equals("Who is the co-ordinator?")) {
System.out.print("Process[" + this.process.getPid() + "]:");
out.println(this.process);
}
}
if (counter == 10) {//after serving 10 requests go down
this.process.setCoOrdinatorFlag(false);
this.process.setDownflag(true);
try {
incoming.close();
s.close();
sock[this.process.getPid() - 1].close();
Thread.sleep((this.r.nextInt(10) + 1) * 50000);//going down
recovery();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
#Override
public void run() {
try {
sock[this.process.getPid() - 1] = new ServerSocket(10000 + this.process.getPid());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
while (true) {
if (process.isCoOrdinatorFlag()) {
//serve other processes
serve();
} else {
while (true) {
//Execute some task
executeJob();
//Ping the co-ordinator
pingCoOrdinator();
if (Election.isElectionFlag()) {
if (!sendMessage()) {//elect self as co-ordinator
System.out.println("New Co-Ordinator: Process[" + this.process.getPid() + "]");
this.process.setCoOrdinatorFlag(true);
Election.setElectionFlag(false);
break;
}
}
}
}
}
}
}
When I am trying to execute the code out of the 4 threads which I have created some threads are waiting premanently using wait() call. They are not being notified by notifyAll(). Can anyone suggest why this is happening?
Each thread is calling wait() on itself (on its own Thread1 instance). That means that when you call notifyAll() on that same Thread1 instance, only the single Thread1 that is waiting it will be notified, and not all the other threads.
What you have to do is make all your Thread1 objects call wait() on a single, common object, and also call notifyAll() on that same object.
Ofcourse you have to synchronize on the common object when you call wait() or notifyAll() on it; if you don't do that, you'll get an IllegalMonitorStateException.
// Object to be used as a lock; pass this to all Thread1 instances
Object lock = new Object();
// Somewhere else in your code
synchronized (lock) {
lock.wait();
}
// Where you want to notify
synchronized (lock) {
lock.notifyAll();
}
Both notify() (or notifyAll()) and wait() must be written into synchronized block on the same monitor.
For example:
synchronized(myLock) {
wait();
}
..................
synchronized(myLock) {
notifyAll();
}

Categories