From b1078581d4730d4944180a739fcce51a39259112 Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Sun, 3 Nov 2019 12:55:03 +0100 Subject: Initialize gradle project --- .../pl/edu/mimuw/cloudatlas/model/Attribute.java | 106 ++++++++ .../edu/mimuw/cloudatlas/model/AttributesMap.java | 282 +++++++++++++++++++++ .../model/IncompatibleTypesException.java | 81 ++++++ .../pl/edu/mimuw/cloudatlas/model/PathName.java | 180 +++++++++++++ .../java/pl/edu/mimuw/cloudatlas/model/Type.java | 81 ++++++ .../edu/mimuw/cloudatlas/model/TypeCollection.java | 116 +++++++++ .../edu/mimuw/cloudatlas/model/TypePrimitive.java | 108 ++++++++ .../model/UnsupportedConversionException.java | 67 +++++ .../model/UnsupportedValueOperationException.java | 69 +++++ .../java/pl/edu/mimuw/cloudatlas/model/Value.java | 241 ++++++++++++++++++ .../edu/mimuw/cloudatlas/model/ValueBoolean.java | 93 +++++++ .../edu/mimuw/cloudatlas/model/ValueContact.java | 100 ++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueDouble.java | 111 ++++++++ .../edu/mimuw/cloudatlas/model/ValueDuration.java | 272 ++++++++++++++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueInt.java | 133 ++++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueList.java | 275 ++++++++++++++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueNull.java | 155 +++++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueSet.java | 232 +++++++++++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueSimple.java | 89 +++++++ .../pl/edu/mimuw/cloudatlas/model/ValueString.java | 120 +++++++++ .../pl/edu/mimuw/cloudatlas/model/ValueTime.java | 116 +++++++++ .../java/pl/edu/mimuw/cloudatlas/model/ZMI.java | 166 ++++++++++++ 22 files changed, 3193 insertions(+) create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/IncompatibleTypesException.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/PathName.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/TypeCollection.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedConversionException.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedValueOperationException.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueBoolean.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueContact.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDouble.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueInt.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueNull.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSet.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSimple.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueString.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ValueTime.java create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java (limited to 'src/main/java') diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java new file mode 100644 index 0000000..46ffab3 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/Attribute.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +/** + * Represents an attribute (without value, name only). + *

+ * A valid attribute name is an identifier starting with a letter and containing only letters and digits. It can + * additionally start with an ampersand - such names are reserved for queries. + *

+ * This class is immutable. + */ +public class Attribute { + private final String name; + + /** + * Creates a new Attribute object with the specified name. + * + * @param name the name of the attribute + * @throws IllegalArgumentException if the name does not meet the rules + */ + public Attribute(String name) { + if(!name.matches("^&?[a-zA-Z]{1}[a-zA-z0-9_]*$")) + throw new IllegalArgumentException("Invalid name: may contain only letters, digits, underscores, " + + "must start with a letter and may optionally have an ampersand at the beginning."); + this.name = name; + } + + /** + * Indicates whether an attribute represents a query. This is true if and only if the attribute's name starts with an ampersand. + * + * @param attribute the attribute to check + * @return whether the attribute represents a query + */ + public static boolean isQuery(Attribute attribute) { + return attribute.getName().startsWith("&"); + } + + /** + * Gets the name of this attribute. + * + * @return string representing name + */ + public String getName() { + return name; + } + + /** + * Returns a hash code value for this attribute. For proper behavior when using Attribute objects in + * HashMap, HashSet etc. this is the hash code of a string representing the attribute's name. + * + * @return hash code for this attribute + */ + @Override + public int hashCode() { + return name.hashCode(); + } + + /** + * Indicates whether another object is equal to this attribute. + * + * @param object the object to check + * @return true if and only if the object is an instance of Attribute class and has + * an identical name + */ + @Override + public boolean equals(Object object) { + if(object == null) + return false; + if(getClass() != object.getClass()) + return false; + return name.equals(((Attribute)object).name); + } + + /** + * Returns a textual representation of this attribute. + * + * @return the name of this attribute + */ + @Override + public String toString() { + return 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 new file mode 100644 index 0000000..4065ad6 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/AttributesMap.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Represents a map from Attribute to Value. It cannot contain duplicate keys. + */ +public class AttributesMap implements Iterable>, Cloneable { + private Map map = new HashMap(); + + private void checkNulls(Attribute attribute, Value value) { + if(attribute == null) + throw new NullPointerException("The attribute cannot be null."); + if(value == null) + throw new NullPointerException( + "The value cannot be null. You may want create a Value object that contains null."); + } + + /** + * Adds a new attribute-value mapping. The + * attribute cannot already exist in the map. To overwrite an existing attribute, use + * {@link #addOrChange(Attribute, Value)} instead. + * + * @param attribute the attribute to add + * @param value the value for attribute + * @throws IllegalArgumentException if the attribute already exists in this map + * @throws NullPointerException if either the attribute or the value is null; + * for null value, create a Value object containing null + * @see #addOrChange(Attribute, Value) + * @see #add(String, Value) + * @see #add(Entry) + * @see #add(AttributesMap) + */ + public void add(Attribute attribute, Value value) { + if(getOrNull(attribute) != null) + throw new IllegalArgumentException("Attribute \"" + attribute.getName() + + "\" already exists. Use method addOrChange(Attribute, Value) instead."); + checkNulls(attribute, value); + map.put(attribute, value); + } + + /** + * Adds a new attribute mapping to the specified value. Convenient version of + * {@link #add(Attribute, Value)}. + * + * @param name the attribute name + * @param value the attribute value + * @see #add(Attribute, Value) + * @see #addOrChange(String, Value) + */ + public void add(String name, Value value) { + add(new Attribute(name), value); + } + + /** + * Adds a new mapping to this map. Convenient version of {@link #add(Attribute, Value)}. + * + * @param entry a pair containing both an attribute and a value + * @see #add(Attribute, Value) + * @see #addOrChange(Entry) + */ + public void add(Entry entry) { + add(entry.getKey(), entry.getValue()); + } + + /** + * Adds all entries from another map to this map. This method uses {@link #add(Attribute, Value)}, so it throws an + * exception when trying to overwrite an existing attribute. + * + * @param attributes the map to add + * @see #add(Attribute, Value) + * @see #addOrChange(AttributesMap) + */ + public void add(AttributesMap attributes) { + for(Entry entry : attributes.map.entrySet()) + add(entry); + } + + /** + * Adds to this map a new attribute mapping to the specified value. Unlike + * {@link #add(Attribute, Value)}, this method overwrites an existing attribute with the same name. + * + * @param attribute the attribute to add or overwrite + * @param value the value for the attribute + * @throws NullPointerException if either the attribute or the value is null; + * for null value create a Value object containing null + * @see #add(Attribute, Value) + * @see #addOrChange(String, Value) + * @see #addOrChange(Entry) + * @see #addOrChange(AttributesMap) + */ + public void addOrChange(Attribute attribute, Value value) { + map.put(attribute, value); + checkNulls(attribute, value); + } + + /** + * Adds a new attribute mapping to the specified value or overwrites an existing one. Convenient + * version of {@link #addOrChange(Attribute, Value)}. + * + * @param name the attribute name + * @param value the attribute value + * @see #addOrChange(Attribute, Value) + * @see #add(String, Value) + */ + public void addOrChange(String name, Value value) { + addOrChange(new Attribute(name), value); + } + + /** + * Adds a new mapping to this map or overwrites an existing one with the same attribute name. Convenient version of + * {@link #addOrChange(Attribute, Value)}. + * + * @param entry a pair containing both an attribute and a value + * @see #addOrChange(Attribute, Value) + * @see #add(Entry) + */ + public void addOrChange(Entry entry) { + addOrChange(entry.getKey(), entry.getValue()); + } + + /** + * Adds all entries from another map to this map. If any attribute with the same name exists in this map, it will be + * overwritten. + * + * @param attributes the map to add + * @see #addOrChange(Attribute, Value) + * @see #add(AttributesMap) + */ + public void addOrChange(AttributesMap attributes) { + for(Entry entry : attributes.map.entrySet()) + addOrChange(entry); + } + + private void checkAttribute(Attribute attribute) { + if(attribute == null) + throw new NullPointerException("The attribute cannot be null."); + } + + /** + * Gets the value mapped to the specified attribute. If such a mapping does not exist, this method throws + * an exception. If this is not an expected behavior, use {@link #getOrNull(Attribute)} instead. + * + * @param attribute the attribute to obtain + * @return the value mapped to attribute + * @throws IllegalArgumentException if no value is mapped to attribute + * @throws NullPointerException if attribute is null + * @see #getOrNull(Attribute) + * @see #get(String) + */ + public Value get(Attribute attribute) { + Value value = getOrNull(attribute); + if(value == null) + throw new IllegalArgumentException("Attribute " + attribute.getName() + + " does not exist. Use method getOrNull(Attribute) instead."); + return value; + } + + /** + * Gets the value mapped to the specified attribute. Convenient version of {@link #get(Attribute)}. + * + * @param name name of the attribute + * @return the value mapped to the specified attribute + * @see #get(Attribute) + * @see #getOrNull(String) + */ + public Value get(String name) { + return get(new Attribute(name)); + } + + /** + * Gets the value mapped to the specified attribute. Unlike {@link #get(Attribute)}, this method + * returns null if the requested mapping does not exist. + * + * @param attribute the attribute to obtain + * @return the value mapped to attribute or null if it does not exist + * @throws NullPointerException if the attribute is null + * @see #get(Attribute) + * @see #getOrNull(String) + */ + public Value getOrNull(Attribute attribute) { + checkAttribute(attribute); + return map.get(attribute); + } + + /** + * Gets the value mapped to the specified attribute. Convenient version of {@link #getOrNull(Attribute)}. + * + * @param name name of the attribute + * @return the value mapped to specified attribute or null if it does not exist + * @see #getOrNull(Attribute) + * @see #getOr(String) + */ + public Value getOrNull(String name) { + return getOrNull(new Attribute(name)); + } + + /** + * Removes the specified attribute and its value from this map. If attribute does not + * exist, this method doesn't do anything. + * + * @param attribute the attribute to remove + * @throws NullPointerException if attribute is null + * @see #remove(String) + */ + public void remove(Attribute attribute) { + checkAttribute(attribute); + map.remove(attribute); + } + + /** + * Removes the specified attribute and its value from this map. Convenient version of {@link #remove(Attribute)}. + * + * @param name the name of the attribute to remove + * @see #remove(Attribute) + */ + public void remove(String name) { + map.remove(new Attribute(name)); + } + + /** + * Returns an iterator over all entries stored in this map. + * + * @return an iterator for this map + * @see java.util.Iterator + * @see java.lang.Iterable + */ + @Override + public Iterator> iterator() { + return map.entrySet().iterator(); + } + + /** + * Creates a copy of this map. Since Value and Attribute are immutable classes, this + * method does not clone them. + * + * @return a copy of this map containing identical entries + */ + @Override + public AttributesMap clone() { + AttributesMap result = new AttributesMap(); + result.add(this); + return result; + } + + /** + * Returns a string representation of this map listing all key-value pairs stored in it. + * + * @return a string representation of this object + */ + @Override + public String toString() { + return map.toString(); + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/IncompatibleTypesException.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/IncompatibleTypesException.java new file mode 100644 index 0000000..65c719e --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/IncompatibleTypesException.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Value.Operation; + +/** + * An exception thrown when an unsupported binary operation on values is requested. + * + * @see UnsupportedValueOperationException + * @see UnsupportedConversionException + */ +@SuppressWarnings("serial") +public class IncompatibleTypesException extends UnsupportedOperationException { + private final Type left; + private final Type right; + private final Operation operation; + + /** + * Creates a new object representing this exception. + * + * @param left type of a left operand + * @param right type of a right operand + * @param operation an operation that caused this exception + */ + protected IncompatibleTypesException(Type left, Type right, Operation operation) { + super("Incompatible types: " + left + " and " + right + " in operation " + operation + "."); + this.left = left; + this.right = right; + this.operation = operation; + } + + /** + * Gets the type of the left operand in the operation that caused this exception. + * + * @return the type of the left operand + */ + public Type getLeft() { + return left; + } + + /** + * Gets the type of the right operand in the operation that caused this exception. + * + * @return the type of the right operand + */ + public Type getRight() { + return right; + } + + /** + * Gets an object representing the operation that caused this exception. + * + * @return the operation that caused this exception + */ + public Operation getOperation() { + return operation; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/PathName.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/PathName.java new file mode 100644 index 0000000..7f3a9ac --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/PathName.java @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Represent a fully qualified name of a zone, also known as a global name or a path name. Objects of this class are immutable. + */ +public class PathName { + /** + * Object representing the name of the root zone (/). + */ + public static final PathName ROOT = new PathName("/"); + + private final List components; + private final String name; + + /** + * Creates a PathName object representing the specified path. For the root zone, there are three + * accepted forms: null reference, empty string or slash. Any other zone is represented by a string + * starting with slash and containing names of zones at each level of the hierarchy, separated by slashes. Zone names + * must contain only letters and digits. + * + * @param name path name of a zone, for instance: /warsaw/uw/violet07 + * @throws IllegalArgumentException if the name is incorrect + */ + public PathName(String name) { + // we accept null and "/" as names of a root zone, however, we convert all of them to "" + name = name == null || name.equals("/")? "" : name.trim(); + if(!name.matches("(/\\w+)*")) + throw new IllegalArgumentException("Incorrect fully qualified name: " + name + "."); + this.name = name; + components = name.equals("")? new ArrayList() : Arrays.asList(name.substring(1).split("/")); + } + + /** + * Creates a PathName object from a collection of zone names. Every zone name must contain only + * letters and digits. + * + * @param components a collection of zone names at subsequent levels of hierarchy (starting from root); an empty + * collection represents the root zone + * @throws IllegalArgumentException if any zone name is incorrect + */ + public PathName(Collection components) { + this.components = new ArrayList(components); + if(components.isEmpty()) + this.name = ""; + else { + String currentName = ""; + for(String c : components) { + currentName += "/" + c; + if(!c.matches("\\w+")) + throw new IllegalArgumentException("Incorrect component " + c + "."); + } + this.name = currentName; + } + } + + /** + * Gets zone names at subsequent levels of hierarchy, starting from the root. For the root zone, this method returns an + * empty collection. Modifying the returned list will throw an exception. + * + * @return a collection of zones names + */ + public List getComponents() { + return Collections.unmodifiableList(components); + } + + /** + * Gets a full path name. For the root zone, this method returns an empty string. + * + * @return a path name represented by this object + * @see #toString() + */ + public String getName() { + return name; + } + + /** + * Gets a name one level up in the hierarchy. For the root zone, this method returns a new instance of the same zone. + * + * @return a new PathName object representing a zone one level up in the hierarchy + */ + public PathName levelUp() { + List componentsUp = new ArrayList(components); + if(!componentsUp.isEmpty()) + componentsUp.remove(componentsUp.size() - 1); + return new PathName(componentsUp); + } + + /** + * Gets a name one level down in a hierarchy. + * + * @param son zone name at a lower level + * @return a new PathName object representing a zone one level down in the hierarchy + */ + public PathName levelDown(String son) { + return new PathName(name + "/" + son); + } + + /** + * Gets a zone name at the lowest level (highest number) in a hierarchy. + * + * @return a leaf zone + * @throws UnsupportedOperationException if this object represents the root zone + */ + public String getSingletonName() { + try { + return components.get(components.size() - 1); + } catch(IndexOutOfBoundsException exception) { + throw new UnsupportedOperationException("getSingletonName() is not supported for the root zone."); + } + } + + /** + * Returns a hash code value for this object. This method returns a hash code of a string representing the full path + * name. + * + * @return a hash code for this object + */ + @Override + public int hashCode() { + return name.hashCode(); + } + + /** + * Indicates whether this object is equal to another. A PathName object is equal to other objects of + * the same class representing identical path names. + * + * @param object the object to check + * @return whether object's name is equal to this one's + */ + @Override + public boolean equals(Object object) { + if(object == null) + return false; + if(getClass() != object.getClass()) + return false; + return name.equals(((PathName)object).name); + } + + /** + * Returns a textual representation for this PathName. For the root zone, unlike {@link #getName()}, + * this method returns a slash. + * + * @return a path name for this object + * @see #getName() + */ + @Override + public String toString() { + return name.equals("")? "/" : getName(); + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java new file mode 100644 index 0000000..986db71 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/Type.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +/** + * A type of a value that may be stored as an attribute. + */ +public abstract class Type { + /** + * 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, + } + + private final PrimaryType primaryType; + + /** + * Creates a Type object with a given primary type. + * + * @param primaryType a primary type for this type + */ + public Type(PrimaryType primaryType) { + this.primaryType = primaryType; + } + + /** + * Returns the primary type of this type. + * + * @return a primary type + */ + public PrimaryType getPrimaryType() { + return primaryType; + } + + /** + * Indicates whether this type can be implicitly "cast" to the given one and vice versa. This is introduced to deal with + * null values. In practice, two types are compatible either if they are the same or if one them is a special + * "null type". + * + * @param type a type to check + * @return whether two types are compatible with each other + * @see TypePrimitive#NULL + * @see ValueNull + */ + public boolean isCompatible(Type type) { + return getPrimaryType() == PrimaryType.NULL || type.getPrimaryType() == PrimaryType.NULL; + } + + /** + * Indicates whether this type represents a collection. + * + * @return true for collections, false otherwise + */ + public boolean isCollection() { + return false; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/TypeCollection.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/TypeCollection.java new file mode 100644 index 0000000..da5d848 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/TypeCollection.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.util.Collection; + +import pl.edu.mimuw.cloudatlas.model.Type; +import pl.edu.mimuw.cloudatlas.model.TypePrimitive; +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueNull; + +/** + * Represents a collection type with a specified element type. + * + * @see TypePrimitve + */ +public class TypeCollection extends Type { + private final Type elementType; + + /** + * Creates a new collection type. + * + * @param primaryType a type of this collection (set, list etc.) + * @param elementType a type of elements of this collection; may be a complex type (for instance + * another TypeCollection) + */ + public TypeCollection(PrimaryType primaryType, Type elementType) { + super(primaryType); + switch(primaryType) { + case LIST: + case SET: + break; + default: + throw new IllegalArgumentException("This class can represent a collection only (list, set etc.)."); + } + this.elementType = elementType; + } + + /** + * Gets a type of elements stored in this collection. + * + * @return type of element in this collection + */ + public Type getElementType() { + return elementType; + } + + /** + * Returns a textual representation of this collection, for instance: "SET of (STRING)". + * + * @return a textual representation of this type + */ + @Override + public String toString() { + return getPrimaryType().toString() + " of (" + elementType.toString() + ")"; + } + + @Override + public boolean isCompatible(Type type) { + return super.isCompatible(type) + || (getPrimaryType() == type.getPrimaryType() && elementType + .isCompatible(((TypeCollection)type).elementType)); + } + + @Override + public boolean isCollection() { + return true; + } + + /** + * Returns a type of all elements in the specified collection. If the collection is empty, this method returns + * {@link TypePrimitive#NULL}. If the collection contains at least two elements of distinct types that are not nulls, + * an exception is thrown. + * + * @param collection a collection of values to check + * @return type of elements in this collection + * @throws IllegalArgumentException if the collection contains non-null elements of different types + */ + public static Type computeElementType(Collection collection) { + Type mainType = null; + + for(Value v : collection) { + if(v.isNull()) + v = ValueNull.getInstance(); + if(mainType == null) { + if(v.getType().getPrimaryType() != Type.PrimaryType.NULL) + mainType = v.getType(); + } else if(!mainType.isCompatible(v.getType())) + throw new IllegalArgumentException("Collection has non-null elements of different types."); + } + + return mainType == null? TypePrimitive.NULL : mainType; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java new file mode 100644 index 0000000..ab28cb4 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/TypePrimitive.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +/** + * Convenient class for types that just wrap ordinary Java types. + * + * @see TypeCollection + */ +public class TypePrimitive extends Type { + /** + * Boolean type. + */ + public static final TypePrimitive BOOLEAN = new TypePrimitive(PrimaryType.BOOLEAN); + + /** + * Contact type. + */ + public static final TypePrimitive CONTACT = new TypePrimitive(PrimaryType.CONTACT); + + /** + * Double type. + */ + public static final TypePrimitive DOUBLE = new TypePrimitive(PrimaryType.DOUBLE); + + /** + * Duration type. + */ + public static final TypePrimitive DURATION = new TypePrimitive(PrimaryType.DURATION); + + /** + * Integer type. + */ + public static final TypePrimitive INTEGER = new TypePrimitive(PrimaryType.INT); + + /** + * A special null type that represents null values of an unknown type. It can be converted to any other type. + * + * @see Type#isCompatible(Type) + * @see ValueNull + */ + public static final TypePrimitive NULL = new TypePrimitive(PrimaryType.NULL); + + /** + * String type. + */ + public static final TypePrimitive STRING = new TypePrimitive(PrimaryType.STRING); + + /** + * Time type. + */ + public static final TypePrimitive TIME = new TypePrimitive(PrimaryType.TIME); + + private TypePrimitive(PrimaryType primaryType) { + super(primaryType); + switch(primaryType) { + case BOOLEAN: + case CONTACT: + case DOUBLE: + case DURATION: + case INT: + case NULL: + case STRING: + case TIME: + break; + default: + throw new IllegalArgumentException( + "This class can represent a primitive type only (boolean, int etc.)."); + } + } + + /** + * Gets a textual representation of this type. + * + * @return a string representing this type + */ + @Override + public String toString() { + return getPrimaryType().toString(); + } + + @Override + public boolean isCompatible(Type type) { + return super.isCompatible(type) || getPrimaryType() == type.getPrimaryType(); + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedConversionException.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedConversionException.java new file mode 100644 index 0000000..6f30360 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedConversionException.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +/** + * An exception describing an unsupported conversion of a value to another type. + * + * @see IncompatibleTypesException + * @see UnsupportedValueOperationException + */ +@SuppressWarnings("serial") +public class UnsupportedConversionException extends UnsupportedOperationException { + private final Type from; + private final Type to; + + /** + * Creates a new instance of this this exception. + * + * @param from source type of an unsupported conversion + * @param to destination type of an unsupported conversion + */ + protected UnsupportedConversionException(Type from, Type to) { + super("Type " + from + " cannot be converted to " + to + "."); + this.from = from; + this.to = to; + } + + /** + * Gets the source type of the unsupported conversion that caused this exception. + * + * @return source type + */ + public Type getFrom() { + return from; + } + + /** + * Gets the destination type of the unsupported conversion that caused this exception. + * + * @return destination type + */ + public Type getTo() { + return to; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedValueOperationException.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedValueOperationException.java new file mode 100644 index 0000000..bb3aa1f --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/UnsupportedValueOperationException.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Value.Operation; + +/** + * An exception caused by calling an unsupported unary operation on value. + * + * @see IncompatibleTypesException + * @see UnsupportedConversionException + */ +@SuppressWarnings("serial") +public class UnsupportedValueOperationException extends UnsupportedOperationException { + private final Type left; + private final Operation operation; + + /** + * Creates a new object representing this exception. + * + * @param left type of a value that was an argument of an operation that caused this exception + * @param operation the operation that caused this exception + */ + protected UnsupportedValueOperationException(Type left, Operation operation) { + super("Type: " + left + " does not provide operation " + operation + "."); + this.left = left; + this.operation = operation; + } + + /** + * Gets the type of value that was the argument to the operation that caused this exception. + * + * @return first argument of the operation + */ + public Type getLeft() { + return left; + } + + /** + * Gets the operation that caused this exception. + * + * @return the operation + */ + public Operation getOperation() { + return operation; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java new file mode 100644 index 0000000..c4054cf --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/Value.java @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Value; + +/** + * A single value stored as an attribute. + */ +public abstract class Value { + /** + * An operation that may be performed on values. + */ + public enum Operation { + EQUAL, COMPARE, ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULO, AND, OR, REG_EXPR, NEGATE, VALUE_SIZE, + } + + /** + * Gets the type of this value. + * + * @return type of this value + */ + public abstract Type getType(); + + /** + * Indicates whether this value is null. Distinct from a Value reference that is null + * itself. + * + * @return true if and only if this value is null + */ + public abstract boolean isNull(); + + protected final void sameTypesOrThrow(Value value, Operation operation) { + if(!getType().isCompatible(value.getType())) + throw new IncompatibleTypesException(getType(), value.getType(), operation); + } + + /** + * Checks whether this value is equal to the specified one (operator ==). + * + * @param value the right side of the operator + * @return a ValueBoolean representing true if and only if both values are equal + * @throws UnsupportedValueOperationException if this operation is unsupported for these values + */ + public Value isEqual(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.EQUAL); + } + + /** + * Indicates whether this object is equal to another one. + * + * @param object the object to check + * @return whether two objects are equal + */ + @Override + public boolean equals(Object object) { + if(!(object instanceof Value)) + return false; + return ((ValueBoolean)isEqual((Value)object)).getValue(); + } + + /** + * Checks whether this value is lower than the specified one (operator <=). + * + * @param value the right side of the operator + * @return a ValueBoolean representing true if and only if this value is lower than the provided one + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * incompatible or non-numeric types) + */ + public Value isLowerThan(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.COMPARE); + } + + /** + * Returns a new value created by adding argument to this value (operator +). + * + * @param value the right side of the operator + * @return a sum of two values + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * incompatible or non-numeric types) + */ + public Value addValue(Value value) { + // name clash with add from List interface + throw new UnsupportedValueOperationException(getType(), Operation.ADD); + } + + /** + * Returns a new value created by subtracting argument from this value (operator -). + * + * @param value the right side of the operator + * @return a difference of two values + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * incompatible or non-numeric types) + */ + public Value subtract(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.SUBTRACT); + } + + /** + * Returns a new value created by multiplying this value by an argument (operator *). + * + * @param value the right side of the operator + * @return a product of two values + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * incompatible or non-numeric types) + */ + public Value multiply(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.MULTIPLY); + } + + /** + * Returns a new value created by dividing this value by an argument (operator /). + * + * @param value the right side of the operator + * @return a quotient of two values + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * incompatible or non-numeric types) + */ + public Value divide(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.DIVIDE); + } + + /** + * Returns the remainder of division of this value by an argument (operator %). + * + * @param value the right side of the operator + * @return a remainder + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * incompatible or non-numeric types) + */ + public Value modulo(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.MODULO); + } + + /** + * Returns the result of a logical AND (operator &&). + * + * @param value the right side of the operator + * @return a conjunction of the two values + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * non-boolean types) + */ + public Value and(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.AND); + } + + /** + * Returns the result of a logical OR (operator ||). + * + * @param value the right side of the operator + * @return an alternative of two values + * @throws UnsupportedValueOperationException if this operator is unsupported for these values (for example + * non-boolean types) + */ + public Value or(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.OR); + } + + /** + * Returns a result of trying to match to this value with a regular expression specified as an argument. + * + * @param value the regular expression to match against + * @return a ValueBoolean representing true if and only if this value matches provided regular + * expression + * @throws UnsupportedValueOperationException if this operator is unsupported for these values + */ + public Value regExpr(Value value) { + throw new UnsupportedValueOperationException(getType(), Operation.REG_EXPR); + } + + /** + * Returns the negation (numeric or logical) of this value. This may refer to operator - or !, depending on type. + * + * @return a value that is the negation of this value + * @throws UnsupportedValueOperationException if this operator is unsupported for this value + */ + public Value negate() { // !, - + throw new UnsupportedValueOperationException(getType(), Operation.NEGATE); + } + + /** + * Returns the size of this value. Semantics depend on type. + * + * @return a size of this value + * @throws UnsupportedValueOperationException if this operation is unsupported for this value + */ + public Value valueSize() { + // name clash with size from List interface + throw new UnsupportedValueOperationException(getType(), Operation.VALUE_SIZE); + } + + /** + * Returns this value converted to another type. + * + * @param to a desired type + * @return this value converted to the type + * @throws UnsupportedConversionException if a requested conversion is unsupported + */ + public abstract Value convertTo(Type to); + + /** + * Returns a textual representation of this value. This method uses conversion to ValueString. + * + * @return a textual representation of this value + * @see #convertTo(Type) + */ + @Override + public String toString() { + return ((ValueString)convertTo(TypePrimitive.STRING)).getValue(); + } + + /** + * Returns a default value (such as an uninitialized variable). This may be 0 for integer types, + * false for boolean, null for complex types, etc. + * + * @return a default value of this type + */ + public abstract Value getDefaultValue(); +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueBoolean.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueBoolean.java new file mode 100644 index 0000000..57078c2 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueBoolean.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueBoolean; + +/** + * A class that wraps a Java Boolean object. + */ +public class ValueBoolean extends ValueSimple { + /** + * Constructs a new ValueBoolean object wrapping the specified value. + * + * @param value the value to wrap + */ + public ValueBoolean(Boolean value) { + super(value); + } + + @Override + public Type getType() { + return TypePrimitive.BOOLEAN; + } + + @Override + public Value getDefaultValue() { + return new ValueBoolean(false); + } + + @Override + public ValueBoolean isLowerThan(Value value) { + sameTypesOrThrow(value, Operation.COMPARE); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(!getValue() && ((ValueBoolean)value).getValue()); + } + + @Override + public ValueBoolean and(Value value) { + sameTypesOrThrow(value, Operation.AND); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue() && ((ValueBoolean)value).getValue()); + } + + @Override + public ValueBoolean or(Value value) { + sameTypesOrThrow(value, Operation.OR); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue() || ((ValueBoolean)value).getValue()); + } + + @Override + public ValueBoolean negate() { + return new ValueBoolean(isNull()? null : !getValue()); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case BOOLEAN: + return this; + case STRING: + return getValue() == null? ValueString.NULL_STRING : new ValueString(getValue().toString()); + default: + throw new UnsupportedConversionException(getType(), type); + } + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueContact.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueContact.java new file mode 100644 index 0000000..670a025 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueContact.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.net.InetAddress; + +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueContact; + +/** + * A class that represents a contact to a node. The contact consists of a full path name of this node and its IP + * address. + *

+ * This class is immutable. + */ +public class ValueContact extends Value { + private final PathName name; + private final InetAddress address; + + /** + * Constructs a new ValueContact with the specified path name and IP address. + * + * @param name the full path name of a node + * @param address the IP address of the node + */ + public ValueContact(PathName name, InetAddress address) { + this.name = name; + this.address = address; + } + + @Override + public Value getDefaultValue() { + return new ValueContact(null, null); + } + + /** + * Returns a name stored in this object. + * + * @return the name of a node + */ + public PathName getName() { + return name; + } + + /** + * Returns an IP address stored in this object. + * + * @return the IP address of a node + */ + public InetAddress getAddress() { + return address; + } + + @Override + public Type getType() { + return TypePrimitive.CONTACT; + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case CONTACT: + return this; + case STRING: + if(isNull()) + return ValueString.NULL_STRING; + else + return new ValueString("(" + name.toString() + ", " + address.toString() + ")"); + default: + throw new UnsupportedConversionException(getType(), type); + } + } + + @Override + public boolean isNull() { + return name == null || address == null; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDouble.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDouble.java new file mode 100644 index 0000000..920a8ef --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDouble.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueDouble; + +/** + * A class that wraps a Java Double object. + */ +public class ValueDouble extends ValueSimple { + /** + * Constructs a new ValueDouble object wrapping the specified value. + * + * @param value the value to wrap + */ + public ValueDouble(Double value) { + super(value); + } + + @Override + public Type getType() { + return TypePrimitive.DOUBLE; + } + + @Override + public Value getDefaultValue() { + return new ValueDouble(0.0); + } + + @Override + public ValueBoolean isLowerThan(Value value) { + sameTypesOrThrow(value, Operation.COMPARE); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue() < ((ValueDouble)value).getValue()); + } + + @Override + public ValueDouble addValue(Value value) { + sameTypesOrThrow(value, Operation.ADD); + if(isNull() || value.isNull()) + return new ValueDouble(null); + return new ValueDouble(getValue() + ((ValueDouble)value).getValue()); + } + + @Override + public ValueDouble subtract(Value value) { + sameTypesOrThrow(value, Operation.SUBTRACT); + if(isNull() || value.isNull()) + return new ValueDouble(null); + return new ValueDouble(getValue() - ((ValueDouble)value).getValue()); + } + + @Override + public ValueDouble multiply(Value value) { + sameTypesOrThrow(value, Operation.MULTIPLY); + if(isNull() || value.isNull()) + return new ValueDouble(null); + return new ValueDouble(getValue() * ((ValueDouble)value).getValue()); + } + + @Override + public ValueDouble divide(Value value) { + sameTypesOrThrow(value, Operation.DIVIDE); + if(isNull() || value.isNull()) + return new ValueDouble(null); + return new ValueDouble(getValue() / ((ValueDouble)value).getValue()); + } + + @Override + public ValueDouble negate() { + return new ValueDouble(isNull()? null : -getValue()); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case DOUBLE: + return this; + case INT: + return new ValueInt(getValue() == null? null : getValue().longValue()); + case STRING: + return getValue() == null? ValueString.NULL_STRING : new ValueString(getValue().toString()); + default: + throw new UnsupportedConversionException(getType(), type); + } + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java new file mode 100644 index 0000000..bf9d0e0 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueDuration.java @@ -0,0 +1,272 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.lang.IllegalArgumentException; +import java.text.ParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A class representing duration in milliseconds. The duration can be negative. This is a simple wrapper of a Java + * Long object. + */ +public class ValueDuration extends ValueSimple { + public static class InvalidFormatException extends IllegalArgumentException { + } + + /** + * Regex pattern for duration strings. + */ + private static final Pattern DURATION_PATTERN = Pattern.compile( + "(?[+-])(?\\d+) " + + "(?[0-1][0-9]|2[0-3]):(?[0-5][0-9]):(?[0-5][0-9])." + + "(?[0-9]{3})" + ); + + /** + * Constructs a new ValueDuration object wrapping the specified value. + * + * @param value the value to wrap + */ + public ValueDuration(Long value) { + super(value); + } + + @Override + public Type getType() { + return TypePrimitive.DURATION; + } + + @Override + public Value getDefaultValue() { + return new ValueDuration(0l); + } + + /** + * Constructs a new ValueDuration object from the specified amounts of different time units. + * + * @param seconds a number of full seconds + * @param milliseconds a number of milliseconds (an absolute value does not have to be lower than 1000) + */ + public ValueDuration(long seconds, long milliseconds) { + this(seconds * 1000l + milliseconds); + } + + /** + * Constructs a new ValueDuration object from the specified amounts of different time units. + * + * @param minutes a number of full minutes + * @param seconds a number of full seconds (an absolute value does not have to be lower than 60) + * @param milliseconds a number of milliseconds (an absolute value does not have to be lower than 1000) + */ + public ValueDuration(long minutes, long seconds, long milliseconds) { + this(minutes * 60l + seconds, milliseconds); + } + + /** + * Constructs a new ValueDuration object from the specified amounts of different time units. + * + * @param hours a number of full hours + * @param minutes a number of full minutes (an absolute value does not have to be lower than 60) + * @param seconds a number of full seconds (an absolute value does not have to be lower than 60) + * @param milliseconds a number of milliseconds (an absolute value does not have to be lower than 1000) + */ + public ValueDuration(long hours, long minutes, long seconds, long milliseconds) { + this(hours * 60l + minutes, seconds, milliseconds); + } + + /** + * Constructs a new ValueDuration object from the specified amounts of different time units. + * + * @param days a number of full days + * @param hours a number of full hours (an absolute value does not have to be lower than 24) + * @param minutes a number of full minutes (an absolute value does not have to be lower than 60) + * @param seconds a number of full seconds (an absolute value does not have to be lower than 60) + * @param milliseconds a number of milliseconds (an absolute value does not have to be lower than 1000) + */ + public ValueDuration(long days, long hours, long minutes, long seconds, long milliseconds) { + this(days * 24l + hours, minutes, seconds, milliseconds); + } + + /** + * Constructs a new ValueDuration object from its textual representation. The representation has + * format: sd hh:mm:ss.lll where: + *

+ *

+ * All fields are obligatory. + * + * @param value a textual representation of a duration + * @throws IllegalArgumentException if value does not meet described rules + */ + public ValueDuration(String value) { + this(parseDuration(value)); + } + + private static long parseDuration(String value) { + Matcher matcher = DURATION_PATTERN.matcher(value); + if (!matcher.matches()) { + throw new InvalidFormatException(); + } + + long result = parseLongGroup(matcher, "days"); + result *= 24; + result += parseLongGroup(matcher, "hours"); + result *= 60; + result += parseLongGroup(matcher, "minutes"); + result *= 60; + result += parseLongGroup(matcher, "seconds"); + result *= 1000; + result += parseLongGroup(matcher, "milliseconds"); + result *= matcher.group("sign").equals("+") ? 1 : -1; + + return result; + } + + private static long parseLongGroup(Matcher matcher, String group) { + return Long.parseLong(matcher.group(group)); + } + + @Override + public ValueBoolean isLowerThan(Value value) { + sameTypesOrThrow(value, Operation.COMPARE); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue() < ((ValueDuration)value).getValue()); + } + + @Override + public ValueDuration addValue(Value value) { + sameTypesOrThrow(value, Operation.ADD); + if (isNull() || value.isNull()) { + return new ValueDuration((Long) null); + } + + return new ValueDuration(getValue() + ((ValueDuration)value).getValue()); + } + + @Override + public ValueDuration subtract(Value value) { + sameTypesOrThrow(value, Operation.SUBTRACT); + if (isNull() || value.isNull()) + return new ValueDuration((Long) null); + return new ValueDuration(getValue() - ((ValueDuration)value).getValue()); + } + + @Override + public ValueDuration multiply(Value value) { + if (!value.getType().isCompatible(TypePrimitive.INTEGER)) { + throw new IncompatibleTypesException(getType(), value.getType(), Operation.MULTIPLY); + } + + if (isNull() || value.isNull()) { + return new ValueDuration((Long) null); + } + + return new ValueDuration(getValue() * ((ValueInt)value).getValue()); + } + + @Override + public Value divide(Value value) { + if (!value.getType().isCompatible(TypePrimitive.INTEGER)) { + throw new IncompatibleTypesException(getType(), value.getType(), Operation.MULTIPLY); + } + + if (isNull() || value.isNull()) { + return new ValueDuration((Long) null); + } + + if (((ValueInt)value).getValue() == 0l) { + throw new ArithmeticException("Division by zero."); + } + + return new ValueDuration(getValue() / ((ValueInt)value).getValue()); + } + + @Override + public ValueDuration modulo(Value value) { + if (!value.getType().isCompatible(TypePrimitive.INTEGER)) { + throw new IncompatibleTypesException(getType(), value.getType(), Operation.MULTIPLY); + } + + if (isNull() || value.isNull()) { + return new ValueDuration((Long) null); + } + + if (((ValueInt)value).getValue() == 0l) { + throw new ArithmeticException("Division by zero."); + } + + return new ValueDuration(getValue() % ((ValueInt)value).getValue()); + } + + @Override + public ValueDuration negate() { + if(isNull()) { + return new ValueDuration((Long) null); + } + + return new ValueDuration(-getValue()); + } + + public String toString() { + long remainingUnits = getValue(); + boolean positive = remainingUnits >= 0; + remainingUnits = positive ? remainingUnits : -remainingUnits; + + long milliseconds = remainingUnits % 1000; + remainingUnits /= 1000; + long seconds = remainingUnits % 60; + remainingUnits /= 60; + long minutes = remainingUnits % 60; + remainingUnits /= 60; + long hours = remainingUnits % 24; + remainingUnits /= 24; + long days = remainingUnits; + + return (positive ? "+" : "-") + Long.toString(days) + " " + Long.toString(hours) + + ":" + Long.toString(minutes) + ":" + Long.toString(seconds) + "." + + Long.toString(milliseconds); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case STRING: + return getValue() == null? ValueString.NULL_STRING : new ValueString(toString()); + case DURATION: + return this; + default: + throw new UnsupportedConversionException(getType(), type); + } + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueInt.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueInt.java new file mode 100644 index 0000000..8811d57 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueInt.java @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Type.PrimaryType; +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueInt; + +/** + * A class that wraps a Java Long object. + */ +public class ValueInt extends ValueSimple { + /** + * Constructs a new ValueInt object wrapping the specified value. + * + * @param value the value to wrap + */ + public ValueInt(Long value) { + super(value); + } + + @Override + public Type getType() { + return TypePrimitive.INTEGER; + } + + @Override + public Value getDefaultValue() { + return new ValueInt(0l); + } + + @Override + public ValueBoolean isLowerThan(Value value) { + sameTypesOrThrow(value, Operation.COMPARE); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue() < ((ValueInt)value).getValue()); + } + + @Override + public ValueInt addValue(Value value) { + sameTypesOrThrow(value, Operation.ADD); + if(isNull() || value.isNull()) + return new ValueInt(null); + return new ValueInt(getValue() + ((ValueInt)value).getValue()); + } + + @Override + public ValueInt subtract(Value value) { + sameTypesOrThrow(value, Operation.SUBTRACT); + if(isNull() || value.isNull()) + return new ValueInt(null); + return new ValueInt(getValue() - ((ValueInt)value).getValue()); + } + + @Override + public Value multiply(Value value) { + if(value.getType().getPrimaryType() == PrimaryType.DURATION) + return value.multiply(this); + sameTypesOrThrow(value, Operation.MULTIPLY); + if(isNull() || value.isNull()) + return new ValueInt(null); + return new ValueInt(getValue() * ((ValueInt)value).getValue()); + } + + @Override + public ValueDouble divide(Value value) { + sameTypesOrThrow(value, Operation.DIVIDE); + if(value.isNull()) + return new ValueDouble(null); + if(((ValueInt)value).getValue() == 0l) + throw new ArithmeticException("Division by zero."); + if(isNull()) + return new ValueDouble(null); + return new ValueDouble((double)getValue() / ((ValueInt)value).getValue()); + } + + @Override + public ValueInt modulo(Value value) { + sameTypesOrThrow(value, Operation.MODULO); + if(value.isNull()) + return new ValueInt(null); + if(((ValueInt)value).getValue() == 0l) + throw new ArithmeticException("Division by zero."); + if(isNull()) + return new ValueInt(null); + return new ValueInt(getValue() % ((ValueInt)value).getValue()); + } + + @Override + public ValueInt negate() { + return new ValueInt(isNull()? null : -getValue()); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case DOUBLE: + return new ValueDouble(getValue() == null? null : getValue().doubleValue()); + case DURATION: + return new ValueDuration(getValue()); + case INT: + return this; + case STRING: + return getValue() == null? ValueString.NULL_STRING : new ValueString(Long.toString(getValue() + .longValue())); + default: + throw new UnsupportedConversionException(getType(), type); + } + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java new file mode 100644 index 0000000..76d59ff --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueList.java @@ -0,0 +1,275 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; + +import pl.edu.mimuw.cloudatlas.model.TypeCollection; +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueList; + +/** + * A value representing a list of values of the specified type. Implements List interface. + *

+ * All constructors take a type of elements stored in this list. This type is checked when adding elements to the list + * and an IllegalArgumentException is thrown in case of a mismatch. + * + * @see java.util.List + */ +public class ValueList extends ValueSimple> implements List { + private TypeCollection type; + + /** + * Creates a new ValueList containing all the elements in the specified list. + * + * @param value a list which content will be copied to this value + * @param elementType type of elements stored in this list + */ + public ValueList(List value, Type elementType) { + this(elementType); + if(value != null) + setValue(value); + } + + /** + * Creates an empty list. + * + * @param elementType type of elements stored in this list + */ + public ValueList(Type elementType) { + super(new ArrayList()); + type = new TypeCollection(Type.PrimaryType.LIST, elementType); + } + + @Override + public Type getType() { + return type; + } + + @Override + public Value getDefaultValue() { + return new ValueList(((TypeCollection)this.getType()).getElementType()); + } + + /** + * Gets a List containing all the objects stored in this value. Modifying the returned list will cause an + * exception. + */ + @Override + public List getValue() { + return getList() == null? null : Collections.unmodifiableList(getList()); + } + + @Override + public ValueList addValue(Value value) { + sameTypesOrThrow(value, Operation.ADD); + if(isNull() || value.isNull()) + return new ValueList(null, ((TypeCollection)getType()).getElementType()); + List result = new ArrayList(getValue()); + result.addAll(((ValueList)value).getValue()); + return new ValueList(result, ((TypeCollection)getType()).getElementType()); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case LIST: + if(getType().isCompatible(type)) + return this; + throw new UnsupportedConversionException(getType(), type); + case SET: + if(this.type.getElementType().isCompatible(((TypeCollection)type).getElementType())) { + if(this.isNull()) + return new ValueSet(null, this.type.getElementType()); + Set set = new HashSet(); + set.addAll(this); + return new ValueSet(set, this.type.getElementType()); + } + throw new UnsupportedConversionException(getType(), type); + case STRING: + return getValue() == null? ValueString.NULL_STRING : new ValueString(getValue().toString()); + default: + throw new UnsupportedConversionException(getType(), type); + } + } + + @Override + public ValueInt valueSize() { + return new ValueInt((getList() == null? null : (long)getList().size())); + } + + @Override + public void setValue(List list) { + if(list == null) + super.setValue(null); + else { + super.setValue(new ArrayList()); + for(Value e : list) + add(e); + } + } + + private List getList() { + return super.getValue(); + } + + private void checkElement(Value element) { + if(element == null) + throw new IllegalArgumentException("If you want to use null, create an object containing null instead."); + if(!type.getElementType().isCompatible(element.getType())) + throw new IllegalArgumentException("This list contains elements of type " + + type.getElementType().toString() + " only. Incompatible with elements of type: " + + element.getType().toString()); + } + + @Override + public boolean add(Value e) { + checkElement(e); + return getList().add(e); + } + + @Override + public void add(int index, Value element) { + checkElement(element); + getList().add(index, element); + } + + @Override + public boolean addAll(Collection c) { + for(Value e : c) + checkElement(e); + return getList().addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + for(Value e : c) + checkElement(e); + return getList().addAll(index, c); + } + + @Override + public void clear() { + getList().clear(); + } + + @Override + public boolean contains(Object o) { + return getList().contains(o); + } + + @Override + public boolean containsAll(Collection c) { + return getList().containsAll(c); + } + + @Override + public Value get(int index) { + return getList().get(index); + } + + @Override + public int indexOf(Object o) { + return getList().indexOf(o); + } + + @Override + public boolean isEmpty() { + return getList().isEmpty(); + } + + @Override + public Iterator iterator() { + return getList().iterator(); + } + + @Override + public int lastIndexOf(Object o) { + return getList().lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return getList().listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return getList().listIterator(index); + } + + @Override + public boolean remove(Object o) { + return getList().remove(o); + } + + @Override + public Value remove(int index) { + return getList().remove(index); + } + + @Override + public boolean removeAll(Collection c) { + return getList().removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return getList().retainAll(c); + } + + @Override + public Value set(int index, Value element) { + checkElement(element); + return getList().set(index, element); + } + + @Override + public int size() { + return getList().size(); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return new ValueList(getList().subList(fromIndex, toIndex), type.getElementType()); + } + + @Override + public Object[] toArray() { + return getList().toArray(); + } + + @Override + public Y[] toArray(Y[] a) { + return getList().toArray(a); + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueNull.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueNull.java new file mode 100644 index 0000000..c628beb --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueNull.java @@ -0,0 +1,155 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueNull; + +/** + * A special null value of an unknown type. This class is a singleton. + * + * @see TypePrimitve#NULL + * @see Type#isCompatible(Value) + */ +public class ValueNull extends Value { + private static ValueNull instance = null; + + private ValueNull() {} + + /** + * Gets a singleton instance of the ValueNull class. Every call to this method returns the same + * reference. + * + * @return an instance of ValueNull + */ + public static ValueNull getInstance() { + if(instance == null) + instance = new ValueNull(); + return instance; + } + + @Override + public Value getDefaultValue() { + return instance; + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case STRING: + return ValueString.NULL_STRING; + default: + return this; + } + } + + @Override + public Type getType() { + return TypePrimitive.NULL; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public Value isEqual(Value value) { + return new ValueBoolean(isNull() && value.isNull()); + } + + @Override + public Value isLowerThan(Value value) { + if(value == getInstance()) + return this; + return value.isLowerThan(this); + } + + @Override + public Value addValue(Value value) { + if(value == getInstance()) + return this; + return value.addValue(this); + } + + @Override + public Value subtract(Value value) { + if(value == getInstance()) + return this; + return value.subtract(this); + } + + @Override + public Value multiply(Value value) { + if(value == getInstance()) + return this; + return value.multiply(this); + } + + @Override + public Value divide(Value value) { + if(value == getInstance()) + return this; + return value.divide(this); + } + + @Override + public Value modulo(Value value) { + if(value == getInstance()) + return this; + return value.modulo(this); + } + + @Override + public Value and(Value value) { + if(value == getInstance()) + return this; + return value.and(this); + } + + @Override + public Value or(Value value) { + if(value == getInstance()) + return this; + return value.or(this); + } + + @Override + public Value regExpr(Value value) { + if(value == getInstance()) + return this; + return value.regExpr(this); + } + + @Override + public Value negate() { + return this; + } + + @Override + public Value valueSize() { + return this; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSet.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSet.java new file mode 100644 index 0000000..9843cd4 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSet.java @@ -0,0 +1,232 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import pl.edu.mimuw.cloudatlas.model.TypeCollection; +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueSet; + +/** + * A value representing a set of values of the specified type. Implements Set interface. + *

+ * All constructors take a type of elements stored in this set. This type is checked when adding elements to the set and + * an IllegalArgumentException is thrown in case of a mismatch. + * + * @see java.util.Set + */ +public class ValueSet extends ValueSimple> implements Set { + private TypeCollection type; + + /** + * Creates a new ValueSet containing all the elements in the specified set. + * + * @param value a set which content will be copied to this value + * @param elementType type of elements stored in this set + */ + public ValueSet(Set value, Type elementType) { + this(elementType); + if(value != null) + setValue(value); + } + + /** + * Creates an empty set. + * + * @param elementType type of elements stored in this set + */ + public ValueSet(Type elementType) { + super(new HashSet()); + type = new TypeCollection(Type.PrimaryType.SET, elementType); + } + + @Override + public Type getType() { + return type; + } + + @Override + public Value getDefaultValue() { + return new ValueSet(((TypeCollection)this.getType()).getElementType()); + } + + /** + * Gets a Set containing all the objects stored in this value. Modifying the returned list will cause an + * exception. + */ + @Override + public Set getValue() { + return getSet() == null? null : Collections.unmodifiableSet(getSet()); + } + + @Override + public ValueSet addValue(Value value) { + sameTypesOrThrow(value, Operation.ADD); + if(isNull() || value.isNull()) + return new ValueSet(null, ((TypeCollection)getType()).getElementType()); + Set result = new HashSet(getValue()); + result.addAll(((ValueSet)value).getValue()); + return new ValueSet(result, ((TypeCollection)getType()).getElementType()); + } + + @Override + public ValueInt valueSize() { + return new ValueInt((getSet() == null? null : (long)getSet().size())); + } + + @Override + public void setValue(Set set) { + if(set == null) + super.setValue(null); + else { + super.setValue(new HashSet()); + for(Value e : set) + add(e); + } + } + + private Set getSet() { + return super.getValue(); + } + + private void checkElement(Value element) { + if(element == null) + throw new IllegalArgumentException("If you want to use null, create an object containing null instead."); + if(!type.getElementType().isCompatible(element.getType())) + throw new IllegalArgumentException("This set contains elements of type " + type.getElementType().toString() + + " only. Incompatible with elements of type: " + element.getType().toString()); + } + + @Override + public boolean add(Value e) { + checkElement(e); + return getSet().add(e); + } + + @Override + public boolean addAll(Collection c) { + for(Value e : c) + checkElement(e); + return getSet().addAll(c); + } + + @Override + public void clear() { + getSet().clear(); + } + + @Override + public boolean contains(Object o) { + return getSet().contains(o); + } + + @Override + public boolean containsAll(Collection c) { + return getSet().containsAll(c); + } + + @Override + public boolean isEmpty() { + return getSet().isEmpty(); + } + + @Override + public Iterator iterator() { + return getSet().iterator(); + } + + @Override + public boolean remove(Object o) { + return getSet().remove(o); + } + + @Override + public boolean removeAll(Collection c) { + return getSet().removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return getSet().retainAll(c); + } + + @Override + public int size() { + return getSet().size(); + } + + @Override + public Object[] toArray() { + return getSet().toArray(); + } + + @Override + public U[] toArray(U[] a) { + return getSet().toArray(a); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case SET: + if(getType().isCompatible(type)) + return this; + throw new UnsupportedConversionException(getType(), type); + case LIST: + if(this.type.getElementType().isCompatible(((TypeCollection)type).getElementType())) { + if(this.isNull()) + return new ValueList(null, this.type.getElementType()); + List list = new ArrayList(); + list.addAll(this); + return new ValueList(list, this.type.getElementType()); + } + throw new UnsupportedConversionException(getType(), type); + case STRING: + if(getValue() == null) + return ValueString.NULL_STRING; + StringBuilder sb = new StringBuilder(); + sb.append("{"); + boolean notFirst = false; + for(Value v : getValue()) { + if(notFirst) { + sb.append(", "); + } else + notFirst = true; + sb.append(v.toString()); + } + sb.append("}"); + return new ValueString(sb.toString()); + default: + throw new UnsupportedConversionException(getType(), type); + } + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSimple.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSimple.java new file mode 100644 index 0000000..803510f --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueSimple.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +/** + * Class for wrapping Java types into Value objects. + *

+ * This class is immutable. + * + * @param a wrapped type + */ +abstract class ValueSimple extends Value { + private T value; + + /** + * Constructs a new Value wrapping the specified value. + * + * @param value the value to wrap + */ + public ValueSimple(T value) { + setValue(value); + } + + /** + * Returns a hash code value for this object. This is a hash code of underlying wrapped object. + * + * @return the hash code for this value + */ + @Override + public int hashCode() { + return getValue().hashCode(); + } + + /** + * Gets a wrapped object. + * + * @return the wrapped value + */ + public T getValue() { + return value; + } + + /** + * Sets a wrapped value. This method is not public to ensure that the underlying value cannot be changed. + * + * @param value the value to set + */ + void setValue(T value) { + this.value = value; + } + + @Override + public boolean isNull() { + return value == null; + } + + @SuppressWarnings("unchecked") + @Override + public Value isEqual(Value v) { + sameTypesOrThrow(v, Operation.EQUAL); + if(isNull() && v.isNull()) + return new ValueBoolean(true); + else if(isNull() || v.isNull()) + return new ValueBoolean(false); + return new ValueBoolean(value.equals(((ValueSimple)v).getValue())); + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueString.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueString.java new file mode 100644 index 0000000..314c602 --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueString.java @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.text.ParseException; + +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueString; + +/** + * A class that wraps a Java String object. + */ +public class ValueString extends ValueSimple { + /** + * Result of converting values representing null to ValueString. + */ + protected static final ValueString NULL_STRING = new ValueString("NULL"); + + /** + * Constructs a new ValueString object wrapping the specified value. + * + * @param value the value to wrap + */ + public ValueString(String value) { + super(value); + } + + @Override + public Type getType() { + return TypePrimitive.STRING; + } + + @Override + public Value getDefaultValue() { + return new ValueString(""); + } + + @Override + public ValueBoolean isLowerThan(Value value) { + sameTypesOrThrow(value, Operation.COMPARE); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue().compareTo(((ValueString)value).getValue()) < 0); + } + + @Override + public ValueString addValue(Value value) { + sameTypesOrThrow(value, Operation.ADD); + if(isNull() || value.isNull()) + return new ValueString(null); + return new ValueString(getValue().concat(((ValueString)value).getValue())); + } + + @Override + public ValueBoolean regExpr(Value value) { + sameTypesOrThrow(value, Operation.REG_EXPR); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue().matches(((ValueString)value).getValue())); + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case BOOLEAN: + return new ValueBoolean(Boolean.parseBoolean(getValue())); + case DOUBLE: + try { + return new ValueDouble(Double.parseDouble(getValue())); + } catch(NumberFormatException exception) { + return new ValueDouble(null); + } + case DURATION: + return new ValueDuration(getValue()); + case INT: + try { + return new ValueInt(Long.parseLong(getValue())); + } catch(NumberFormatException exception) { + return new ValueInt(null); + } + case STRING: + return getValue() == null? ValueString.NULL_STRING : this; + case TIME: + try { + return new ValueTime(getValue()); + } catch(ParseException exception) { + return new ValueTime((Long)null); + } + default: + throw new UnsupportedConversionException(getType(), type); + } + } + + @Override + public ValueInt valueSize() { + return new ValueInt(getValue() == null? null : (long)getValue().length()); + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueTime.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueTime.java new file mode 100644 index 0000000..8dd04fc --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueTime.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueTime; + +/** + * A class representing a POSIX time in milliseconds. This is a simple wrapper of a Java Long object. + */ +public class ValueTime extends ValueSimple { + /** + * A format string for constructing from or converting to a String object. + */ + public static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); + + /** + * Constructs a new ValueTime object wrapping the specified value. + * + * @param value the POSIX time + */ + public ValueTime(Long value) { + super(value); + } + + @Override + public Type getType() { + return TypePrimitive.TIME; + } + + @Override + public Value getDefaultValue() { + return new ValueTime(0l); + } + + /** + * Constructs a new ValueTime object from its textual representation. + * + * @param time a time formatted according to {@link #TIME_FORMAT} + * @throws ParseException if the time is incorrect + * @see #TIME_FORMAT + */ + public ValueTime(String time) throws ParseException { + this(TIME_FORMAT.parse(time).getTime()); + } + + @Override + public ValueBoolean isLowerThan(Value value) { + sameTypesOrThrow(value, Operation.COMPARE); + if(isNull() || value.isNull()) + return new ValueBoolean(null); + return new ValueBoolean(getValue() < ((ValueTime)value).getValue()); + } + + @Override + public ValueTime addValue(Value value) { + if(!value.getType().isCompatible(TypePrimitive.DURATION)) + throw new IncompatibleTypesException(getType(), value.getType(), Operation.ADD); + if(isNull() || value.isNull()) + return new ValueTime((Long)null); + return new ValueTime(getValue() + ((ValueDuration)value).getValue()); + } + + @Override + public Value subtract(Value value) { + if(value.getType().isCompatible(TypePrimitive.DURATION)) { + if(isNull() || value.isNull()) + return new ValueTime((Long)null); + return new ValueTime(getValue() - ((ValueDuration)value).getValue()); + } else if(value.getType().isCompatible(TypePrimitive.TIME)) { + if(isNull() || value.isNull()) + return new ValueTime((Long)null); + return new ValueDuration(getValue() - ((ValueTime)value).getValue()); + } + throw new IncompatibleTypesException(getType(), value.getType(), Operation.SUBTRACT); + + } + + @Override + public Value convertTo(Type type) { + switch(type.getPrimaryType()) { + case STRING: + return getValue() == null? ValueString.NULL_STRING : new ValueString(TIME_FORMAT.format(getValue())); + case TIME: + return this; + 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 new file mode 100644 index 0000000..a6b78da --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ZMI.java @@ -0,0 +1,166 @@ +/** + * Copyright (c) 2014, University of Warsaw + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package pl.edu.mimuw.cloudatlas.model; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; + +/** + * A zone management information object. This object is a single node in a zone hierarchy. It stores zone attributes as well as + * references to its father and sons in the tree. + */ +public class ZMI implements Cloneable { + private final AttributesMap attributes = new AttributesMap(); + + private final List sons = new ArrayList(); + private ZMI father; + + /** + * Creates a new ZMI with no father (the root zone) and empty sons list. + */ + public ZMI() { + this(null); + } + + /** + * Creates a new ZMI with the specified node as a father and empty sons list. This method does not perform any + * operation on father. In particular, setting this object father's son must be done + * separately. + * + * @param father the father of this ZMI + * @see #addSon(ZMI) + */ + public ZMI(ZMI father) { + this.father = father; + } + + /** + * Gets the father of this ZMI. + * + * @return the father of this ZMI or null if this is the root zone + */ + public ZMI getFather() { + return father; + } + + /** + * Sets or changes the father of this ZMI in the tree. This method does not perform any operation on + * father. In particular, setting this object as father's son must be done separately. + * + * @param father a new father for this ZMI + * @see #addSon(ZMI) + */ + public void setFather(ZMI father) { + this.father = father; + } + + /** + * Gets the list of sons of this ZMI. Modifying a value in the returned list will cause an exception. + * + * @return the list of sons + */ + public List getSons() { + return Collections.unmodifiableList(sons); + } + + /** + * Adds the specified ZMI to the list of sons of this ZMI. This method does not perform any operation on + * son. In particular, setting this object as son's father must be done separately. + * + * @param son + * @see #ZMI(ZMI) + * @see #setFather(ZMI) + */ + public void addSon(ZMI son) { + sons.add(son); + } + + /** + * Removes the specified ZMI from the list of sons of this ZMI. This method does not perform any operation on + * son. In particular, its father remains unchanged. + * + * @param son + * @see #setFather(ZMI) + */ + public void removeSon(ZMI son) { + sons.remove(son); + } + + /** + * Gets a map of all the attributes stored in this ZMI. + * + * @return map of attributes + */ + public AttributesMap getAttributes() { + return attributes; + } + + /** + * Prints recursively in a prefix order (starting from this ZMI) a whole tree with all the attributes. + * + * @param stream a destination stream + * @see #toString() + */ + public void printAttributes(PrintStream stream) { + for(Entry entry : attributes) + stream.println(entry.getKey() + " : " + entry.getValue().getType() + " = " + entry.getValue()); + System.out.println(); + for(ZMI son : sons) + son.printAttributes(stream); + } + + /** + * Creates an independent copy of a whole hierarchy. A returned ZMI has the same reference as father (but the + * father does not have a reference to it as a son). For the root zone, the copy is completely independent, since + * its father is null. + * + * @return a deep copy of this ZMI + */ + @Override + public ZMI clone() { + ZMI result = new ZMI(father); + result.attributes.add(attributes.clone()); + for(ZMI son : sons) { + ZMI sonClone = son.clone(); + result.sons.add(sonClone); + sonClone.father = result; + } + return result; + } + + /** + * Prints a textual representation of this ZMI. It contains only attributes of this node. + * + * @return a textual representation of this object + * @see #printAttributes(PrintStream) + */ + @Override + public String toString() { + return attributes.toString(); + } +} -- cgit v1.2.3