diff --git a/.classpath b/.classpath
index b1c91767e..e4f57ce5d 100644
--- a/.classpath
+++ b/.classpath
@@ -3,11 +3,10 @@
-
-
-
+
+
diff --git a/build.xml b/build.xml
index b22a61dfb..e3d072c4c 100644
--- a/build.xml
+++ b/build.xml
@@ -5,7 +5,7 @@
-
+
@@ -18,6 +18,8 @@
+
+
@@ -41,8 +43,8 @@
-
-
+
+
@@ -90,6 +92,7 @@
-
-
-
-
-
-
-
+
+
@@ -332,9 +330,14 @@
-
+
+
+
+
+
+
@@ -391,7 +394,7 @@
windowtitle="las2peer Unit Test Documentation"
failonerror="yes"
encoding="utf8"
- classpath="${lib.cp}:${tmp.classes}"
+ classpath="${lib.cp}:${tmp.classes}:${lib.junit}"
>
@@ -443,21 +446,21 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/img/logo/README.md b/img/logo/README.md
new file mode 100644
index 000000000..52b473dbe
--- /dev/null
+++ b/img/logo/README.md
@@ -0,0 +1,35 @@
+# las2peer logos
+
+A collection of the las2peer logo
+
+## Standard logo
+![logo](https://rwth-acis.github.io/las2peer/logo/vector/las2peer-logo.svg)
+
+| File | Resolution
+| ------------- | ------------- |
+| [.svg](logo/vector/las2peer-logo.svg) | |
+| [.eps](logo/vector/las2peer-logo.eps) | |
+| [.pdf](logo/vector/las2peer-logo.pdf) | |
+| [.png](logo/bitmap/las2peer-logo-16x16.png) |16x16|
+| [.png](logo/bitmap/las2peer-logo-32x32.png) |32x32|
+| [.png](logo/bitmap/las2peer-logo-64x64.png) |64x64|
+| [.png](logo/bitmap/las2peer-logo-128x128.png) |128x128|
+
+
+## Logo with text
+
+![logo with text](https://rwth-acis.github.io/las2peer/logo/text/logo_text_black.svg)
+
+
+| File |
+| ------------- |
+| [Black text](logo/text/logo_text_black.svg) |
+
+ - White text
+
+![logo with text](https://rwth-acis.github.io/las2peer/logo/text/logo_text_white.svg)
+
+
+| File |
+| ------------- |
+| [White text](logo/text/logo_text_white.svg) |
diff --git a/img/logo/text/logo_text_black.svg b/img/logo/text/logo_text_black.svg
new file mode 100644
index 000000000..088bfcfcf
--- /dev/null
+++ b/img/logo/text/logo_text_black.svg
@@ -0,0 +1,411 @@
+
+
+
+
diff --git a/img/logo/text/logo_text_white.svg b/img/logo/text/logo_text_white.svg
new file mode 100644
index 000000000..6cea05d42
--- /dev/null
+++ b/img/logo/text/logo_text_white.svg
@@ -0,0 +1,411 @@
+
+
+
+
diff --git a/ivy/ivy.xml b/ivy/ivy.xml
index a9ce9b518..dacc11c94 100644
--- a/ivy/ivy.xml
+++ b/ivy/ivy.xml
@@ -1,15 +1,17 @@
-
+
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/ivy/pom_template.xml b/ivy/pom_template.xml
new file mode 100644
index 000000000..3c360994c
--- /dev/null
+++ b/ivy/pom_template.xml
@@ -0,0 +1,16 @@
+
+${ivy.pom.license}
+${ivy.pom.header}
+
+
+ 4.0.0
+ ${ivy.pom.groupId}
+ ${ivy.pom.artifactId}
+ ${ivy.pom.packaging}
+ ${ivy.pom.version}
+ ${ivy.pom.name}
+ ${ivy.pom.description}
+ ${ivy.pom.url}
+ ${ivy.now}
+
\ No newline at end of file
diff --git a/src/main/java/i5/las2peer/communication/Message.java b/src/main/java/i5/las2peer/communication/Message.java
index b4e24811f..c956fbf57 100644
--- a/src/main/java/i5/las2peer/communication/Message.java
+++ b/src/main/java/i5/las2peer/communication/Message.java
@@ -1,18 +1,5 @@
package i5.las2peer.communication;
-import java.io.Serializable;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Signature;
-import java.security.SignatureException;
-import java.util.Date;
-import java.util.Random;
-
-import javax.crypto.SecretKey;
-
-import org.apache.commons.codec.binary.Base64;
-
import i5.las2peer.p2p.AgentNotKnownException;
import i5.las2peer.persistency.EncodingFailedException;
import i5.las2peer.persistency.MalformedXMLException;
@@ -25,9 +12,28 @@
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
import i5.las2peer.tools.XmlTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Base64;
+import java.util.Date;
+import java.util.Random;
+
+import javax.crypto.SecretKey;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
import rice.p2p.commonapi.NodeHandle;
/**
@@ -40,7 +46,7 @@
*
* Therefore, it is necessary, that the generating Thread has access to the private key of the sending agent.
*
- * When specifiying a topic, the message will be sent to all agents listening to the topic. Since these agents are not
+ * When specifying a topic, the message will be sent to all agents listening to the topic. Since these agents are not
* known, the message will not be encrypted.
*
*/
@@ -133,8 +139,8 @@ public Message() {
* @throws SerializationException
*
*/
- public Message(Agent from, Agent to, Serializable data)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Agent from, Agent to, Serializable data) throws EncodingFailedException, L2pSecurityException,
+ SerializationException {
this(from, to, data, DEFAULT_TIMEOUT);
}
@@ -149,8 +155,8 @@ public Message(Agent from, Agent to, Serializable data)
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws SerializationException
*/
- public Message(Agent from, Agent to, Serializable data, long timeOutMs)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Agent from, Agent to, Serializable data, long timeOutMs) throws EncodingFailedException,
+ L2pSecurityException, SerializationException {
if (from == null || to == null) {
throw new IllegalArgumentException("null not allowed as sender or recipient!");
}
@@ -182,8 +188,8 @@ public Message(Agent from, Agent to, Serializable data, long timeOutMs)
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws SerializationException
*/
- public Message(Agent from, Agent to, XmlAble data)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Agent from, Agent to, XmlAble data) throws EncodingFailedException, L2pSecurityException,
+ SerializationException {
this(from, to, data, DEFAULT_TIMEOUT);
}
@@ -198,8 +204,8 @@ public Message(Agent from, Agent to, XmlAble data)
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws SerializationException
*/
- public Message(Agent from, Agent to, XmlAble data, long timeoutMs)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Agent from, Agent to, XmlAble data, long timeoutMs) throws EncodingFailedException,
+ L2pSecurityException, SerializationException {
sender = from;
senderId = from.getId();
recipient = to;
@@ -220,8 +226,8 @@ public Message(Agent from, Agent to, XmlAble data, long timeoutMs)
* @throws L2pSecurityException
* @throws SerializationException
*/
- public Message(Agent from, long topic, Serializable data)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Agent from, long topic, Serializable data) throws EncodingFailedException, L2pSecurityException,
+ SerializationException {
this(from, topic, data, DEFAULT_TIMEOUT);
}
@@ -236,8 +242,8 @@ public Message(Agent from, long topic, Serializable data)
* @throws L2pSecurityException
* @throws SerializationException
*/
- public Message(Agent from, long topic, Serializable data, long timeoutMs)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Agent from, long topic, Serializable data, long timeoutMs) throws EncodingFailedException,
+ L2pSecurityException, SerializationException {
if (from == null) {
throw new IllegalArgumentException("null not allowed as sender!");
}
@@ -287,8 +293,8 @@ private void finalizeConstructor() throws EncodingFailedException, L2pSecurityEx
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws SerializationException
*/
- public Message(Message responseTo, XmlAble data, long timeoutMs)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Message responseTo, XmlAble data, long timeoutMs) throws EncodingFailedException,
+ L2pSecurityException, SerializationException {
if (!responseTo.isOpen()) {
throw new IllegalStateException("the original message has to be open to create a response to it!");
}
@@ -318,8 +324,8 @@ public Message(Message responseTo, XmlAble data, long timeoutMs)
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws EncodingFailedException
*/
- public Message(Message responseTo, XmlAble data)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Message responseTo, XmlAble data) throws EncodingFailedException, L2pSecurityException,
+ SerializationException {
this(responseTo, data, DEFAULT_TIMEOUT);
}
@@ -333,8 +339,8 @@ public Message(Message responseTo, XmlAble data)
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws SerializationException
*/
- public Message(Message responseTo, Serializable data, long timeoutMs)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Message responseTo, Serializable data, long timeoutMs) throws EncodingFailedException,
+ L2pSecurityException, SerializationException {
if (!responseTo.isOpen()) {
throw new IllegalStateException("the original message has to be open to create a response to it!");
}
@@ -365,8 +371,8 @@ public Message(Message responseTo, Serializable data, long timeoutMs)
* @throws L2pSecurityException the private key of the sender is not accessible for signing
* @throws SerializationException
*/
- public Message(Message responseTo, Serializable data)
- throws EncodingFailedException, L2pSecurityException, SerializationException {
+ public Message(Message responseTo, Serializable data) throws EncodingFailedException, L2pSecurityException,
+ SerializationException {
this(responseTo, data, DEFAULT_TIMEOUT);
}
@@ -386,7 +392,7 @@ private String getContentString() throws SerializationException {
sContent = ((XmlAble) content).toXmlString();
} else {
typeAttr = "Serializable";
- sContent = Base64.encodeBase64String(SerializeTools.serialize((Serializable) content));
+ sContent = Base64.getEncoder().encodeToString(SerializeTools.serialize((Serializable) content));
}
String attrs = "";
@@ -557,8 +563,8 @@ public Object getContent() throws L2pSecurityException {
/**
* open the envelope, i.e. decrypt the content with the private key of the receiving agent
*
- * The storage has to know an unlocked version of the recipient agent! (i.e. a {@link i5.las2peer.security.AgentContext}
- * bound to him.
+ * The storage has to know an unlocked version of the recipient agent! (i.e. a
+ * {@link i5.las2peer.security.AgentContext} bound to him.
*
* @param storage
* @throws L2pSecurityException
@@ -580,8 +586,7 @@ public void open(AgentStorage storage) throws L2pSecurityException, AgentNotKnow
* @throws L2pSecurityException the private key of the receiver has to be unlocked for decryption
* @throws AgentNotKnownException
*/
- public void open(Agent unlockedRecipient, AgentStorage storage)
- throws L2pSecurityException, AgentNotKnownException {
+ public void open(Agent unlockedRecipient, AgentStorage storage) throws L2pSecurityException, AgentNotKnownException {
if (isOpen()) {
return;
}
@@ -600,19 +605,21 @@ public void open(Agent unlockedRecipient, AgentStorage storage)
}
}
- Element root = null;
try {
- String contentString;
+ byte[] rawContent;
if (!isTopic()) {
SecretKey contentKey = recipient.decryptSymmetricKey(baContentKey);
- contentString = new String(CryptoTools.decryptSymmetric(baEncryptedContent, contentKey),
- StandardCharsets.UTF_8);
+ rawContent = CryptoTools.decryptSymmetric(baEncryptedContent, contentKey);
} else { // topics are not encrypted
- contentString = new String(baEncryptedContent, StandardCharsets.UTF_8);
+ rawContent = baEncryptedContent;
}
- root = Parser.parse(contentString, false);
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(new ByteArrayInputStream(rawContent));
+ doc.getDocumentElement().normalize();
+ Element root = doc.getDocumentElement();
if (!root.hasAttribute("sender")) {
throw new L2pSecurityException("content block needs sender attribute!");
@@ -656,19 +663,17 @@ public void open(Agent unlockedRecipient, AgentStorage storage)
}
if (root.getAttribute("type").equals("Serializable")) {
- content = SerializeTools.deserialize(Base64.decodeBase64(root.getFirstChild().getText()));
+ content = SerializeTools.deserializeBase64(root.getTextContent());
} else {
content = XmlTools.createFromXml(root.getFirstChild().toString(), root.getAttribute("class"));
}
} catch (CryptoException e) {
throw new L2pSecurityException("Crypto-Problems: Unable to open message content", e);
- } catch (XMLSyntaxException e) {
- throw new L2pSecurityException("xml syntax problems with decryption!", e);
} catch (SerializationException e) {
throw new L2pSecurityException("deserializiation problems with decryption!", e);
} catch (ClassNotFoundException e) {
throw new L2pSecurityException("content class missing with decryption!", e);
- } catch (MalformedXMLException e) {
+ } catch (MalformedXMLException | ParserConfigurationException | SAXException | IOException e) {
throw new L2pSecurityException("xml syntax problems with decryption!", e);
}
@@ -691,6 +696,11 @@ public void verifySignature() throws L2pSecurityException {
sig.update(contentBytes);
if (!sig.verify(baSignature)) {
+ System.out.println("---------------------");
+ System.out.println("Signature invalid. Please report the output text to LAS-353.");
+ System.out.println("--------------------- [BEGIN] ---------------------");
+ System.out.println(this.toXmlString()); // TODO LAS-353 logging; remove when resolved
+ System.out.println("--------------------- [END] ---------------------");
throw new L2pSecurityException("Signature invalid!");
}
} catch (InvalidKeyException e) {
@@ -785,16 +795,17 @@ public String toXmlString() {
receiver = "to=\"" + recipientId + "\"";
encryption = " encryption=\"" + CryptoTools.getSymmetricAlgorithm() + "\"";
contentKey = "\t" + Base64.encodeBase64String(baContentKey) + "\n";
+ + "\" encoding=\"base64\">" + Base64.getEncoder().encodeToString(baContentKey) + "\n";
} else {
receiver = "topic=\"" + topicId + "\"";
}
return "\n" + sending + "\t" + Base64.encodeBase64String(baEncryptedContent) + "\n"
- + contentKey + "\t"
- + Base64.encodeBase64String(baSignature) + "\n" + "\n";
+ + encryption + " encoding=\"base64\">" + Base64.getEncoder().encodeToString(baEncryptedContent)
+ + "\n" + contentKey + "\t" + Base64.getEncoder().encodeToString(baSignature)
+ + "\n" + "\n";
}
/**
@@ -805,38 +816,19 @@ public String toXmlString() {
*/
public void setStateFromXml(String xml) throws MalformedXMLException {
try {
- Element root = Parser.parse(xml);
+ Element root = XmlTools.getRootElement(xml, "las2peer:message");
- Element sending = null;
- if (root.getChildren("sendingNode").hasMoreElements()) {
- sending = root.getChildren("sendingNode").nextElement();
+ Element sending = XmlTools.getOptionalElement(root, "sendingNode");
+ if (sending != null) {
if (!"base64".equals(sending.getAttribute("encoding"))) {
throw new MalformedXMLException("base64 encoding of sending node expected!");
}
- sendingNodeId = SerializeTools.deserializeBase64(sending.getFirstChild().getText());
+ sendingNodeId = SerializeTools.deserializeBase64(sending.getTextContent());
}
- if (!root.getName().equals("message")) {
- throw new MalformedXMLException("message expected!");
- }
- Element content;
- if (root.getChildren("content").hasMoreElements()) {
- content = root.getChildren("content").nextElement();
- } else {
- throw new MalformedXMLException("content expected!");
- }
-
- Element contentKey = null;
- if (root.getChildren("contentKey").hasMoreElements()) {
- contentKey = root.getChildren("contentKey").nextElement();
- }
-
- Element signature;
- if (root.getChildren("signature").hasMoreElements()) {
- signature = root.getChildren("signature").nextElement();
- } else {
- throw new MalformedXMLException("signature expected!");
- }
+ Element content = XmlTools.getSingularElement(root, "content");
+ Element contentKey = XmlTools.getOptionalElement(root, "contentKey");
+ Element signature = XmlTools.getSingularElement(root, "signature");
if (!root.hasAttribute("from")) {
throw new MalformedXMLException("needed from attribute missing!");
@@ -877,10 +869,10 @@ public void setStateFromXml(String xml) throws MalformedXMLException {
// sender = AgentStorage.getAgent( Long.parseLong(root.getAttribute ( "from")));
// recipient = AgentStorage.getAgent( Long.parseLong(root.getAttribute ( "to")));
- baEncryptedContent = Base64.decodeBase64(content.getFirstChild().getText());
- baSignature = Base64.decodeBase64(signature.getFirstChild().getText());
+ baEncryptedContent = Base64.getDecoder().decode(content.getTextContent());
+ baSignature = Base64.getDecoder().decode(signature.getTextContent());
if (contentKey != null) {
- baContentKey = Base64.decodeBase64(contentKey.getFirstChild().getText());
+ baContentKey = Base64.getDecoder().decode(contentKey.getTextContent());
}
timestampMs = Long.parseLong(root.getAttribute("generated"));
@@ -890,12 +882,8 @@ public void setStateFromXml(String xml) throws MalformedXMLException {
if (root.hasAttribute("responseTo")) {
responseToId = Long.parseLong(root.getAttribute("responseTo"));
}
-
- content = null;
} catch (NumberFormatException e) {
throw new MalformedXMLException("to or from attribute is not a long!", e);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Xml parsing problems", e);
} catch (SerializationException e) {
throw new MalformedXMLException("deserialization problems (sending node id)", e);
}
diff --git a/src/main/java/i5/las2peer/p2p/LocalNode.java b/src/main/java/i5/las2peer/p2p/LocalNode.java
index 7db2ecf6f..37354ec5d 100644
--- a/src/main/java/i5/las2peer/p2p/LocalNode.java
+++ b/src/main/java/i5/las2peer/p2p/LocalNode.java
@@ -97,9 +97,28 @@ public void registerReceiver(MessageReceiver receiver)
throws AgentAlreadyRegisteredException, L2pSecurityException, AgentException {
super.registerReceiver(receiver);
+ if (receiver instanceof Agent) {
+ Agent agent = (Agent) receiver;
+ try {
+ htKnownAgents.put(((Agent) receiver).getId(), agent.toXmlString());
+ } catch (SerializationException e) {
+ throw new AgentException("Could not register agent reciever", e);
+ }
+ }
+
deliverPendingMessages(receiver.getResponsibleForAgentId(), getNodeId());
}
+ // TODO this code should be here or not?
+// @Override
+// public void unregisterReceiver(MessageReceiver receiver) throws AgentNotKnownException, NodeException {
+// super.unregisterReceiver(receiver);
+// if (receiver instanceof Agent) {
+// Agent agent = (Agent) receiver;
+// htKnownAgents.remove(agent.getId());
+// }
+// }
+
@Override
public void sendMessage(Message message, MessageResultListener listener, SendMode mode) {
message.setSendingNodeId(this.getNodeId());
@@ -210,8 +229,9 @@ public Object[] findRegisteredAgent(long agentId, int hintOfExpectedCount) throw
@Override
public Agent getAgent(long id) throws AgentNotKnownException {
- if (locallyKnownAgents.hasAgent(id)) {
- return locallyKnownAgents.getAgent(id);
+ Agent anonymous = getAnonymous();
+ if (id == anonymous.getId()) { // TODO use isAnonymous, special ID or Classing for identification
+ return anonymous;
} else {
synchronized (htKnownAgents) {
String xml = htKnownAgents.get(id);
@@ -220,9 +240,7 @@ public Agent getAgent(long id) throws AgentNotKnownException {
}
try {
- Agent result = Agent.createFromXml(xml);
- locallyKnownAgents.registerAgent(result);
- return result;
+ return Agent.createFromXml(xml);
} catch (MalformedXMLException e) {
throw new AgentNotKnownException("XML problems with storage!", e);
}
@@ -249,8 +267,6 @@ public void storeAgent(Agent agent) throws L2pSecurityException, AgentException
throw new AgentException("Serialization failed!", e);
}
- locallyKnownAgents.registerAgent(agent);
-
htKnownAgents.put(agent.getId(), agentXml);
if (agent instanceof UserAgent) {
@@ -288,7 +304,6 @@ public void updateAgent(Agent agent) throws AgentException, L2pSecurityException
throw new AgentException("Serialization failed!", e);
}
- locallyKnownAgents.registerAgent(agent);
htKnownAgents.put(agent.getId(), agentXml);
if (agent instanceof UserAgent) {
diff --git a/src/main/java/i5/las2peer/p2p/Node.java b/src/main/java/i5/las2peer/p2p/Node.java
index 39c4c40bf..3e9af3871 100644
--- a/src/main/java/i5/las2peer/p2p/Node.java
+++ b/src/main/java/i5/las2peer/p2p/Node.java
@@ -50,7 +50,6 @@
import i5.las2peer.security.AgentContext;
import i5.las2peer.security.AgentException;
import i5.las2peer.security.AgentStorage;
-import i5.las2peer.security.BasicAgentStorage;
import i5.las2peer.security.GroupAgent;
import i5.las2peer.security.L2pSecurityException;
import i5.las2peer.security.Mediator;
@@ -158,7 +157,6 @@ public enum NodeStatus {
private String sInformationFileName = DEFAULT_INFORMATION_FILE;
private KeyPair nodeKeyPair;
- protected BasicAgentStorage locallyKnownAgents;
/**
* maps names and emails to UserAgents
@@ -226,8 +224,6 @@ public Node(L2pClassManager baseClassLoader, boolean standardObserver, boolean m
nodeKeyPair = CryptoTools.generateKeyPair();
nodeServiceCache = new NodeServiceCache(this, nodeServiceCacheLifetime, nodeServiceCacheResultCount);
- locallyKnownAgents = new BasicAgentStorage(this);
- locallyKnownAgents.registerAgent(getAnonymous());
userManager = new UserAgentManager(this);
aliasManager = new ServiceAliasManager(this);
@@ -581,16 +577,6 @@ public void registerReceiver(MessageReceiver receiver)
throw new L2pSecurityException("An agent has to be unlocked for registering at a node");
}
- if (!knowsAgentLocally(agent.getId())) {
- try {
- storeAgent(agent);
- } catch (AgentAlreadyRegisteredException e) {
- System.out.println(
- "Just for notice - not an error: tried to store an already known agent before registering");
- // nothing to do
- }
- }
-
try {
// ensure (unlocked) context
getAgentContext((Agent) receiver);
@@ -1018,16 +1004,6 @@ public boolean hasAgent(long id) {
}
}
- /**
- * Checks, if an agent of the given id is known locally.
- *
- * @param agentId
- * @return true, if this agent is (already) known here at this node
- */
- public boolean knowsAgentLocally(long agentId) {
- return locallyKnownAgents.hasAgent(agentId);
- }
-
/**
* Gets a local registered agent by its id.
*
diff --git a/src/main/java/i5/las2peer/p2p/NodeInformation.java b/src/main/java/i5/las2peer/p2p/NodeInformation.java
index d1fd04cd4..cd1f5b0aa 100644
--- a/src/main/java/i5/las2peer/p2p/NodeInformation.java
+++ b/src/main/java/i5/las2peer/p2p/NodeInformation.java
@@ -3,9 +3,12 @@
import java.io.IOException;
import java.io.Serializable;
import java.security.PublicKey;
-import java.util.Enumeration;
import java.util.Vector;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
import i5.las2peer.persistency.MalformedXMLException;
import i5.las2peer.persistency.VerificationFailedException;
import i5.las2peer.persistency.XmlAble;
@@ -15,9 +18,7 @@
import i5.las2peer.tools.FileContentReader;
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+import i5.las2peer.tools.XmlTools;
/**
* A NodeInformation gives basic information about a node.
@@ -267,10 +268,8 @@ public String toString() {
* @return the node information contained in the given XML file
* @throws MalformedXMLException
* @throws IOException
- * @throws XMLSyntaxException
*/
- public static NodeInformation createFromXmlFile(String filename)
- throws MalformedXMLException, IOException, XMLSyntaxException {
+ public static NodeInformation createFromXmlFile(String filename) throws MalformedXMLException, IOException {
return createFromXml(FileContentReader.read(filename));
}
@@ -282,12 +281,11 @@ public static NodeInformation createFromXmlFile(String filename)
* @return a node information
*
*
- * @throws XMLSyntaxException
* @throws MalformedXMLException
* @throws IOException
*/
public static NodeInformation createFromXmlFile(String filename, ServiceAgent[] serviceAgents)
- throws XMLSyntaxException, MalformedXMLException, IOException {
+ throws MalformedXMLException, IOException {
NodeInformation result = createFromXmlFile(filename);
result.setServices(serviceAgents);
@@ -300,50 +298,56 @@ public static NodeInformation createFromXmlFile(String filename, ServiceAgent[]
* @param xml
* @return node information contained in the given XML string
* @throws MalformedXMLException
- * @throws XMLSyntaxException
*/
- public static NodeInformation createFromXml(String xml) throws MalformedXMLException, XMLSyntaxException {
- Element root = Parser.parse(xml, false);
- if (!root.getName().equals("las2peerNode")) {
- throw new MalformedXMLException("not a node information but a " + root.getName());
- }
+ public static NodeInformation createFromXml(String xml) throws MalformedXMLException {
+ Element root = XmlTools.getRootElement(xml, "las2peerNode");
NodeInformation result = new NodeInformation();
try {
- Enumeration children = root.getChildren();
- while (children.hasMoreElements()) {
- Element child = children.nextElement();
-
- if (child.getName().equals("adminName")) {
- result.adminName = child.getFirstChild().getText();
- } else if (child.getName().equals("adminEmail")) {
- result.adminEmail = child.getFirstChild().getText();
- } else if (child.getName().equals("organization")) {
- result.organization = child.getFirstChild().getText();
- } else if (child.getName().equals("description")) {
- result.description = child.getFirstChild().getText();
- } else if (child.getName().equals("nodeHandle")) {
- result.nodeHandle = SerializeTools.deserializeBase64(child.getChild(1).getFirstChild().getText());
- } else if (child.getName().equals("nodeKey")) {
- result.nodeKey = (PublicKey) SerializeTools.deserializeBase64(child.getFirstChild().getText());
- } else if (child.getName().equals("signature")) {
- result.signature = (byte[]) SerializeTools.deserializeBase64(child.getFirstChild().getText());
- } else if (child.getName().equals("services")) {
+ NodeList children = root.getChildNodes();
+ for (int c = 0; c < children.getLength(); c++) {
+ Node node = children.item(c);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ // XXX logging
+ continue;
+ }
+ Element child = (Element) node;
+
+ if (child.getTagName().equals("adminName")) {
+ result.adminName = child.getTextContent();
+ } else if (child.getTagName().equals("adminEmail")) {
+ result.adminEmail = child.getTextContent();
+ } else if (child.getTagName().equals("organization")) {
+ result.organization = child.getTextContent();
+ } else if (child.getTagName().equals("description")) {
+ result.description = child.getTextContent();
+ } else if (child.getTagName().equals("nodeHandle")) {
+ Element serializedNodeHandle = XmlTools.getSingularElement(child, "serialized");
+ result.nodeHandle = SerializeTools.deserializeBase64(serializedNodeHandle.getTextContent());
+ } else if (child.getTagName().equals("nodeKey")) {
+ result.nodeKey = (PublicKey) SerializeTools.deserializeBase64(child.getTextContent());
+ } else if (child.getTagName().equals("signature")) {
+ result.signature = (byte[]) SerializeTools.deserializeBase64(child.getTextContent());
+ } else if (child.getTagName().equals("services")) {
Vector serviceClasses = new Vector();
-
- Enumeration services = child.getChildren();
- while (services.hasMoreElements()) {
- Element service = services.nextElement();
- if (!service.getName().equals("serviceClass")) {
+ NodeList services = child.getChildNodes();
+ for (int s = 0; s < services.getLength(); s++) {
+ Node serviceNode = services.item(s);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ // XXX logging
+ continue;
+ }
+ Element service = (Element) serviceNode;
+ if (!service.getTagName().equals("serviceClass")) {
throw new MalformedXMLException(service + " is not a service class element");
}
- serviceClasses.add(service.getFirstChild().getText());
+ serviceClasses.add(service.getTextContent());
}
result.hostedServices = serviceClasses.toArray(new ServiceNameVersion[0]);
} else {
- throw new MalformedXMLException("unknown xml element: " + child.getName());
+ throw new MalformedXMLException("unknown xml element: " + child.getTagName());
}
}
diff --git a/src/main/java/i5/las2peer/p2p/NodeServiceCache.java b/src/main/java/i5/las2peer/p2p/NodeServiceCache.java
index 02146751e..d14e0c17c 100644
--- a/src/main/java/i5/las2peer/p2p/NodeServiceCache.java
+++ b/src/main/java/i5/las2peer/p2p/NodeServiceCache.java
@@ -295,10 +295,12 @@ private boolean update(ServiceNameVersion service, boolean exact, Agent acting)
try {
res.open(acting, runningAt);
} catch (Exception e) {
+ // XXX logging
continue;
}
if (!(res.getContent() instanceof ServiceDiscoveryContent)) {
+ // XXX logging
continue;
}
diff --git a/src/main/java/i5/las2peer/p2p/PastryNodeImpl.java b/src/main/java/i5/las2peer/p2p/PastryNodeImpl.java
index dc9fee173..f2e299873 100644
--- a/src/main/java/i5/las2peer/p2p/PastryNodeImpl.java
+++ b/src/main/java/i5/las2peer/p2p/PastryNodeImpl.java
@@ -18,6 +18,7 @@
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.logging.Level;
import i5.las2peer.api.StorageCollisionHandler;
import i5.las2peer.api.StorageEnvelopeHandler;
@@ -28,6 +29,7 @@
import i5.las2peer.classLoaders.L2pClassManager;
import i5.las2peer.communication.Message;
import i5.las2peer.communication.MessageException;
+import i5.las2peer.logging.L2pLogger;
import i5.las2peer.logging.NodeObserver.Event;
import i5.las2peer.p2p.pastry.MessageEnvelope;
import i5.las2peer.p2p.pastry.NodeApplication;
@@ -60,6 +62,8 @@
*/
public class PastryNodeImpl extends Node {
+ private static final L2pLogger logger = L2pLogger.getInstance(PastryNodeImpl.class);
+
private static final int AGENT_GET_TIMEOUT = 10000;
private static final int AGENT_STORE_TIMEOUT = 10000;
private static final int ARTIFACT_GET_TIMEOUT = 10000;
@@ -122,15 +126,24 @@ public PastryNodeImpl(L2pClassManager classLoader, boolean useMonitoringObserver
* be random.
*/
public PastryNodeImpl(String bootstrap, STORAGE_MODE storageMode, String storageDir, Long nodeIdSeed) {
- super(null, true, false);
+ this(null, null, bootstrap, storageMode, storageDir, nodeIdSeed);
+ }
+
+ public PastryNodeImpl(L2pClassManager classManager, Integer port, String bootstrap, STORAGE_MODE storageMode,
+ String storageDir, Long nodeIdSeed) {
+ super(classManager, true, false);
pastryBindAddress = InetAddress.getLoopbackAddress();
- // use system defined port
- try {
- ServerSocket tmpSocket = new ServerSocket(0);
- tmpSocket.close();
- pastryPort = tmpSocket.getLocalPort();
- } catch (IOException e) {
- throw new RuntimeException(e);
+ if (port == null) {
+ // use system defined port
+ try {
+ ServerSocket tmpSocket = new ServerSocket(0);
+ tmpSocket.close();
+ pastryPort = tmpSocket.getLocalPort();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ pastryPort = port;
}
this.bootStrap = bootstrap;
this.mode = storageMode;
@@ -155,7 +168,7 @@ private void setupPastryEnvironment() {
break;
}
} catch (Exception e) {
- // XXX logging
+ logger.log(Level.FINER, "Exception while checking for config file '" + filename + "'", e);
}
}
Hashtable properties = new Hashtable<>();
@@ -188,6 +201,9 @@ private void setupPastryEnvironment() {
if (pastryBindAddress != null && pastryBindAddress.isLoopbackAddress()) {
properties.put("allow_loopback_address", "1");
}
+ if (!properties.containsKey("p2p_past_messageTimeout")) {
+ properties.put("p2p_past_messageTimeout", "120000");
+ }
if (!properties.containsKey("pastry_socket_known_network_address")) {
if (!properties.containsKey("pastry_socket_known_network_address_port")) {
properties.put("pastry_socket_known_network_address_port", "80");
@@ -198,8 +214,7 @@ private void setupPastryEnvironment() {
}
for (String prop : properties.keySet()) {
pastryEnvironment.getParameters().setString(prop, properties.get(prop));
- // XXX logging
- System.out.println("setting: " + prop + ": '" + properties.get(prop) + "'");
+ logger.info("setting: " + prop + ": '" + properties.get(prop) + "'");
}
}
@@ -458,9 +473,11 @@ public void sendMessage(Message message, Object atNodeId, MessageResultListener
try {
application.sendMessage(new MessageEnvelope(pastryNode.getLocalHandle(), message), (NodeHandle) atNodeId);
} catch (MalformedXMLException e) {
+ logger.log(Level.SEVERE, "Can't read message XML", e);
observerNotice(Event.MESSAGE_FAILED, pastryNode, message.getSenderId(), atNodeId, message.getRecipientId(),
"XML exception!");
} catch (MessageException e) {
+ logger.log(Level.SEVERE, "Could not send message", e);
observerNotice(Event.MESSAGE_FAILED, pastryNode, message.getSenderId(), atNodeId, message.getRecipientId(),
"Message exception!");
}
@@ -519,20 +536,26 @@ public NodeApplication getApplication() {
@Override
public Agent getAgent(long id) throws AgentNotKnownException {
- if (locallyKnownAgents.hasAgent(id)) {
- return locallyKnownAgents.getAgent(id);
- } else {
- observerNotice(Event.AGENT_GET_STARTED, pastryNode, id, null, (Long) null, "");
- try {
+ // no caching here, because agents may have changed in the network
+ observerNotice(Event.AGENT_GET_STARTED, pastryNode, id, null, (Long) null, "");
+ try {
+ Agent agentFromNet = null;
+ Agent anonymous = getAnonymous();
+ if (id == anonymous.getId()) { // TODO use isAnonymous, special ID or Classing for identification
+ agentFromNet = anonymous;
+ } else {
Envelope agentEnvelope = pastStorage.fetchEnvelope(Envelope.getAgentIdentifier(id), AGENT_GET_TIMEOUT);
- Agent agentFromNet = Agent.createFromXml((String) agentEnvelope.getContent());
- observerNotice(Event.AGENT_GET_SUCCESS, pastryNode, id, null, (Long) null, "");
- locallyKnownAgents.registerAgent(agentFromNet);
- return agentFromNet;
- } catch (Exception e) {
- observerNotice(Event.AGENT_GET_FAILED, pastryNode, id, null, (Long) null, "");
- throw new AgentNotKnownException("Unable to retrieve Agent " + id + " from past storage", e);
+ agentFromNet = Agent.createFromXml((String) agentEnvelope.getContent());
}
+ observerNotice(Event.AGENT_GET_SUCCESS, pastryNode, id, null, (Long) null, "");
+ return agentFromNet;
+ } catch (Exception e) {
+ // TODO bad exception handling
+ // actually ArtifactNotFoundException is the only one that should cause an AgentNotKnownException here
+ // maybe the interface should be changed to throw an AgentException instead
+ logger.log(Level.WARNING, "Unable to retrieve Agent " + id + " from past storage", e);
+ observerNotice(Event.AGENT_GET_FAILED, pastryNode, id, null, (Long) null, "");
+ throw new AgentNotKnownException("Unable to retrieve Agent " + id + " from past storage", e);
}
}
@@ -542,17 +565,8 @@ public void storeAgent(Agent agent) throws L2pSecurityException, AgentException
throw new L2pSecurityException("You have to unlock the agent before storage!");
// because the agent has to sign itself
}
- if (locallyKnownAgents.hasAgent(agent.getId())) {
- throw new AgentAlreadyRegisteredException("This agent is already known locally!");
- }
+ // TODO check if anonymous should be stored and deny
observerNotice(Event.AGENT_UPLOAD_STARTED, pastryNode, agent, "");
- try {
- Agent stored = getAgent(agent.getId());
- observerNotice(Event.AGENT_UPLOAD_FAILED, pastryNode, agent, "Agent already known!");
- throw new AgentAlreadyRegisteredException("I already know stored version: " + stored);
- } catch (AgentNotKnownException e) {
- }
- locallyKnownAgents.registerAgent(agent);
try {
Envelope agentEnvelope = null;
try {
@@ -569,7 +583,6 @@ public void storeAgent(Agent agent) throws L2pSecurityException, AgentException
}
observerNotice(Event.AGENT_UPLOAD_SUCCESS, pastryNode, agent, "");
} catch (CryptoException | SerializationException | StorageException e) {
- locallyKnownAgents.unregisterAgent(agent);
observerNotice(Event.AGENT_UPLOAD_FAILED, pastryNode, agent, "Got interrupted!");
throw new AgentException("Storage has been interrupted", e);
}
diff --git a/src/main/java/i5/las2peer/persistency/Envelope.java b/src/main/java/i5/las2peer/persistency/Envelope.java
index f883b86db..561d45582 100644
--- a/src/main/java/i5/las2peer/persistency/Envelope.java
+++ b/src/main/java/i5/las2peer/persistency/Envelope.java
@@ -4,7 +4,6 @@
import java.security.PublicKey;
import java.util.Base64;
import java.util.Collection;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
@@ -13,6 +12,10 @@
import javax.crypto.SecretKey;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
import i5.las2peer.execution.L2pThread;
import i5.las2peer.logging.L2pLogger;
import i5.las2peer.p2p.AgentNotKnownException;
@@ -25,9 +28,7 @@
import i5.las2peer.tools.CryptoTools;
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+import i5.las2peer.tools.XmlTools;
public class Envelope implements Serializable, XmlAble {
@@ -318,81 +319,78 @@ public String toXmlString() throws SerializationException {
/**
* factory for generating an envelope from the given XML String representation
*
- * @param root
+ * @param rootElement
* @return envelope created from the given XML String serialization
* @throws MalformedXMLException
*/
- public static Envelope createFromXml(Element root) throws MalformedXMLException {
- try {
- if (!root.getName().equals("envelope")) {
- throw new MalformedXMLException("not an envelope");
- }
- if (!root.hasAttribute("identifier")) {
- throw new MalformedXMLException("identifier attribute expected!");
- }
- if (!root.hasAttribute("version")) {
- throw new MalformedXMLException("version attribute expected!");
- }
- String identifier = root.getAttribute("identifier");
- long version = Long.parseLong(root.getAttribute("version"));
- Element content = root.getFirstChild();
- if (!content.getName().equals("content")) {
- throw new MalformedXMLException("envelope content expected");
- }
- if (!content.getAttribute("encoding").equals("Base64")) {
- throw new MalformedXMLException("base 64 encoding of the content expected");
- }
- byte[] rawContent = Base64.getDecoder().decode(content.getFirstChild().getText());
- Element keys = root.getChild(1);
- if (!keys.getName().equals("keys")) {
- throw new MalformedXMLException("not an envelope");
+ public static Envelope createFromXml(Element rootElement) throws MalformedXMLException {
+ if (!rootElement.hasAttribute("identifier")) {
+ throw new MalformedXMLException("identifier attribute expected!");
+ }
+ String identifier = rootElement.getAttribute("identifier");
+ if (!rootElement.hasAttribute("version")) {
+ throw new MalformedXMLException("version attribute expected!");
+ }
+ long version = Long.parseLong(rootElement.getAttribute("version"));
+ // read content from XML
+ Element content = XmlTools.getSingularElement(rootElement, "las2peer:content");
+ if (!content.getAttribute("encoding").equals("Base64")) {
+ throw new MalformedXMLException("base 64 encoding of the content expected");
+ }
+ byte[] rawContent = Base64.getDecoder().decode(content.getTextContent());
+ // read reader keys from XML
+ Element keys = XmlTools.getSingularElement(rootElement, "las2peer:keys");
+ if (!keys.getAttribute("encoding").equalsIgnoreCase("base64")) {
+ throw new MalformedXMLException(
+ "base 64 encoding of the content expected - got: " + keys.getAttribute("encoding"));
+ }
+ if (!keys.getAttribute("encryption").equalsIgnoreCase(CryptoTools.getAsymmetricAlgorithm())) {
+ throw new MalformedXMLException(
+ CryptoTools.getAsymmetricAlgorithm() + " encryption of the content expected");
+ }
+ HashMap readerKeys = new HashMap<>();
+ NodeList enKeys = keys.getChildNodes();
+ for (int n = 0; n < enKeys.getLength(); n++) {
+ Node node = enKeys.item(n);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ // XXX logging
+ continue;
}
- if (!keys.getAttribute("encoding").equals("base64")) {
- throw new MalformedXMLException(
- "base 64 encoding of the content expected - got: " + keys.getAttribute("encoding"));
+ Element key = (Element) node;
+ if (!key.getNodeName().equals("las2peer:key")) {
+ throw new MalformedXMLException("key expected");
}
- if (!keys.getAttribute("encryption").equals(CryptoTools.getAsymmetricAlgorithm())) {
- throw new MalformedXMLException(
- CryptoTools.getAsymmetricAlgorithm() + " encryption of the content expected");
+ String strPublicKey = key.getAttribute("public");
+ try {
+ PublicKey publicKey = CryptoTools.stringToPublicKey(strPublicKey);
+ byte[] encryptedReaderKey = Base64.getDecoder().decode(key.getFirstChild().getTextContent());
+ readerKeys.put(publicKey, encryptedReaderKey);
+ } catch (CryptoException e) {
+ throw new MalformedXMLException("Could not convert string to public key", e);
}
- // reader keys
- HashMap readerKeys = new HashMap<>();
- for (Enumeration enKeys = keys.getChildren(); enKeys.hasMoreElements();) {
- Element key = enKeys.nextElement();
- if (!key.getName().equals("key")) {
- throw new MalformedXMLException("key expected");
- }
- String strPublicKey = key.getAttribute("public");
- try {
- PublicKey publicKey = CryptoTools.stringToPublicKey(strPublicKey);
- byte[] encryptedReaderKey = Base64.getDecoder().decode(key.getFirstChild().getText());
- readerKeys.put(publicKey, encryptedReaderKey);
- } catch (CryptoException e) {
- throw new MalformedXMLException("Could not convert string to public key", e);
- }
+ }
+ // groups
+ Element groups = XmlTools.getSingularElement(rootElement, "las2peer:groups");
+ HashSet readerGroupIds = new HashSet<>();
+ NodeList enGroups = groups.getChildNodes();
+ for (int n = 0; n < enGroups.getLength(); n++) {
+ Node node = enKeys.item(n);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ // XXX logging
+ continue;
}
- // groups
- Element groups = root.getChild(2);
- if (!groups.getName().equals("groups")) {
- throw new MalformedXMLException("groups tag expected");
+ Element group = (Element) node;
+ if (!group.getNodeName().equals("las2peer:group")) {
+ throw new MalformedXMLException("group expected");
}
- HashSet readerGroupIds = new HashSet<>();
- for (Enumeration enGroups = groups.getChildren(); enGroups.hasMoreElements();) {
- Element group = enGroups.nextElement();
- if (!group.getName().equals("group")) {
- throw new MalformedXMLException("group expected");
- }
- if (!group.hasAttribute("id")) {
- throw new MalformedXMLException("group id expected");
- }
- long groupId = Long.valueOf(group.getAttribute("id"));
- readerGroupIds.add(groupId);
+ if (!group.hasAttribute("id")) {
+ throw new MalformedXMLException("group id expected");
}
- return new Envelope(identifier, version, readerKeys, readerGroupIds, rawContent);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("problems with parsing the XML document", e);
+ long groupId = Long.valueOf(group.getAttribute("id"));
+ readerGroupIds.add(groupId);
}
+ return new Envelope(identifier, version, readerKeys, readerGroupIds, rawContent);
}
/**
@@ -403,11 +401,7 @@ public static Envelope createFromXml(Element root) throws MalformedXMLException
* @throws MalformedXMLException
*/
public static Envelope createFromXml(String xml) throws MalformedXMLException {
- try {
- return createFromXml(Parser.parse(xml, false));
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("problems with parsing the xml document", e);
- }
+ return createFromXml(XmlTools.getRootElement(xml, "las2peer:envelope"));
}
}
diff --git a/src/main/java/i5/las2peer/security/Agent.java b/src/main/java/i5/las2peer/security/Agent.java
index b258d6151..3499890a8 100644
--- a/src/main/java/i5/las2peer/security/Agent.java
+++ b/src/main/java/i5/las2peer/security/Agent.java
@@ -1,15 +1,17 @@
package i5.las2peer.security;
+import java.io.File;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
+import java.util.Base64;
import javax.crypto.SecretKey;
-import org.apache.commons.codec.binary.Base64;
+import org.w3c.dom.Element;
import i5.las2peer.communication.Message;
import i5.las2peer.communication.MessageException;
@@ -21,9 +23,7 @@
import i5.las2peer.tools.CryptoTools;
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+import i5.las2peer.tools.XmlTools;
/**
* An Agent is the basic acting entity in the las2peer network. At the moment, an agent can represent a simple user, a
@@ -225,7 +225,7 @@ public byte[] signContent(byte[] plainData) throws CryptoException, L2pSecurityE
* @return encoded version or the private key
*/
protected String getEncodedPrivate() {
- return Base64.encodeBase64String(baEncrypedPrivate);
+ return Base64.getEncoder().encodeToString(baEncrypedPrivate);
}
/**
@@ -289,6 +289,20 @@ public Node getRunningAtNode() {
return runningAt;
}
+ /**
+ * Factory: Create an agent from its XML file representation.
+ *
+ * Depending on the type attribute of the root node, the type will be a {@link UserAgent}, {@link GroupAgent},
+ * {@link ServiceAgent}. Creation of {@link MonitoringAgent}s is not supported.
+ *
+ * @param xmlFile
+ * @return an agent
+ * @throws MalformedXMLException
+ */
+ public static Agent createFromXml(File xmlFile) throws MalformedXMLException {
+ return createFromXml(XmlTools.getRootElement(xmlFile, "las2peer:agent"));
+ }
+
/**
* Factory: Create an agent from its XML string representation.
*
@@ -300,11 +314,7 @@ public Node getRunningAtNode() {
* @throws MalformedXMLException
*/
public static Agent createFromXml(String xml) throws MalformedXMLException {
- try {
- return createFromXml(Parser.parse(xml, false));
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
- }
+ return createFromXml(XmlTools.getRootElement(xml, "las2peer:agent"));
}
/**
@@ -313,32 +323,22 @@ public static Agent createFromXml(String xml) throws MalformedXMLException {
* Depending on the type attribute of the root node, the type will be a {@link UserAgent}, {@link GroupAgent},
* {@link ServiceAgent}. Creation of {@link MonitoringAgent}s is not supported.
*
- * @param root
+ * @param rootElement
* @return an agent
* @throws MalformedXMLException
*/
- public static Agent createFromXml(Element root) throws MalformedXMLException {
- try {
- if (!root.getName().equals("agent")) {
- throw new MalformedXMLException("this is not an agent but a " + root.getName());
- }
-
- String type = root.getAttribute("type");
-
- if ("user".equals(type)) {
- return UserAgent.createFromXml(root);
- } else if ("group".equals(type)) {
- return GroupAgent.createFromXml(root);
- } else if ("service".equals(type)) {
- return ServiceAgent.createFromXml(root);
- } else if ("monitoring".equals(type)) {
- return MonitoringAgent.createFromXml(root);
- } else {
- throw new MalformedXMLException("Unknown agent type: " + type);
- }
-
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
+ public static Agent createFromXml(Element rootElement) throws MalformedXMLException {
+ String type = rootElement.getAttribute("type");
+ if ("user".equalsIgnoreCase(type)) {
+ return UserAgent.createFromXml(rootElement);
+ } else if ("group".equalsIgnoreCase(type)) {
+ return GroupAgent.createFromXml(rootElement);
+ } else if ("service".equalsIgnoreCase(type)) {
+ return ServiceAgent.createFromXml(rootElement);
+ } else if ("monitoring".equalsIgnoreCase(type)) {
+ return MonitoringAgent.createFromXml(rootElement);
+ } else {
+ throw new MalformedXMLException("Unknown agent type: " + type);
}
}
diff --git a/src/main/java/i5/las2peer/security/GroupAgent.java b/src/main/java/i5/las2peer/security/GroupAgent.java
index 0b57f2628..959682ef2 100755
--- a/src/main/java/i5/las2peer/security/GroupAgent.java
+++ b/src/main/java/i5/las2peer/security/GroupAgent.java
@@ -1,5 +1,19 @@
package i5.las2peer.security;
+import java.io.Serializable;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Random;
+
+import javax.crypto.SecretKey;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
import i5.las2peer.communication.Message;
import i5.las2peer.communication.MessageException;
import i5.las2peer.logging.L2pLogger;
@@ -12,22 +26,7 @@
import i5.las2peer.tools.CryptoTools;
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
-
-import java.io.Serializable;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Random;
-
-import javax.crypto.SecretKey;
-
-import org.apache.commons.codec.binary.Base64;
+import i5.las2peer.tools.XmlTools;
/**
* An agent representing a group of other agents.
@@ -71,13 +70,14 @@ protected GroupAgent(long id, PublicKey pubKey, byte[] encryptedPrivate, Hashtab
* @throws CryptoException
* @throws SerializationException
*/
- protected GroupAgent(long id, KeyPair keys, SecretKey secret, Agent[] members) throws L2pSecurityException,
- CryptoException, SerializationException {
+ protected GroupAgent(long id, KeyPair keys, SecretKey secret, Agent[] members)
+ throws L2pSecurityException, CryptoException, SerializationException {
super(id, keys, secret);
symmetricGroupKey = secret;
- for (Agent a : members)
+ for (Agent a : members) {
addMember(a, false);
+ }
lockPrivateKey();
}
@@ -105,8 +105,8 @@ public void unlockPrivateKey(Agent agent) throws L2pSecurityException, Serializa
* @throws SerializationException
* @throws CryptoException
*/
- public void unlockPrivateKeyRecursive(Agent agent, AgentStorage agentStorage) throws L2pSecurityException,
- SerializationException, CryptoException {
+ public void unlockPrivateKeyRecursive(Agent agent, AgentStorage agentStorage)
+ throws L2pSecurityException, SerializationException, CryptoException {
if (isMember(agent)) {
unlockPrivateKey(agent);
return;
@@ -138,8 +138,9 @@ public void unlockPrivateKeyRecursive(Agent agent, AgentStorage agentStorage) th
private void decryptSecretKey(Agent agent) throws SerializationException, CryptoException, L2pSecurityException {
byte[] crypted = htEncryptedKeyVersions.get(agent.getId());
- if (crypted == null)
+ if (crypted == null) {
throw new L2pSecurityException("the given agent is not listed as a group member!");
+ }
symmetricGroupKey = agent.decryptSymmetricKey(crypted);
}
@@ -166,10 +167,11 @@ public void addMember(Agent a) throws L2pSecurityException, CryptoException, Ser
* @throws SerializationException
* @throws CryptoException
*/
- private final void addMember(Agent a, boolean securityCheck) throws L2pSecurityException, CryptoException,
- SerializationException {
- if (securityCheck && isLocked())
+ private final void addMember(Agent a, boolean securityCheck)
+ throws L2pSecurityException, CryptoException, SerializationException {
+ if (securityCheck && isLocked()) {
throw new L2pSecurityException("you have to unlock this group first!");
+ }
byte[] cryptedSecret = CryptoTools.encryptAsymmetric(symmetricGroupKey, a.getPublicKey());
htEncryptedKeyVersions.put(a.getId(), cryptedSecret);
@@ -331,15 +333,17 @@ public void removeMemberRecursive(Agent a) throws L2pSecurityException {
* @throws L2pSecurityException
*/
public void removeMember(long id) throws L2pSecurityException {
- if (isLocked())
+ if (isLocked()) {
throw new L2pSecurityException("You have to unlock this agent first!");
+ }
htEncryptedKeyVersions.remove(id);
}
public void removeMemberRecursive(long id) throws L2pSecurityException {
- if (isLocked())
+ if (isLocked()) {
throw new L2pSecurityException("You have to unlock this agent first!");
+ }
htEncryptedKeyVersions.remove(id);
for (Long memberId : htEncryptedKeyVersions.keySet()) {
@@ -369,7 +373,7 @@ public String toXmlString() {
for (Long id : htEncryptedKeyVersions.keySet()) {
keyList += "\t\t"
- + Base64.encodeBase64String(htEncryptedKeyVersions.get(id)) + "\n";
+ + Base64.getEncoder().encodeToString(htEncryptedKeyVersions.get(id)) + "\n";
}
StringBuffer result = new StringBuffer("\n" + "\t" + getId() + "\n"
@@ -395,29 +399,18 @@ public String toXmlString() {
}
/**
- * factory - create an instance of GroupAgent from its xml representation
+ * factory - create an instance of GroupAgent from its XML representation
*
* @param xml
* @return a group agent
* @throws MalformedXMLException
*/
public static GroupAgent createFromXml(String xml) throws MalformedXMLException {
- try {
- Element root = Parser.parse(xml, false);
-
- if (!"group".equals(root.getAttribute("type")))
- throw new MalformedXMLException("group agent expeced");
- if (!"agent".equals(root.getName()))
- throw new MalformedXMLException("agent expected");
-
- return createFromXml(root);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
- }
+ return createFromXml(XmlTools.getRootElement(xml, "las2peer:agent"));
}
/**
- * factory - create an instance of GroupAgent based on a xml node
+ * factory - create an instance of GroupAgent based on a XML node
*
* @param root
* @return a group agent
@@ -425,97 +418,65 @@ public static GroupAgent createFromXml(String xml) throws MalformedXMLException
*/
public static GroupAgent createFromXml(Element root) throws MalformedXMLException {
try {
- Element elId = null;
- Element pubKey = null;
- Element privKey = null;
- Element encryptedKeys = null;
- Element groupname = null;
- Element userdata = null;
-
- Enumeration children = root.getChildren();
- while (children.hasMoreElements()) {
- Element next = children.nextElement();
- String name = next.getName();
- if (name.equals("id")) {
- elId = next;
- } else if (name.equals("publickey")) {
- pubKey = next;
- } else if (name.equals("privatekey")) {
- privKey = next;
- } else if (name.equals("unlockKeys")) {
- encryptedKeys = next;
- } else if (name.equals("groupname")) {
- groupname = next;
- } else if (name.equals("userdata")) {
- userdata = next;
- }
- }
-
- if (elId == null) {
- throw new MalformedXMLException("element id expected");
- }
-
- if (pubKey == null) {
- throw new MalformedXMLException("public key expected");
- }
+ // read id field from XML
+ Element elId = XmlTools.getSingularElement(root, "id");
+ long id = Long.parseLong(elId.getTextContent());
+ // read public key from XML
+ Element pubKey = XmlTools.getSingularElement(root, "publickey");
if (!pubKey.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
-
- if (privKey == null) {
- throw new MalformedXMLException("private key expected");
- }
+ PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getTextContent());
+ // read private key from XML
+ Element privKey = XmlTools.getSingularElement(root, "privatekey");
if (!privKey.getAttribute("encrypted").equals(CryptoTools.getSymmetricAlgorithm())) {
throw new MalformedXMLException(CryptoTools.getSymmetricAlgorithm() + " expected");
}
-
- if (encryptedKeys == null) {
- throw new MalformedXMLException("unlockKeys expected");
- }
+ byte[] encPrivate = Base64.getDecoder().decode(privKey.getTextContent());
+ // read member keys from XML
+ Element encryptedKeys = XmlTools.getSingularElement(root, "unlockKeys");
if (!encryptedKeys.getAttribute("method").equals(CryptoTools.getAsymmetricAlgorithm())) {
throw new MalformedXMLException("base64 encoding expected");
}
-
- long id = Long.parseLong(elId.getFirstChild().getText());
- PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getFirstChild().getText());
- byte[] encPrivate = Base64.decodeBase64(privKey.getFirstChild().getText());
-
Hashtable htMemberKeys = new Hashtable();
- for (Enumeration enKeys = encryptedKeys.getChildren(); enKeys.hasMoreElements();) {
- Element elKey = enKeys.nextElement();
-
- if (!elKey.getName().equals("keyentry"))
- throw new MalformedXMLException("unlockKeys expected");
- if (!elKey.hasAttribute("forAgent"))
+ NodeList enGroups = encryptedKeys.getElementsByTagName("keyentry");
+ for (int n = 0; n < enGroups.getLength(); n++) {
+ org.w3c.dom.Node node = enGroups.item(n);
+ short nodeType = node.getNodeType();
+ if (nodeType != org.w3c.dom.Node.ELEMENT_NODE) {
+ throw new MalformedXMLException(
+ "Node type (" + nodeType + ") is not type element (" + org.w3c.dom.Node.ELEMENT_NODE + ")");
+ }
+ Element elKey = (Element) node;
+ if (!elKey.hasAttribute("forAgent")) {
throw new MalformedXMLException("forAgent attribute expected");
- if (!elKey.getAttribute("encoding").equals("base64"))
+ }
+ if (!elKey.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
+ }
long agentId = Long.parseLong(elKey.getAttribute("forAgent"));
- byte[] content = Base64.decodeBase64(elKey.getFirstChild().getText());
+ byte[] content = Base64.getDecoder().decode(elKey.getTextContent());
htMemberKeys.put(agentId, content);
}
-
GroupAgent result = new GroupAgent(id, publicKey, encPrivate, htMemberKeys);
- // attach optional fields
+ // read and set optional fields
+ Element groupname = XmlTools.getOptionalElement(root, "groupname");
if (groupname != null) {
- result.name = groupname.getFirstChild().getText();
+ result.name = groupname.getTextContent();
}
+ Element userdata = XmlTools.getOptionalElement(root, "userdata");
if (userdata != null) {
- String base64UserData = userdata.getFirstChild().getText();
- result.userData = SerializeTools.deserializeBase64(base64UserData);
+ result.userData = SerializeTools.deserializeBase64(userdata.getTextContent());
}
return result;
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
} catch (SerializationException e) {
throw new MalformedXMLException("Deserialization problems", e);
} catch (L2pSecurityException e) {
throw new MalformedXMLException("Security Problems creating an agent from the xml string", e);
}
-
}
/**
@@ -527,8 +488,8 @@ public static GroupAgent createFromXml(Element root) throws MalformedXMLExceptio
* @throws CryptoException
* @throws SerializationException
*/
- public static GroupAgent createGroupAgent(Agent[] members) throws L2pSecurityException, CryptoException,
- SerializationException {
+ public static GroupAgent createGroupAgent(Agent[] members)
+ throws L2pSecurityException, CryptoException, SerializationException {
Random r = new Random();
return new GroupAgent(r.nextLong(), CryptoTools.generateKeyPair(), CryptoTools.generateSymmetricKey(), members);
}
@@ -568,8 +529,8 @@ public void receiveMessage(Message message, AgentContext context) throws Message
L2pLogger.logEvent(Event.SERVICE_ERROR, e1.getMessage());
}
if (member == null) {
- L2pLogger.logEvent(Event.SERVICE_ERROR, "No agent for group member " + memberId
- + " found! Skipping member.");
+ L2pLogger.logEvent(Event.SERVICE_ERROR,
+ "No agent for group member " + memberId + " found! Skipping member.");
continue;
}
try {
diff --git a/src/main/java/i5/las2peer/security/MonitoringAgent.java b/src/main/java/i5/las2peer/security/MonitoringAgent.java
index 1af9be5a5..0d0e611ec 100644
--- a/src/main/java/i5/las2peer/security/MonitoringAgent.java
+++ b/src/main/java/i5/las2peer/security/MonitoringAgent.java
@@ -3,9 +3,10 @@
import java.io.Serializable;
import java.security.KeyPair;
import java.security.PublicKey;
+import java.util.Base64;
import java.util.Random;
-import org.apache.commons.codec.binary.Base64;
+import org.w3c.dom.Element;
import i5.las2peer.communication.Message;
import i5.las2peer.communication.MessageException;
@@ -18,9 +19,7 @@
import i5.las2peer.tools.CryptoTools;
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+import i5.las2peer.tools.XmlTools;
/**
*
@@ -145,7 +144,7 @@ public String toXmlString() {
+ "\n" + "\t" + SerializeTools.serializeToBase64(getPublicKey())
+ "\n" + "\t\n"
- + "\t\t" + Base64.encodeBase64String(getSalt()) + "\n"
+ + "\t\t" + Base64.getEncoder().encodeToString(getSalt()) + "\n"
+ "\t\t" + getEncodedPrivate() + "\n" + "\t\n");
result.append("\n");
@@ -169,79 +168,53 @@ public String toXmlString() {
*
*/
public static MonitoringAgent createFromXml(String xml) throws MalformedXMLException {
- try {
- Element root = Parser.parse(xml, false);
- if (!"monitoring".equals(root.getAttribute("type"))) {
- throw new MalformedXMLException("Monitoring agent expected");
- }
- if (!"agent".equals(root.getName())) {
- throw new MalformedXMLException("Agent expeced");
- }
- return createFromXml(root);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
- }
+ return createFromXml(XmlTools.getRootElement(xml, "las2peer:agent"));
}
/**
*
* Sets the state of the object from a string representation resulting from a previous {@link #toXmlString} call.
*
- * @param root parsed XML document
+ * @param rootElement parsed XML document
* @return
* @exception MalformedXMLException
*
*/
- public static MonitoringAgent createFromXml(Element root) throws MalformedXMLException {
+ public static MonitoringAgent createFromXml(Element rootElement) throws MalformedXMLException {
try {
- Element elId = root.getFirstChild();
- long id = Long.parseLong(elId.getFirstChild().getText());
-
- Element pubKey = root.getChild(1);
- if (!pubKey.getName().equals("publickey")) {
- throw new MalformedXMLException("public key expected");
- }
+ // read id from XML
+ Element elId = XmlTools.getSingularElement(rootElement, "id");
+ long id = Long.parseLong(elId.getTextContent());
+ // read public key from XML
+ Element pubKey = XmlTools.getSingularElement(rootElement, "publickey");
if (!pubKey.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
-
- PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getFirstChild().getText());
-
- Element privKey = root.getChild(2);
- if (!privKey.getName().equals("privatekey")) {
- throw new MalformedXMLException("private key expected");
- }
+ PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getTextContent());
+ // read private key from XML
+ Element privKey = XmlTools.getSingularElement(rootElement, "privatekey");
if (!privKey.getAttribute("encrypted").equals(CryptoTools.getSymmetricAlgorithm())) {
throw new MalformedXMLException(CryptoTools.getSymmetricAlgorithm() + " expected");
}
if (!privKey.getAttribute("keygen").equals(CryptoTools.getSymmetricKeygenMethod())) {
throw new MalformedXMLException(CryptoTools.getSymmetricKeygenMethod() + " expected");
}
-
- Element elSalt = privKey.getFirstChild();
- if (!elSalt.getName().equals("salt")) {
- throw new MalformedXMLException("salt expected");
- }
+ // read salt from XML
+ Element elSalt = XmlTools.getSingularElement(rootElement, "salt");
if (!elSalt.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
-
- byte[] salt = Base64.decodeBase64(elSalt.getFirstChild().getText());
-
- Element data = privKey.getChild(1);
- if (!data.getName().equals("data")) {
- throw new MalformedXMLException("data expected");
- }
+ byte[] salt = Base64.getDecoder().decode(elSalt.getTextContent());
+ // read data from XML
+ Element data = XmlTools.getSingularElement(rootElement, "data");
if (!data.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
- byte[] encPrivate = Base64.decodeBase64(data.getFirstChild().getText());
+ byte[] encPrivate = Base64.getDecoder().decode(data.getTextContent());
MonitoringAgent result = new MonitoringAgent(id, publicKey, encPrivate, salt);
return result;
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing XML string", e);
} catch (SerializationException e) {
throw new MalformedXMLException("Deserialization problems", e);
}
diff --git a/src/main/java/i5/las2peer/security/ServiceAgent.java b/src/main/java/i5/las2peer/security/ServiceAgent.java
index 3ea3dd5e9..185530112 100644
--- a/src/main/java/i5/las2peer/security/ServiceAgent.java
+++ b/src/main/java/i5/las2peer/security/ServiceAgent.java
@@ -6,9 +6,10 @@
import java.lang.reflect.Method;
import java.security.KeyPair;
import java.security.PublicKey;
+import java.util.Base64;
import java.util.Random;
-import org.apache.commons.codec.binary.Base64;
+import org.w3c.dom.Element;
import i5.las2peer.api.Service;
import i5.las2peer.classLoaders.ClassLoaderException;
@@ -38,9 +39,7 @@
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
import i5.las2peer.tools.SimpleTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+import i5.las2peer.tools.XmlTools;
/**
* A service agent represents a service and its access rights in the las2peer setting.
@@ -105,9 +104,9 @@ public String toXmlString() {
+ "\t" + getId() + "\n" + "\t"
+ SerializeTools.serializeToBase64(getPublicKey()) + "\n" + "\t\n" + "\t\t" + Base64.encodeBase64String(getSalt()) + "\n"
- + "\t\t" + getEncodedPrivate() + "\n" + "\t\n"
- + "\n";
+ + "\">\n" + "\t\t" + Base64.getEncoder().encodeToString(getSalt())
+ + "\n" + "\t\t" + getEncodedPrivate() + "\n"
+ + "\t\n" + "\n";
} catch (SerializationException e) {
throw new RuntimeException("Serialization problems with keys");
}
@@ -315,82 +314,55 @@ public static ServiceAgent createServiceAgent(String serviceName, String passphr
* @throws MalformedXMLException
*/
public static ServiceAgent createFromXml(String xml) throws MalformedXMLException {
- try {
- Element root = Parser.parse(xml, false);
-
- if (!"service".equals(root.getAttribute("type"))) {
- throw new MalformedXMLException("service agent expeced");
- }
- if (!"agent".equals(root.getName())) {
- throw new MalformedXMLException("agent expected");
- }
-
- return createFromXml(root);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
- }
+ return createFromXml(XmlTools.getRootElement(xml, "las2peer:agent"));
}
/**
* factory: create a service agent from the given xml representation
*
- * @param root
+ * @param rootElement
* @return a service agent
* @throws MalformedXMLException
*/
- public static ServiceAgent createFromXml(Element root) throws MalformedXMLException {
+ public static ServiceAgent createFromXml(Element rootElement) throws MalformedXMLException {
try {
- Element elId = root.getFirstChild();
- if (!root.hasAttribute("serviceclass")) {
+ // read service class from XML
+ if (!rootElement.hasAttribute("serviceclass")) {
throw new MalformedXMLException("serviceclass attribute expected!");
}
- ServiceNameVersion service = ServiceNameVersion.fromString(root.getAttribute("serviceclass"));
-
- long id = Long.parseLong(elId.getFirstChild().getText());
-
- Element pubKey = root.getChild(1);
- if (!pubKey.getName().equals("publickey")) {
- throw new MalformedXMLException("public key expected");
- }
+ ServiceNameVersion service = ServiceNameVersion.fromString(rootElement.getAttribute("serviceclass"));
+ // read id from XML
+ Element elId = XmlTools.getSingularElement(rootElement, "id");
+ long id = Long.parseLong(elId.getTextContent());
+ // read public key from XML
+ Element pubKey = XmlTools.getSingularElement(rootElement, "publickey");
if (!pubKey.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
-
- PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getFirstChild().getText());
-
- Element privKey = root.getChild(2);
- if (!privKey.getName().equals("privatekey")) {
- throw new MalformedXMLException("private key expected");
- }
+ PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getTextContent());
+ // read private key from XML
+ Element privKey = XmlTools.getSingularElement(rootElement, "privatekey");
if (!privKey.getAttribute("encrypted").equals(CryptoTools.getSymmetricAlgorithm())) {
throw new MalformedXMLException(CryptoTools.getSymmetricAlgorithm() + " expected");
}
if (!privKey.getAttribute("keygen").equals(CryptoTools.getSymmetricKeygenMethod())) {
throw new MalformedXMLException(CryptoTools.getSymmetricKeygenMethod() + " expected");
}
-
- Element elSalt = privKey.getFirstChild();
- if (!elSalt.getName().equals("salt")) {
- throw new MalformedXMLException("salt expected");
- }
+ // read salt from XML
+ Element elSalt = XmlTools.getSingularElement(rootElement, "salt");
if (!elSalt.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
- byte[] salt = Base64.decodeBase64(elSalt.getFirstChild().getText());
-
- Element data = privKey.getChild(1);
- if (!data.getName().equals("data")) {
- throw new MalformedXMLException("data expected");
- }
+ byte[] salt = Base64.getDecoder().decode(elSalt.getTextContent());
+ // read data from XML
+ Element data = XmlTools.getSingularElement(rootElement, "data");
if (!data.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
- byte[] encPrivate = Base64.decodeBase64(data.getFirstChild().getText());
+ byte[] encPrivate = Base64.getDecoder().decode(data.getTextContent());
return new ServiceAgent(id, service, publicKey, encPrivate, salt);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
} catch (SerializationException e) {
throw new MalformedXMLException("Deserialization problems", e);
}
diff --git a/src/main/java/i5/las2peer/security/UserAgent.java b/src/main/java/i5/las2peer/security/UserAgent.java
index c4e5916e4..0cf22b5b5 100644
--- a/src/main/java/i5/las2peer/security/UserAgent.java
+++ b/src/main/java/i5/las2peer/security/UserAgent.java
@@ -3,10 +3,11 @@
import java.io.Serializable;
import java.security.KeyPair;
import java.security.PublicKey;
+import java.util.Base64;
import java.util.Random;
import java.util.regex.Pattern;
-import org.apache.commons.codec.binary.Base64;
+import org.w3c.dom.Element;
import i5.las2peer.communication.Message;
import i5.las2peer.communication.MessageException;
@@ -19,9 +20,7 @@
import i5.las2peer.tools.CryptoTools;
import i5.las2peer.tools.SerializationException;
import i5.las2peer.tools.SerializeTools;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
+import i5.las2peer.tools.XmlTools;
/**
* An UserAgent represent a (End)user of the las2peer system.
@@ -151,7 +150,7 @@ public String toXmlString() {
+ "\t" + SerializeTools.serializeToBase64(getPublicKey())
+ "\n" + "\t\n"
- + "\t\t" + Base64.encodeBase64String(getSalt()) + "\n"
+ + "\t\t" + Base64.getEncoder().encodeToString(getSalt()) + "\n"
+ "\t\t" + getEncodedPrivate() + "\n" + "\t\n");
if (sLoginName != null) {
@@ -161,7 +160,8 @@ public String toXmlString() {
result.append("\t" + sEmail + "\n");
}
if (userData != null) {
- result.append("\t" + SerializeTools.serializeToBase64(userData) + "\n");
+ result.append("\t" + SerializeTools.serializeToBase64(userData)
+ + "\n");
}
result.append("\n");
@@ -186,20 +186,7 @@ public String toXmlString() {
*
*/
public static UserAgent createFromXml(String xml) throws MalformedXMLException {
- try {
- Element root = Parser.parse(xml, false);
-
- if (!"user".equals(root.getAttribute("type"))) {
- throw new MalformedXMLException("user agent expected");
- }
-
- if (!"agent".equals(root.getName())) {
- throw new MalformedXMLException("agent expected");
- }
- return createFromXml(root);
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
- }
+ return createFromXml(XmlTools.getRootElement(xml, "las2peer:agent"));
}
/**
@@ -237,7 +224,7 @@ public static UserAgent createUserAgent(long id, String passphrase) throws Crypt
/**
* Sets the state of the object from a string representation resulting from a previous {@link #toXmlString} call.
*
- * @param root parsed xml document
+ * @param root parsed XML document
* @return
*
* @exception MalformedXMLException
@@ -245,77 +232,58 @@ public static UserAgent createUserAgent(long id, String passphrase) throws Crypt
*/
public static UserAgent createFromXml(Element root) throws MalformedXMLException {
try {
- Element elId = root.getFirstChild();
- long id = Long.parseLong(elId.getFirstChild().getText());
-
- Element pubKey = root.getChild(1);
- if (!pubKey.getName().equals("publickey")) {
- throw new MalformedXMLException("public key expected");
- }
+ // read id field from XML
+ Element elId = XmlTools.getSingularElement(root, "id");
+ long id = Long.parseLong(elId.getTextContent());
+ // read public key from XML
+ Element pubKey = XmlTools.getSingularElement(root, "publickey");
if (!pubKey.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
-
- PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getFirstChild().getText());
-
- Element privKey = root.getChild(2);
- if (!privKey.getName().equals("privatekey")) {
- throw new MalformedXMLException("private key expected");
- }
+ PublicKey publicKey = (PublicKey) SerializeTools.deserializeBase64(pubKey.getTextContent());
+ // read private key from XML
+ Element privKey = XmlTools.getSingularElement(root, "privatekey");
if (!privKey.getAttribute("encrypted").equals(CryptoTools.getSymmetricAlgorithm())) {
throw new MalformedXMLException(CryptoTools.getSymmetricAlgorithm() + " expected");
}
if (!privKey.getAttribute("keygen").equals(CryptoTools.getSymmetricKeygenMethod())) {
throw new MalformedXMLException(CryptoTools.getSymmetricKeygenMethod() + " expected");
}
-
- Element elSalt = privKey.getFirstChild();
- if (!elSalt.getName().equals("salt")) {
- throw new MalformedXMLException("salt expected");
- }
+ Element dataPrivate = XmlTools.getSingularElement(privKey, "data");
+ byte[] encPrivate = Base64.getDecoder().decode(dataPrivate.getTextContent());
+ // read salt from XML
+ Element elSalt = XmlTools.getSingularElement(root, "salt");
if (!elSalt.getAttribute("encoding").equals("base64")) {
throw new MalformedXMLException("base64 encoding expected");
}
+ byte[] salt = Base64.getDecoder().decode(elSalt.getTextContent());
- byte[] salt = Base64.decodeBase64(elSalt.getFirstChild().getText());
-
- Element data = privKey.getChild(1);
- if (!data.getName().equals("data")) {
- throw new MalformedXMLException("data expected");
- }
- if (!data.getAttribute("encoding").equals("base64")) {
- throw new MalformedXMLException("base64 encoding expected");
- }
- byte[] encPrivate = Base64.decodeBase64(data.getFirstChild().getText());
-
+ // required fields complete, create result
UserAgent result = new UserAgent(id, publicKey, encPrivate, salt);
- int cnt = 3;
- Element login = root.getChild(cnt);
- if (login != null && login.getName().equals("login")) {
- result.sLoginName = login.getFirstChild().getText();
- cnt++;
- }
+ // read and set optional fields
- Element email = root.getChild(cnt);
+ // optional login name
+ Element login = XmlTools.getOptionalElement(root, "login");
+ if (login != null) {
+ result.sLoginName = login.getTextContent();
+ }
+ // optional email address
+ Element email = XmlTools.getOptionalElement(root, "email");
if (email != null) {
- if (!email.getName().equals("email")) {
- throw new MalformedXMLException("email or login element expected!");
- }
- result.sEmail = email.getFirstChild().getText();
- cnt++;
+ result.sEmail = email.getTextContent();
}
-
- Element xmlUserData = root.getChild(cnt);
- if (xmlUserData != null && xmlUserData.getName().equals("userdata")) {
- String base64UserData = xmlUserData.getFirstChild().getText();
- result.userData = SerializeTools.deserializeBase64(base64UserData);
- cnt++;
+ // optional user data
+ Element userdata = XmlTools.getOptionalElement(root, "userdata");
+ if (userdata != null) {
+ if (userdata.hasAttribute("encoding")
+ && !userdata.getAttribute("encoding").equalsIgnoreCase("base64")) {
+ throw new MalformedXMLException("base64 encoding expected");
+ }
+ result.userData = SerializeTools.deserializeBase64(userdata.getTextContent());
}
return result;
- } catch (XMLSyntaxException e) {
- throw new MalformedXMLException("Error parsing xml string", e);
} catch (SerializationException e) {
throw new MalformedXMLException("Deserialization problems", e);
}
diff --git a/src/main/java/i5/las2peer/testing/TestSuite.java b/src/main/java/i5/las2peer/testing/TestSuite.java
index 2192f0541..703345945 100644
--- a/src/main/java/i5/las2peer/testing/TestSuite.java
+++ b/src/main/java/i5/las2peer/testing/TestSuite.java
@@ -62,9 +62,9 @@ public static ArrayList launchNetwork(int numOfNodes, STORAGE_MO
System.out.println("bootstrap node launched with id " + bootstrapNode.getNodeId());
// add more nodes
for (int num = 1; num <= numOfNodes - 1; num++) {
- PastryNodeImpl node2 = addNode(bootstrapPort, storageMode, (long) num);
- result.add(node2);
- System.out.println("network node launched with id " + bootstrapNode.getNodeId());
+ PastryNodeImpl node = addNode(bootstrapPort, storageMode, (long) num);
+ result.add(node);
+ System.out.println("network node launched with id " + node.getNodeId());
}
return result;
}
diff --git a/src/main/java/i5/las2peer/tools/CommandPrompt.java b/src/main/java/i5/las2peer/tools/CommandPrompt.java
index ee0341800..12c60c4fb 100644
--- a/src/main/java/i5/las2peer/tools/CommandPrompt.java
+++ b/src/main/java/i5/las2peer/tools/CommandPrompt.java
@@ -600,6 +600,9 @@ else if (split.length > 2) {
} else if (split[0].equals("?") || split[0].equals("help")) {
printHelp();
return ReturnStatus.OK_PROCEED;
+ } else if (split[0].equals("v") || split[0].equals("version")) {
+ printVersion();
+ return ReturnStatus.OK_PROCEED;
}
return ReturnStatus.NOT_KNOWN_PROCEED;
@@ -697,6 +700,8 @@ public void printHelp() {
+ "\thelp / ?\tprint this message\n\n"
+ + "\tversion / ?\tv returns the las2peer version running on this node.\n\n"
+
+ "\tp(rint) [var1] [var2] ...\n" + "\t\t\tprint the contents of the given local variables\n\n"
+ "\tpackage\t[some.package.name]\n\n"
@@ -723,6 +728,15 @@ public void printHelp() {
+ "Lines statring with // or # will be ignored\n\n");
}
+ /**
+ * Prints the las2peer version.
+ */
+ public void printVersion() {
+ Package p = L2pNodeLauncher.class.getPackage();
+ String version = p.getImplementationVersion();
+ System.out.println("las2peer version \"" + version + "\"");
+ }
+
/**
* print a simple prompt and wait for input
*
diff --git a/src/main/java/i5/las2peer/tools/L2pNodeLauncher.java b/src/main/java/i5/las2peer/tools/L2pNodeLauncher.java
index 720149c28..730f08212 100644
--- a/src/main/java/i5/las2peer/tools/L2pNodeLauncher.java
+++ b/src/main/java/i5/las2peer/tools/L2pNodeLauncher.java
@@ -1,5 +1,24 @@
package i5.las2peer.tools;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
import i5.las2peer.api.Connector;
import i5.las2peer.api.ConnectorException;
import i5.las2peer.api.exceptions.ArtifactNotFoundException;
@@ -19,7 +38,6 @@
import i5.las2peer.p2p.ServiceNameVersion;
import i5.las2peer.p2p.TimeoutException;
import i5.las2peer.persistency.EncodingFailedException;
-import i5.las2peer.persistency.Envelope;
import i5.las2peer.persistency.MalformedXMLException;
import i5.las2peer.persistency.SharedStorage.STORAGE_MODE;
import i5.las2peer.security.Agent;
@@ -30,27 +48,6 @@
import i5.las2peer.security.PassphraseAgent;
import i5.las2peer.security.ServiceAgent;
import i5.las2peer.security.UserAgent;
-import i5.simpleXML.Element;
-import i5.simpleXML.Parser;
-import i5.simpleXML.XMLSyntaxException;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
import rice.p2p.commonapi.NodeHandle;
/**
@@ -99,8 +96,8 @@ public PastryNodeImpl getNode() {
* @throws NumberFormatException
* @throws SerializationException
*/
- public String getEnvelope(String id) throws NumberFormatException, ArtifactNotFoundException, StorageException,
- SerializationException {
+ public String getEnvelope(String id)
+ throws NumberFormatException, ArtifactNotFoundException, StorageException, SerializationException {
return node.fetchEnvelope(id).toXmlString();
}
@@ -204,48 +201,32 @@ public boolean accept(File dir, String name) {
}
})) {
try {
- Element xmlRoot = Parser.parse(xmlFile, false);
- if (xmlRoot.getName().equalsIgnoreCase(Agent.class.getSimpleName())) {
- Agent agent = Agent.createFromXml(xmlRoot);
- agentIdToXml.put(agent.getId(), xmlFile.getName());
- if (agent instanceof PassphraseAgent) {
- String passphrase = htPassphrases.get(xmlFile.getName());
- if (passphrase != null) {
- ((PassphraseAgent) agent).unlockPrivateKey(passphrase);
- } else {
- printWarning("\t- got no passphrase for agent from " + xmlFile.getName());
- }
- node.storeAgent(agent);
- printMessage("\t- stored agent from " + xmlFile);
- } else if (agent instanceof GroupAgent) {
- GroupAgent ga = (GroupAgent) agent;
- groupAgents.add(ga);
+ // maybe an agent?
+ Agent agent = Agent.createFromXml(xmlFile);
+ agentIdToXml.put(agent.getId(), xmlFile.getName());
+ if (agent instanceof PassphraseAgent) {
+ String passphrase = htPassphrases.get(xmlFile.getName());
+ if (passphrase != null) {
+ ((PassphraseAgent) agent).unlockPrivateKey(passphrase);
} else {
- throw new IllegalArgumentException("Unknown agent type: " + agent.getClass());
+ printWarning("\t- got no passphrase for agent from " + xmlFile.getName());
}
- } else if (xmlRoot.getName().equalsIgnoreCase(Envelope.class.getSimpleName())) {
- Envelope e = Envelope.createFromXml(xmlRoot);
- // TODO fix upload Envelope from startup directory
- node.storeArtifact(e);
- printMessage("\t- stored artifact from " + xmlFile);
+ node.storeAgent(agent);
+ printMessage("\t- stored agent from " + xmlFile);
+ } else if (agent instanceof GroupAgent) {
+ GroupAgent ga = (GroupAgent) agent;
+ groupAgents.add(ga);
} else {
- printWarning("Ingoring unknown XML object (" + xmlRoot.getName() + ") in '" + xmlFile.toString()
- + "'!");
+ throw new IllegalArgumentException("Unknown agent type: " + agent.getClass());
}
- } catch (XMLSyntaxException e1) {
- printError("Unable to parse XML contents of '" + xmlFile.toString() + "'!");
} catch (MalformedXMLException e) {
printError("unable to deserialize contents of " + xmlFile.toString() + "!");
- } catch (IOException e) {
- printError("problems reading the contents of " + xmlFile.toString() + ": " + e);
} catch (L2pSecurityException e) {
printError("error storing agent from " + xmlFile.toString() + ": " + e);
} catch (AgentAlreadyRegisteredException e) {
printError("agent from " + xmlFile.toString() + " already known at this node!");
} catch (AgentException e) {
printError("unable to generate agent " + xmlFile.toString() + "!");
- } catch (StorageException e) {
- printError("unable to store contents of " + xmlFile.toString() + "!");
}
}
// wait till all user agents are added from startup directory to unlock group agents
@@ -388,8 +369,8 @@ public void stopConnector(String connectorClass) {
* @throws InstantiationException
* @throws IllegalAccessException
*/
- private Connector loadConnector(String classname) throws ClassNotFoundException, InstantiationException,
- IllegalAccessException {
+ private Connector loadConnector(String classname)
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class> connectorClass = L2pNodeLauncher.class.getClassLoader().loadClass(classname);
Connector connector = (Connector) connectorClass.newInstance();
return connector;
@@ -433,8 +414,8 @@ public boolean registerUserAgent(String id, String passphrase) {
* @throws AgentAlreadyRegisteredException
* @throws AgentException
*/
- public void registerUserAgent(UserAgent agent) throws L2pSecurityException, AgentAlreadyRegisteredException,
- AgentException {
+ public void registerUserAgent(UserAgent agent)
+ throws L2pSecurityException, AgentAlreadyRegisteredException, AgentException {
registerUserAgent(agent, null);
}
@@ -539,9 +520,9 @@ private Serializable invoke(String serviceIdentifier, String serviceMethod, Seri
* @throws EncodingFailedException
* @throws TimeoutException
*/
- public ListMethodsContent getServiceMethods(String serviceNameVersion) throws L2pSecurityException,
- AgentNotKnownException, InterruptedException, EncodingFailedException, SerializationException,
- TimeoutException {
+ public ListMethodsContent getServiceMethods(String serviceNameVersion)
+ throws L2pSecurityException, AgentNotKnownException, InterruptedException, EncodingFailedException,
+ SerializationException, TimeoutException {
if (currentUser == null) {
throw new IllegalStateException("please log in a valid user with registerUserAgent before!");
}
@@ -598,8 +579,13 @@ public void startService(String serviceNameVersion, String defaultPass) throws E
Files.write(file.toPath(), a.toXmlString().getBytes());
// save passphrase
- Files.write(Paths.get(DEFAULT_SERVICE_AGENT_DIRECTORY + "passphrases.txt"), ("\n" + serviceNameVersion
- + ".xml;" + defaultPass).getBytes(), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
+ Path passphrasesPath = Paths.get(DEFAULT_SERVICE_AGENT_DIRECTORY + "passphrases.txt");
+ String passphraseLine = serviceNameVersion + ".xml;" + defaultPass;
+ try {
+ Files.write(passphrasesPath, ("\n" + passphraseLine).getBytes(), StandardOpenOption.APPEND);
+ } catch (NoSuchFileException e) {
+ Files.write(passphrasesPath, passphraseLine.getBytes(), StandardOpenOption.CREATE);
+ }
}
// get passphrase from file
@@ -645,8 +631,8 @@ public ServiceAgent startServiceXml(String file, String passphrase) throws Excep
* @throws L2pSecurityException
* @throws AgentException
*/
- public void startService(Agent serviceAgent) throws AgentAlreadyRegisteredException, L2pSecurityException,
- AgentException {
+ public void startService(Agent serviceAgent)
+ throws AgentAlreadyRegisteredException, L2pSecurityException, AgentException {
if (!(serviceAgent instanceof ServiceAgent)) {
throw new IllegalArgumentException("given Agent is not a service agent!");
@@ -668,8 +654,8 @@ public void startService(Agent serviceAgent) throws AgentAlreadyRegisteredExcept
* @throws NoSuchServiceException
* @throws NodeException
*/
- public void stopService(String serviceNameVersion) throws AgentNotKnownException, NoSuchServiceException,
- NodeException {
+ public void stopService(String serviceNameVersion)
+ throws AgentNotKnownException, NoSuchServiceException, NodeException {
ServiceAgent agent = node.getLocalServiceAgent(ServiceNameVersion.fromString(serviceNameVersion));
node.unregisterReceiver(agent);
}
@@ -706,9 +692,8 @@ public void unlockAgent(PassphraseAgent agent, String passphrase) throws L2pSecu
* start interactive console mode based on a {@link i5.las2peer.tools.CommandPrompt}
*/
public void interactive() {
- System.out.println("Entering interactive mode for node "
- + this.getNode().getPastryNode().getId().toStringFull() + "\n"
- + "-----------------------------------------------\n"
+ System.out.println("Entering interactive mode for node " + this.getNode().getPastryNode().getId().toStringFull()
+ + "\n" + "-----------------------------------------------\n"
+ "Enter 'help' for further information of the console.\n"
+ "Use all public methods of the L2pNodeLauncher class for interaction with the P2P network.\n\n");
@@ -760,6 +745,11 @@ private L2pNodeLauncher(int port, String bootstrap, STORAGE_MODE storageMode, bo
commandPrompt = new CommandPrompt(this);
}
+ private L2pNodeLauncher(L2pClassManager cl, Integer port, String bootstrap) {
+ node = new PastryNodeImpl(cl, port, bootstrap, STORAGE_MODE.MEMORY, null, null);
+ commandPrompt = new CommandPrompt(this);
+ }
+
/**
* actually start the node
*
@@ -807,6 +797,7 @@ private static void printError(String message) {
* @throws NodeException
*/
public static L2pNodeLauncher launchSingle(Iterable args) throws NodeException {
+ boolean debugMode = false;
Integer port = null;
String bootstrap = null;
STORAGE_MODE storageMode = null;
@@ -821,7 +812,9 @@ public static L2pNodeLauncher launchSingle(Iterable args) throws NodeExc
String arg = itArg.next();
itArg.remove();
String larg = arg.toLowerCase();
- if (larg.equals("-p") == true || larg.equals("--port") == true) {
+ if (larg.equals("-debug") || larg.equals("--debug")) {
+ debugMode = true;
+ } else if (larg.equals("-p") == true || larg.equals("--port") == true) {
if (itArg.hasNext() == false) {
printWarning("ignored '" + arg + "', because port number expected after it");
} else {
@@ -902,15 +895,21 @@ public static L2pNodeLauncher launchSingle(Iterable args) throws NodeExc
commands.add(arg);
}
}
- // check parameters
- if (port == null) {
- printError("no port number specified");
- return null;
- } else if (port < 1) {
- printError("invalid port number specified");
- return null;
+ // check parameters and launch node
+ if (debugMode) {
+ System.err.println("WARNING! Launching node in DEBUG mode! THIS NODE IS NON PERSISTENT!");
+ return launchDebug(port, bootstrap, sLogDir, serviceDirectories, commands);
+ } else {
+ if (port == null) {
+ printError("no port number specified");
+ return null;
+ } else if (port < 1) {
+ printError("invalid port number specified");
+ return null;
+ }
+ return launchSingle(port, bootstrap, storageMode, observer, sLogDir, serviceDirectories, nodeIdSeed,
+ commands);
}
- return launchSingle(port, bootstrap, storageMode, observer, sLogDir, serviceDirectories, nodeIdSeed, commands);
}
public static L2pNodeLauncher launchSingle(int port, String bootstrap, STORAGE_MODE storageMode, boolean observer,
@@ -959,6 +958,51 @@ public static L2pNodeLauncher launchSingle(int port, String bootstrap, STORAGE_M
return launcher;
}
+ private static L2pNodeLauncher launchDebug(Integer port, String boostrap, String sLogDir,
+ Iterable serviceDirectories, Iterable commands) throws NodeException {
+ // check parameters
+ if (sLogDir != null) {
+ try {
+ L2pLogger.setGlobalLogDirectory(sLogDir);
+ } catch (Exception ex) {
+ printWarning("couldn't use '" + sLogDir + "' as log directory." + ex);
+ }
+ }
+ if (serviceDirectories == null) {
+ ArrayList directories = new ArrayList<>();
+ directories.add(DEFAULT_SERVICE_DIRECTORY);
+ serviceDirectories = directories;
+ }
+ if (commands == null) {
+ commands = new ArrayList<>();
+ }
+ // instantiate launcher
+ L2pClassManager cl = new L2pClassManager(new FileSystemRepository(serviceDirectories, true),
+ L2pNodeLauncher.class.getClassLoader());
+ L2pNodeLauncher launcher = new L2pNodeLauncher(cl, port, boostrap);
+ // handle commands
+ try {
+ launcher.start();
+
+ for (String command : commands) {
+ System.out.println("Handling: '" + command + "'");
+ launcher.commandPrompt.handleLine(command);
+ }
+
+ if (launcher.isFinished()) {
+ printMessage("All commands have been handled and shutdown has been called -> end!");
+ } else {
+ printMessage("All commands have been handled -- keeping node open!");
+ }
+ } catch (NodeException e) {
+ launcher.bFinished = true;
+ logger.printStackTrace(e);
+ throw e;
+ }
+
+ return launcher;
+ }
+
/**
* Prints a help message for command line usage.
*
@@ -976,6 +1020,9 @@ public static void printHelp(String message) {
System.out.println("Help Message:");
System.out.println("\t['--help'|'-h']");
+ System.out.println("las2peer version:");
+ System.out.println("\t['--version'|'-v']");
+
System.out.println("\nStart Node:");
System.out
.println("\t{optional: --colored-shell|-c} -p [port] {optional1} {optional2} {method1} {method2} ...");
@@ -991,11 +1038,11 @@ public static void printHelp(String message) {
System.out.println("\t--port|-p [port] specifies the port number of the node\n");
System.out.println("\tno bootstrap argument states, that a complete new las2peer network is to start");
System.out.println("\tor");
- System.out
- .println("\t--bootstrap|-b [host-list] requires a comma seperated list of [address:ip] pairs of bootstrap nodes to connect to. This argument can occur multiple times.\n");
+ System.out.println(
+ "\t--bootstrap|-b [host-list] requires a comma seperated list of [address:ip] pairs of bootstrap nodes to connect to. This argument can occur multiple times.\n");
System.out.println("\t--observer|-o starts a monitoring observer at this node\n");
- System.out
- .println("\t--node-id-seed|-n [long] generates the node id by using this seed to provide persistence\n");
+ System.out.println(
+ "\t--node-id-seed|-n [long] generates the node id by using this seed to provide persistence\n");
System.out
.println("\t--storage-mode|-m filesystem|memory sets Pastry's storage mode, defaults to filesystem\n");
@@ -1019,6 +1066,15 @@ public static void printHelp() {
printHelp(null);
}
+ /**
+ * Prints the las2peer version.
+ */
+ public static void printVersion() {
+ Package p = L2pNodeLauncher.class.getPackage();
+ String version = p.getImplementationVersion();
+ System.out.println("las2peer version \"" + version + "\"");
+ }
+
/**
* Main method for command line processing.
*
@@ -1082,8 +1138,12 @@ public static void main(String[] argv) throws InterruptedException, MalformedXML
if (larg.equals("-h") == true || larg.equals("--help") == true) { // Help Message
printHelp();
System.exit(1);
+ } else if (larg.equals("-v") || larg.equals("--version")) {
+ printVersion();
+ System.exit(1);
} else if (larg.equals("-w") || larg.equals("--windows-shell")) {
- printWarning("Ignoring obsolete argument '" + arg + ", because colored output is disabled by default.");
+ printWarning(
+ "Ignoring obsolete argument '" + arg + "', because colored output is disabled by default.");
} else if (larg.equals("-c") == true || larg.equals("--colored-shell") == true) { // turn on colored output
ColoredOutput.allOn();
} else { // node instance parameter
diff --git a/src/main/java/i5/las2peer/tools/SerializeTools.java b/src/main/java/i5/las2peer/tools/SerializeTools.java
index 2158c0426..30c9807d4 100755
--- a/src/main/java/i5/las2peer/tools/SerializeTools.java
+++ b/src/main/java/i5/las2peer/tools/SerializeTools.java
@@ -7,11 +7,10 @@
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
+import java.util.Base64;
import javax.crypto.SecretKey;
-import org.apache.commons.codec.binary.Base64;
-
/**
* Static class as collection of serialization and deserialization methods.
*
@@ -47,7 +46,7 @@ public static byte[] serialize(Serializable s) throws SerializationException {
* @throws SerializationException
*/
public static String serializeToBase64(Serializable s) throws SerializationException {
- return Base64.encodeBase64String(serialize(s));
+ return Base64.getEncoder().encodeToString(serialize(s));
}
/**
@@ -103,7 +102,7 @@ protected Class> resolveClass(ObjectStreamClass desc) throws IOException, Clas
* @throws SerializationException
*/
public static Serializable deserializeBase64(String base64) throws SerializationException {
- return deserialize(Base64.decodeBase64(base64));
+ return deserialize(Base64.getDecoder().decode(base64));
}
/**
diff --git a/src/main/java/i5/las2peer/tools/XmlTools.java b/src/main/java/i5/las2peer/tools/XmlTools.java
index bcbe63e0c..85fa994dc 100644
--- a/src/main/java/i5/las2peer/tools/XmlTools.java
+++ b/src/main/java/i5/las2peer/tools/XmlTools.java
@@ -1,8 +1,21 @@
package i5.las2peer.tools;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
import i5.las2peer.persistency.MalformedXMLException;
import i5.las2peer.persistency.XmlAble;
@@ -44,21 +57,24 @@ public static XmlAble createFromXml(String xml, String classname)
public static XmlAble createFromXml(String xml, Class> c) throws MalformedXMLException, SerializationException {
try {
Method createFromXml = c.getDeclaredMethod("createFromXml", String.class);
- if (Modifier.isStatic(createFromXml.getModifiers()))
+ if (Modifier.isStatic(createFromXml.getModifiers())) {
return (XmlAble) createFromXml.invoke(null, xml);
+ }
} catch (Exception e1) {
- if (e1 instanceof MalformedXMLException)
+ if (e1 instanceof MalformedXMLException) {
throw (MalformedXMLException) e1;
- // just try next idea
+ // just try next idea
+ }
}
try {
Constructor> constr = c.getDeclaredConstructor(String.class);
return (XmlAble) constr.newInstance(xml);
} catch (Exception e) {
- if (e instanceof MalformedXMLException)
+ if (e instanceof MalformedXMLException) {
throw (MalformedXMLException) e;
- // again just the next one
+ // again just the next one
+ }
}
try {
@@ -68,11 +84,132 @@ public static XmlAble createFromXml(String xml, Class> c) throws MalformedXMLE
return result;
} catch (Exception e) {
- if (e instanceof MalformedXMLException)
+ if (e instanceof MalformedXMLException) {
throw (MalformedXMLException) e;
+ }
}
throw new SerializationException("unable to generate a new instance for the given xml: " + xml);
}
+ /**
+ * Gets the root element from the given XML String and throws an exception if the name does not match with the given
+ * name.
+ *
+ * @param xml The XML String that should be parsed.
+ * @param rootElementName The tag name of the root element. CASE SENSITIVE
+ * @return Returns the root element with the given tag name.
+ * @throws MalformedXMLException If the root element does not have the given name or multiple root elements exist.
+ */
+ public static Element getRootElement(String xml, String rootElementName) throws MalformedXMLException {
+ try {
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
+ return getRootElement(doc, rootElementName);
+ } catch (ParserConfigurationException | IOException | SAXException e) {
+ throw new MalformedXMLException("Error parsing xml string", e);
+ }
+ }
+
+ /**
+ * Gets the root element from the given file containing only ONE XML representation and throws an exception if the
+ * name does not match with the given name.
+ *
+ * @param xmlFile The file containing one XML representation that should be parsed.
+ * @param rootElementName The tag name of the root element. CASE SENSITIVE
+ * @return Returns the root element with the given tag name.
+ * @throws MalformedXMLException If the root element does not have the given name or multiple root elements exist.
+ */
+ public static Element getRootElement(File xmlFile, String rootElementName) throws MalformedXMLException {
+ try {
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document doc = dBuilder.parse(xmlFile);
+ return getRootElement(doc, rootElementName);
+ } catch (ParserConfigurationException | IOException | SAXException e) {
+ throw new MalformedXMLException("Error parsing xml string", e);
+ }
+ }
+
+ /**
+ * Gets the root element from the given document type containing only ONE XML representation and throws an exception
+ * if the name does not match with the given name.
+ *
+ * @param document The document type containing one XML representation that should be parsed.
+ * @param rootElementName The tag name of the root element. CASE SENSITIVE
+ * @return Returns the root element with the given tag name.
+ * @throws MalformedXMLException If the root element does not have the given name or multiple root elements exist.
+ */
+ public static Element getRootElement(Document document, String rootElementName) throws MalformedXMLException {
+ document.getDocumentElement().normalize();
+ NodeList nList = document.getElementsByTagName(rootElementName);
+ int len = nList.getLength();
+ if (len != 1) {
+ throw new MalformedXMLException(
+ "Exactly one element '" + rootElementName + "' per XML document expected! Found: " + len);
+ }
+ org.w3c.dom.Node rootNode = nList.item(0);
+ String rootNodeName = rootNode.getNodeName();
+ if (!rootNodeName.equalsIgnoreCase(rootElementName)) {
+ throw new MalformedXMLException("This is not an " + rootElementName + " but a " + rootNodeName);
+ }
+ short rootNodeType = rootNode.getNodeType();
+ if (rootNodeType != org.w3c.dom.Node.ELEMENT_NODE) {
+ throw new MalformedXMLException("Root node type (" + rootNodeType + ") is not type element ("
+ + org.w3c.dom.Node.ELEMENT_NODE + ")");
+ }
+ return (Element) rootNode;
+ }
+
+ /**
+ * Gets exactly one child tag from given parent XML element. Otherwise throws an exception.
+ *
+ * @param parent The parent XML element.
+ * @param tagName The tag name of the singular child element. CASE SENSITIVE
+ * @return Returns the child element with the given tag name.
+ * @throws MalformedXMLException If not exactly one child has the specified tag name or it's not a node itself.
+ */
+ public static Element getSingularElement(Element parent, String tagName) throws MalformedXMLException {
+ NodeList nodeList = parent.getElementsByTagName(tagName);
+ int len = nodeList.getLength();
+ if (len != 1) {
+ throw new MalformedXMLException("Exactly one '" + tagName + "' element expected! Found: " + len);
+ }
+ org.w3c.dom.Node firstNode = nodeList.item(0);
+ short nodeType = firstNode.getNodeType();
+ if (nodeType != org.w3c.dom.Node.ELEMENT_NODE) {
+ throw new MalformedXMLException(
+ "Node type (" + nodeType + ") is not type element (" + org.w3c.dom.Node.ELEMENT_NODE + ")");
+ }
+ return (Element) firstNode;
+ }
+
+ /**
+ * Gets one optional child tag from given parent XML element. If more than one child matches an exception is thrown.
+ *
+ * @param parent The parent XML element.
+ * @param tagName The tag name of the optional child element. CASE SENSITIVE
+ * @return Returns the child element with the given tag name or null if no child matches the given tag name.
+ * @throws MalformedXMLException If more than one child has the specified tag name or it's not a node itself.
+ */
+ public static Element getOptionalElement(Element parent, String tagName) throws MalformedXMLException {
+ NodeList nodeList = parent.getElementsByTagName(tagName);
+ int len = nodeList.getLength();
+ if (len > 1) {
+ throw new MalformedXMLException("Only one '" + tagName + "' element expected!");
+ } else if (len == 1) {
+ org.w3c.dom.Node firstNode = nodeList.item(0);
+ short nodeType = firstNode.getNodeType();
+ if (nodeType != org.w3c.dom.Node.ELEMENT_NODE) {
+ throw new MalformedXMLException(
+ "Node type (" + nodeType + ") is not type element (" + org.w3c.dom.Node.ELEMENT_NODE + ")");
+ }
+ return (Element) firstNode;
+ } else {
+ // no child element with tag name found
+ return null;
+ }
+ }
+
}
diff --git a/src/test/java/i5/las2peer/p2p/NodeInformationTest.java b/src/test/java/i5/las2peer/p2p/NodeInformationTest.java
index 1ead825d7..2a5d286c9 100644
--- a/src/test/java/i5/las2peer/p2p/NodeInformationTest.java
+++ b/src/test/java/i5/las2peer/p2p/NodeInformationTest.java
@@ -6,12 +6,11 @@
import org.junit.Test;
import i5.las2peer.persistency.MalformedXMLException;
-import i5.simpleXML.XMLSyntaxException;
public class NodeInformationTest {
@Test
- public void testXmlAndBack() throws XMLSyntaxException, MalformedXMLException {
+ public void testXmlAndBack() throws MalformedXMLException {
NodeInformation testee = NodeInformation.createFromXml(
"test@bla.comStevensome desc");
diff --git a/src/test/java/i5/las2peer/p2p/NodeServiceCacheTest.java b/src/test/java/i5/las2peer/p2p/NodeServiceCacheTest.java
index 894995b6b..51838ae2b 100644
--- a/src/test/java/i5/las2peer/p2p/NodeServiceCacheTest.java
+++ b/src/test/java/i5/las2peer/p2p/NodeServiceCacheTest.java
@@ -102,7 +102,7 @@ public void testIntegration() throws CryptoException, L2pSecurityException, Agen
@Test
public void testGlobalServices() throws CryptoException, L2pSecurityException, AgentAlreadyRegisteredException,
AgentException, CloneNotSupportedException, MalformedXMLException, IOException, NodeException {
- // Attention when chaning NodeServiceCache parameters
+ // Attention when changing NodeServiceCache parameters
// You may have to adjust these results afterwards since this may influence the selected versions
// launch nodes
diff --git a/src/test/java/i5/las2peer/persistency/AgentUpdateTest.java b/src/test/java/i5/las2peer/persistency/AgentUpdateTest.java
new file mode 100644
index 000000000..9f7d611a3
--- /dev/null
+++ b/src/test/java/i5/las2peer/persistency/AgentUpdateTest.java
@@ -0,0 +1,61 @@
+package i5.las2peer.persistency;
+
+import java.util.ArrayList;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import i5.las2peer.p2p.PastryNodeImpl;
+import i5.las2peer.security.Agent;
+import i5.las2peer.security.GroupAgent;
+import i5.las2peer.security.UserAgent;
+import i5.las2peer.testing.MockAgentFactory;
+import i5.las2peer.testing.TestSuite;
+
+public class AgentUpdateTest {
+
+ /**
+ * This test launches a network with two nodes. The first node creates an GroupAgent and modifies it. The second
+ * node verifies that all changes are correctly stored in the network.
+ */
+ @Test
+ public void testGroupAgentUpdate() {
+ try {
+ // launch network
+ ArrayList nodes = TestSuite.launchNetwork(2);
+ PastryNodeImpl firstNode = nodes.get(0);
+ // create agents
+ UserAgent smith = MockAgentFactory.getAdam();
+ UserAgent neo = MockAgentFactory.getEve();
+ neo.unlockPrivateKey("evespass");
+ GroupAgent group = GroupAgent.createGroupAgent(new Agent[] { smith, neo });
+ group.unlockPrivateKey(neo);
+ // store agents
+ firstNode.storeAgent(group);
+ PastryNodeImpl secondNode = nodes.get(1);
+ GroupAgent fetched = (GroupAgent) secondNode.getAgent(group.getId());
+ // check attributes of both GroupAgents
+ Assert.assertEquals(group.getId(), fetched.getId());
+ Assert.assertEquals(group.getName(), fetched.getName());
+ Assert.assertEquals(group.getPublicKey(), fetched.getPublicKey());
+ Assert.assertEquals(group.getSize(), fetched.getSize());
+ Assert.assertArrayEquals(group.getMemberList(), fetched.getMemberList());
+ // update GroupAgent on first node
+ UserAgent morpheus = MockAgentFactory.getAbel();
+ group.addMember(morpheus);
+ firstNode.storeAgent(group);
+ // fetch GroupAgent again on second node
+ fetched = (GroupAgent) secondNode.getAgent(group.getId());
+ // check (again) attributes of both GroupAgents
+ Assert.assertEquals(group.getId(), fetched.getId());
+ Assert.assertEquals(group.getName(), fetched.getName());
+ Assert.assertEquals(group.getPublicKey(), fetched.getPublicKey());
+ Assert.assertEquals(group.getSize(), fetched.getSize());
+ Assert.assertArrayEquals(group.getMemberList(), fetched.getMemberList());
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail();
+ }
+ }
+
+}
diff --git a/src/test/java/i5/las2peer/persistency/EnvelopeTest.java b/src/test/java/i5/las2peer/persistency/EnvelopeTest.java
index b4386226f..7a1c8aacb 100644
--- a/src/test/java/i5/las2peer/persistency/EnvelopeTest.java
+++ b/src/test/java/i5/las2peer/persistency/EnvelopeTest.java
@@ -33,7 +33,7 @@ public class EnvelopeTest {
private ArrayList nodes;
private boolean asyncTestState;
- private static class ExceptionHandler implements StorageExceptionHandler {
+ private class ExceptionHandler implements StorageExceptionHandler {
@Override
public void onException(Exception e) {
e.printStackTrace();
@@ -41,7 +41,7 @@ public void onException(Exception e) {
}
}
- private static final ExceptionHandler storageExceptionHandler = new ExceptionHandler();
+ private final ExceptionHandler storageExceptionHandler = new ExceptionHandler();
@Rule
public TestName name = new TestName();
@@ -184,11 +184,12 @@ public void onEnvelopeReceived(Envelope envelope) {
}, null, storageExceptionHandler);
// wait till the envelope was fetched
System.out.println("Waiting ...");
- for (int n = 1; n <= 100; n++) {
+ long timeout = System.currentTimeMillis() + 120000000L; // two minutes timeout
+ while (System.currentTimeMillis() < timeout) {
if (asyncTestState) {
return;
}
- Thread.sleep(400);
+ Thread.sleep(200);
}
Assert.fail("Unexpected result");
} catch (Exception e) {
@@ -307,7 +308,7 @@ public void testCollisionWithoutCollisionManager() {
smith.unlockPrivateKey("adamspass");
Envelope envelope1 = node1.createUnencryptedEnvelope("test", "Hello World 1!");
Envelope envelope2 = node1.createUnencryptedEnvelope("test", "Hello World 2!");
- // upload envelope
+ // upload first envelope
node1.storeEnvelopeAsync(envelope1, smith, new StorageStoreResultHandler() {
@Override
public void onResult(Serializable serializable, int successfulOperations) {
@@ -320,13 +321,18 @@ public void onResult(Serializable serializable, int successfulOperations) {
Assert.fail("Exception expected!");
}
}, null, new StorageExceptionHandler() {
+ private boolean testComplete = false;
+
@Override
public void onException(Exception e) {
- if (e instanceof EnvelopeAlreadyExistsException) {
- System.out.println("Expected exception '" + e.toString() + "' received.");
- asyncTestState = true;
- } else {
- storageExceptionHandler.onException(e);
+ synchronized (this) {
+ if (e instanceof EnvelopeAlreadyExistsException) {
+ System.out.println("Expected exception '" + e.toString() + "' received.");
+ testComplete = true;
+ asyncTestState = true;
+ } else if (!testComplete) { // test yet incomplete
+ storageExceptionHandler.onException(e);
+ }
}
}
});
diff --git a/src/test/java/i5/las2peer/persistency/TestCryptoMethods.java b/src/test/java/i5/las2peer/persistency/TestCryptoMethods.java
index 5a2e61555..ac1d036a6 100755
--- a/src/test/java/i5/las2peer/persistency/TestCryptoMethods.java
+++ b/src/test/java/i5/las2peer/persistency/TestCryptoMethods.java
@@ -12,6 +12,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
+import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -20,7 +21,6 @@
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
-import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
public class TestCryptoMethods {
@@ -121,9 +121,9 @@ public void testBase64() throws UnsupportedEncodingException {
String testMessage = "Dies ist eine längere Nachricht, die ich gerne in Base64 encodieren möchte.";
byte[] bytes = testMessage.getBytes("UTF-8");
- String encoded = Base64.encodeBase64String(bytes);
+ String encoded = Base64.getEncoder().encodeToString(bytes);
- byte[] decoded = Base64.decodeBase64(encoded);
+ byte[] decoded = Base64.getDecoder().decode(encoded);
String decodedMessage = new String(decoded, "UTF-8");