From cfe104f54c3982781a31039a703a1875d26beea0 Mon Sep 17 00:00:00 2001 From: Pascal Maczey Date: Mon, 19 Nov 2018 14:19:49 +0100 Subject: [PATCH] Assignment 4 schedule and aggregation of order #12 --- src/main/java/org/team_pjt/Start.java | 6 +- .../java/org/team_pjt/agents/BaseAgent.java | 1 + .../java/org/team_pjt/agents/ClientDummy.java | 130 +++++++++- .../org/team_pjt/agents/OrderProcessing.java | 237 +++++++++++------- .../org/team_pjt/agents/SchedulerAgent.java | 10 + .../org/team_pjt/behaviours/shutdown.java | 5 +- src/main/java/org/team_pjt/objects/Order.java | 36 ++- 7 files changed, 324 insertions(+), 101 deletions(-) diff --git a/src/main/java/org/team_pjt/Start.java b/src/main/java/org/team_pjt/Start.java index f645a58..a9a9bba 100644 --- a/src/main/java/org/team_pjt/Start.java +++ b/src/main/java/org/team_pjt/Start.java @@ -146,13 +146,13 @@ public static List buildCMD(List agents, JSONArray jaBakeries, J for (String a : agents) { if(isHost){ if(a.contains("Scheduler")){ - appendAgentAndArguments(sb, bakery.toString().replaceAll(",", "###"), a); + appendAgentAndArguments(sb, bakery.toString().replaceAll(",", "###") + "," + joMeta.toString().replaceAll(",", "###"), a); sb.append(";"); continue; } if(a.contains("OrderProcessing")) { bakery = (JSONObject)bakery_iterator.next(); - appendAgentAndArguments(sb, bakery.toString().replaceAll(",", "###"), a); + appendAgentAndArguments(sb, bakery.toString().replaceAll(",", "###") + "," + joMeta.toString().replaceAll(",", "###"), a); sb.append(";"); continue; } @@ -160,7 +160,7 @@ public static List buildCMD(List agents, JSONArray jaBakeries, J else { if(a.contains("Client")){ JSONObject client = (JSONObject)customer_iterator.next(); - appendAgentAndArguments(sb, client.toString().replaceAll(",", "###"), a); + appendAgentAndArguments(sb, client.toString().replaceAll(",", "###") + "," + joMeta.toString().replaceAll(",", "###"), a); sb.append(";"); continue; } diff --git a/src/main/java/org/team_pjt/agents/BaseAgent.java b/src/main/java/org/team_pjt/agents/BaseAgent.java index 3a4c24a..7c3ea36 100644 --- a/src/main/java/org/team_pjt/agents/BaseAgent.java +++ b/src/main/java/org/team_pjt/agents/BaseAgent.java @@ -128,6 +128,7 @@ public void action(){ currentDay = day; currentHour = hour; allowAction = true; + finished(); } else { block(); diff --git a/src/main/java/org/team_pjt/agents/ClientDummy.java b/src/main/java/org/team_pjt/agents/ClientDummy.java index 88298dc..e63756c 100644 --- a/src/main/java/org/team_pjt/agents/ClientDummy.java +++ b/src/main/java/org/team_pjt/agents/ClientDummy.java @@ -2,6 +2,7 @@ import jade.core.AID; import jade.core.Agent; +import jade.core.behaviours.CyclicBehaviour; import jade.core.behaviours.OneShotBehaviour; import jade.core.behaviours.TickerBehaviour; import jade.core.behaviours.WakerBehaviour; @@ -18,25 +19,27 @@ import org.team_pjt.objects.Location; import org.team_pjt.objects.Order; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.util.*; public class ClientDummy extends BaseAgent { private AID[] aidSchedulerAgents; - private List orders; + private List ordersToSent; + private List ordersSent; + private List ordersReceived; private String guid; private String name; private int type; private Location location; + private int endDays; protected void setup(){ + super.setup(); Object[] oArguments = getArguments(); if(!readArgs(oArguments)){ System.out.println("No parameters given for ClientDummy " + getName()); } register("customer", guid); - addBehaviour(new shutdown()); + addBehaviour(new OrderTimeChecker()); } private boolean readArgs(Object[] oArguments) { @@ -49,16 +52,129 @@ private boolean readArgs(Object[] oArguments) { this.type = joClient.getInt("type"); this.location = new Location(joClient.getJSONObject("location").getDouble("y"),joClient.getJSONObject("location").getDouble("x")); - orders = new LinkedList<>(); + ordersToSent = new LinkedList<>(); Iterator order_iterator = joClient.getJSONArray("orders").iterator(); while(order_iterator.hasNext()) { JSONObject joOrder = (JSONObject)order_iterator.next(); - orders.add(new Order(joOrder.toString())); + ordersToSent.add(new Order(joOrder.toString())); } + Collections.sort(ordersToSent, new Comparator() { + @Override + public int compare(Order o1, Order o2) { + if(o1.getOrderDay() < o2.getOrderDay()) { + return -1; + } + else if(o1.getOrderDay() == o2.getOrderDay() && o1.getOrderHour() < o2.getOrderHour()) { + return -1; + } + else if(o1.getOrderDay() == o2.getOrderDay() && o1.getOrderHour() == o2.getOrderHour()) { + return 0; + } + return 1; + } + }); + + JSONObject meta_data = new JSONObject(((String)oArguments[1]).replaceAll("###", ",")); + this.endDays = meta_data.getInt("durationInDays"); + return true; } return false; } + + private class OrderTimeChecker extends CyclicBehaviour { + + @Override + public void action() { + if(getCurrentDay() >= endDays) { + System.out.println("system shutdown!"); + addBehaviour(new shutdown()); + } + System.out.println(getCurrentDay() + " - " + getCurrentHour()); + if(ordersToSent.get(0).getOrderDay() == getCurrentDay() && ordersToSent.get(0).getOrderHour() == getCurrentHour()) { + myAgent.addBehaviour(new RequestPerformer(ordersToSent.get(0))); + ordersSent.add(ordersToSent.remove(0)); + } + } + } + + private class RequestPerformer extends OneShotBehaviour { + private AID[] orderProcessingAgents; + private Order order; + private Hashtable> proposedPrices; + private ACLMessage lastSendMessage; + private ACLMessage lastReceivedMessage; +// private int proposalStep = 0; + + public RequestPerformer(Order order) { + super(); + proposedPrices = new Hashtable<>(); + this.order = order; + } + + @Override + public void action() { + findOrderProcessingAgents(); + sendCallForProposal(); + receiveProposals(); + } + + private void sendCallForProposal() { + ACLMessage cfp = new ACLMessage(ACLMessage.CFP); + cfp.setConversationId(order.getGuid()); + cfp.setContent(order.toJSONString()); + for(AID agent : orderProcessingAgents) { + cfp.addReceiver(agent); + } + myAgent.send(cfp); + lastSendMessage = cfp; + } + + private void receiveProposals() { + int proposalCounter = 0; + MessageTemplate proposalTemplate = MessageTemplate.or(MessageTemplate.MatchPerformative(ACLMessage.PROPOSE), + MessageTemplate.MatchPerformative(ACLMessage.REFUSE)); + ACLMessage proposal = myAgent.receive(proposalTemplate); + while(proposalCounter != orderProcessingAgents.length) { + if (proposal != null) { + proposalCounter++; + if(proposal.getPerformative() == ACLMessage.REFUSE) { + System.out.println("Bakery " + proposal.getSender() + " refused call for proposal with message:"); + System.out.println(proposal.getContent()); + } + else { + Hashtable available_products = new Hashtable<>(); + JSONObject order = new JSONObject(proposal.getContent()); + for(String product_name : order.getJSONObject("products").keySet()) { + available_products.put(product_name, order.getJSONObject("products").getDouble(product_name)); + } + proposedPrices.put(proposal.getSender().getName(), available_products); + } + } else { + block(); + } + } + } + + private void findOrderProcessingAgents() { + DFAgentDescription template = new DFAgentDescription(); + ServiceDescription sd = new ServiceDescription(); + sd.setType("OrderProcessing"); + template.addServices(sd); + try { + DFAgentDescription[] result = DFService.search(myAgent, template); + orderProcessingAgents = new AID[result.length]; + for (int i = 0; i < result.length; ++i) { + orderProcessingAgents[i] = result[i].getName(); + } + } + catch (FIPAException fe) { + System.out.println("Error searching OrderProcessingAgents"); + fe.printStackTrace(); + } + System.out.println(orderProcessingAgents.length + " OrderProcessingAgents found!"); + } + } } diff --git a/src/main/java/org/team_pjt/agents/OrderProcessing.java b/src/main/java/org/team_pjt/agents/OrderProcessing.java index 4fdf3d1..6c67ba3 100644 --- a/src/main/java/org/team_pjt/agents/OrderProcessing.java +++ b/src/main/java/org/team_pjt/agents/OrderProcessing.java @@ -1,6 +1,7 @@ package org.team_pjt.agents; import jade.core.AID; +import jade.core.behaviours.CyclicBehaviour; import jade.core.behaviours.TickerBehaviour; import jade.domain.DFService; import jade.domain.FIPAAgentManagement.DFAgentDescription; @@ -10,35 +11,38 @@ import jade.lang.acl.MessageTemplate; import org.json.JSONArray; import org.json.JSONObject; -import org.team_pjt.behaviours.receiveKillMessage; import org.team_pjt.behaviours.shutdown; +import org.team_pjt.objects.Order; import org.team_pjt.objects.Product; import org.team_pjt.objects.Location; -//import org.team_pjt.objects.Product; import java.util.*; // ToDo OrderProcessing in OrderProcessingAgent umbenennen public class OrderProcessing extends BaseAgent { - public static final String DURATION = "duration"; private String sBakeryId; private Location lLocation; private HashMap hmProducts; // = Available Products - private StringBuffer sbResponseArray; - private boolean bFeasibleOrder; private AID aidScheduler; + private AID[] allAgents; + private int endDays; protected void setup(){ super.setup(); - DFAgentDescription[] dfSchedulerAgentResult = new DFAgentDescription[0]; Object[] oArguments = getArguments(); if (!readArgs(oArguments)) { System.out.println("No parameter given for OrderProcessing " + getName()); } -// registerAgent(); - super.register("OrderProcessing", this.sBakeryId); + this.register("OrderProcessing", this.sBakeryId); + findScheduler(); + addBehaviour(new OfferRequestServer()); + System.out.println("OrderProcessing " + getName() + " ready"); + + } + + private void findScheduler() { + DFAgentDescription[] dfSchedulerAgentResult = new DFAgentDescription[0]; DFAgentDescription template = new DFAgentDescription(); ServiceDescription sd = new ServiceDescription(); -// sd.setType("scheduler"+); sd.setName("scheduler-"+sBakeryId.split("-")[1]); template.addServices(sd); while (dfSchedulerAgentResult.length == 0) { @@ -49,65 +53,41 @@ protected void setup(){ } } aidScheduler = dfSchedulerAgentResult[0].getName(); - addBehaviour(new shutdown()); - System.out.println("OrderProcessing " + getName() + " ready"); - + System.out.println("Scheduler found! - " + aidScheduler); } - private void checkOrderForFeasibility(AID aidSender, JSONArray jsaCustomerArray) { - bFeasibleOrder = false; - Iterator iCustomerArray = jsaCustomerArray.iterator(); - while(iCustomerArray.hasNext()){ - sbResponseArray = new StringBuffer(); - sbResponseArray.append("{"); - JSONObject jsoObject = (JSONObject) iCustomerArray.next(); - JSONArray jsaOrders = jsoObject.getJSONArray("orders"); - Iterator iJsaIterator = jsaOrders.iterator(); - while(iJsaIterator.hasNext()){ - JSONObject oNextProduct = (JSONObject) iJsaIterator.next(); - JSONObject jsoProducts = oNextProduct.getJSONObject("products"); - Iterator iKeys = jsoProducts.keys(); - // Jan provisorisch - int i = 0; - while(iKeys.hasNext()){ - String sNextProduct = iKeys.next(); - if(hmProducts.get(sNextProduct)!= null){ - if(!bFeasibleOrder){ - JSONObject jsodeliveryDate = oNextProduct.getJSONObject("deliveryDate"); - sbResponseArray.append("deliveryDate:"); - sbResponseArray.append(jsodeliveryDate.toString()); - sbResponseArray.append(","); - sbResponseArray.append("products: {"); - } - if(i != 0){ - sbResponseArray.append(","); - } - bFeasibleOrder = true; - sbResponseArray.append(sNextProduct + ":" + jsoProducts.getInt(sNextProduct)); - i++; - } - } - } - sbResponseArray.append("}}"); - sbResponseArray.toString(); - ACLMessage almCustomerResponseMessage = null; - if (bFeasibleOrder) { - almCustomerResponseMessage = new ACLMessage(ACLMessage.PROPOSE); - almCustomerResponseMessage.addReceiver(aidScheduler); - almCustomerResponseMessage.setContent(sbResponseArray.toString()); - } else { - almCustomerResponseMessage = new ACLMessage(ACLMessage.REFUSE); - almCustomerResponseMessage.setContent("No matching products"); + private void findAllAgents() { + DFAgentDescription template = new DFAgentDescription(); + ServiceDescription sd = new ServiceDescription(); + template.addServices(sd); + try { + DFAgentDescription[] result = DFService.search(this, template); + allAgents = new AID[result.length]; + int counter = 0; + for(DFAgentDescription ad : result) { + allAgents[counter] = ad.getName(); + counter++; } - // ToDo Antwort vom Scheduler einbauen - almCustomerResponseMessage.addReceiver(aidSender); - super.send(almCustomerResponseMessage); - if(bFeasibleOrder){ - addOrderToQueue(); - distributeOrder(); + } + catch (FIPAException fe) { + fe.printStackTrace(); + allAgents = new AID[0]; + } + } + + private boolean checkForAvailableProducts(List neededProducts) { + boolean bFeasibleOrder = false; + List notAvailableProducts = new LinkedList<>(); + for (String product_name : neededProducts) { + if(!hmProducts.containsKey(product_name)) { + notAvailableProducts.add(product_name); } - bFeasibleOrder = false; } + if(neededProducts.size() != notAvailableProducts.size()) { + bFeasibleOrder = true; + } + neededProducts.removeAll(notAvailableProducts); + return bFeasibleOrder; } private void addOrderToQueue() { @@ -118,31 +98,6 @@ private void distributeOrder() { } -// private void registerAgent() { -// DFAgentDescription dfd = new DFAgentDescription(); -// dfd.setName(getAID()); -// ServiceDescription sd = new ServiceDescription(); -// sd.setType("schedulerbakery"); -// sd.setName(this.sBakeryId); -// dfd.addServices(sd); -// try { -// DFService.register(this, dfd); -// } catch (FIPAException e) { -// e.printStackTrace(); -// } -// } - - private String prepareArguments(Object[] oArguments) { - String[] stringArray = Arrays.copyOf(oArguments, oArguments.length, String[].class); - StringBuilder sbBuilder = new StringBuilder(); - for(int i = 0; i< stringArray.length;i++){ - sbBuilder.append(stringArray[i]); - if(i < stringArray.length - 1){sbBuilder.append(",");} - } - String sArguments = sbBuilder.toString(); - return sArguments; - } - private boolean readArgs(Object[] oArgs){ if(oArgs != null && oArgs.length > 0){ hmProducts = new HashMap<>(); @@ -155,15 +110,116 @@ private boolean readArgs(Object[] oArgs){ while(product_iterator.hasNext()) { JSONObject jsoProduct = (JSONObject) product_iterator.next(); Product product = new Product(jsoProduct.toString()); + hmProducts.put(product.getGuid(), product); } JSONObject jsoLocation = bakery.getJSONObject("location"); lLocation = new Location(jsoLocation.getDouble("y"), jsoLocation.getDouble("x")); + + JSONObject meta_data = new JSONObject(((String)oArgs[1]).replaceAll("###", ",")); + this.endDays = meta_data.getInt("durationInDays"); + return true; } else { return false; } } + + private class OfferRequestServer extends CyclicBehaviour { + private boolean bFeasibleOrder; + + private void sendNotFeasibleMessage(ACLMessage msg, String content) { + ACLMessage clientReply = msg.createReply(); + clientReply.setPerformative(ACLMessage.REFUSE); + clientReply.setContent(content); + myAgent.send(clientReply); + } + + @Override + public void action() { + if(getCurrentDay() >= endDays) { + System.out.println("system shutdown!"); + addBehaviour(new shutdown()); + } + MessageTemplate cfpMT = MessageTemplate.MatchPerformative(ACLMessage.CFP); + ACLMessage cfpMsg = myAgent.receive(cfpMT); + if(cfpMsg != null) { + Order order = new Order(cfpMsg.getContent()); + List order_av_products = new LinkedList<>(order.getProducts().keySet()); + bFeasibleOrder = checkForAvailableProducts(order_av_products); + + if(!bFeasibleOrder) { + sendNotFeasibleMessage(cfpMsg, "No needed Product available!"); + return; + } + + ACLMessage schedulerRequest = new ACLMessage(ACLMessage.REQUEST); + Hashtable order_products = order.getProducts(); + + for(String product_name : order_products.keySet()) { + if(!order_av_products.contains(product_name)) { + order_products.remove(product_name); + } + } + + order.setProducts(order_products); + schedulerRequest.setConversationId(order.getGuid()); + schedulerRequest.setContent(order.toJSONString()); + myAgent.send(schedulerRequest); + + MessageTemplate schedulerReply = MessageTemplate.and(MessageTemplate.MatchConversationId(order.getGuid()), + MessageTemplate.MatchSender(aidScheduler)); + ACLMessage schedulerMessage = myAgent.receive(schedulerReply); + if(schedulerMessage != null) { + if(schedulerMessage.getPerformative() == ACLMessage.CONFIRM) { + ACLMessage proposeMsg = cfpMsg.createReply(); + proposeMsg.setPerformative(ACLMessage.PROPOSE); + + JSONObject proposeObject = new JSONObject(); + JSONObject products = new JSONObject(); + proposeObject.put("guid", order.getGuid()); + for(String product_name : order.getProducts().keySet()) { + double priceAllProductsOfType = hmProducts.get(product_name).getSalesPrice() * order.getProducts().get(product_name); + products.put(product_name, priceAllProductsOfType); + } + proposeObject.put("products", products); + proposeMsg.setContent(proposeObject.toString()); + proposeMsg.setConversationId(order.getGuid()); + myAgent.send(proposeMsg); + + MessageTemplate proposalReplyMT = MessageTemplate.and(MessageTemplate.MatchConversationId(order.getGuid()), + MessageTemplate.MatchSender(cfpMsg.getSender())); + ACLMessage proposalReply = myAgent.receive(proposalReplyMT); + if(proposalReply != null) { + if(proposalReply.getPerformative() == ACLMessage.ACCEPT_PROPOSAL) { + + // send to all Agents, send to schedule to addToQueue + } + else if (proposalReply.getPerformative() == ACLMessage.REJECT_PROPOSAL) { + return; + } + } + else { + block(); + } + } + else if(schedulerMessage.getPerformative() == ACLMessage.DISCONFIRM) { + bFeasibleOrder = false; + } + if(!bFeasibleOrder) { + sendNotFeasibleMessage(cfpMsg, "Not able to schedule Order!"); + return; + } + } + else { + block(); + } + } + else { + block(); + } + } + } } /* @@ -213,4 +269,9 @@ private boolean readArgs(Object[] oArgs){ * Sender: SchedulerAgent * Receiver: OrderProcessingAgent * Content: String -> Scheduling impossible + * Propagate accepted Orders: + * Type: PROPAGATE + * Sender: SchedulerAgent + * Receiver: allAgents + * Content: JSONArray -> sorted List of all received Orders */ \ No newline at end of file diff --git a/src/main/java/org/team_pjt/agents/SchedulerAgent.java b/src/main/java/org/team_pjt/agents/SchedulerAgent.java index eff01c5..38e8647 100644 --- a/src/main/java/org/team_pjt/agents/SchedulerAgent.java +++ b/src/main/java/org/team_pjt/agents/SchedulerAgent.java @@ -6,6 +6,8 @@ import jade.lang.acl.MessageTemplate; import org.json.JSONArray; import org.json.JSONObject; +import org.team_pjt.behaviours.shutdown; +import org.team_pjt.objects.Order; import org.team_pjt.objects.Product; import java.util.HashMap; @@ -15,6 +17,8 @@ public class SchedulerAgent extends BaseAgent { private HashMap hmPrepTables; private HashMap hmKneadingMachine; private HashMap hmProducts; // = Available Products + private HashMap scheduledOrders; + private int endDays; protected void setup(){ super.setup(); @@ -23,6 +27,12 @@ protected void setup(){ addBehaviour(new CyclicBehaviour() { @Override public void action() { + if(getCurrentDay() >= endDays) { + System.out.println("system shutdown!"); + addBehaviour(new shutdown()); + } +// System.out.println(getCurrentDay() + " - " + getCurrentHour()); +// System.out.println(getAllowAction()); ACLMessage aclmProducts = (ACLMessage) myAgent.receive(MessageTemplate.MatchPerformative(ACLMessage.PROPOSE)); if(aclmProducts != null &&(aclmProducts.getPerformative() == ACLMessage.PROPOSE)){ String sContent = aclmProducts.getContent(); diff --git a/src/main/java/org/team_pjt/behaviours/shutdown.java b/src/main/java/org/team_pjt/behaviours/shutdown.java index 9201130..fa1cfe0 100644 --- a/src/main/java/org/team_pjt/behaviours/shutdown.java +++ b/src/main/java/org/team_pjt/behaviours/shutdown.java @@ -18,12 +18,13 @@ public void action() { shutdownMessage.addReceiver(myAgent.getAMS()); shutdownMessage.setLanguage(FIPANames.ContentLanguage.FIPA_SL); shutdownMessage.setOntology(JADEManagementOntology.getInstance().getName()); + System.out.println("shutdown " + myAgent.getName()); try { myAgent.getContentManager().fillContent(shutdownMessage,new Action(myAgent.getAID(), new ShutdownPlatform())); -// myAgent.send(shutdownMessage); + myAgent.send(shutdownMessage); } catch (Exception e) { - //LOGGER.error(e); + e.printStackTrace(); } } diff --git a/src/main/java/org/team_pjt/objects/Order.java b/src/main/java/org/team_pjt/objects/Order.java index 90eddac..3eaac9d 100644 --- a/src/main/java/org/team_pjt/objects/Order.java +++ b/src/main/java/org/team_pjt/objects/Order.java @@ -8,6 +8,7 @@ public class Order { private String customer_agent_id; + private String guid; private int order_day; private int order_hour; private int delivery_day; @@ -17,11 +18,12 @@ public class Order { public Order(String json_order_string) { products = new Hashtable<>(); JSONObject order = new JSONObject(json_order_string); - customer_agent_id = order.getString("customer_id"); + customer_agent_id = order.getString("customerId"); order_day = order.getJSONObject("orderDate").getInt("day"); order_hour = order.getJSONObject("orderDate").getInt("hour"); delivery_day = order.getJSONObject("deliveryDate").getInt("day"); delivery_hour = order.getJSONObject("deliveryDate").getInt("hour"); + guid = order.getString("guid"); Iterator prouct_name_it = order.getJSONObject("products").keys(); @@ -31,6 +33,14 @@ public Order(String json_order_string) { } } + public String getGuid() { + return guid; + } + + public void setGuid(String guid) { + this.guid = guid; + } + public int getOrderDay() { return order_day; } @@ -70,4 +80,28 @@ public Hashtable getProducts() { public void setProducts(Hashtable products) { this.products = products; } + + public String toJSONString() { + JSONObject order = new JSONObject(); + + JSONObject orderDate = new JSONObject(); + orderDate.put("day", order_day); + orderDate.put("hour", order_hour); + + JSONObject deliveryDate = new JSONObject(); + orderDate.put("day", delivery_day); + orderDate.put("hour", delivery_hour); + + JSONObject loc_products = new JSONObject(); + for(String product_name : products.keySet()) { + loc_products.put(product_name, products.get(product_name)); + } + + order.put("customerId", customer_agent_id); + order.put("guid", guid); + order.put("orderDater", orderDate); + order.put("deliveryDate", deliveryDate); + order.put("products", loc_products); + return order.toString(); + } }