diff --git a/.gitignore b/.gitignore index 09e3bc9b241c477ea341af9ee029becad0c2148c..064cdbf0b877fcaa6cd1c833b345298c993bffe4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /bin/ /target/ +.idea/ +*.iml +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7a25f1b73de2df837837e5f3985ac40555600ad7 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +## Freie Universität Berlin cryptocurrency (fucoin) + + + +### How to run? + +We assume that the project is based in `<project-folder>` and maven is as command line tool installed. + +``` +$> cd <project-folder> +$> mvn compile +$> mvn exec:java +``` + + +### Dependencies + +* Java 8 +* Maven +* Akka Actor \ No newline at end of file diff --git a/pom.xml b/pom.xml index ccdd40ba7e08a14b15f3b932107be1e45b380f39..9bf2c6d5319c4ce47d79e13325a52750cc823b3b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,26 +1,55 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>JavaAkkaFuCoin</groupId> - <artifactId>JavaAkkaFuCoin</artifactId> - <version>0.0.1-SNAPSHOT</version> - <build> - <sourceDirectory>src</sourceDirectory> - <plugins> - <plugin> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> - <configuration> - <source>1.8</source> - <target>1.8</target> - </configuration> - </plugin> - </plugins> - </build> - <dependencies> - <dependency> - <groupId>com.typesafe.akka</groupId> - <artifactId>akka-actor_2.11</artifactId> - <version>2.4-M1</version> - </dependency> - </dependencies> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>JavaAkkaFuCoin</groupId> + <artifactId>JavaAkkaFuCoin</artifactId> + <version>0.0.1-SNAPSHOT</version> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + <!-- java doc + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.10.4</version> + </plugin> + --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.5.0</version> + <executions> + <execution> + <goals> + <goal>exec</goal> + </goals> + </execution> + </executions> + <configuration> + <mainClass>fucoin.Main</mainClass> + <executable>maven</executable> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>com.typesafe.akka</groupId> + <artifactId>akka-actor_2.11</artifactId> + <version>2.4.7</version> + </dependency> + <dependency> + <groupId>com.typesafe.akka</groupId> + <artifactId>akka-remote_2.11</artifactId> + <version>2.4.7</version> + </dependency> + </dependencies> </project> \ No newline at end of file diff --git a/src/fucoin/AbstractNode.java b/src/fucoin/AbstractNode.java deleted file mode 100644 index 912b0a2c0cfdb57c3cab8f0ee36cd0ce3fde9f68..0000000000000000000000000000000000000000 --- a/src/fucoin/AbstractNode.java +++ /dev/null @@ -1,58 +0,0 @@ -package fucoin; - -import java.io.Serializable; -import java.util.HashMap; - -import akka.actor.ActorRef; -import akka.actor.UntypedActor; - -public abstract class AbstractNode extends UntypedActor implements Serializable { - - // Returns the akka-style address as String, which - // could be converted to an ActorRef object later - public String getAddress() { - return getAddress(getSelf()); - } - - public String getAddress(ActorRef self) { - return self.path().toSerializationFormatWithAddress(self.path().address()); - } - - // The which receives Action objects - public abstract void onReceive(Object message); - - // Holds references to neighbors that were in - // contact with this wallet during runtime; - // The key corresponds to the Wallet's name - private transient HashMap<String, ActorRef> knownNeighbors = new HashMap<String, ActorRef>(); - - // Holds references to neighbors this wallet - // synchronizes itself to (the Wallet object); - // The key corresponds to the Wallet's name - public transient HashMap<String, ActorRef> localNeighbors = new HashMap<String, ActorRef>(); - - // Holds all Wallets from network participants - // which synchronize their state (Wallet object) - // with us; - // The key corresponds to the Wallet's name - public transient HashMap<String, AbstractWallet> backedUpNeighbors = new HashMap<String, AbstractWallet>(); - - public transient HashMap<ActorRef, Integer> amounts = new HashMap<ActorRef, Integer>(); - - public boolean addKnownNeighbor(String key, ActorRef value) { - if(!knownNeighbors.containsKey(key)){ - knownNeighbors.put(key,value); - return true; - } - return false; - } - - public HashMap<String, ActorRef> getKnownNeighbors() { - return knownNeighbors; - } - - public void log(String string) { - System.out.println(getSelf().path().name()+": "+string); - } - -} \ No newline at end of file diff --git a/src/fucoin/AbstractWallet.java b/src/fucoin/AbstractWallet.java deleted file mode 100644 index e77b6741fe070bf95bb93046940d0c6865db3cf9..0000000000000000000000000000000000000000 --- a/src/fucoin/AbstractWallet.java +++ /dev/null @@ -1,27 +0,0 @@ -package fucoin; - -public abstract class AbstractWallet extends AbstractNode{ - - // Constructor - public AbstractWallet(String name) { - this.name = name; - } - - // Returns the name of this wallet, e.g. "Lieschen Müller" - public String getName() { - return this.name; - } - - // Performs housekeeping operations, e.g. pushes - // backedUpNeighbor-entries to other neighbors - public abstract void leave(); - - // The amount this wallet currently holds - public int amount; - - // The name of this wallet (does never change, no - // duplicates in network assumed) - public final String name; - - -} diff --git a/src/fucoin/IWallet.java b/src/fucoin/IWallet.java deleted file mode 100644 index 54ec9b3291fdd832ffdd6c67411d10e2bfb80562..0000000000000000000000000000000000000000 --- a/src/fucoin/IWallet.java +++ /dev/null @@ -1,13 +0,0 @@ -package fucoin; -import java.util.Vector; - -import fucoin.gui.IWalletControle; - - -public interface IWallet extends IWalletControle{ - //Vector<WalletPointer> join(); - void storeOrUpdate(Wallet w); - void invalidateWallet(Wallet w); - void receiveTransaction(int amount); - //Vector<WalletPointer> searchWallet(String adress); -} diff --git a/src/fucoin/Main.java b/src/fucoin/Main.java deleted file mode 100644 index 494bce433d6edc803353107f795c45977f6de723..0000000000000000000000000000000000000000 --- a/src/fucoin/Main.java +++ /dev/null @@ -1,77 +0,0 @@ -package fucoin; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; - -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; - -import fucoin.actions.join.ServerActionJoin; -import fucoin.supervisor.SuperVisor; - - - -public class Main { - - public static void main(String[] args) throws InterruptedException { - File file = new File("application.conf"); - System.out.println("config found? " + file.exists()); - Config config = ConfigFactory.parseFile(file); - ActorSystem system = ActorSystem.create("Core", config); - ActorRef superVisorActor = system.actorOf(SuperVisor.props(),"SuperVisor"); - List<ActorRef> activeActors = new ArrayList<ActorRef>(); - ActorRef a1 = system.actorOf(Wallet.props(null,"","Main",superVisorActor),"Main"); - ActorRef a2 = system.actorOf(Wallet.props(a1,"Main","Main2",superVisorActor),"Main2"); - superVisorActor.tell(new ServerActionJoin("Main"), a1); - superVisorActor.tell(new ServerActionJoin("Main2"), a2); - - //a2.tell(new ActionInvokeSentMoney("Main", 200), a2); - //activeActors.add(a1); - /* - int maxrounds = 100; - int maxactors = 10; - for(int actor=0; actor<maxactors;actor++){ - activeActors.add(system.actorOf(Wallet.props(a1,"Main","Main"+actor,superVisorActor),"Main"+actor)); - } - List<List<ActorRef>> offline = new ArrayList<List<ActorRef>>(); - - for(int listnr=0; listnr<maxrounds;listnr++){ - offline.add(new ArrayList<ActorRef>()); - } - - for(int timestep=0; timestep<maxrounds;timestep++){ - System.out.println("timestamp:"+timestep); - List<ActorRef> removedActors = new ArrayList<ActorRef>(); - for(ActorRef actor:activeActors){ - if(Math.random()<0.6){ - actor.tell(new ActionInvokeSentMoney("Main"+(int)Math.floor(Math.random()*maxactors), (int) (Math.round(Math.random()*100))), actor); - } - if(Math.random()<0.2){ - removedActors.add(actor); - int offtime = timestep+(int)(Math.random()*6)+2; - - offline.get(Math.min(offtime, maxrounds-1)).add(actor); - } - } - activeActors.removeAll(removedActors); - for(ActorRef actorName:offline.get(timestep)){ - actorName.tell(new ActionInvokeRevive(), actorName); - activeActors.add(actorName); - } - for(ActorRef removedActor : removedActors){ - removedActor.tell(new ActionInvokeLeave(), removedActor); - } - - Thread.sleep(1000); - System.out.println("timestamp end:"+timestep); - System.out.println("activeActors:"+activeActors); - System.out.println("revived"+offline.get(timestep)); - - } - superVisorActor.tell(new ActionInvokeUpdate(), superVisorActor); - */ - } -} diff --git a/src/fucoin/MainRemote.java b/src/fucoin/MainRemote.java deleted file mode 100644 index 309bae2951caf6bd4b66df846f58ea8eec7bb4e2..0000000000000000000000000000000000000000 --- a/src/fucoin/MainRemote.java +++ /dev/null @@ -1,32 +0,0 @@ -package fucoin; - -import java.io.File; - -import akka.actor.ActorPath; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Address; - -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; - -public class MainRemote { - public static ActorRef remoteSuperVisorActor; - - public static void main(String[] args) throws InterruptedException { - - File file = new File("application.conf"); - System.out.println("config found? " + file.exists()); - Config config = ConfigFactory.parseFile(file); - ActorSystem system = ActorSystem.create("Test", config); - - Address address = new Address("akka.tcp", "Core", "127.0.0.1", 1234); - System.out.println(address); - String path = "akka.tcp://Core@127.0.0.1:1234/user/Main"; - System.out.println(system.actorSelection(ActorPath.fromString(path))); - - System.out.println(ActorPath.isValidPathElement(""+address+"/user/Main")); - ActorRef a1 = system.actorOf(Wallet.props(null,"","Main2",remoteSuperVisorActor),"Main2"); - - } -} diff --git a/src/fucoin/Wallet.java b/src/fucoin/Wallet.java deleted file mode 100644 index 70f26fd81a94ae30e0cb5afeaf122774b7750467..0000000000000000000000000000000000000000 --- a/src/fucoin/Wallet.java +++ /dev/null @@ -1,173 +0,0 @@ -package fucoin; - -import akka.actor.ActorRef; -import akka.actor.Props; -import fucoin.actions.ClientAction; -import fucoin.actions.join.ActionJoin; -import fucoin.actions.join.ActionJoinAnswer; -import fucoin.actions.join.ServerActionJoin; -import fucoin.actions.persist.ActionInvokeLeave; -import fucoin.actions.persist.ActionInvokeRevive; -import fucoin.actions.transaction.ActionGetAmountAnswer; -import fucoin.actions.transaction.ActionInvokeSentMoney; -import fucoin.gui.IWalletControle; -import fucoin.gui.IWalletGuiControle; - -public class Wallet extends AbstractWallet implements IWalletControle{ - - private ActorRef preknownNeighbour; - private ActorRef remoteSuperVisorActor; - private IWalletGuiControle gui; - private String preknownNeighbourName; - private boolean isActive; - - public Wallet(ActorRef preknownNeighbour, String preknownNeighbourName, String walletName, ActorRef remoteSuperVisorActor) { - super(walletName); - this.preknownNeighbourName=preknownNeighbourName; - this.preknownNeighbour=preknownNeighbour; - this.remoteSuperVisorActor=remoteSuperVisorActor; - } - - public void addAmount(int amount) { - setAmount(this.amount+amount); - log(" My amount is now "+this.amount); - - } - - @Override - public void leave() { - getSelf().tell(new ActionInvokeLeave(), getSelf()); - } - - @Override - public void onReceive(Object message) { - log(message.getClass().getSimpleName()); - - //log(getSender().path().name()+" invokes "+getSelf().path().name()+" to do "+message.getClass().getSimpleName()); - if(message instanceof ActionInvokeRevive){ - ((ActionInvokeRevive) message).doAction(this); - } - if(!isActive&&!(message instanceof ActionInvokeRevive))return; - //System.out.println(message); - if(message instanceof ClientAction){ - ((ClientAction) message).doAction(this); - } - - } - - @Override - public void preStart() throws Exception { - isActive=true; - if(gui!=null){ - gui.setAddress(getAddress()); - } - String path = "akka.tcp://Core@127.0.0.1:1234/user/Main"; - //System.out.println(getContext().provider().getExternalAddressFor(getSelf().path().address())); - //log("my address should be "+getAddress()); - //log(""+preknownNeighbour); - //knownNeighbors.put(getName(),getSelf()); - - //System.out.println(knownNeighbors); - if(preknownNeighbour!=null){ - addKnownNeighbor(preknownNeighbourName,preknownNeighbour); - preknownNeighbour.tell(new ActionJoin(), getSelf()); - ActionJoinAnswer aja = new ActionJoinAnswer(); - aja.someNeighbors.putAll(getKnownNeighbors()); - aja.someNeighbors.put(name, getSelf()); - preknownNeighbour.tell(aja, getSelf()); - - } - //setAmount(100); - //remoteSuperVisorActor.tell(new ServerActionJoin(name), getSelf()); - } - - @Override - public void postStop() throws Exception { - leave(); - super.postStop(); - - } - - - public static Props props(ActorRef preknownNeighbour, String preknownNeighbourName, String walletName, ActorRef remoteSuperVisorActor) { - return Props.create(Wallet.class,new WalletCreator(preknownNeighbour,preknownNeighbourName,walletName,remoteSuperVisorActor)); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof Wallet){ - Wallet wobj = (Wallet) obj; - return amount==wobj.amount&&name.equals(wobj.name); - } - return false; - } - - public void setGui(IWalletGuiControle gui) { - this.gui=gui; - } - - public void setAmount(int amount){ - this.amount = amount; - if(remoteSuperVisorActor != null){ - remoteSuperVisorActor.tell(new ActionGetAmountAnswer(getAddress(), getName(), amount), getSelf()); - } - if(gui!=null){ - gui.setAmount(this.amount); - } - } - - public ActorRef getPreknownNeighbour() { - return preknownNeighbour; - } - - public ActorRef getRemoteSuperVisorActor() { - return remoteSuperVisorActor; - } - - public IWalletGuiControle getGui() { - return gui; - } - - public String getPreknownNeighbourName() { - return preknownNeighbourName; - } - - public boolean isActive() { - return isActive; - } - - @Override - public boolean addKnownNeighbor(String key, ActorRef value) { - log(key+" is newNeighbor?"+!getKnownNeighbors().containsKey(key)); - if(getKnownNeighbors().containsKey(key)||key.equals(name)){ - return false; - } - boolean newNeighbor = super.addKnownNeighbor(key, value); - if(gui!=null&&newNeighbor){ - gui.addKnownAddress(key); - } - return newNeighbor; - } - - public void setPreknownNeighbour(ActorRef preknownNeighbour) { - this.preknownNeighbour = preknownNeighbour; - } - - public void setRemoteSuperVisorActor(ActorRef remoteSuperVisorActor) { - this.remoteSuperVisorActor = remoteSuperVisorActor; - } - - public void setPreknownNeighbourName(String preknownNeighbourName) { - this.preknownNeighbourName = preknownNeighbourName; - } - - public void setActive(boolean isActive) { - this.isActive = isActive; - } - - @Override - public void send(String address, int amount) { - getSelf().tell(new ActionInvokeSentMoney(address, amount), getSelf()); - } - -} diff --git a/src/fucoin/WalletCreator.java b/src/fucoin/WalletCreator.java deleted file mode 100644 index 3918b11f173ac183c1c7d89ce5f1d76a38d98663..0000000000000000000000000000000000000000 --- a/src/fucoin/WalletCreator.java +++ /dev/null @@ -1,34 +0,0 @@ -package fucoin; - -import akka.actor.ActorRef; -import akka.japi.Creator; -import fucoin.gui.IWalletGuiControle; -import fucoin.gui.WalletGui; - -public class WalletCreator implements Creator<Wallet> { - - private ActorRef preknownNeighbour; - private String walletName; - private ActorRef remoteSuperVisorActor; - private String preknownNeighbourName; - - public WalletCreator(ActorRef preknownNeighbour, String preknownNeighbourName, String walletName, ActorRef remoteSuperVisorActor) { - this.preknownNeighbour=preknownNeighbour; - this.preknownNeighbourName=preknownNeighbourName; - this.walletName=walletName; - this.remoteSuperVisorActor=remoteSuperVisorActor; - - } - - @Override - public Wallet create() throws Exception { - Wallet wallet = new Wallet(preknownNeighbour,preknownNeighbourName, walletName,remoteSuperVisorActor); - - IWalletGuiControle gui = new WalletGui(wallet); - wallet.setGui(gui); - return wallet; - } - - - -} diff --git a/src/fucoin/actions/Action.java b/src/fucoin/actions/Action.java deleted file mode 100644 index 926c6b2175997bf4b24e7b75d0796c7d1020e55a..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/Action.java +++ /dev/null @@ -1,21 +0,0 @@ -package fucoin.actions; - -import fucoin.AbstractNode; -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; - -public abstract class Action<T extends AbstractNode> { - private ActorRef self; - - public final void doAction(T abstractNode){ - this.self=abstractNode.getSelf(); - onAction(abstractNode.getSender(),abstractNode.getSelf(),abstractNode.getContext(),abstractNode); - } - - protected abstract void onAction(ActorRef sender, ActorRef self, UntypedActorContext context, T abstractNode); - - public void log(String string) { - System.out.println(self.path().name()+": "+string); - } - -} diff --git a/src/fucoin/actions/ClientAction.java b/src/fucoin/actions/ClientAction.java deleted file mode 100644 index e4f5119d968f78fa6330e753db914a0676160296..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/ClientAction.java +++ /dev/null @@ -1,12 +0,0 @@ -package fucoin.actions; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public abstract class ClientAction extends Action<Wallet>{ - @Override - protected abstract void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet abstractNode); - -} diff --git a/src/fucoin/actions/join/ActionJoin.java b/src/fucoin/actions/join/ActionJoin.java deleted file mode 100644 index 93b690dfed24b0cddb3eb7305b3725c174d78e4d..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/join/ActionJoin.java +++ /dev/null @@ -1,18 +0,0 @@ -package fucoin.actions.join; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.AbstractNode; - -//Used to join the network (a pre known participant/Wallet must be known) -public class ActionJoin extends GeneralAction{ - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, AbstractNode node) { - ActionJoinAnswer aja = new ActionJoinAnswer(); - aja.someNeighbors.putAll(node.getKnownNeighbors()); - sender.tell(aja, self); - } - -} diff --git a/src/fucoin/actions/join/ActionJoinAnswer.java b/src/fucoin/actions/join/ActionJoinAnswer.java deleted file mode 100644 index b230b1a51030b0958b879b951f9d36d859105873..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/join/ActionJoinAnswer.java +++ /dev/null @@ -1,27 +0,0 @@ -package fucoin.actions.join; - -import java.util.HashMap; -import java.util.Map.Entry; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; -import fucoin.actions.ClientAction; -import fucoin.actions.persist.ActionSearchMyWallet; - -// Returns some neighbors that might be used as known -// and/or local neighbors -public class ActionJoinAnswer extends ClientAction{ - public final HashMap<String, ActorRef> someNeighbors = new HashMap<>(); - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - log("someNeighbors:"+someNeighbors); - for(Entry<String, ActorRef> neighbor : someNeighbors.entrySet()){ - wallet.addKnownNeighbor(neighbor.getKey(),neighbor.getValue()); - } - for(Entry<String, ActorRef> neighbor : someNeighbors.entrySet()){ - neighbor.getValue().tell(new ActionSearchMyWallet(wallet.getName()), self); - } - } - -} diff --git a/src/fucoin/actions/join/GeneralAction.java b/src/fucoin/actions/join/GeneralAction.java deleted file mode 100644 index 8ddb5175b14c2c77174d588712e6d884df72674a..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/join/GeneralAction.java +++ /dev/null @@ -1,8 +0,0 @@ -package fucoin.actions.join; - -import fucoin.AbstractNode; -import fucoin.actions.Action; - -public abstract class GeneralAction extends Action<AbstractNode> { - -} diff --git a/src/fucoin/actions/join/Join.java b/src/fucoin/actions/join/Join.java deleted file mode 100644 index eccba13555aad1ac4665f503a359952659a22010..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/join/Join.java +++ /dev/null @@ -1,10 +0,0 @@ -package fucoin.actions.join; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.AbstractNode; -import fucoin.Wallet; -import fucoin.actions.ClientAction; - -public abstract class Join extends ClientAction{ -} diff --git a/src/fucoin/actions/join/ServerActionJoin.java b/src/fucoin/actions/join/ServerActionJoin.java deleted file mode 100644 index 9dfc08a69efd041da94c1e53507a07a8fa176cf6..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/join/ServerActionJoin.java +++ /dev/null @@ -1,27 +0,0 @@ -package fucoin.actions.join; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.actions.transaction.ActionInvokeDistributedCommitedTransfer; -import fucoin.actions.transaction.SuperVisorAction; -import fucoin.supervisor.SuperVisor; - -public class ServerActionJoin extends SuperVisorAction { - private String name; - - public ServerActionJoin(String name) { - this.name = name; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, SuperVisor node) { - ActionJoinAnswer aja = new ActionJoinAnswer(); - aja.someNeighbors.putAll(node.getKnownNeighbors()); - sender.tell(aja, self); - node.addKnownNeighbor(name, sender); - self.tell( - new ActionInvokeDistributedCommitedTransfer(self, sender, 100), - sender); - } -} diff --git a/src/fucoin/actions/persist/ActionInvalidate.java b/src/fucoin/actions/persist/ActionInvalidate.java deleted file mode 100644 index f5068d3317ce4b479ff5f3c020498975e134164f..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/persist/ActionInvalidate.java +++ /dev/null @@ -1,19 +0,0 @@ -package fucoin.actions.persist; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.AbstractNode; -import fucoin.Wallet; - -// May be used to delete a stored Wallet on another participant -public class ActionInvalidate extends Persist{ - public final String name; - public ActionInvalidate(String name) { - this.name = name; - } - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - wallet.backedUpNeighbors.remove(name); - } -} diff --git a/src/fucoin/actions/persist/ActionInvokeLeave.java b/src/fucoin/actions/persist/ActionInvokeLeave.java deleted file mode 100644 index e8d0102425d73694789694c5a7d2d815264bef56..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/persist/ActionInvokeLeave.java +++ /dev/null @@ -1,24 +0,0 @@ -package fucoin.actions.persist; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionInvokeLeave extends Persist{ - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - for(ActorRef neighbor : wallet.getKnownNeighbors().values()){ - if(self.compareTo(neighbor)!=0){ - neighbor.tell(new ActionStoreOrUpdate(wallet), self); - } - } - - - wallet.setActive(false); - wallet.backedUpNeighbors.clear(); - wallet.getKnownNeighbors().clear(); - } - -} diff --git a/src/fucoin/actions/persist/ActionInvokeRevive.java b/src/fucoin/actions/persist/ActionInvokeRevive.java deleted file mode 100644 index d1bf1015bcfd9005776c2460c999eac031efc693..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/persist/ActionInvokeRevive.java +++ /dev/null @@ -1,17 +0,0 @@ -package fucoin.actions.persist; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; -import fucoin.actions.join.ActionJoin; - -public class ActionInvokeRevive extends Persist{ - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - wallet.setActive(true); - wallet.getPreknownNeighbour().tell(new ActionJoin(), self); - } - -} diff --git a/src/fucoin/actions/persist/ActionInvokeUpdate.java b/src/fucoin/actions/persist/ActionInvokeUpdate.java deleted file mode 100644 index e71f052f00a7c114f9a4bfadadc5fb0f139d9656..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/persist/ActionInvokeUpdate.java +++ /dev/null @@ -1,16 +0,0 @@ -package fucoin.actions.persist; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionInvokeUpdate extends Persist{ - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - // TODO Auto-generated method stub - - } - -} diff --git a/src/fucoin/actions/persist/ActionSearchMyWallet.java b/src/fucoin/actions/persist/ActionSearchMyWallet.java deleted file mode 100644 index 885cbd6f17593e6fb281a2682345ebc286ad09b4..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/persist/ActionSearchMyWallet.java +++ /dev/null @@ -1,28 +0,0 @@ -package fucoin.actions.persist; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.AbstractWallet; -import fucoin.Wallet; - -// Used to search a Wallet by name, i.e. the own wallet if we just -// joined the network; If a receiving participant holds the stored Wallet, -// he returns it, otherwise, he might use gossiping methods to go on -// with the search; -// Note: You should also forward the sender (the participant who actually -// searches for this Wallet, so that it can be returnd the direct way) -public class ActionSearchMyWallet extends Persist{ - public final String name; - public ActionSearchMyWallet(String name) { - this.name = name; - } - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - wallet.addKnownNeighbor(name, sender); - AbstractWallet storedWallet =wallet.backedUpNeighbors.get(name); - if(storedWallet!=null){ - sender.tell(new ActionSearchMyWalletAnswer(storedWallet), self); - } - } -} diff --git a/src/fucoin/actions/persist/ActionSearchMyWalletAnswer.java b/src/fucoin/actions/persist/ActionSearchMyWalletAnswer.java deleted file mode 100644 index 933692867d9ce1b5ef49a4aad1081ec14b88f59e..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/persist/ActionSearchMyWalletAnswer.java +++ /dev/null @@ -1,20 +0,0 @@ -package fucoin.actions.persist; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.AbstractWallet; -import fucoin.Wallet; - -// Used to return a searched Wallet -public class ActionSearchMyWalletAnswer extends Persist { - public final AbstractWallet w; - public ActionSearchMyWalletAnswer(AbstractWallet w) { - this.w = w; - } - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - wallet.setAmount(w.amount); - sender.tell(new ActionInvalidate(wallet.name), self); - } -} diff --git a/src/fucoin/actions/search/ActionSearchWalletReference.java b/src/fucoin/actions/search/ActionSearchWalletReference.java deleted file mode 100644 index 05385ada1b2a15721c1afd5e60edc3ab86653f50..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/search/ActionSearchWalletReference.java +++ /dev/null @@ -1,46 +0,0 @@ -package fucoin.actions.search; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -//Used to return a Wallet reference (akka-style string which can -// be transformed to an ActorRef) -public class ActionSearchWalletReference extends Search{ - - public final String name; - public final List<ActorRef> ttl = new ArrayList<ActorRef>(); - public ActionSearchWalletReference(String name) { - this.name = name; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - log(wallet.getKnownNeighbors()+"contains "+name+"?"); - ttl.add(self); - ActionSearchWalletReferenceAnswer answer = null; - if(this.name.equals(wallet.getName())){ - answer = new ActionSearchWalletReferenceAnswer(name,wallet.getAddress(),ttl); - }else if(wallet.backedUpNeighbors.containsKey(name)){ - answer = new ActionSearchWalletReferenceAnswer(name,wallet.backedUpNeighbors.get(name).getAddress(),ttl); - } else if(wallet.getKnownNeighbors().containsKey(name)){ - answer = new ActionSearchWalletReferenceAnswer(name,wallet.getAddress(wallet.getKnownNeighbors().get(name)),ttl); - } else if (ttl.size()<5){ - for(ActorRef neighbor : wallet.getKnownNeighbors().values()){ - if(!ttl.contains(neighbor)){ - neighbor.tell(this, self); - } - } - } - //User unknown by this Wallet - if(answer!=null&&ttl.size()>0){ - ttl.get(ttl.size()-1).tell(answer, self); - } - } - -} diff --git a/src/fucoin/actions/search/ActionSearchWalletReferenceAnswer.java b/src/fucoin/actions/search/ActionSearchWalletReferenceAnswer.java deleted file mode 100644 index 6cc2f403bc4b5616108ee021ca9375e9e2ab509e..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/search/ActionSearchWalletReferenceAnswer.java +++ /dev/null @@ -1,30 +0,0 @@ -package fucoin.actions.search; - -import java.util.List; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionSearchWalletReferenceAnswer extends Search { - - public final String address; - public final String name; - public final List<ActorRef> pathToSearchedWallet; - public ActionSearchWalletReferenceAnswer(String name,String address, List<ActorRef> pathToSearchedWallet) { - this.address = address; - this.name=name; - this.pathToSearchedWallet=pathToSearchedWallet; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - ActorRef target = context.actorSelection(address).anchor(); - wallet.addKnownNeighbor(name,target); - int pos = pathToSearchedWallet.indexOf(self); - if(pos>0){ - pathToSearchedWallet.get(pos-1).tell(this, self); - } - } -} diff --git a/src/fucoin/actions/transaction/ActionCommitDistributedCommitedTransfer.java b/src/fucoin/actions/transaction/ActionCommitDistributedCommitedTransfer.java deleted file mode 100644 index 2b72a72d38c2c098cf41fa0d97f1e961be6a70ae..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionCommitDistributedCommitedTransfer.java +++ /dev/null @@ -1,57 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; -import fucoin.actions.ClientAction; -import fucoin.supervisor.DistributedCommitedTransferRequest; - -public class ActionCommitDistributedCommitedTransfer extends ClientAction{ - - private ActorRef source; - private ActorRef target; - private int amount; - private boolean granted; - private long timestamp; - private long id; - - - public ActionCommitDistributedCommitedTransfer(ActorRef source, - ActorRef target, int amount, boolean granted, long timestamp, long id) { - this.source=source; - this.target=target; - this.amount=amount; - this.granted=granted; - this.timestamp=timestamp; - this.id=id; - } - - public ActionCommitDistributedCommitedTransfer( - DistributedCommitedTransferRequest outdatedRequest) { - this.source=outdatedRequest.getSource(); - this.target=outdatedRequest.getTarget(); - this.amount=0; - this.granted=false; - this.timestamp=outdatedRequest.getTimeout(); - this.id=outdatedRequest.getId(); - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - log("ActionCommitDistributedCommitedTransfer is granted?"+granted); - if(granted){ - Integer sourceAmount = wallet.amounts.getOrDefault(source,0); - Integer targetAmount = wallet.amounts.getOrDefault(target,0); - wallet.amounts.put(source,sourceAmount-amount); - wallet.amounts.put(target,targetAmount+amount); - if(source.compareTo(self)==0)wallet.amount-=amount; - else if(target.compareTo(self)==0)wallet.amount+=amount; - wallet.log("have now "+wallet.amounts.get(self)+" Fucoins"); - }else{ - log("abort transaction with id"+id); - } - log("wallet.amounts:"+wallet.amounts); - } - -} diff --git a/src/fucoin/actions/transaction/ActionGetAmount.java b/src/fucoin/actions/transaction/ActionGetAmount.java deleted file mode 100644 index ad9737ba7e41b9db992f03e5e798eff1c929dd86..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionGetAmount.java +++ /dev/null @@ -1,16 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionGetAmount extends Transaction { - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - ActionGetAmountAnswer agaa = new ActionGetAmountAnswer(wallet.getAddress(),wallet.getName(),wallet.amount); - sender.tell(agaa, self); - } - -} diff --git a/src/fucoin/actions/transaction/ActionGetAmountAnswer.java b/src/fucoin/actions/transaction/ActionGetAmountAnswer.java deleted file mode 100644 index 4a85da1c2d1b5bb7206ab52954e25a5daf639cf5..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionGetAmountAnswer.java +++ /dev/null @@ -1,25 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionGetAmountAnswer extends Transaction { - - public String address; - public String name; - public int amount; - - public ActionGetAmountAnswer(String address, String name, int amount) { - this.address=address; - this.name=name; - this.amount=amount; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - - } - -} diff --git a/src/fucoin/actions/transaction/ActionInvokeDistributedCommitedTransfer.java b/src/fucoin/actions/transaction/ActionInvokeDistributedCommitedTransfer.java deleted file mode 100644 index 655aa8df515de02ff5922f075b989cb0551623a3..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionInvokeDistributedCommitedTransfer.java +++ /dev/null @@ -1,37 +0,0 @@ -package fucoin.actions.transaction; - -import java.util.HashMap; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; -import fucoin.supervisor.DistributedCommitedTransferRequest; -import fucoin.supervisor.SuperVisor; - -public class ActionInvokeDistributedCommitedTransfer extends CoordinatorTransaction{ - - private ActorRef source; - private ActorRef target; - private int amount; - - public ActionInvokeDistributedCommitedTransfer(ActorRef source, - ActorRef target, int amount) { - this.source=source; - this.target=target; - this.amount=amount; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, SuperVisor superVisor) { - log("invoke transaction "+source.path().name()+" sends "+amount+" to "+target.path().name()); - long timeout = System.currentTimeMillis()+500; - DistributedCommitedTransferRequest ds = new DistributedCommitedTransferRequest(source,target,timeout); - superVisor.addDistributedCommitedTransferRequest(ds); - ActionPrepareDistributedCommitedTransfer apdct = new ActionPrepareDistributedCommitedTransfer(source,target,amount,timeout,ds.getId()); - for(ActorRef neighbor : superVisor.getKnownNeighbors().values()){ - neighbor.tell(apdct, self); - } - } - -} diff --git a/src/fucoin/actions/transaction/ActionInvokeSentMoney.java b/src/fucoin/actions/transaction/ActionInvokeSentMoney.java deleted file mode 100644 index 7a2ee7eae3841bae1fabf6ccfb4cf27d9311cfa6..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionInvokeSentMoney.java +++ /dev/null @@ -1,41 +0,0 @@ -package fucoin.actions.transaction; - - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; -import fucoin.actions.search.ActionSearchWalletReference; - -public class ActionInvokeSentMoney extends Transaction{ - public final String name; - public final int amount; - public ActionInvokeSentMoney(String name, int amount) { - this.name=name; - this.amount = amount; - } - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - log(wallet.getKnownNeighbors()+""); - if(wallet.getKnownNeighbors().containsKey(name)){ - wallet.getRemoteSuperVisorActor().tell( - new ActionInvokeDistributedCommitedTransfer(self,wallet.getKnownNeighbors().get(name),amount), sender); - }else{ - ActionSearchWalletReference aswr = new ActionSearchWalletReference(name); - for(ActorRef neighbor : wallet.getKnownNeighbors().values()){ - neighbor.tell(aswr, self); - } - sleep(self, context, 200); - self.tell(this, self); - } - } - private void sleep(ActorRef self, UntypedActorContext context, int sleeptime) { - try { - context.unwatch(self); - Thread.sleep(sleeptime); - context.watch(self); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } -} diff --git a/src/fucoin/actions/transaction/ActionInvokeSentMoney2.java b/src/fucoin/actions/transaction/ActionInvokeSentMoney2.java deleted file mode 100644 index 743e0b873e361acc05a9c8e8ab9eb95a1f3badf4..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionInvokeSentMoney2.java +++ /dev/null @@ -1,22 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionInvokeSentMoney2 extends Transaction{ - public final String name; - public final int amount; - public ActionInvokeSentMoney2(String name, int amount) { - this.name=name; - this.amount = amount; - } - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - if(wallet.getKnownNeighbors().containsKey(name)){ - wallet.addAmount(-amount); - wallet.getKnownNeighbors().get(name).tell(new ActionReceiveTransaction(amount), self); - } - } -} diff --git a/src/fucoin/actions/transaction/ActionPrepareDistributedCommitedTransfer.java b/src/fucoin/actions/transaction/ActionPrepareDistributedCommitedTransfer.java deleted file mode 100644 index decf2b9a32fc661a6d1cf4c569c35047d72fd01b..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionPrepareDistributedCommitedTransfer.java +++ /dev/null @@ -1,33 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; - -public class ActionPrepareDistributedCommitedTransfer extends Transaction{ - - private ActorRef source; - private ActorRef target; - private int amount; - private long timestamp; - private long id; - - public ActionPrepareDistributedCommitedTransfer(ActorRef source, - ActorRef target, int amount, long timestamp, long id) { - this.source=source; - this.target=target; - this.amount=amount; - this.timestamp=timestamp; - this.id=id; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - boolean granted = sender.compareTo(source)==0 //sender is supervisor(bank) has allways money - ||(wallet.amounts.containsKey(source) //sender is unknown, might be valid - &&wallet.amounts.getOrDefault(source,0)>=amount) ; //sender have enough money - sender.tell(new ActionPrepareDistributedCommitedTransferAnswer(source, target, amount,timestamp,granted,id),self); - } - -} diff --git a/src/fucoin/actions/transaction/ActionPrepareDistributedCommitedTransferAnswer.java b/src/fucoin/actions/transaction/ActionPrepareDistributedCommitedTransferAnswer.java deleted file mode 100644 index e479c385962a7041be1d47eab25220237613c9d7..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionPrepareDistributedCommitedTransferAnswer.java +++ /dev/null @@ -1,55 +0,0 @@ -package fucoin.actions.transaction; - -import fucoin.supervisor.DistributedCommitedTransferRequest; -import fucoin.supervisor.SuperVisor; -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; - -public class ActionPrepareDistributedCommitedTransferAnswer extends CoordinatorTransaction { - - private ActorRef source; - private ActorRef target; - private int amount; - private boolean granted; - private long timestamp; - private long id; - - public ActionPrepareDistributedCommitedTransferAnswer(ActorRef source, - ActorRef target, int amount, long timestamp, boolean granted, long id) { - this.source=source; - this.target=target; - this.amount=amount; - this.granted=granted; - this.timestamp=timestamp; - this.id=id; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, SuperVisor superVisor) { - log(""+superVisor.getKnownNeighbors()); - log("granted?"+granted); - DistributedCommitedTransferRequest request = superVisor.getRequest(id); - if(granted){ - if(request==null)//unknown DistributedCommitedTransferRequest ignore - return; - int newCount = request.addPositiveAnswer(sender); - if(newCount == superVisor.getKnownNeighbors().size()){ - ActionCommitDistributedCommitedTransfer acdct = new ActionCommitDistributedCommitedTransfer(source,target,amount,true,timestamp,id); - for(ActorRef neighbor : request.getAnswers()){ - neighbor.tell(acdct, self); - } - superVisor.deleteRequest(request); - } - }else{ - //A client wants to rollback - if(request!=null){ - ActionCommitDistributedCommitedTransfer acdct = new ActionCommitDistributedCommitedTransfer(source,target,amount,false,timestamp,id); - for(ActorRef neighbor : request.getAnswers()){ - neighbor.tell(acdct, self); - } - } - } - } - -} diff --git a/src/fucoin/actions/transaction/ActionReceiveTransaction.java b/src/fucoin/actions/transaction/ActionReceiveTransaction.java deleted file mode 100644 index 6abdc2a14efd5d3822b8644d2ba89c6837c37dd4..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/ActionReceiveTransaction.java +++ /dev/null @@ -1,18 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.Wallet; -//Used to send (positive amount) or retreive money (negative amount) -public class ActionReceiveTransaction extends Transaction { - final public int amount; - public ActionReceiveTransaction(int amount) { - this.amount = amount; - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - wallet.addAmount(wallet.amount); - } -} diff --git a/src/fucoin/actions/transaction/CoordinatorTransaction.java b/src/fucoin/actions/transaction/CoordinatorTransaction.java deleted file mode 100644 index 7c95795ea03734797cfb7ef4279785cf1f59d0de..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/CoordinatorTransaction.java +++ /dev/null @@ -1,16 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.AbstractNode; -import fucoin.Wallet; -import fucoin.actions.ClientAction; -import fucoin.supervisor.SuperVisor; - -public abstract class CoordinatorTransaction extends SuperVisorAction{ - -@Override -protected abstract void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, SuperVisor abstractNode); - -} diff --git a/src/fucoin/actions/transaction/SuperVisorAction.java b/src/fucoin/actions/transaction/SuperVisorAction.java deleted file mode 100644 index a6bce1ee7b60d7f0008315459b5a5551d97ec05c..0000000000000000000000000000000000000000 --- a/src/fucoin/actions/transaction/SuperVisorAction.java +++ /dev/null @@ -1,11 +0,0 @@ -package fucoin.actions.transaction; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.actions.Action; -import fucoin.actions.ClientAction; -import fucoin.supervisor.SuperVisor; - -public abstract class SuperVisorAction extends Action<SuperVisor>{ - -} diff --git a/src/fucoin/gui/IWalletControle.java b/src/fucoin/gui/IWalletControle.java deleted file mode 100644 index f56fbde20afd9e9c07bfa34e1ade438ab7d76786..0000000000000000000000000000000000000000 --- a/src/fucoin/gui/IWalletControle.java +++ /dev/null @@ -1,7 +0,0 @@ -package fucoin.gui; - - -public interface IWalletControle { - public void leave(); - public void send(String address, int amount); -} diff --git a/src/fucoin/gui/IWalletGuiControle.java b/src/fucoin/gui/IWalletGuiControle.java deleted file mode 100644 index 55d46acd3c35a3504d395644486b94f27b8a5a73..0000000000000000000000000000000000000000 --- a/src/fucoin/gui/IWalletGuiControle.java +++ /dev/null @@ -1,12 +0,0 @@ -package fucoin.gui; - - -public interface IWalletGuiControle { - public void setAddress(String address); - public void setAmount(int amount); - public void addKnownAddress(String address); - public void addLogMsg(String msg); - - - -} diff --git a/src/fucoin/gui/WalletControle.java b/src/fucoin/gui/WalletControle.java deleted file mode 100644 index 9bb8b77b6a5d1ea972366bf15f2f11cdb4d27ab7..0000000000000000000000000000000000000000 --- a/src/fucoin/gui/WalletControle.java +++ /dev/null @@ -1,24 +0,0 @@ -package fucoin.gui; - -import fucoin.Wallet; - - -public class WalletControle implements IWalletControle{ - - private Wallet wallet; - - public WalletControle(Wallet wallet) { - this.wallet=wallet; - } - - @Override - public void leave() { - wallet.leave(); - } - - @Override - public void send(String name, int amount) { - wallet.send(name, amount); - } - -} diff --git a/src/fucoin/gui/WalletCoreGui.java b/src/fucoin/gui/WalletCoreGui.java deleted file mode 100644 index 6e2e4c57320d94b9b5cdeb486e5993e05149f3e5..0000000000000000000000000000000000000000 --- a/src/fucoin/gui/WalletCoreGui.java +++ /dev/null @@ -1,51 +0,0 @@ -package fucoin.gui; - -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTextField; - -import akka.actor.Address; -import akka.actor.AddressFromURIString; - -public class WalletCoreGui { - public WalletCoreGui() { - JFrame frame = new JFrame("Manager"); - frame.setLayout(new GridLayout(3,2)); - frame.add(new JLabel("Connect to:")); - JTextField input = new JTextField("akka://MySystem/user/main"); - frame.add(input); - frame.add(new JLabel("Name:")); - JTextField name = new JTextField("<Name>"); - frame.add(name); - JButton button = new JButton("connect"); - button.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - /*MessageDispatcherConfigurator mc = null; - String id = input.getText()+"-dispatched"; - int hroughput = 1; - Duration d = Duration.ofSeconds(2); - - - Dispatcher d = new Dispatcher(mc,id, 1, d, Executors.newSingleThreadExecutor(),1000);*/ - String path = "akka.tcp://Test@127.0.0.1:1234/user/main"; - Address addr = AddressFromURIString.parse(path); - //RemoteScope remoteScope = new RemoteScope(addr); - //Deploy deploy = new Deploy(remoteScope); - //Props remoteWallet = Props.apply(deploy, Wallet.class, null); - - - } - }); - - frame.add(button); - frame.setSize(300, 300); - frame.setVisible(true); - } -} diff --git a/src/fucoin/gui/WalletGui.java b/src/fucoin/gui/WalletGui.java deleted file mode 100644 index 0c09c87545921ea984b353d1b5c20ec8cbf05c4a..0000000000000000000000000000000000000000 --- a/src/fucoin/gui/WalletGui.java +++ /dev/null @@ -1,163 +0,0 @@ -package fucoin.gui; - -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JTextField; - - -public class WalletGui implements IWalletGuiControle{ - DefaultListModel<String> log = new DefaultListModel<String>(); - - private JFrame window = new JFrame("test"); - JPanel topPanel = new JPanel(); - JLabel lblMyAddress = new JLabel("My Address:"); - JTextField txtMyAddress = new JTextField("<MyAddress>"); - JLabel lblEmpty = new JLabel(""); - JLabel lblMyAmount = new JLabel("My FUCs"); - JTextField txtMyAmount = new JTextField("<MyFUCs>"); - JPanel centerPanel = new JPanel(); - JLabel lblSendTo = new JLabel("Send to:"); - JComboBox<String> txtSendTo = new JComboBox<String>(); - JLabel lblSendAmount = new JLabel("Amount:"); - JTextField txtSendAmount = new JTextField("<Amount>"); - JButton btnSend = new JButton("Send"); - JButton btnSearch = new JButton("Search"); - JButton btnStore = new JButton("Store"); - JButton btnExit = new JButton("Exit"); - JPanel bottomPanel = new JPanel(); - JList<String> txtLog = new JList<String>(log); - -public WalletGui(IWalletControle walletControle) { - - - window.setSize(400, 600); - window.setLayout(new GridLayout(3, 1)); - topPanel.setLayout(new GridLayout(2, 3)); - // Row 1 - topPanel.add(lblMyAddress); - topPanel.add(txtMyAddress); - topPanel.add(lblEmpty); - // Row 2 - topPanel.add(lblMyAmount); - topPanel.add(txtMyAmount); - window.add(topPanel); - //<hr> - centerPanel.setLayout(new GridLayout(4, 1)); - // Row 1 - JPanel centerup = new JPanel(); - centerup.setLayout(new BorderLayout()); - centerup.add(lblSendTo,BorderLayout.WEST); - centerup.add(txtSendTo,BorderLayout.CENTER); - centerPanel.add(centerup); - - JPanel centerup2 = new JPanel(); - centerup2.setLayout(new BorderLayout()); - JTextField sendToNewEdt = new JTextField(); - centerup2.add(sendToNewEdt,BorderLayout.CENTER); - JButton addNewButton = new JButton("Add"); - addNewButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - txtSendTo.addItem(sendToNewEdt.getText()); - } - }); - centerup2.add(addNewButton,BorderLayout.EAST); - centerPanel.add(centerup2); - - // Row 2 - JPanel centerdown = new JPanel(); - centerdown.setLayout(new GridLayout(1, 3)); - centerdown.add(lblSendAmount); - centerdown.add(txtSendAmount); - centerdown.add(btnSend); - centerPanel.add(centerdown); - //centerPanel.add(new JLabel("")); - // Row 3 - JPanel centerdown2 = new JPanel(); - centerdown2.setLayout(new GridLayout(1, 3)); - centerdown2.add(btnSearch); - centerdown2.add(btnStore); - centerdown2.add(btnExit); - centerPanel.add(centerdown2); - window.add(centerPanel); - //<hr> - bottomPanel.setLayout(new GridLayout(1, 1)); - bottomPanel.add(txtLog); - window.add(bottomPanel); - window.setVisible(true); - - btnSend.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - walletControle.send(txtSendTo.getSelectedItem().toString(), Integer.parseInt(txtSendAmount.getText())); - } - }); - - btnStore.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - } - }); - - btnExit.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - window.dispose(); - } - }); - - window.addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { - System.out.println("window closing"); - walletControle.leave(); - super.windowClosing(e); - - } - @Override - public void windowClosed(WindowEvent e) { - System.out.println("window closing"); - walletControle.leave(); - super.windowClosing(e); - } - }); -} - -@Override -public void setAddress(String address) { - txtMyAddress.setText(address); - window.setTitle(address); -} -@Override -public void setAmount(int amount) { - txtMyAmount.setText(""+amount); -} - -@Override -public void addKnownAddress(String address) { - - txtSendTo.addItem(address); -} -@Override -public void addLogMsg(String msg) { - log.addElement(msg); -} -} diff --git a/src/fucoin/supervisor/ActionUpdateQueue.java b/src/fucoin/supervisor/ActionUpdateQueue.java deleted file mode 100644 index 82cc40c06210a1b9719b3c62ed7923ac032dc0dd..0000000000000000000000000000000000000000 --- a/src/fucoin/supervisor/ActionUpdateQueue.java +++ /dev/null @@ -1,39 +0,0 @@ -package fucoin.supervisor; - -import java.util.ArrayList; -import java.util.List; - -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; -import fucoin.actions.transaction.ActionCommitDistributedCommitedTransfer; -import fucoin.actions.transaction.SuperVisorAction; - -public class ActionUpdateQueue extends SuperVisorAction{ - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, SuperVisor superVisor) { - - List<DistributedCommitedTransferRequest> deletes = superVisor.updateList(); - - for(DistributedCommitedTransferRequest outdatedRequest : deletes){ - ActionCommitDistributedCommitedTransfer acdct = new ActionCommitDistributedCommitedTransfer(outdatedRequest); - for(ActorRef neighbor : superVisor.getKnownNeighbors().values()){ - neighbor.tell(acdct, self); - } - } - sleep(self,context,1000); - self.tell(this, self); - } - - private void sleep(ActorRef self, UntypedActorContext context, int sleeptime) { - try { - context.unwatch(self); - Thread.sleep(sleeptime); - context.watch(self); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - -} diff --git a/src/fucoin/supervisor/AmountTableModel.java b/src/fucoin/supervisor/AmountTableModel.java deleted file mode 100644 index fb91ce4813b9500f700e02f407b49c3df6ae71e5..0000000000000000000000000000000000000000 --- a/src/fucoin/supervisor/AmountTableModel.java +++ /dev/null @@ -1,15 +0,0 @@ -package fucoin.supervisor; - -import javax.swing.table.DefaultTableModel; - -public class AmountTableModel extends DefaultTableModel{ -public AmountTableModel() { - super(new Object[]{"Address","Name","Amount"},0); -} - -public void clear() { - while(getRowCount()>0){ - removeRow(0); - } -} -} diff --git a/src/fucoin/supervisor/DistributedCommitedTransferRequest.java b/src/fucoin/supervisor/DistributedCommitedTransferRequest.java deleted file mode 100644 index a27f873dc259cdcb19986898c5b2d883bd53815a..0000000000000000000000000000000000000000 --- a/src/fucoin/supervisor/DistributedCommitedTransferRequest.java +++ /dev/null @@ -1,58 +0,0 @@ -package fucoin.supervisor; - -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -import fucoin.Wallet; -import fucoin.actions.transaction.Transaction; -import akka.actor.ActorRef; -import akka.actor.UntypedActorContext; - -public class DistributedCommitedTransferRequest extends Transaction { - private final static Random random = new Random(System.currentTimeMillis()+System.nanoTime()); - private ActorRef source; - private ActorRef target; - private long timeout; - private long id; - private List<ActorRef> answers = new LinkedList<ActorRef>(); - - public DistributedCommitedTransferRequest(ActorRef source, ActorRef target, - long timeout) { - this.source=source; - this.target=target; - this.timeout=timeout; - this.id=random.nextLong(); - } - - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - - } - - public ActorRef getSource() { - return source; - } - - public ActorRef getTarget() { - return target; - } - - public long getTimeout() { - return timeout; - } - - public int addPositiveAnswer(ActorRef sender) { - answers.add(sender); - return answers.size(); - } - - public List<ActorRef> getAnswers() { - return answers; - } - - public long getId() { - return id; - } -} diff --git a/src/fucoin/supervisor/SuperVisor.java b/src/fucoin/supervisor/SuperVisor.java deleted file mode 100644 index a6adcaa7fd08f0feb95ae85cd8b92a8ae72a105a..0000000000000000000000000000000000000000 --- a/src/fucoin/supervisor/SuperVisor.java +++ /dev/null @@ -1,96 +0,0 @@ -package fucoin.supervisor; - -import java.awt.Label; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.concurrent.Semaphore; - -import akka.actor.ActorRef; -import akka.actor.Props; -import fucoin.AbstractNode; -import fucoin.actions.Action; -import fucoin.actions.persist.ActionInvokeUpdate; - -public class SuperVisor extends AbstractNode { - - - private AmountTableModel amountTableModel; - private Label averageamountLbl; - - public SuperVisor(AmountTableModel amountTableModel, Label averageamountLbl) { - this.amountTableModel = amountTableModel; - this.averageamountLbl = averageamountLbl; - } - - @Override - public void onReceive(Object msg) { - log(msg.getClass().getSimpleName()); - - ((Action) msg).doAction(this); - } - - Semaphore mutex = new Semaphore(1); - private Map<Long,DistributedCommitedTransferRequest> requestQueue; - - public static Props props() { - return Props.create(SuperVisor.class, new SuperVisorCreator()); - } - - public void updateValues() { - getSelf().tell(new ActionInvokeUpdate(), getSelf()); - } - - public void exit() { - getContext().stop(getSelf()); - } - - @Override - public void postStop() throws Exception { - super.postStop(); - } - - public void addDistributedCommitedTransferRequest( - DistributedCommitedTransferRequest request) { - requestQueue.put(request.getId(),request); - } - - @Override - public void preStart() throws Exception { - super.preStart(); - requestQueue = new HashMap<Long,DistributedCommitedTransferRequest>(); - self().tell(new ActionUpdateQueue(), self()); - } - /** - * filters the request for outdated and removes them - * @return deleted outdated request - */ - public List<DistributedCommitedTransferRequest> updateList(){ - List<Long> deletesIds = new ArrayList<Long>(); - List<DistributedCommitedTransferRequest> deletes = new ArrayList<DistributedCommitedTransferRequest>(); - for(Entry<Long, DistributedCommitedTransferRequest> outdatedRequest : requestQueue.entrySet()){ - if(outdatedRequest.getValue().getTimeout()<System.currentTimeMillis()){ - deletesIds.add(outdatedRequest.getKey()); - deletes.add(outdatedRequest.getValue()); - } - } - for(Long delete : deletesIds){ - requestQueue.remove(delete); - } - - return deletes; - } - - public DistributedCommitedTransferRequest getRequest(Long id) { - DistributedCommitedTransferRequest searchedrequest = requestQueue.get(id); - return searchedrequest ; - } - - public void deleteRequest(DistributedCommitedTransferRequest request) { - requestQueue.remove(request.getId()); - } -} diff --git a/src/fucoin/supervisor/SuperVisorCreator.java b/src/fucoin/supervisor/SuperVisorCreator.java deleted file mode 100644 index a67730de47715233853f4bf71a5f6c026193bd8e..0000000000000000000000000000000000000000 --- a/src/fucoin/supervisor/SuperVisorCreator.java +++ /dev/null @@ -1,56 +0,0 @@ -package fucoin.supervisor; - -import java.awt.GridLayout; -import java.awt.Label; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JScrollPane; -import javax.swing.JTable; - -import akka.japi.Creator; - -public class SuperVisorCreator implements Creator<SuperVisor>{ - - @Override - public SuperVisor create() throws Exception { - - JFrame frame = new JFrame("Server"); - frame.setLayout(new GridLayout(3, 2)); - frame.add(new Label("All Amounts:")); - AmountTableModel amountTableModel = new AmountTableModel(); - JTable amountListView = new JTable(amountTableModel); - frame.add(new JScrollPane(amountListView)); - frame.add(new Label("Average Amounts:")); - Label averageamountLbl = new Label("Average Amounts:"); - frame.add(averageamountLbl); - JButton updateBtn = new JButton("Update"); - JButton exitBtn = new JButton("exit"); - frame.add(updateBtn); - frame.add(exitBtn); - - SuperVisor sv = new SuperVisor(amountTableModel,averageamountLbl); - updateBtn.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - sv.updateValues(); - } - }); - exitBtn.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - sv.exit(); - frame.setVisible(false); - } - }); - frame.setSize(200, 400); - frame.setVisible(true); - - return sv; - } - -} diff --git a/src/main/java/fucoin/AbstractNode.java b/src/main/java/fucoin/AbstractNode.java new file mode 100644 index 0000000000000000000000000000000000000000..437262c5c1f4f7472674e58e445abb1104136d56 --- /dev/null +++ b/src/main/java/fucoin/AbstractNode.java @@ -0,0 +1,76 @@ +package fucoin; + +import akka.actor.ActorRef; +import akka.actor.Address; +import akka.actor.UntypedActor; +import fucoin.actions.transaction.ActionGetAmount; +import fucoin.wallet.AbstractWallet; + +import java.io.Serializable; +import java.util.HashMap; + +public abstract class AbstractNode extends UntypedActor implements Serializable { + + /** + * Returns the akka-style address as String, + * which could be converted to an ActorRef object later + * + * @return + */ + public String getAddress() { + return getAddress(getSelf()); + } + + public String getAddress(ActorRef self) { + Address remoteAddr = getContext().system().provider().getDefaultAddress(); + return self.path().toStringWithAddress(remoteAddr); + } + + /** + * The which receives Action objects + * + * @param message + */ + public abstract void onReceive(Object message); + + /** + * Holds references to neighbors that were in contact with this wallet during runtime; + * The key corresponds to the WalletImpl's name + */ + private transient HashMap<String, ActorRef> knownNeighbors = new HashMap<String, ActorRef>(); + + /** + * Holds references to neighbors + * this wallet synchronizes itself to (the WalletImpl object); + * The key corresponds to the WalletImpl's name + */ + public transient HashMap<String, ActorRef> localNeighbors = new HashMap<String, ActorRef>(); + + /** + * Holds all Wallets from network participants + * which synchronize their state (WalletImpl object) with us; + * The key corresponds to the WalletImpl's name + */ + public transient HashMap<String, AbstractWallet> backedUpNeighbors = + new HashMap<String, AbstractWallet>(); + + public transient HashMap<ActorRef, Integer> amounts = new HashMap<ActorRef, Integer>(); + + public boolean addKnownNeighbor(String key, ActorRef value) { + if (!knownNeighbors.containsKey(key)) { + knownNeighbors.put(key, value); + value.tell(new ActionGetAmount(), getSelf()); + return true; + } + return false; + } + + public HashMap<String, ActorRef> getKnownNeighbors() { + return knownNeighbors; + } + + public void log(String string) { + System.out.println(getSelf().path().name() + ": " + string); + } + +} \ No newline at end of file diff --git a/src/main/java/fucoin/Main.java b/src/main/java/fucoin/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..c715d6ffd66799df36f686e6607c96a3c2ec9a43 --- /dev/null +++ b/src/main/java/fucoin/Main.java @@ -0,0 +1,75 @@ +package fucoin; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import fucoin.actions.join.ActionJoinAnswer; +import fucoin.setup.NetworkInterfaceReader; +import fucoin.supervisor.SuperVisorImpl; +import fucoin.wallet.WalletImpl; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + + +public class Main { + + private static int numberOfWallets = 2; + + private static ActorSystem cSystem; + + private static ActorRef cSuperVisorActor; + + private static List<ActorRef> cActiveActors = new ArrayList<>(); + + static { + String hostname = NetworkInterfaceReader.readDefaultHostname(); + + //Load configuration from current directory or from resources directory of jar + File file = new File("application.conf"); + Config config = ConfigFactory.parseFile(file); + if (!file.exists()) { + System.out.println("Load default application.conf"); + config = ConfigFactory.parseResources("application.conf"); + } else { + System.out.println("Load local application.conf"); + } + + //Init System Actor System + cSystem = ActorSystem.create("Core", ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname).withFallback(config)); + cSuperVisorActor = cSystem.actorOf(SuperVisorImpl.props(), "SuperVisorImpl"); + } + + public static void main(String[] args) throws InterruptedException { + createWallets(); + } + + private static void createWallets() { + //Init Wallets + for (int i = 0; i < numberOfWallets; i++) { + + String nameOfTheWallet = "Wallet" + String.valueOf(i); + Props props; + + if (i > 0) { + //chain the wallets. wallet2 knows wallet1, wallet3 knows wallet2 and so on. + props = WalletImpl.props(cActiveActors.get(i - 1), nameOfTheWallet); + } else { + props = WalletImpl.props(null, nameOfTheWallet); + } + + ActorRef actorRef = cSystem.actorOf(props, nameOfTheWallet); + + // first wallet does not have a neighbour, so it can't send a ActionJoin to anybody + // instead we send directly an ActionJoinAnswer with the supervisor reference + if (i == 0) { + actorRef.tell(new ActionJoinAnswer(cSuperVisorActor), cSuperVisorActor); + } + + cActiveActors.add(actorRef); + } + } +} diff --git a/src/main/java/fucoin/MainRemote.java b/src/main/java/fucoin/MainRemote.java new file mode 100644 index 0000000000000000000000000000000000000000..67c8520b0547a598a0cdc321c450324e1efca881 --- /dev/null +++ b/src/main/java/fucoin/MainRemote.java @@ -0,0 +1,97 @@ +package fucoin; + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import akka.util.Timeout; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import fucoin.setup.NetworkInterfaceReader; +import fucoin.setup.SelectableNetworkInterface; +import fucoin.setup.SetupDialogPanel; +import fucoin.wallet.WalletImpl; +import scala.concurrent.Await; +import scala.concurrent.duration.FiniteDuration; + +import javax.swing.*; +import java.io.File; +import java.util.concurrent.TimeUnit; + +public class MainRemote { + + public static void main(String[] args) throws InterruptedException { + + String hostname = NetworkInterfaceReader.readDefaultHostname(); + + //Load configuration from current directory or from resources directory of jar + File file = new File("application.conf"); + Config config = ConfigFactory.parseFile(file); + if (!file.exists()) { + System.out.println("Load default application.conf"); + config = ConfigFactory.parseResources("application.conf"); + } else { + System.out.println("Load local application.conf"); + } + + //Init System Actor System + ActorSystem system = ActorSystem.create("Remote", ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname).withFallback(config)); + + //JPanel dialogPanel = createDialogPanel(hostname); + SetupDialogPanel dialogPanel = new SetupDialogPanel(hostname); + + Timeout timeout = new Timeout(5, TimeUnit.SECONDS); + ActorRef preknownNeighbour = null; + + String walletName = null; + String path; + + while (preknownNeighbour == null) { + + int result = JOptionPane.showConfirmDialog(null, dialogPanel, "Connect to wallet network", JOptionPane.OK_CANCEL_OPTION); + + // terminate if user clicked cancel + if (result == JOptionPane.CANCEL_OPTION) { + if (system != null) { + system.terminate(); + } + return; + } + + SelectableNetworkInterface selectedHostname = dialogPanel.getNetworkInterface(); + + if (!selectedHostname.getHostName().equals(hostname)) { + if (system != null) { + try { + Await.result(system.terminate(), new FiniteDuration(5, TimeUnit.SECONDS)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + hostname = selectedHostname.getHostName(); + system = ActorSystem.create("Remote", ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + hostname).withFallback(config)); + } + + walletName = dialogPanel.getWalletName(); + path = dialogPanel.getAddressOfNeighbour(); + + // check input + if (path.equals("") || walletName.equals("")) { + continue; + } + + // resolve the given address + ActorSelection selection = system.actorSelection(path); + + try { + preknownNeighbour = Await.result(selection.resolveOne(timeout), timeout.duration()); + } catch (Exception e) { + System.err.println("Something went wrong while resolving: " + e.getMessage()); + } + } + + // spawn wallet + system.actorOf(WalletImpl.props(preknownNeighbour, walletName), walletName); + + } +} diff --git a/src/main/java/fucoin/actions/Action.java b/src/main/java/fucoin/actions/Action.java new file mode 100644 index 0000000000000000000000000000000000000000..2704740195efebcb6e8aa2bd63b394e3263f95de --- /dev/null +++ b/src/main/java/fucoin/actions/Action.java @@ -0,0 +1,20 @@ +package fucoin.actions; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.AbstractNode; + +import java.io.Serializable; + +public abstract class Action<T extends AbstractNode> implements Serializable { + private ActorRef self; + + public final void doAction(T abstractNode) { + this.self = abstractNode.getSelf(); + onAction(abstractNode.getSender(), abstractNode.getSelf(), + abstractNode.getContext(), abstractNode); + } + + protected abstract void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, T abstractNode); +} diff --git a/src/main/java/fucoin/actions/ClientAction.java b/src/main/java/fucoin/actions/ClientAction.java new file mode 100644 index 0000000000000000000000000000000000000000..3be489ca1e3bd8806e4edcc2ccdc9dbd93fc31d3 --- /dev/null +++ b/src/main/java/fucoin/actions/ClientAction.java @@ -0,0 +1,12 @@ +package fucoin.actions; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +public abstract class ClientAction extends Action<AbstractWallet> { + @Override + protected abstract void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet abstractNode); + +} diff --git a/src/main/java/fucoin/actions/join/ActionJoin.java b/src/main/java/fucoin/actions/join/ActionJoin.java new file mode 100644 index 0000000000000000000000000000000000000000..e7bd81419911b9291a7d4da154d227020f1828a8 --- /dev/null +++ b/src/main/java/fucoin/actions/join/ActionJoin.java @@ -0,0 +1,21 @@ +package fucoin.actions.join; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.ClientAction; +import fucoin.wallet.AbstractWallet; + +/** + * This action is used by nodes wanting to join the network. + */ +public class ActionJoin extends ClientAction { + + @Override + protected void onAction(ActorRef sender, ActorRef self, UntypedActorContext context, AbstractWallet node) { + + // send the joined node all known neighbours from node and a reference to the supervisor + ActionJoinAnswer aja = new ActionJoinAnswer(node.getRemoteSuperVisorActor()); + aja.someNeighbors.putAll(node.getKnownNeighbors()); + sender.tell(aja, self); + } +} diff --git a/src/main/java/fucoin/actions/join/ActionJoinAnswer.java b/src/main/java/fucoin/actions/join/ActionJoinAnswer.java new file mode 100644 index 0000000000000000000000000000000000000000..49cecf1d89a416a85ed8c6749cdfa841da57d232 --- /dev/null +++ b/src/main/java/fucoin/actions/join/ActionJoinAnswer.java @@ -0,0 +1,48 @@ +package fucoin.actions.join; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.ClientAction; +import fucoin.actions.persist.ActionSearchMyWallet; +import fucoin.wallet.AbstractWallet; + +import java.util.HashMap; +import java.util.Map.Entry; + +/** + * This action is the response from a wallet which is already in the network + * to a wallet which wants to join the network. + * <p> + * The node in the network sends all its known neighbours which then become + * neighbours of the new node. This action also contains a reference to the + * supervisor. If this is the first time the new node learned about the systems + * supervisor, it proceeds to register at the supervisor. + */ +public class ActionJoinAnswer extends ClientAction { + public final HashMap<String, ActorRef> someNeighbors = new HashMap<>(); + public final ActorRef supervisor; + + public ActionJoinAnswer(ActorRef supervisor) { + this.supervisor = supervisor; + } + + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + + wallet.log("Addressed to " + self.path().name() + " from " + sender.path().name() + ": someNeighbors:" + someNeighbors); + + // your neighbours? my neighbours! + for (Entry<String, ActorRef> neighbor : someNeighbors.entrySet()) { + wallet.addKnownNeighbor(neighbor.getKey(), neighbor.getValue()); + } + for (Entry<String, ActorRef> neighbor : someNeighbors.entrySet()) { + neighbor.getValue().tell(new ActionSearchMyWallet(wallet.getName()), self); + } + + // register at the supervisor if the wallet just learned about it + if (wallet.getRemoteSuperVisorActor() == null) { + wallet.setRemoteSuperVisorActor(supervisor); + } + } + +} diff --git a/src/main/java/fucoin/actions/join/ServerActionJoin.java b/src/main/java/fucoin/actions/join/ServerActionJoin.java new file mode 100644 index 0000000000000000000000000000000000000000..4c57b136f65958aa606bb75b7f404ca8e6edaf70 --- /dev/null +++ b/src/main/java/fucoin/actions/join/ServerActionJoin.java @@ -0,0 +1,32 @@ +package fucoin.actions.join; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.transaction.ActionInvokeDistributedCommittedTransfer; +import fucoin.actions.transaction.SuperVisorAction; +import fucoin.supervisor.SuperVisorImpl; + +/** + * Used by nodes to register at the supervisor. In return, the supervisor + * sends all its neighbours to the node and initiates the transfer of a fixed amount + * of FUCs to get started. + */ +public class ServerActionJoin extends SuperVisorAction { + private String name; + + public ServerActionJoin(String name) { + this.name = name; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, SuperVisorImpl node) { + ActionJoinAnswer aja = new ActionJoinAnswer(node.getSelf()); + aja.someNeighbors.putAll(node.getKnownNeighbors()); + sender.tell(aja, self); + node.addKnownNeighbor(name, sender); + self.tell( + new ActionInvokeDistributedCommittedTransfer(self, sender, 100), + sender); + } +} diff --git a/src/main/java/fucoin/actions/persist/ActionInvalidate.java b/src/main/java/fucoin/actions/persist/ActionInvalidate.java new file mode 100644 index 0000000000000000000000000000000000000000..71c37742bf1865dc6d8f22759f38cab49c962205 --- /dev/null +++ b/src/main/java/fucoin/actions/persist/ActionInvalidate.java @@ -0,0 +1,22 @@ +package fucoin.actions.persist; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +/** + * May be used to delete a stored WalletImpl on another participant + */ +public class ActionInvalidate extends Persist { + public final String name; + + public ActionInvalidate(String name) { + this.name = name; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.backedUpNeighbors.remove(name); + } +} diff --git a/src/main/java/fucoin/actions/persist/ActionInvokeLeave.java b/src/main/java/fucoin/actions/persist/ActionInvokeLeave.java new file mode 100644 index 0000000000000000000000000000000000000000..201c090bad9b3c9f8e5b9ec68610e67cabeb9379 --- /dev/null +++ b/src/main/java/fucoin/actions/persist/ActionInvokeLeave.java @@ -0,0 +1,24 @@ +package fucoin.actions.persist; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +public class ActionInvokeLeave extends Persist { + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + for (ActorRef neighbor : wallet.getKnownNeighbors().values()) { + if (self.compareTo(neighbor) != 0) { + neighbor.tell(new ActionStoreOrUpdate(wallet), self); + } + } + + + wallet.setActive(false); + wallet.backedUpNeighbors.clear(); + wallet.getKnownNeighbors().clear(); + } + +} diff --git a/src/main/java/fucoin/actions/persist/ActionInvokeRevive.java b/src/main/java/fucoin/actions/persist/ActionInvokeRevive.java new file mode 100644 index 0000000000000000000000000000000000000000..6bfdb845aea1086ebae9c66a2449062f35f29bc3 --- /dev/null +++ b/src/main/java/fucoin/actions/persist/ActionInvokeRevive.java @@ -0,0 +1,17 @@ +package fucoin.actions.persist; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.join.ActionJoin; +import fucoin.wallet.AbstractWallet; + +public class ActionInvokeRevive extends Persist { + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.setActive(true); + wallet.getPreKnownNeighbour().tell(new ActionJoin(), self); + } + +} diff --git a/src/main/java/fucoin/actions/persist/ActionInvokeUpdate.java b/src/main/java/fucoin/actions/persist/ActionInvokeUpdate.java new file mode 100644 index 0000000000000000000000000000000000000000..78149b5126791f523f54a40b19a4328cca6d2d51 --- /dev/null +++ b/src/main/java/fucoin/actions/persist/ActionInvokeUpdate.java @@ -0,0 +1,16 @@ +package fucoin.actions.persist; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +public class ActionInvokeUpdate extends Persist { + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/fucoin/actions/persist/ActionSearchMyWallet.java b/src/main/java/fucoin/actions/persist/ActionSearchMyWallet.java new file mode 100644 index 0000000000000000000000000000000000000000..5d4078ec4a2cba068e649e72f57120557dc2a166 --- /dev/null +++ b/src/main/java/fucoin/actions/persist/ActionSearchMyWallet.java @@ -0,0 +1,29 @@ +package fucoin.actions.persist; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +// Used to search a WalletImpl by name, i.e. the own wallet if we just +// joined the network; If a receiving participant holds the stored WalletImpl, +// he returns it, otherwise, he might use gossiping methods to go on +// with the search; +// Note: You should also forward the sender (the participant who actually +// searches for this WalletImpl, so that it can be returnd the direct way) +public class ActionSearchMyWallet extends Persist { + public final String name; + + public ActionSearchMyWallet(String name) { + this.name = name; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.addKnownNeighbor(name, sender); + AbstractWallet storedWallet = wallet.backedUpNeighbors.get(name); + if (storedWallet != null) { + sender.tell(new ActionSearchMyWalletAnswer(storedWallet), self); + } + } +} diff --git a/src/main/java/fucoin/actions/persist/ActionSearchMyWalletAnswer.java b/src/main/java/fucoin/actions/persist/ActionSearchMyWalletAnswer.java new file mode 100644 index 0000000000000000000000000000000000000000..4f3f29bb0bf4b005be9a6f04b589119638ccc714 --- /dev/null +++ b/src/main/java/fucoin/actions/persist/ActionSearchMyWalletAnswer.java @@ -0,0 +1,23 @@ +package fucoin.actions.persist; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +/** + * Used to return a searched WalletImpl + */ +public class ActionSearchMyWalletAnswer extends Persist { + public final AbstractWallet w; + + public ActionSearchMyWalletAnswer(AbstractWallet w) { + this.w = w; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.setAmount(w.getAmount()); + sender.tell(new ActionInvalidate(wallet.getName()), self); + } +} diff --git a/src/fucoin/actions/persist/ActionStoreOrUpdate.java b/src/main/java/fucoin/actions/persist/ActionStoreOrUpdate.java similarity index 53% rename from src/fucoin/actions/persist/ActionStoreOrUpdate.java rename to src/main/java/fucoin/actions/persist/ActionStoreOrUpdate.java index 977c1990ead2e8f54354319881409671c2aed527..83b9f73015764f60108f721ead7da50ab7f5def7 100644 --- a/src/fucoin/actions/persist/ActionStoreOrUpdate.java +++ b/src/main/java/fucoin/actions/persist/ActionStoreOrUpdate.java @@ -2,19 +2,20 @@ package fucoin.actions.persist; import akka.actor.ActorRef; import akka.actor.UntypedActorContext; -import fucoin.AbstractNode; -import fucoin.AbstractWallet; -import fucoin.Wallet; +import fucoin.wallet.AbstractWallet; +import fucoin.wallet.WalletImpl; //Used to push the state of my/a wallet to another participant public class ActionStoreOrUpdate extends Persist { public final AbstractWallet w; + public ActionStoreOrUpdate(AbstractWallet w) { this.w = w; } - @Override - protected void onAction(ActorRef sender, ActorRef self, - UntypedActorContext context, Wallet wallet) { - wallet.backedUpNeighbors.put(w.name, w); - } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.backedUpNeighbors.put(w.getName(), w); + } } diff --git a/src/fucoin/actions/persist/Persist.java b/src/main/java/fucoin/actions/persist/Persist.java similarity index 57% rename from src/fucoin/actions/persist/Persist.java rename to src/main/java/fucoin/actions/persist/Persist.java index 1a42e145ad17ba914350aa5c55efe3fa320dad4a..75574a7f1d925d0dbba50602024b00a6df9f3822 100644 --- a/src/fucoin/actions/persist/Persist.java +++ b/src/main/java/fucoin/actions/persist/Persist.java @@ -2,6 +2,6 @@ package fucoin.actions.persist; import fucoin.actions.ClientAction; -public abstract class Persist extends ClientAction{ - +public abstract class Persist extends ClientAction { + } diff --git a/src/main/java/fucoin/actions/search/ActionSearchWalletReference.java b/src/main/java/fucoin/actions/search/ActionSearchWalletReference.java new file mode 100644 index 0000000000000000000000000000000000000000..fe514e2802102260c18970ab58ce7e85f2e40324 --- /dev/null +++ b/src/main/java/fucoin/actions/search/ActionSearchWalletReference.java @@ -0,0 +1,48 @@ +package fucoin.actions.search; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +import java.util.ArrayList; +import java.util.List; + +/** + * Used to return a WalletImpl reference (akka-style string which can + * be transformed to an ActorRef) + */ +public class ActionSearchWalletReference extends Search { + + public final String name; + public final List<ActorRef> ttl = new ArrayList<>(); + + public ActionSearchWalletReference(String name) { + this.name = name; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.log(wallet.getKnownNeighbors() + "contains " + name + "?"); + ttl.add(self); + ActionSearchWalletReferenceAnswer answer = null; + if (this.name.equals(wallet.getName())) { + answer = new ActionSearchWalletReferenceAnswer(name, wallet.getAddress(), ttl); + } else if (wallet.backedUpNeighbors.containsKey(name)) { + answer = new ActionSearchWalletReferenceAnswer(name, wallet.backedUpNeighbors.get(name).getAddress(), ttl); + } else if (wallet.getKnownNeighbors().containsKey(name)) { + answer = new ActionSearchWalletReferenceAnswer(name, wallet.getAddress(wallet.getKnownNeighbors().get(name)), ttl); + } else if (ttl.size() < 5) { + for (ActorRef neighbor : wallet.getKnownNeighbors().values()) { + if (!ttl.contains(neighbor)) { + neighbor.tell(this, self); + } + } + } + //User unknown by this WalletImpl + if (answer != null && ttl.size() > 0) { + ttl.get(ttl.size() - 1).tell(answer, self); + } + } + +} diff --git a/src/main/java/fucoin/actions/search/ActionSearchWalletReferenceAnswer.java b/src/main/java/fucoin/actions/search/ActionSearchWalletReferenceAnswer.java new file mode 100644 index 0000000000000000000000000000000000000000..d1bbdd00f1210d77645e68b477d3bc084011f5ae --- /dev/null +++ b/src/main/java/fucoin/actions/search/ActionSearchWalletReferenceAnswer.java @@ -0,0 +1,31 @@ +package fucoin.actions.search; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +import java.util.List; + +public class ActionSearchWalletReferenceAnswer extends Search { + + public final String address; + public final String name; + public final List<ActorRef> pathToSearchedWallet; + + public ActionSearchWalletReferenceAnswer(String name, String address, List<ActorRef> pathToSearchedWallet) { + this.address = address; + this.name = name; + this.pathToSearchedWallet = pathToSearchedWallet; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + ActorRef target = context.actorSelection(address).anchor(); + wallet.addKnownNeighbor(name, target); + int pos = pathToSearchedWallet.indexOf(self); + if (pos > 0) { + pathToSearchedWallet.get(pos - 1).tell(this, self); + } + } +} diff --git a/src/fucoin/actions/search/Search.java b/src/main/java/fucoin/actions/search/Search.java similarity index 57% rename from src/fucoin/actions/search/Search.java rename to src/main/java/fucoin/actions/search/Search.java index 505f91562dd12d58b8cdd1cd0e168556c11eecdc..56dc7d24443fc7d7dd3d9250b1c464ee07c38331 100644 --- a/src/fucoin/actions/search/Search.java +++ b/src/main/java/fucoin/actions/search/Search.java @@ -2,6 +2,6 @@ package fucoin.actions.search; import fucoin.actions.ClientAction; -public abstract class Search extends ClientAction{ - +public abstract class Search extends ClientAction { + } diff --git a/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java b/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java new file mode 100644 index 0000000000000000000000000000000000000000..884c132f99f58f41c58ce6de15df90ca162fbfec --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java @@ -0,0 +1,69 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.ClientAction; +import fucoin.supervisor.DistributedCommittedTransferRequest; +import fucoin.wallet.AbstractWallet; + +public class ActionCommitDistributedCommittedTransfer extends ClientAction { + + private ActorRef source; + private ActorRef target; + protected int amount; + private boolean granted; + private long timestamp; + private long id; + + + public ActionCommitDistributedCommittedTransfer(ActorRef source, ActorRef target, + int amount, boolean granted, long timestamp, long id) { + this.source = source; + this.target = target; + this.amount = amount; + this.granted = granted; + this.timestamp = timestamp; + this.id = id; + } + + public ActionCommitDistributedCommittedTransfer( + DistributedCommittedTransferRequest outdatedRequest) { + this.source = outdatedRequest.getSource(); + this.target = outdatedRequest.getTarget(); + this.amount = outdatedRequest.getAmount(); + this.granted = false; + this.timestamp = outdatedRequest.getTimeout(); + this.id = outdatedRequest.getId(); + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.log("ActionCommitDistributedCommittedTransfer is granted? " + granted); + if (granted) { + + Integer sourceAmount = wallet.amounts.getOrDefault(source, 0); + Integer targetAmount = wallet.amounts.getOrDefault(target, 0); + wallet.amounts.put(source, sourceAmount - amount); + wallet.amounts.put(target, targetAmount + amount); + + if (source.compareTo(self) == 0) { + wallet.setAmount(wallet.getAmount() - amount); + wallet.logTransactionSuccess("Sent " + amount + " FUC to " + target.path().name()); + } else if (target.compareTo(self) == 0) { + wallet.setAmount(wallet.getAmount() + amount); + wallet.logTransactionSuccess("Received " + amount + " FUC from " + source.path().name()); + } + + } else { + wallet.log("abort transaction with id" + id); + + if (source.compareTo(self) == 0) { + wallet.logTransactionFail("Failed to send " + amount + " FUC to " + target.path().name() + " (Commit has not been granted)"); + } + + } + wallet.log("wallet.amounts:" + wallet.amounts); + } + +} diff --git a/src/main/java/fucoin/actions/transaction/ActionGetAmount.java b/src/main/java/fucoin/actions/transaction/ActionGetAmount.java new file mode 100644 index 0000000000000000000000000000000000000000..6cbcbfd1c5c177d8e9861b14061f5d2bf354e029 --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionGetAmount.java @@ -0,0 +1,16 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +public class ActionGetAmount extends Transaction { + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + ActionGetAmountAnswer agaa = new ActionGetAmountAnswer(wallet.getAddress(), wallet.getName(), wallet.getAmount()); + sender.tell(agaa, self); + } + +} diff --git a/src/main/java/fucoin/actions/transaction/ActionGetAmountAnswer.java b/src/main/java/fucoin/actions/transaction/ActionGetAmountAnswer.java new file mode 100644 index 0000000000000000000000000000000000000000..272c8d6d9d33913a1840515c924d21b28134dccd --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionGetAmountAnswer.java @@ -0,0 +1,26 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; +import fucoin.wallet.WalletImpl; + +public class ActionGetAmountAnswer extends Transaction { + + public String address; + public String name; + public int amount; + + public ActionGetAmountAnswer(String address, String name, int amount) { + this.address = address; + this.name = name; + this.amount = amount; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.amounts.put(sender, amount); + } + +} diff --git a/src/main/java/fucoin/actions/transaction/ActionInvokeDistributedCommittedTransfer.java b/src/main/java/fucoin/actions/transaction/ActionInvokeDistributedCommittedTransfer.java new file mode 100644 index 0000000000000000000000000000000000000000..f3bf02db907f58dbe852398313c0bbc1e3cbbbd3 --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionInvokeDistributedCommittedTransfer.java @@ -0,0 +1,38 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.supervisor.DistributedCommittedTransferRequest; +import fucoin.supervisor.SuperVisorImpl; + +public class ActionInvokeDistributedCommittedTransfer extends CoordinatorTransaction { + + private ActorRef source; + private ActorRef target; + private int amount; + + public ActionInvokeDistributedCommittedTransfer(ActorRef source, + ActorRef target, int amount) { + this.source = source; + this.target = target; + this.amount = amount; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, SuperVisorImpl superVisor) { + superVisor.log("invoke transaction " + source.path().name() + + " sends " + amount + + " to " + target.path().name()); + + long timeout = System.currentTimeMillis() + 500; + + DistributedCommittedTransferRequest ds = new DistributedCommittedTransferRequest(source, target, amount, timeout); + superVisor.addDistributedCommitedTransferRequest(ds); + ActionPrepareDistributedCommittedTransfer apdct = new ActionPrepareDistributedCommittedTransfer(source, target, amount, timeout, ds.getId()); + for (ActorRef neighbor : superVisor.getKnownNeighbors().values()) { + neighbor.tell(apdct, self); + } + } + +} diff --git a/src/main/java/fucoin/actions/transaction/ActionInvokeSentMoney.java b/src/main/java/fucoin/actions/transaction/ActionInvokeSentMoney.java new file mode 100644 index 0000000000000000000000000000000000000000..6f3bd3e2817b47e8d3df213f150fa45a5efe04bf --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionInvokeSentMoney.java @@ -0,0 +1,44 @@ +package fucoin.actions.transaction; + + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.search.ActionSearchWalletReference; +import fucoin.wallet.AbstractWallet; + +public class ActionInvokeSentMoney extends Transaction { + public final String name; + public final int amount; + + public ActionInvokeSentMoney(String name, int amount) { + this.name = name; + this.amount = amount; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.log(wallet.getKnownNeighbors() + ""); + if (wallet.getKnownNeighbors().containsKey(name)) { + wallet.getRemoteSuperVisorActor().tell( + new ActionInvokeDistributedCommittedTransfer(self, wallet.getKnownNeighbors().get(name), amount), sender); + } else { + ActionSearchWalletReference aswr = new ActionSearchWalletReference(name); + for (ActorRef neighbor : wallet.getKnownNeighbors().values()) { + neighbor.tell(aswr, self); + } + sleep(self, context, 200); + self.tell(this, self); + } + } + + private void sleep(ActorRef self, UntypedActorContext context, int timeOfIdle) { + try { + context.unwatch(self); + Thread.sleep(timeOfIdle); + context.watch(self); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java b/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java new file mode 100644 index 0000000000000000000000000000000000000000..7e7de88bf5a58168b49d67a333dedd266fe90cb7 --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java @@ -0,0 +1,38 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +public class ActionPrepareDistributedCommittedTransfer extends Transaction { + + private ActorRef source; + private ActorRef target; + private int amount; + private long timestamp; + private long id; + + public ActionPrepareDistributedCommittedTransfer(ActorRef source, ActorRef target, + int amount, long timestamp, long id) { + this.source = source; + this.target = target; + this.amount = amount; + this.timestamp = timestamp; + this.id = id; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + boolean granted = amount > 0 && + //sender is supervisor(bank) has always money + (sender.compareTo(source) == 0 + //sender is unknown, might be valid + || (wallet.amounts.containsKey(source) + //sender have enough money + && wallet.amounts.getOrDefault(source, 0) >= amount)); + + sender.tell(new ActionPrepareDistributedCommittedTransferAnswer(source, target, amount, timestamp, granted, id), self); + } + +} diff --git a/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransferAnswer.java b/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransferAnswer.java new file mode 100644 index 0000000000000000000000000000000000000000..3d2a0c094016678fe8d9ec18d64fed148be73eaa --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransferAnswer.java @@ -0,0 +1,57 @@ +package fucoin.actions.transaction; + +import fucoin.supervisor.DistributedCommittedTransferRequest; +import fucoin.supervisor.SuperVisorImpl; +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; + +public class ActionPrepareDistributedCommittedTransferAnswer extends CoordinatorTransaction { + + private ActorRef source; + private ActorRef target; + private int amount; + private boolean granted; + private long timestamp; + private long id; + + public ActionPrepareDistributedCommittedTransferAnswer(ActorRef source, + ActorRef target, int amount, long timestamp, boolean granted, long id) { + this.source = source; + this.target = target; + this.amount = amount; + this.granted = granted; + this.timestamp = timestamp; + this.id = id; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, SuperVisorImpl superVisor) { + superVisor.log("" + superVisor.getKnownNeighbors()); + superVisor.log("granted?" + granted); + DistributedCommittedTransferRequest request = superVisor.getRequest(id); + if (granted) { + if (request == null)//unknown DistributedCommittedTransferRequest ignore + return; + int newCount = request.addPositiveAnswer(sender); + + if (newCount == superVisor.getKnownNeighbors().size()) { + ActionCommitDistributedCommittedTransfer acdct = new ActionCommitDistributedCommittedTransfer(source, target, amount, true, timestamp, id); + for (ActorRef neighbor : request.getAnswers()) { + neighbor.tell(acdct, self); + } + superVisor.deleteRequest(request); + } + } else { + //A client wants to rollback + if (request != null) { + superVisor.log("Client does not grant commit of " + amount + " FUC (" + source.path().name() + " -> " + target.path().name() + ")"); + ActionCommitDistributedCommittedTransfer acdct = new ActionCommitDistributedCommittedTransfer(source, target, amount, false, timestamp, id); + for (ActorRef neighbor : request.getAnswers()) { + neighbor.tell(acdct, self); + } + } + } + } + +} diff --git a/src/main/java/fucoin/actions/transaction/ActionReceiveTransaction.java b/src/main/java/fucoin/actions/transaction/ActionReceiveTransaction.java new file mode 100644 index 0000000000000000000000000000000000000000..4250b8e15c6852d134f8e061db1754271813aad5 --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/ActionReceiveTransaction.java @@ -0,0 +1,22 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.wallet.AbstractWallet; + +/** + * Used to send (positive amount) or retrieve money (negative amount) + */ +public class ActionReceiveTransaction extends Transaction { + final public int amount; + + public ActionReceiveTransaction(int amount) { + this.amount = amount; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + wallet.addAmount(wallet.getAmount()); + } +} diff --git a/src/main/java/fucoin/actions/transaction/CoordinatorTransaction.java b/src/main/java/fucoin/actions/transaction/CoordinatorTransaction.java new file mode 100644 index 0000000000000000000000000000000000000000..b28dc56f2174166cb81abda28ba6f11540bb3c87 --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/CoordinatorTransaction.java @@ -0,0 +1,13 @@ +package fucoin.actions.transaction; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.supervisor.SuperVisorImpl; + +public abstract class CoordinatorTransaction extends SuperVisorAction { + + @Override + protected abstract void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, SuperVisorImpl abstractNode); + +} diff --git a/src/main/java/fucoin/actions/transaction/SuperVisorAction.java b/src/main/java/fucoin/actions/transaction/SuperVisorAction.java new file mode 100644 index 0000000000000000000000000000000000000000..19e93a885d76155f28378790bfd358a52c7a281c --- /dev/null +++ b/src/main/java/fucoin/actions/transaction/SuperVisorAction.java @@ -0,0 +1,8 @@ +package fucoin.actions.transaction; + +import fucoin.actions.Action; +import fucoin.supervisor.SuperVisorImpl; + +public abstract class SuperVisorAction extends Action<SuperVisorImpl> { + +} diff --git a/src/fucoin/actions/transaction/Transaction.java b/src/main/java/fucoin/actions/transaction/Transaction.java similarity index 56% rename from src/fucoin/actions/transaction/Transaction.java rename to src/main/java/fucoin/actions/transaction/Transaction.java index d764afc6192c3d786aa74a564a30a5a2e350cabb..fd418f95ea9cb650543b803a911ab1d011ac6ac0 100644 --- a/src/fucoin/actions/transaction/Transaction.java +++ b/src/main/java/fucoin/actions/transaction/Transaction.java @@ -2,6 +2,6 @@ package fucoin.actions.transaction; import fucoin.actions.ClientAction; -public abstract class Transaction extends ClientAction{ - +public abstract class Transaction extends ClientAction { + } diff --git a/src/main/java/fucoin/gui/LogCellRenderer.java b/src/main/java/fucoin/gui/LogCellRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..5087daec62868bb8cfd661da6f56a049fcfd4ca0 --- /dev/null +++ b/src/main/java/fucoin/gui/LogCellRenderer.java @@ -0,0 +1,37 @@ +package fucoin.gui; + +import javax.swing.*; +import java.awt.*; + +public class LogCellRenderer extends DefaultListCellRenderer { + + private static final Color SUCCESS_COLOR = new Color(56, 127, 56); + private static final Color FAIL_COLOR = new Color(217, 83, 79); + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + + if (value instanceof LogMessage) { + LogMessage msg = (LogMessage) value; + + switch (msg.getContext()) { + + case TRANSACTION_SUCCESS: + setForeground(SUCCESS_COLOR); + break; + case TRANSACTION_FAIL: + setForeground(FAIL_COLOR); + break; + case DEBUG: + break; + } + } + + if(isSelected){ + setForeground(Color.WHITE); + } + + return this; + } +} diff --git a/src/main/java/fucoin/gui/LogMessage.java b/src/main/java/fucoin/gui/LogMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..9b04de43e3509c43fed8e392b40c6357a77bb251 --- /dev/null +++ b/src/main/java/fucoin/gui/LogMessage.java @@ -0,0 +1,34 @@ +package fucoin.gui; + + +public class LogMessage { + + public enum Context { + TRANSACTION_SUCCESS, TRANSACTION_FAIL, DEBUG + } + + private String message; + private Context context; + + public LogMessage(String message) { + this(message, Context.DEBUG); + } + + public LogMessage(String message, Context context) { + this.message = message; + this.context = context; + } + + public String getMessage() { + return message; + } + + public Context getContext() { + return context; + } + + @Override + public String toString() { + return getMessage(); + } +} diff --git a/src/main/java/fucoin/gui/SuperVisorGuiControl.java b/src/main/java/fucoin/gui/SuperVisorGuiControl.java new file mode 100644 index 0000000000000000000000000000000000000000..bea5e7ae5004ddbd003beb1b5fe82dbbdb3620b1 --- /dev/null +++ b/src/main/java/fucoin/gui/SuperVisorGuiControl.java @@ -0,0 +1,10 @@ +package fucoin.gui; + +public interface SuperVisorGuiControl { + /** + * Call from SuperVisorImpl after poison pill or kill + */ + void onLeave(); + + void log(String message); +} diff --git a/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java b/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..81a379ae96d0230c5fb3bfe4b7296d7ce75ba7ab --- /dev/null +++ b/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java @@ -0,0 +1,75 @@ +package fucoin.gui; + +import fucoin.supervisor.SuperVisorImpl; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class SuperVisorGuiControlImpl implements SuperVisorGuiControl { + private SuperVisorImpl superVisor; + private JFrame frame; + + private DefaultListModel<String> log = new DefaultListModel<>(); + private JList<String> txtLog = new JList<>(log); + private JScrollPane logPane = new JScrollPane(txtLog); + + public SuperVisorGuiControlImpl(SuperVisorImpl sv) { + superVisor = sv; + init(); + } + + private void init() { + //Show AWT window for runtime information + frame = new JFrame("Server"); + JPanel contentPanel = new JPanel(); + contentPanel.setLayout(new GridLayout(2, 1)); + + //Init Amount Table and SuperVisorImpl + + JTable amountListView = new JTable(superVisor.getAmountTableModel()); + contentPanel.add(new JScrollPane(amountListView)); + + contentPanel.add(logPane); + + frame.add(contentPanel, BorderLayout.CENTER); + + //Exit Button and shutdown supervisor + JButton exitBtn = new JButton("Stop Supervisor"); + exitBtn.addActionListener(e -> { + superVisor.exit(); + frame.setVisible(false); + frame.dispose(); + }); + frame.add(exitBtn, BorderLayout.PAGE_END); + frame.setSize(800, 600); + frame.setVisible(true); + + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + super.windowClosing(e); + superVisor.exit(); + } + }); + } + + @Override + public void onLeave() { + frame.dispose(); + } + + @Override + public void log(String message) { + // One day, we may have a server log GUI as well.. + // Until then, we just print it to the console + //System.out.println(message); + SwingUtilities.invokeLater(() -> { + log.addElement(message); + + // auto scroll to the bottom + txtLog.ensureIndexIsVisible(log.size() - 1); + }); + } +} diff --git a/src/main/java/fucoin/gui/WalletGuiControl.java b/src/main/java/fucoin/gui/WalletGuiControl.java new file mode 100644 index 0000000000000000000000000000000000000000..90bdbdb4e43b6d8fe346d0ebce46996304200696 --- /dev/null +++ b/src/main/java/fucoin/gui/WalletGuiControl.java @@ -0,0 +1,22 @@ +package fucoin.gui; + + +public interface WalletGuiControl { + void setAddress(String address); + + void setAmount(int amount); + + void addKnownAddress(String address); + + void addLogMsg(String msg); + + void addTransactionLogMessageSuccess(String message); + + void addTransactionLogMessageFail(String message); + + /** + * Tell the GUI, that the wallet is a remote wallet. + */ + void setRemote(); + +} diff --git a/src/main/java/fucoin/gui/WalletGuiControlImpl.java b/src/main/java/fucoin/gui/WalletGuiControlImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2a2e008f3ba57d8e55cf49c6597acba091220366 --- /dev/null +++ b/src/main/java/fucoin/gui/WalletGuiControlImpl.java @@ -0,0 +1,248 @@ +package fucoin.gui; + +import akka.actor.ActorSelection; +import fucoin.wallet.AbstractWallet; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.Enumeration; + +public class WalletGuiControlImpl implements WalletGuiControl { + + private DefaultListModel<LogMessage> log = new DefaultListModel<>(); + + private JFrame window = new JFrame("test"); + private JPanel topPanel = new JPanel(); + private JTextField txtMyName = new JTextField("<MyName>"); + private JTextField txtMyAddress = new JTextField("<MyAddress>"); + private JLabel lblMyAmount = new JLabel("My FUCs: "); + private JLabel txtMyAmount = new JLabel(" <MyFUCs>"); + private JPanel centerPanel = new JPanel(); + private JLabel lblSendTo = new JLabel("Send to:"); + private JComboBox<String> txtSendTo = new JComboBox<>(); + private JLabel lblSendAmount = new JLabel("Amount:"); + private JTextField txtSendAmount = new JTextField(""); + private JButton btnSend = new JButton("Send"); + private JButton btnSearch = new JButton("Search"); + private JButton btnStore = new JButton("Store"); + private JButton btnExit = new JButton("Exit"); + private JPanel bottomPanel = new JPanel(); + private JList<LogMessage> txtLog = new JList<>(log); + private JScrollPane logPane = new JScrollPane(txtLog); + private JCheckBox showDebug; + + public WalletGuiControlImpl(AbstractWallet wallet) { + + window.setSize(400, 600); + window.setLayout(new GridLayout(3, 1)); + topPanel.setLayout(new GridLayout(2, 1)); + // Row 1 + JPanel row1 = new JPanel(); + row1.setLayout(new BoxLayout(row1, BoxLayout.PAGE_AXIS)); + + txtMyName.setHorizontalAlignment(JTextField.CENTER); + txtMyName.setBorder(BorderFactory.createEmptyBorder()); + txtMyName.setFont(txtMyName.getFont().deriveFont(18f).deriveFont(Font.BOLD)); + txtMyName.setEditable(false); + txtMyName.setForeground(Color.WHITE); + + txtMyName.setText(wallet.getName()); + + txtMyAddress.setHorizontalAlignment(JTextField.CENTER); + txtMyAddress.setBorder(BorderFactory.createEmptyBorder()); + txtMyAddress.setEditable(false); + txtMyAddress.setForeground(Color.WHITE); + + //setTint(new Color(123,94,167)); + setTint(new Color(54, 135, 56)); + + row1.add(txtMyName); + row1.add(txtMyAddress); + topPanel.add(row1); + // Row 2 + JPanel row2 = new JPanel(new GridBagLayout()); + Font fucFont = txtMyAmount.getFont().deriveFont(20f).deriveFont(Font.BOLD); + lblMyAmount.setFont(fucFont); + txtMyAmount.setFont(fucFont); + row2.add(lblMyAmount); + row2.add(txtMyAmount); + topPanel.add(row2); + window.add(topPanel); + //<hr> + centerPanel.setLayout(new GridLayout(4, 1)); + // Row 1 + JPanel centerup = new JPanel(); + centerup.setLayout(new BorderLayout()); + centerup.add(lblSendTo, BorderLayout.WEST); + centerup.add(txtSendTo, BorderLayout.CENTER); + centerPanel.add(centerup); + + JPanel centerup2 = new JPanel(); + centerup2.setLayout(new BorderLayout()); + JTextField sendToNewEdt = new JTextField(); + centerup2.add(sendToNewEdt, BorderLayout.CENTER); + JButton addNewButton = new JButton("Add"); + addNewButton.addActionListener(e -> { + ActorSelection selection = wallet.getContext().actorSelection(sendToNewEdt.getText()); + System.out.println(selection); + }); + centerup2.add(addNewButton, BorderLayout.EAST); + centerPanel.add(centerup2); + + // Row 2 + JPanel centerdown = new JPanel(); + centerdown.setLayout(new GridLayout(1, 3)); + centerdown.add(lblSendAmount); + centerdown.add(txtSendAmount); + centerdown.add(btnSend); + centerPanel.add(centerdown); + + // Row 3 + JPanel centerdown2 = new JPanel(); + centerdown2.setLayout(new GridLayout(1, 3)); + centerdown2.add(btnSearch); + centerdown2.add(btnStore); + centerdown2.add(btnExit); + centerPanel.add(centerdown2); + window.add(centerPanel); + + + bottomPanel.setLayout(new BorderLayout()); + + showDebug = new JCheckBox("Show debug messages in transaction log"); + showDebug.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + txtLog.setModel(log); + } else { + updateFilteredLog(); + } + }); + + bottomPanel.add(showDebug, BorderLayout.NORTH); + bottomPanel.add(logPane, BorderLayout.CENTER); + + window.add(bottomPanel); + window.setVisible(true); + + btnSend.addActionListener(e -> { + wallet.send(txtSendTo.getSelectedItem().toString(), + Integer.parseInt(txtSendAmount.getText())); + }); + + btnStore.addActionListener(e -> { + + }); + + + txtLog.setCellRenderer(new LogCellRenderer()); + + // Disable currently unused controls that might be useful in the future + addNewButton.setEnabled(false); + btnStore.setEnabled(false); + btnSearch.setEnabled(false); + sendToNewEdt.setEditable(false); + + btnExit.addActionListener(e -> window.dispose()); + + window.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + System.out.println("window closing"); + wallet.leave(); + super.windowClosing(e); + + } + + @Override + public void windowClosed(WindowEvent e) { + System.out.println("window closing"); + wallet.leave(); + super.windowClosing(e); + } + }); + } + + /** + * Set the color of the top section + * + * @param color The color used for the upper row. The color for the bottom row is calculated by lightening up the provided color + */ + private void setTint(Color color) { + txtMyName.setBackground(color); + + // Make the secondary color roughly 15% lighter + float amount = 0.15f; + + int red = (int) ((color.getRed() * (1 - amount) / 255 + amount) * 255); + int green = (int) ((color.getGreen() * (1 - amount) / 255 + amount) * 255); + int blue = (int) ((color.getBlue() * (1 - amount) / 255 + amount) * 255); + + txtMyAddress.setBackground(new Color(red, green, blue)); + } + + @Override + public void setAddress(String address) { + txtMyAddress.setText(address); + window.setTitle(address); + } + + @Override + public void setAmount(int amount) { + txtMyAmount.setText(String.valueOf(amount)); + } + + @Override + public void addKnownAddress(String address) { + txtSendTo.addItem(address); + } + + @Override + public void addLogMsg(String msg) { + log(new LogMessage(msg)); + } + + @Override + public void addTransactionLogMessageSuccess(String message) { + log(new LogMessage(message, LogMessage.Context.TRANSACTION_SUCCESS)); + } + + @Override + public void addTransactionLogMessageFail(String message) { + log(new LogMessage(message, LogMessage.Context.TRANSACTION_FAIL)); + } + + @Override + public void setRemote() { + setTint(new Color(45, 94, 167)); + } + + private void log(LogMessage logMessage) { + SwingUtilities.invokeLater(() -> { + log.addElement(logMessage); + + if (!showDebug.isSelected()) { + updateFilteredLog(); + } + + // auto scroll to the bottom + txtLog.ensureIndexIsVisible(log.size() - 1); + }); + } + + private void updateFilteredLog() { + + DefaultListModel<LogMessage> filteredLog = new DefaultListModel<>(); + Enumeration<LogMessage> elements = log.elements(); + while (elements.hasMoreElements()) { + LogMessage logMessage = elements.nextElement(); + LogMessage.Context context = logMessage.getContext(); + if (context == LogMessage.Context.TRANSACTION_FAIL || context == LogMessage.Context.TRANSACTION_SUCCESS) { + filteredLog.addElement(logMessage); + } + } + + txtLog.setModel(filteredLog); + } +} diff --git a/src/main/java/fucoin/setup/NetworkInterfaceReader.java b/src/main/java/fucoin/setup/NetworkInterfaceReader.java new file mode 100644 index 0000000000000000000000000000000000000000..47be4bd08a9aba83786c5e83d5aa07a2124ec957 --- /dev/null +++ b/src/main/java/fucoin/setup/NetworkInterfaceReader.java @@ -0,0 +1,49 @@ +package fucoin.setup; + +import java.net.*; +import java.util.*; + +public class NetworkInterfaceReader { + /** + * Grab a list of all network interfaces and the associated IP addresses to prevent some strange behaviours of + * the <code>InetAddress.getLocalHost().getHostAddress();</code> call + * + * @return The list contains SelectableNetworkInterfaces, that contain the interface name and the associated IP address + */ + public static List<SelectableNetworkInterface> fetchNetworkInterfaces() { + List<SelectableNetworkInterface> map = new ArrayList<>(); + + try { + Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); + + for (NetworkInterface networkInterface : Collections.list(nets)) { + Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses(); + // To ease the setup, currently only IPv4 addresses are supported + Optional<InetAddress> picked = Collections.list(inetAddresses).stream().filter(inetAddress -> !(inetAddress instanceof Inet6Address)).findFirst(); + if (picked.isPresent()) { + String hostAddress = picked.get().getHostAddress(); + map.add(new SelectableNetworkInterface(hostAddress, networkInterface.getDisplayName())); + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + + return map; + } + + /** + * Get the IP address, that is resolved by the system from the host name. + * As a fallback, we return 127.0.0.1, i.e. localhost + */ + public static String readDefaultHostname() { + String hostname = "127.0.0.1"; + try { + hostname = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + return hostname; + } +} diff --git a/src/main/java/fucoin/setup/SelectableNetworkInterface.java b/src/main/java/fucoin/setup/SelectableNetworkInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..8d21975277fb2df1665727f784c39946814627ac --- /dev/null +++ b/src/main/java/fucoin/setup/SelectableNetworkInterface.java @@ -0,0 +1,33 @@ +package fucoin.setup; + +public class SelectableNetworkInterface { + + String hostName; + String interfaceName; + + public SelectableNetworkInterface(String hostName, String interfaceName) { + this.hostName = hostName; + this.interfaceName = interfaceName; + } + + public String getHostName() { + return hostName; + } + + public String getInterfaceName() { + return interfaceName; + } + + @Override + public String toString() { + return getInterfaceName() + " (" + getHostName() + ")"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SelectableNetworkInterface) { + return ((SelectableNetworkInterface) obj).getHostName().equals(this.getHostName()); + } + return super.equals(obj); + } +} diff --git a/src/main/java/fucoin/setup/SetupDialogPanel.java b/src/main/java/fucoin/setup/SetupDialogPanel.java new file mode 100644 index 0000000000000000000000000000000000000000..d5d1edc9157031ad37a6c7bed18241c10e1125aa --- /dev/null +++ b/src/main/java/fucoin/setup/SetupDialogPanel.java @@ -0,0 +1,78 @@ +package fucoin.setup; + +import javax.swing.*; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import java.awt.*; +import java.util.List; + +public class SetupDialogPanel extends JPanel { + private JTextField walletNameField = new JTextField(10); + private JTextField pathField = new JTextField(10); + private JComboBox<SelectableNetworkInterface> hostnameField = new JComboBox<>(); + + public SetupDialogPanel(String defaultHostname) { + super(); + + createComponents(defaultHostname); + } + + private void createComponents(String defaultHostname) { + this.setLayout(new GridLayout(3, 1)); + this.add(new JLabel("Pick your wallet name: ", SwingConstants.LEFT)); + this.add(walletNameField); + this.add(new JLabel("Enter a neighbour node address: ", SwingConstants.LEFT)); + this.add(pathField); + this.add(new JLabel("Select your reachable IP address: ", SwingConstants.LEFT)); + + selectWalletNameField(); + + List<SelectableNetworkInterface> interfaces = NetworkInterfaceReader.fetchNetworkInterfaces(); + + for (SelectableNetworkInterface netint : interfaces) { + hostnameField.addItem(netint); + } + + hostnameField.setSelectedItem(new SelectableNetworkInterface(defaultHostname, "default")); + this.add(hostnameField); + } + + /** + * This method makes sure, that the Wallet name field is selected on display of the dialog + */ + private void selectWalletNameField() { + walletNameField.addAncestorListener(new AncestorListener() { + @Override + public void ancestorAdded(AncestorEvent event) { + final AncestorListener al = this; + SwingUtilities.invokeLater(() -> { + JComponent component = event.getComponent(); + component.requestFocusInWindow(); + component.removeAncestorListener(al); + }); + } + + @Override + public void ancestorRemoved(AncestorEvent event) { + + } + + @Override + public void ancestorMoved(AncestorEvent event) { + + } + }); + } + + public String getWalletName() { + return walletNameField.getText(); + } + + public String getAddressOfNeighbour() { + return pathField.getText(); + } + + public SelectableNetworkInterface getNetworkInterface() { + return (SelectableNetworkInterface) hostnameField.getSelectedItem(); + } +} diff --git a/src/main/java/fucoin/supervisor/ActionUpdateQueue.java b/src/main/java/fucoin/supervisor/ActionUpdateQueue.java new file mode 100644 index 0000000000000000000000000000000000000000..e15ce4b8c757d5e7c7882e4149a5923b56fbc609 --- /dev/null +++ b/src/main/java/fucoin/supervisor/ActionUpdateQueue.java @@ -0,0 +1,38 @@ +package fucoin.supervisor; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.transaction.ActionCommitDistributedCommittedTransfer; +import fucoin.actions.transaction.SuperVisorAction; + +import java.util.List; + +public class ActionUpdateQueue extends SuperVisorAction { + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, SuperVisorImpl superVisor) { + + List<DistributedCommittedTransferRequest> deletes = superVisor.updateList(); + + for (DistributedCommittedTransferRequest outdatedRequest : deletes) { + ActionCommitDistributedCommittedTransfer acdct = new ActionCommitDistributedCommittedTransfer(outdatedRequest); + for (ActorRef neighbor : superVisor.getKnownNeighbors().values()) { + neighbor.tell(acdct, self); + } + } + sleep(self, context, 1000); + self.tell(this, self); + } + + private void sleep(ActorRef self, UntypedActorContext context, int sleeptime) { + try { + context.unwatch(self); + Thread.sleep(sleeptime); + context.watch(self); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/fucoin/supervisor/AmountTableModel.java b/src/main/java/fucoin/supervisor/AmountTableModel.java new file mode 100644 index 0000000000000000000000000000000000000000..b25a22f139b2b4f37749b33604d65c55e5b4d65a --- /dev/null +++ b/src/main/java/fucoin/supervisor/AmountTableModel.java @@ -0,0 +1,33 @@ +package fucoin.supervisor; + +import javax.swing.table.DefaultTableModel; +import java.util.Vector; + +public class AmountTableModel extends DefaultTableModel { + + public AmountTableModel() { + super(new Object[]{"Address", "Name", "Amount"}, 0); + } + + public void clear() { + while (getRowCount() > 0) { + removeRow(0); + } + } + + public void updateTable(String address, String name, int amount) { + + Vector rows = this.getDataVector(); + for (int i = 0; i < rows.size(); i++) { + if (rows.get(i) instanceof Vector) { + Vector<Object> row = (Vector<Object>) rows.get(i); + if (row.get(0).equals(address)) { + setValueAt(amount, i, 2); + return; + } + } + } + + this.addRow(new Object[]{address, name, amount}); + } +} diff --git a/src/main/java/fucoin/supervisor/DistributedCommittedTransferRequest.java b/src/main/java/fucoin/supervisor/DistributedCommittedTransferRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..d4ebd400373f9103c1ed6a5fa8b156b90e613003 --- /dev/null +++ b/src/main/java/fucoin/supervisor/DistributedCommittedTransferRequest.java @@ -0,0 +1,67 @@ +package fucoin.supervisor; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.transaction.Transaction; +import fucoin.wallet.AbstractWallet; + +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +public class DistributedCommittedTransferRequest extends Transaction { + private final static Random random = new Random(System.currentTimeMillis() + System.nanoTime()); + private ActorRef source; + private ActorRef target; + private int amount; + + private long timeout; + private long id; + + private List<ActorRef> answers = new LinkedList<>(); + + public DistributedCommittedTransferRequest(ActorRef source, ActorRef target, int amount, + long timeout) { + this.source = source; + this.target = target; + this.amount = amount; + + this.timeout = timeout; + this.id = random.nextLong(); + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, + UntypedActorContext context, AbstractWallet wallet) { + + } + + public ActorRef getSource() { + return source; + } + + public ActorRef getTarget() { + return target; + } + + public long getTimeout() { + return timeout; + } + + public int addPositiveAnswer(ActorRef sender) { + answers.add(sender); + return answers.size(); + } + + public List<ActorRef> getAnswers() { + return answers; + } + + public long getId() { + return id; + } + + public int getAmount() { + return amount; + } +} diff --git a/src/main/java/fucoin/supervisor/SuperVisorCreator.java b/src/main/java/fucoin/supervisor/SuperVisorCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..088ea7845b3540d8812434c244d48f00d8a6f865 --- /dev/null +++ b/src/main/java/fucoin/supervisor/SuperVisorCreator.java @@ -0,0 +1,24 @@ +package fucoin.supervisor; + +import akka.japi.Creator; +import fucoin.gui.SuperVisorGuiControl; +import fucoin.gui.SuperVisorGuiControlImpl; + +import javax.swing.*; +import java.awt.*; + +/** + * Create SuperVisor with a AWT Window. + * The window displays the information from the supervisor. + */ +public class SuperVisorCreator implements Creator<SuperVisorImpl> { + + @Override + public SuperVisorImpl create() throws Exception { + SuperVisorImpl sv = new SuperVisorImpl(); + SuperVisorGuiControl superVisorGuiControl = new SuperVisorGuiControlImpl(sv); + sv.setGuiControl(superVisorGuiControl); + return sv; + } + +} diff --git a/src/main/java/fucoin/supervisor/SuperVisorImpl.java b/src/main/java/fucoin/supervisor/SuperVisorImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1252f1c9c925c5e9e4fad02fcafd3c69ae2caebd --- /dev/null +++ b/src/main/java/fucoin/supervisor/SuperVisorImpl.java @@ -0,0 +1,126 @@ +package fucoin.supervisor; + +import akka.actor.Props; +import fucoin.actions.Action; +import fucoin.actions.persist.ActionInvokeUpdate; +import fucoin.actions.transaction.ActionGetAmountAnswer; +import fucoin.actions.transaction.SuperVisorAction; +import fucoin.gui.SuperVisorGuiControl; +import fucoin.AbstractNode; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +public class SuperVisorImpl extends AbstractNode { + + private AmountTableModel amountTableModel; + + private Map<Long, DistributedCommittedTransferRequest> requestQueue; + + private SuperVisorGuiControl gui; + + public SuperVisorImpl() { + this.amountTableModel = new AmountTableModel(); + } + + public void setGuiControl(SuperVisorGuiControl gui) { + this.gui = gui; + } + + public SuperVisorImpl(AmountTableModel amountTableModel) { + this.amountTableModel = amountTableModel; + } + + @Override + public void onReceive(Object msg) { + + // dirty but necessary since ActionGetAmountAnswer is a + // ClientAction for some reason + if (msg instanceof ActionGetAmountAnswer) { + ActionGetAmountAnswer answer = (ActionGetAmountAnswer) msg; + amountTableModel.updateTable(answer.address, answer.name, answer.amount); + } /* TODO: Whats happened here?? Why we can invoke doAction of abstract class? */ else if (msg instanceof SuperVisorAction) { + ((Action) msg).doAction(this); + } + } + + public static Props props() { + return Props.create(new SuperVisorCreator()); + } + + public void updateValues() { + getSelf().tell(new ActionInvokeUpdate(), getSelf()); + } + + public void exit() { + getContext().stop(getSelf()); + if (gui != null) { + gui.onLeave(); + } + } + + @Override + public void postStop() throws Exception { + super.postStop(); + } + + public void addDistributedCommitedTransferRequest( + DistributedCommittedTransferRequest request) { + requestQueue.put(request.getId(), request); + } + + @Override + public void preStart() throws Exception { + super.preStart(); + requestQueue = new HashMap<>(); + self().tell(new ActionUpdateQueue(), self()); + } + + /** + * filters the request for outdated and removes them + * + * @return deleted outdated request + */ + public List<DistributedCommittedTransferRequest> updateList() { + List<Long> deletesIds = new ArrayList<>(); + List<DistributedCommittedTransferRequest> deletes = new ArrayList<>(); + for (Entry<Long, DistributedCommittedTransferRequest> outdatedRequest : requestQueue.entrySet()) { + if (outdatedRequest.getValue().getTimeout() < System.currentTimeMillis()) { + deletesIds.add(outdatedRequest.getKey()); + deletes.add(outdatedRequest.getValue()); + } + } + for (Long delete : deletesIds) { + requestQueue.remove(delete); + } + + return deletes; + } + + public DistributedCommittedTransferRequest getRequest(Long id) { + return requestQueue.get(id); + } + + public void deleteRequest(DistributedCommittedTransferRequest request) { + requestQueue.remove(request.getId()); + } + + public AmountTableModel getAmountTableModel() { + return amountTableModel; + } + + public void setAmountTableModel(AmountTableModel amountTableModel) { + this.amountTableModel = amountTableModel; + } + + public void log(String message) { + if (this.gui != null) { + this.gui.log(message); + } else { + System.out.println(message); + } + } +} diff --git a/src/main/java/fucoin/wallet/AbstractWallet.java b/src/main/java/fucoin/wallet/AbstractWallet.java new file mode 100644 index 0000000000000000000000000000000000000000..bc44d051ec250a68db11f9e677b683f985a4c5b8 --- /dev/null +++ b/src/main/java/fucoin/wallet/AbstractWallet.java @@ -0,0 +1,118 @@ +package fucoin.wallet; + +import akka.actor.ActorRef; +import fucoin.AbstractNode; + +import java.io.Serializable; + +/** + * + */ +public abstract class AbstractWallet extends AbstractNode implements Serializable { + + /** + * Currently amount of this wallet + */ + protected int amount; + + /** + * The name of this wallet (does never change, no duplicates in network assumed) + */ + protected final String name; + + /** + * Init. a wallet with a name. + * + * @param name Name of the Wallet + */ + public AbstractWallet(String name) { + this.name = name; + } + + /** + * Returns the name of the wallet + * + * @return Name of the wallet. + */ + public String getName() { + return this.name; + } + + /** + * Performs housekeeping operations, e.g. pushes + * backedUpNeighbor-entries to other neighbors + */ + public abstract void leave(); + + /** + * Returns the current amount of the wallet + * + * @return amount of the wallet + */ + public int getAmount() { + return amount; + } + + /** + * Set new Amount of the wallet. + * + * @param amount New amount of the wallet + */ + public abstract void setAmount(int amount); + + /** + * Add amount to current amount. + * + * @param amount value to add to current account. + */ + public abstract void addAmount(int amount); + + /** + * Sets the wallet into the active state. + * TODO: Is this actually used/necessary/wanted? + * + * @param isActive + */ + public abstract void setActive(boolean isActive); + + /** + * Returns the + * + * @return + */ + public abstract ActorRef getPreKnownNeighbour(); + + /** + * Returns the supervisor of this wallet + * + * @return + */ + public abstract ActorRef getRemoteSuperVisorActor(); + + /** + * @param remoteSuperVisorActor + */ + public abstract void setRemoteSuperVisorActor(ActorRef remoteSuperVisorActor); + + /** + * Appends a message related to a successful transaction to the log + * + * @param msg + */ + public abstract void logTransactionSuccess(String msg); + + /** + * Appends a message related to a successful transaction to the log + * + * @param msg + */ + public abstract void logTransactionFail(String msg); + + /** + * Sends amount FUCs to the wallet with the address adress + * + * @param address Recipients address + * @param amount Amount to send + */ + public abstract void send(String address, int amount); +} diff --git a/src/main/java/fucoin/wallet/WalletCreator.java b/src/main/java/fucoin/wallet/WalletCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..2a512b9f797529e1a24a0508fe91194fb3431226 --- /dev/null +++ b/src/main/java/fucoin/wallet/WalletCreator.java @@ -0,0 +1,24 @@ +package fucoin.wallet; + +import akka.actor.ActorRef; +import akka.japi.Creator; +import fucoin.gui.WalletGuiControlImpl; + +public class WalletCreator implements Creator<AbstractWallet> { + private ActorRef preKnownNeighbour; + private String walletName; + + public WalletCreator(ActorRef preKnownNeighbour, String walletName) { + this.preKnownNeighbour = preKnownNeighbour; + this.walletName = walletName; + } + + @Override + public WalletImpl create() throws Exception { + WalletImpl wallet = new WalletImpl(preKnownNeighbour, walletName); + + WalletGuiControlImpl gui = new WalletGuiControlImpl(wallet); + wallet.setGui(gui); + return wallet; + } +} diff --git a/src/main/java/fucoin/wallet/WalletImpl.java b/src/main/java/fucoin/wallet/WalletImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f35d620fb87a8629bb4238682c119e208b9158b2 --- /dev/null +++ b/src/main/java/fucoin/wallet/WalletImpl.java @@ -0,0 +1,228 @@ +package fucoin.wallet; + +import akka.actor.ActorRef; +import akka.actor.Props; +import fucoin.actions.ClientAction; +import fucoin.actions.join.ActionJoin; +import fucoin.actions.join.ActionJoinAnswer; +import fucoin.actions.join.ServerActionJoin; +import fucoin.actions.persist.ActionInvokeLeave; +import fucoin.actions.persist.ActionInvokeRevive; +import fucoin.actions.transaction.ActionGetAmountAnswer; +import fucoin.actions.transaction.ActionInvokeSentMoney; +import fucoin.gui.WalletGuiControl; + +public class WalletImpl extends AbstractWallet { + + private ActorRef preKnownNeighbour; + private ActorRef remoteSuperVisorActor; + private transient WalletGuiControl gui; + private String preKnownNeighbourName; + private boolean isActive; + + public WalletImpl(String name) { + super(name); + } + + public WalletImpl(ActorRef preKnownNeighbour, String walletName) { + super(walletName); + if (preKnownNeighbour != null) { + this.preKnownNeighbourName = preKnownNeighbour.path().name(); + this.preKnownNeighbour = preKnownNeighbour; + } + } + + public static Props props(ActorRef preKnownNeighbour, String walletName) { + return Props.create(new WalletCreator(preKnownNeighbour, walletName)); + } + + /** + * Adds amount to the current amount of FUCs in the wallet. + * + * @param amount value to add to current account. + */ + public void addAmount(int amount) { + setAmount(this.getAmount() + amount); + log(" My amount is now " + this.getAmount()); + } + + @Override + public void leave() { + getSelf().tell(new ActionInvokeLeave(), getSelf()); + } + + @Override + public void onReceive(Object message) { + + log(getSender().path().name() + " invokes " + getSelf().path().name() + " to do " + message.getClass().getSimpleName()); + if (message instanceof ActionInvokeRevive) { + ((ActionInvokeRevive) message).doAction(this); + } + if (!isActive && !(message instanceof ActionInvokeRevive)) return; + + if (message instanceof ClientAction) { + ((ClientAction) message).doAction(this); + } + + } + + @Override + public void preStart() throws Exception { + + isActive = true; + + if (gui != null) { + String address = getAddress(); + gui.setAddress(address); + if (address.contains("Remote@")) { + gui.setRemote(); + } + } + + if (preKnownNeighbour != null) { + addKnownNeighbor(preKnownNeighbourName, preKnownNeighbour); + preKnownNeighbour.tell(new ActionJoin(), getSelf()); + ActionJoinAnswer aja = new ActionJoinAnswer(this.getRemoteSuperVisorActor()); + aja.someNeighbors.putAll(getKnownNeighbors()); + aja.someNeighbors.put(name, getSelf()); + preKnownNeighbour.tell(aja, getSelf()); + + } + } + + @Override + public void postStop() throws Exception { + leave(); + super.postStop(); + + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof WalletImpl) { + WalletImpl wobj = (WalletImpl) obj; + return amount == wobj.getAmount() && name.equals(wobj.getName()); + } + return false; + } + + /** + * Returns the amount of FUCs currently in the wallet. + * + * @return + */ + public int getAmount() { + return amount; + } + + /** + * Sets the amount of FUCs in the wallet to amount. + * + * @param amount New amount of the wallet + */ + public void setAmount(int amount) { + this.amount = amount; + + if (remoteSuperVisorActor != null) { + remoteSuperVisorActor.tell(new ActionGetAmountAnswer(getAddress(), getName(), amount), getSelf()); + } + if (gui != null) { + gui.setAmount(this.amount); + } + } + + @Override + public ActorRef getPreKnownNeighbour() { + return preKnownNeighbour; + } + + public void setPreKnownNeighbour(ActorRef preKnownNeighbour) { + this.preKnownNeighbour = preKnownNeighbour; + } + + @Override + public ActorRef getRemoteSuperVisorActor() { + return remoteSuperVisorActor; + } + + @Override + public void setRemoteSuperVisorActor(ActorRef remoteSuperVisorActor) { + if (this.remoteSuperVisorActor == null) { + this.remoteSuperVisorActor = remoteSuperVisorActor; + this.remoteSuperVisorActor.tell(new ServerActionJoin(getName()), getSelf()); + } + } + + public WalletGuiControl getGui() { + return gui; + } + + public void setGui(WalletGuiControl gui) { + this.gui = gui; + } + + public String getPreKnownNeighbourName() { + return preKnownNeighbourName; + } + + public void setPreKnownNeighbourName(String preKnownNeighbourName) { + this.preKnownNeighbourName = preKnownNeighbourName; + } + + public boolean isActive() { + return isActive; + } + + public void setActive(boolean isActive) { + this.isActive = isActive; + } + + @Override + public boolean addKnownNeighbor(String key, ActorRef value) { + log(key + " is newNeighbor of " + name + "?" + !getKnownNeighbors().containsKey(key)); + if (getKnownNeighbors().containsKey(key) || key.equals(name)) { + return false; + } + + boolean newNeighbor = super.addKnownNeighbor(key, value); + if (gui != null && newNeighbor) { + gui.addKnownAddress(key); + } + return newNeighbor; + } + + @Override + public void log(String msg) { + if (gui != null) { + gui.addLogMsg(msg); + } else { + System.out.println(msg); + } + } + + + @Override + public void logTransactionSuccess(String msg) { + if (gui != null) { + gui.addTransactionLogMessageSuccess(msg); + } else { + System.out.println(msg); + } + } + + + @Override + public void logTransactionFail(String msg) { + if (gui != null) { + gui.addTransactionLogMessageFail(msg); + } else { + System.out.println(msg); + } + } + + @Override + public void send(String address, int amount) { + getSelf().tell(new ActionInvokeSentMoney(address, amount), getSelf()); + } + +} diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf new file mode 100644 index 0000000000000000000000000000000000000000..b2e7193860f00eee523b79ad7c3898eb69f328d1 --- /dev/null +++ b/src/main/resources/application.conf @@ -0,0 +1,17 @@ +akka { + + actor { + provider = "akka.remote.RemoteActorRefProvider" + warn-about-java-serializer-usage = false + } + + remote { + enabled-transports = ["akka.remote.netty.tcp"] + + netty.tcp { + hostname = "127.0.0.1" + port = 0 + } + } + +} \ No newline at end of file