Skip to content

Instantly share code, notes, and snippets.

@Miha22
Last active November 28, 2021 04:02
Show Gist options
  • Save Miha22/3d39697ce947f01886833572ff99e0d5 to your computer and use it in GitHub Desktop.
Save Miha22/3d39697ce947f01886833572ff99e0d5 to your computer and use it in GitHub Desktop.
Active Object Design Pattern in java
package com.hkr;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import static java.lang.System.out;
public class ActivationList {
private static final Deque<MethodRequest> dispatchQueue = new ArrayDeque<>(5);
public static synchronized void enqueue(MethodRequest methodRequest) {
dispatchQueue.addLast(methodRequest);
out.println("[Added Method Request]: " + methodRequest.getName() + " to dispatchQueue" +
"\nQueue size: " + dispatchQueue.size() + "\n");
}
public static synchronized void remove(int id) {
dispatchQueue.removeIf(m -> {
if(m.getId() == id) {
out.println("[Removed Method Request]: " + m.getName() + " from dispatchQueue\n");
return true;
}
return false;
});
}
public static Iterator<MethodRequest> getIterator() {
return dispatchQueue.iterator();
}
}
package com.hkr;
public class Future {
private final Object result;
private final int statusCode;
private final int methodId;
public Future(int methodId, Object result, int statusCode) {
this.methodId = methodId;
this.result = result;
this.statusCode = statusCode;
}
public int getStatusCode() {
return statusCode;
}
public Object getResult() {
return result;
}
public int getMethodId() {
return methodId;
}
@Override
public String toString() {
return "\t[Future value]: " + result.toString() +
"\n\t[MethodID]: " + methodId +
"\n\t[Status code]: " + statusCode + "\n";
}
}
package com.hkr;
import java.util.Arrays;
public class MethodRequest {
private final String name;
private final int id;
private final Object[] parameters;
private Future future;
private static int counter = 0;
private final OnResultReady onResultReady;
public MethodRequest(String name, OnResultReady onResultReady, Object... parameters) {
this.name = name;
this.parameters = Arrays.stream(parameters).toArray();
this.id = counter++;
future = null;
this.onResultReady = onResultReady;
}
public MethodRequest(String name, OnResultReady onResultReady) {
this(name, onResultReady, new Object[0]);
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public boolean canRun() {
//out.println("Is busy: " + Servant.isBusy(name));
boolean flag = Servant.isBusy(name);
//out.println("Is busy: " + flag);
return !flag;
}
public Future call() {
return Servant.run(id, name, parameters);
}
public void setFuture(Future future) {
this.future = future;
onResultReady.resolve(future);
}
}
package com.hkr;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.lang.System.out;
public class Proxy {
private static final ArrayList<Thread> threads = new ArrayList<>(10);
private static final String[] methodsAvailable = new String[] { "getTimeNow", "getDaysBetween" };
public void showMenu() {
out.print("Welcome to public API/Proxy" +
"\nChoose method you want to execute: " + printMethods() +
"\n\nChoice: "
);
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
MethodRequest methodRequest = createRequest(choice);// Creating MethodRequest based on choice
}
public synchronized void generateRequests(int count) {
for (int i = 0; i < count; i++) {
Thread t = new Thread(() -> {
MethodRequest methodRequest = createRequest(new Random().nextInt(2));// Creating MethodRequest based on choice
});
t.start();
threads.add(t);
}
// AtomicBoolean finished = new AtomicBoolean(true);
//
// threads.forEach(t -> {
// try {
// t.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// if(t.isAlive())
// finished.set(false);
// });
//
// if(finished.get())
// Scheduler.shutdown();
}
private MethodRequest createRequest(int choice) {
MethodRequest methodRequest = null; // Creating MethodRequest
switch (choice) {
case 0:
methodRequest = new MethodRequest(
"getTimeNow",
future -> out.println(future.toString())
);
Scheduler.insert(methodRequest);// inserting into ActivationList
break;
case 1 :
methodRequest = new MethodRequest(
"getDaysBetween",
future -> out.println(future.toString()),
new Date(
121, Calendar.NOVEMBER, 27
).getTime(),
new Date(
121, Calendar.DECEMBER, 29
).getTime()
);
Scheduler.insert(methodRequest);// inserting into ActivationList
break;
}
return methodRequest;
}
private String printMethods() {
StringBuilder stringBuilder = new StringBuilder(2);
Arrays.stream(methodsAvailable).forEach(stringBuilder::append);
return stringBuilder.toString();
}
}
package com.hkr;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import static java.lang.System.out;
public class Scheduler {
private static final Semaphore semaphore = new Semaphore(5, true);
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final ArrayList<Thread> threads = new ArrayList<>(5);
static {
scheduler.scheduleAtFixedRate(Scheduler::run, 0, 3, TimeUnit.SECONDS);
}
public static void insert(MethodRequest methodRequest) {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
ActivationList.enqueue(methodRequest);
}
private static synchronized void run() {
Iterator<MethodRequest> iterator = ActivationList.getIterator();
while(iterator.hasNext()) {
MethodRequest method = iterator.next();
if(method.canRun()) { // can run?
Thread t = new Thread(() -> {
out.printf("[Request ID]: %d" +
"\n[Running]: %s\n\n", method.getId(), method.getName());
ActivationList.remove(method.getId()); // remove/dequeue
semaphore.release();
Future future = method.call(); // call
method.setFuture(future);
});
t.start();
threads.add(t);
}
else {
out.printf("[Request ID]: %d" +
"\n[Rescheduling]: %s\n\n", method.getId(), method.getName());
}
out.println(">>> Going to next method\n");
}
}
public static void shutdown() {
threads.forEach(thread -> {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
scheduler.shutdown();
}
}
package com.hkr;
import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import static java.lang.System.out;
public class Servant {
private static final Semaphore semaphore1 = new Semaphore(1, false);
private static final Semaphore semaphore2 = new Semaphore(1, false);
private static String getTimeNow() {
try {
semaphore1.acquire();
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
semaphore1.release();
return new Date().toString();
}
private static long getDaysBetween(Date date1, Date date2, boolean includeEndDate) {
try {
semaphore2.acquire();
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long millisInDay = 60 * 60 * 24 * 1000;
long difference = Math.abs(date1.getTime() - date2.getTime());
long add = millisInDay - (difference % millisInDay);//is used to calculate true number of days, because by default hours, minutes are also counted
semaphore2.release();
return TimeUnit.MILLISECONDS.toDays(difference + add) + (includeEndDate ? 1 : 0);
}
private static boolean isTimeBusy() {
return semaphore1.availablePermits() == 0;
}
private static boolean isBetweenBusy() {
return semaphore2.availablePermits() == 0;
}
public static boolean isBusy(String methodName){
return methodName.equals("getTimeNow") ? isTimeBusy() : isBetweenBusy();
}
public static Future run(int methodId, String methodName, Object... parameters) {
if(methodName.equals("getTimeNow")) {
if(parameters.length != 0) {
return new Future(methodId, null, 400);
}
return new Future(methodId, getTimeNow(), 200);
}
else if(methodName.equals("getDaysBetween")) {
if(parameters.length != 2)
return new Future(methodId, null, 400);
return new Future(methodId, getDaysBetween(new Date((long)parameters[0]), new Date((long)parameters[1]), false), 200);
}
return new Future(methodId, null, 400);
}
}
@Miha22
Copy link
Author

Miha22 commented Nov 28, 2021

public class Client {

    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        //proxy.showMenu();
        Thread client1 = new Thread(() -> proxy.generateRequests(5));
        client1.start();
        Thread client2 = new Thread(() -> proxy.generateRequests(5));
        client2.start();
    }
}

@Miha22
Copy link
Author

Miha22 commented Nov 28, 2021

Possible output:

[Added Method Request]: getTimeNow to dispatchQueue
Queue size: 1

[Added Method Request]: getDaysBetween to dispatchQueue
Queue size: 2

[Added Method Request]: getDaysBetween to dispatchQueue
Queue size: 3

[Added Method Request]: getTimeNow to dispatchQueue
Queue size: 4

[Added Method Request]: getTimeNow to dispatchQueue
Queue size: 5

Going to next method

Going to next method

Going to next method

Going to next method

Going to next method

[Removed Method Request]: getTimeNow from dispatchQueue

[Removed Method Request]: getTimeNow from dispatchQueue

[Removed Method Request]: getTimeNow from dispatchQueue

[Removed Method Request]: getDaysBetween from dispatchQueue

[Removed Method Request]: getDaysBetween from dispatchQueue

[Added Method Request]: getDaysBetween to dispatchQueue
Queue size: 1

[Added Method Request]: getDaysBetween to dispatchQueue
Queue size: 2

[Added Method Request]: getDaysBetween to dispatchQueue
Queue size: 3

[Added Method Request]: getTimeNow to dispatchQueue
Queue size: 4

[Added Method Request]: getDaysBetween to dispatchQueue
Queue size: 5

Going to next method

Going to next method

Going to next method

Going to next method

Going to next method

[Future value]: Sun Nov 28 06:00:07 EET 2021
[MethodID]: 6
[Status code]: 200

Going to next method

Going to next method

Going to next method

Going to next method

Going to next method

[Future value]: 33
[MethodID]: 5
[Status code]: 200

Going to next method

Going to next method

Going to next method

Going to next method

Going to next method

[Future value]: Sun Nov 28 06:00:12 EET 2021
[MethodID]: 7
[Status code]: 200

Going to next method

Going to next method

Going to next method

Going to next method

Going to next method

[Future value]: 33
[MethodID]: 4
[Status code]: 200

Going to next method

[Removed Method Request]: getDaysBetween from dispatchQueue

Going to next method

Going to next method

[Removed Method Request]: getDaysBetween from dispatchQueue

Going to next method

Going to next method

[Future value]: Sun Nov 28 06:00:17 EET 2021
[MethodID]: 0
[Status code]: 200

Going to next method

Going to next method

Going to next method

[Removed Method Request]: getTimeNow from dispatchQueue

Going to next method

Going to next method

[Future value]: 33
[MethodID]: 2
[Status code]: 200

[Future value]: Sun Nov 28 06:00:25 EET 2021
[MethodID]: 9
[Status code]: 200

Going to next method

Going to next method

Going to next method

Going to next method

[Future value]: 33
[MethodID]: 3
[Status code]: 200

Going to next method

Going to next method

[Removed Method Request]: getDaysBetween from dispatchQueue

[Removed Method Request]: getDaysBetween from dispatchQueue

[Future value]: 33
[MethodID]: 1
[Status code]: 200

[Future value]: 33
[MethodID]: 8
[Status code]: 200

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment