Last active
November 28, 2021 04:02
-
-
Save Miha22/3d39697ce947f01886833572ff99e0d5 to your computer and use it in GitHub Desktop.
Active Object Design Pattern in java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
[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
[Removed Method Request]: getDaysBetween from dispatchQueue
[Removed Method Request]: getDaysBetween from dispatchQueue
[Removed Method Request]: getTimeNow from dispatchQueue
[Removed Method Request]: getDaysBetween from dispatchQueue
[Removed Method Request]: getDaysBetween from dispatchQueue