m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorMartin <marcin.j.chrzanowski@gmail.com>2019-11-18 14:53:44 +0100
committerGitHub <noreply@github.com>2019-11-18 14:53:44 +0100
commite742bf9b8d1bc5ee7a97586510643db6fd3174f2 (patch)
treef1bf701c819a842e1f82e328cf3118556411502f /src/main
parent015e46aa190a36c593eeff8b09cea43d9902de0d (diff)
Implement basic API (#15)
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java5
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/agent/ApiImplementation.java71
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/api/Api.java6
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Main.java10
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java4
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java3
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java6
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java6
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java4
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java5
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java1
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/ValueQuery.java70
-rw-r--r--src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java35
13 files changed, 202 insertions, 24 deletions
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java
index 95ede6e..8eb8b4f 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java
@@ -6,11 +6,14 @@ import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import pl.edu.mimuw.cloudatlas.api.Api;
+import pl.edu.mimuw.cloudatlas.interpreter.Main;
+import pl.edu.mimuw.cloudatlas.model.ZMI;
public class Agent {
public static void main(String[] args) {
try {
- ApiImplementation api = new ApiImplementation();
+ ZMI root = Main.createTestHierarchy2();
+ ApiImplementation api = new ApiImplementation(root);
Api apiStub =
(Api) UnicastRemoteObject.exportObject(api, 0);
Registry registry = LocateRegistry.getRegistry();
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/ApiImplementation.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/ApiImplementation.java
index fd52052..12682a6 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/ApiImplementation.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/ApiImplementation.java
@@ -5,32 +5,91 @@ import java.rmi.RemoteException;
import java.util.Set;
import java.util.HashSet;
+import pl.edu.mimuw.cloudatlas.model.Attribute;
import pl.edu.mimuw.cloudatlas.model.AttributesMap;
+import pl.edu.mimuw.cloudatlas.model.PathName;
import pl.edu.mimuw.cloudatlas.model.ValueContact;
import pl.edu.mimuw.cloudatlas.model.Value;
+import pl.edu.mimuw.cloudatlas.model.ValueQuery;
import pl.edu.mimuw.cloudatlas.model.ValueSet;
import pl.edu.mimuw.cloudatlas.model.ValueNull;
import pl.edu.mimuw.cloudatlas.model.TypePrimitive;
+import pl.edu.mimuw.cloudatlas.model.ZMI;
import pl.edu.mimuw.cloudatlas.api.Api;
public class ApiImplementation implements Api {
+ ZMI root;
+ Set<ValueContact> contacts;
+
+ public ApiImplementation(ZMI root) {
+ this.root = root;
+ this.contacts = new HashSet<ValueContact>();
+ }
+
public Set<String> getZoneSet() throws RemoteException {
- return null;
+ Set<String> zones = new HashSet<String>();
+ collectZoneNames(root, zones);
+ return zones;
+ }
+
+ private void collectZoneNames(ZMI zone, Set<String> names) {
+ names.add(zone.getPathName().toString());
+ for (ZMI son : zone.getSons()) {
+ collectZoneNames(son, names);
+ }
}
- public AttributesMap getZoneAttributeValue(String zoneName) throws RemoteException {
- return null;
+ public AttributesMap getZoneAttributeValues(String zoneName) throws RemoteException {
+ try {
+ ZMI zmi = root.findDescendant(new PathName(zoneName));
+ return zmi.getAttributes();
+ } catch (ZMI.NoSuchZoneException e) {
+ throw new RemoteException("Zone not found", e);
+ }
}
- public void installQuery(String queryName, String query) throws RemoteException {
+ public void installQuery(String name, String queryCode) throws RemoteException {
+ try {
+ ValueQuery query = new ValueQuery(queryCode);
+ Attribute attributeName = new Attribute(name);
+ installQueryInHierarchy(root, attributeName, query);
+ } catch (Exception e) {
+ throw new RemoteException("Failed to install query", e);
+ }
+ }
+
+ private void installQueryInHierarchy(ZMI zmi, Attribute queryName, ValueQuery query) {
+ if (!zmi.getSons().isEmpty()) {
+ zmi.getAttributes().addOrChange(queryName, query);
+ for (ZMI son : zmi.getSons()) {
+ installQueryInHierarchy(son, queryName, query);
+ }
+ }
}
public void uninstallQuery(String queryName) throws RemoteException {
+ uninstallQueryInHierarchy(root, new Attribute(queryName));
+ }
+
+ private void uninstallQueryInHierarchy(ZMI zmi, Attribute queryName) {
+ if (!zmi.getSons().isEmpty()) {
+ zmi.getAttributes().remove(queryName);
+ for (ZMI son : zmi.getSons()) {
+ uninstallQueryInHierarchy(son, queryName);
+ }
+ }
}
- public void setAttributeValue(String attributeName, Value value) throws RemoteException {
+ public void setAttributeValue(String zoneName, String attributeName, Value value) throws RemoteException {
+ try {
+ ZMI zmi = root.findDescendant(new PathName(zoneName));
+ zmi.getAttributes().addOrChange(new Attribute(attributeName), value);
+ } catch (ZMI.NoSuchZoneException e) {
+ throw new RemoteException("Zone not found", e);
+ }
}
- public void setFallbackContacts(Set<ValueContact> serializedContacts) throws RemoteException {
+ public void setFallbackContacts(Set<ValueContact> contacts) throws RemoteException {
+ this.contacts = contacts;
}
}
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/api/Api.java b/src/main/java/pl/edu/mimuw/cloudatlas/api/Api.java
index c5a4581..c62ee39 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/api/Api.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/api/Api.java
@@ -25,14 +25,14 @@ public interface Api extends Remote {
public Set<String> getZoneSet() throws RemoteException;
- public AttributesMap getZoneAttributeValue(String zoneName) throws RemoteException;
+ public AttributesMap getZoneAttributeValues(String zoneName) throws RemoteException;
public void installQuery(String queryName, String query) throws RemoteException;
public void uninstallQuery(String queryName) throws RemoteException;
- public void setAttributeValue(String attributeName, Value value) throws RemoteException;
+ public void setAttributeValue(String zoneName, String attributeName, Value value) throws RemoteException;
- public void setFallbackContacts(Set<ValueContact> serializedContacts) throws RemoteException;
+ public void setFallbackContacts(Set<ValueContact> contacts) throws RemoteException;
}
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Main.java b/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Main.java
index ea9fdb1..979aa92 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Main.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/interpreter/Main.java
@@ -65,11 +65,6 @@ public class Main {
scanner.close();
}
- private static PathName getPathName(ZMI zmi) {
- String name = ((ValueString)zmi.getAttributes().get("name")).getValue();
- return zmi.getFather() == null? PathName.ROOT : getPathName(zmi.getFather()).levelDown(name);
- }
-
private static void executeQueries(ZMI zmi, String query, PrintStream out) throws Exception {
if(!zmi.getSons().isEmpty()) {
for(ZMI son : zmi.getSons())
@@ -78,7 +73,7 @@ public class Main {
Yylex lex = new Yylex(new ByteArrayInputStream(query.getBytes()));
try {
List<QueryResult> result = interpreter.interpretProgram((new parser(lex)).pProgram());
- PathName zone = getPathName(zmi);
+ PathName zone = zmi.getPathName();
for(QueryResult r : result) {
out.println(zone + ": " + r);
zmi.getAttributes().addOrChange(r.getName(), r.getValue());
@@ -249,7 +244,7 @@ public class Main {
return root;
}
- private static ZMI createTestHierarchy2() throws ParseException, UnknownHostException {
+ public static ZMI createTestHierarchy2() throws ParseException, UnknownHostException {
ValueContact violet07Contact = createContact("/uw/violet07", (byte)10, (byte)1, (byte)1, (byte)10);
ValueContact khaki13Contact = createContact("/uw/khaki13", (byte)10, (byte)1, (byte)1, (byte)38);
ValueContact khaki31Contact = createContact("/uw/khaki31", (byte)10, (byte)1, (byte)1, (byte)39);
@@ -368,6 +363,7 @@ public class Main {
khaki13.getAttributes().add("creation", new ValueTime((Long)null));
khaki13.getAttributes().add("cpu_usage", new ValueDouble(0.1));
khaki13.getAttributes().add("num_cores", new ValueInt(null));
+ khaki13.getAttributes().add("num_processes", new ValueInt(107l));
khaki13.getAttributes().add("has_ups", new ValueBoolean(true));
list = Arrays.asList(new Value[] {});
khaki13.getAttributes().add("some_names", new ValueList(list, TypePrimitive.STRING));
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java
index aa0cb64..eb916be 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java
@@ -24,6 +24,8 @@
package pl.edu.mimuw.cloudatlas.model;
+import java.io.Serializable;
+
/**
* Represents an attribute (without value, name only).
* <p>
@@ -32,7 +34,7 @@ package pl.edu.mimuw.cloudatlas.model;
* <p>
* This class is immutable.
*/
-public class Attribute {
+public class Attribute implements Serializable {
private final String name;
/**
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java
index 4065ad6..c74c1df 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java
@@ -24,6 +24,7 @@
package pl.edu.mimuw.cloudatlas.model;
+import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -32,7 +33,7 @@ import java.util.Map.Entry;
/**
* Represents a map from <code>Attribute</code> to <code>Value</code>. It cannot contain duplicate keys.
*/
-public class AttributesMap implements Iterable<Entry<Attribute, Value>>, Cloneable {
+public class AttributesMap implements Iterable<Entry<Attribute, Value>>, Cloneable, Serializable {
private Map<Attribute, Value> map = new HashMap<Attribute, Value>();
private void checkNulls(Attribute attribute, Value value) {
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java
index 986db71..0994cba 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java
@@ -24,16 +24,18 @@
package pl.edu.mimuw.cloudatlas.model;
+import java.io.Serializable;
+
/**
* A type of a value that may be stored as an attribute.
*/
-public abstract class Type {
+public abstract class Type implements Serializable {
/**
* A primary type. This is a characteristic that every type has. It can be extended: for instance a collection may
* be parameterized with a type of stored values.
*/
public static enum PrimaryType {
- BOOLEAN, CONTACT, DOUBLE, DURATION, INT, LIST, NULL, SET, STRING, TIME,
+ BOOLEAN, CONTACT, DOUBLE, DURATION, INT, LIST, NULL, SET, STRING, TIME, QUERY
}
private final PrimaryType primaryType;
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java
index ab28cb4..ad07c0a 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java
@@ -73,6 +73,11 @@ public class TypePrimitive extends Type {
*/
public static final TypePrimitive TIME = new TypePrimitive(PrimaryType.TIME);
+ /**
+ * Query type.
+ */
+ public static final TypePrimitive QUERY = new TypePrimitive(PrimaryType.QUERY);
+
private TypePrimitive(PrimaryType primaryType) {
super(primaryType);
switch(primaryType) {
@@ -84,6 +89,7 @@ public class TypePrimitive extends Type {
case NULL:
case STRING:
case TIME:
+ case QUERY:
break;
default:
throw new IllegalArgumentException(
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java
index c4054cf..55353c1 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java
@@ -26,10 +26,12 @@ package pl.edu.mimuw.cloudatlas.model;
import pl.edu.mimuw.cloudatlas.model.Value;
+import java.io.Serializable;
+
/**
* A single value stored as an attribute.
*/
-public abstract class Value {
+public abstract class Value implements Serializable {
/**
* An operation that may be performed on values.
*/
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java
index 7022bbd..7a74776 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java
@@ -248,7 +248,8 @@ public class ValueDuration extends ValueSimple<Long> {
return new ValueDuration(-getValue());
}
- public String toString() {
+
+ private String makeString() {
long remainingUnits = getValue();
boolean positive = remainingUnits >= 0;
remainingUnits = positive ? remainingUnits : -remainingUnits;
@@ -272,7 +273,7 @@ public class ValueDuration extends ValueSimple<Long> {
public Value convertTo(Type type) {
switch(type.getPrimaryType()) {
case STRING:
- return getValue() == null? ValueString.NULL_STRING : new ValueString(toString());
+ return getValue() == null? ValueString.NULL_STRING : new ValueString(makeString());
case DURATION:
return this;
default:
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java
index 8414cc4..c7f1036 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java
@@ -24,6 +24,7 @@
package pl.edu.mimuw.cloudatlas.model;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueQuery.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueQuery.java
new file mode 100644
index 0000000..d9cbe4c
--- /dev/null
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueQuery.java
@@ -0,0 +1,70 @@
+package pl.edu.mimuw.cloudatlas.model;
+
+import java.io.ByteArrayInputStream;
+
+import pl.edu.mimuw.cloudatlas.interpreter.query.Absyn.Program;
+import pl.edu.mimuw.cloudatlas.interpreter.query.parser;
+import pl.edu.mimuw.cloudatlas.interpreter.query.Yylex;
+import pl.edu.mimuw.cloudatlas.model.Value;
+
+/**
+ * A class that holds a CloudAtlas query.
+ */
+public class ValueQuery extends Value {
+ // Original source code
+ private String code;
+ // Parsed query
+ private Program query;
+ /**
+ * Constructs a new <code>ValueQuery</code> object.
+ *
+ * @param name the name of the query
+ * @param query the code of the query
+ */
+ public ValueQuery(String query) throws Exception {
+ this.code = query;
+ Yylex lex = new Yylex(new ByteArrayInputStream(query.getBytes()));
+ this.query = (new parser(lex)).pProgram();
+ }
+
+ private ValueQuery() {
+ this.code = null;
+ this.query = null;
+ }
+
+ @Override
+ public Type getType() {
+ return TypePrimitive.QUERY;
+ }
+
+ @Override
+ public boolean isNull() {
+ return query == null || code == null;
+ }
+
+ public Value isEqual(Value value) {
+ sameTypesOrThrow(value, Operation.EQUAL);
+ if(isNull() && value.isNull())
+ return new ValueBoolean(true);
+ else if(isNull() || value.isNull())
+ return new ValueBoolean(false);
+ return new ValueBoolean(code.equals(((ValueQuery)value).code));
+ }
+
+ @Override
+ public Value getDefaultValue() {
+ return new ValueQuery();
+ }
+
+ @Override
+ public Value convertTo(Type type) {
+ switch(type.getPrimaryType()) {
+ case QUERY:
+ return this;
+ case STRING:
+ return isNull() ? ValueString.NULL_STRING : new ValueString(code);
+ default:
+ throw new UnsupportedConversionException(getType(), type);
+ }
+ }
+}
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java
index 5a560ae..a311c61 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java
@@ -41,6 +41,11 @@ import com.esotericsoftware.kryo.io.Output;
* references to its father and sons in the tree.
*/
public class ZMI implements Cloneable {
+ public class NoSuchZoneException extends Exception {
+ public NoSuchZoneException(PathName path) {
+ super("No such zone: " + path);
+ }
+ }
private final AttributesMap attributes = new AttributesMap();
private final List<ZMI> sons = new ArrayList<ZMI>();
@@ -85,6 +90,26 @@ public class ZMI implements Cloneable {
this.father = father;
}
+ public ZMI findDescendant(PathName path) throws NoSuchZoneException {
+ ZMI descendant = this;
+ for (String component : path.getComponents()) {
+ boolean foundNextSon = false;
+ for (ZMI son : descendant.getSons()) {
+ if (son.getAttributes().get("name").equals(new ValueString(component))) {
+ descendant = son;
+ foundNextSon = true;
+ break;
+ }
+ }
+
+ if (!foundNextSon) {
+ throw new NoSuchZoneException(path);
+ }
+ }
+
+ return descendant;
+ }
+
/**
* Gets the list of sons of this ZMI. Modifying a value in the returned list will cause an exception.
*
@@ -170,6 +195,16 @@ public class ZMI implements Cloneable {
return attributes.toString();
}
+ /**
+ * Gets the PathName representing this zone.
+ *
+ * @return a <code>PathName</code> object representing this zone
+ */
+ public PathName getPathName() {
+ String name = ((ValueString)getAttributes().get("name")).getValue();
+ return getFather() == null? PathName.ROOT : getFather().getPathName().levelDown(name);
+ }
+
public static ZMI deserialize(InputStream in) {
Kryo kryo = new Kryo();
Input kryoInput = new Input(in);