diff options
Diffstat (limited to 'src/main/java/pl')
22 files changed, 3193 insertions, 0 deletions
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). + * <p> + * 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. + * <p> + * This class is immutable. + */ +public class Attribute { +    private final String name; + +    /** +     * Creates a new <code>Attribute</code> object with the specified <code>name</code>. +     * +     * @param name the name of the attribute +     * @throws IllegalArgumentException if the <code>name</code> 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 <code>attribute</code> 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 <code>attribute</code> 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 <code>Attribute</code> objects in +     * <code>HashMap</code>, <code>HashSet</code> 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 <code>object</code> is an instance of <code>Attribute</code> 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 <code>Attribute</code> to <code>Value</code>. It cannot contain duplicate keys. + */ +public class AttributesMap implements Iterable<Entry<Attribute, Value>>, Cloneable { +    private Map<Attribute, Value> map = new HashMap<Attribute, Value>(); + +    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 <code>attribute</code>-<code>value</code> mapping. The +     * <code>attribute</code> 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 <code>attribute</code> +     * @throws IllegalArgumentException if the <code>attribute</code> already exists in this map +     * @throws NullPointerException if either the <code>attribute</code> or the <code>value</code> is <code>null</code>; +     * for null value, create a <code>Value</code> object containing <code>null</code> +     * @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 <code>value</code>. 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<Attribute, Value> 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<Attribute, Value> entry : attributes.map.entrySet()) +            add(entry); +    } + +    /** +     * Adds to this map a new <code>attribute</code> mapping to the specified <code>value</code>. 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 <code>attribute</code> +     * @throws NullPointerException if either the <code>attribute</code> or the <code>value</code> is <code>null</code>; +     * for null value create a <code>Value</code> object containing <code>null</code> +     * @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 <code>value</code> 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<Attribute, Value> 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<Attribute, Value> 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 <code>attribute</code>. 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 <code>attribute</code> +     * @throws IllegalArgumentException if no value is mapped to <code>attribute</code> +     * @throws NullPointerException if <code>attribute</code> is <code>null</code> +     * @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 <code>attribute</code>. Unlike {@link #get(Attribute)}, this method +     * returns <code>null</code> if the requested mapping does not exist. +     * +     * @param attribute the attribute to obtain +     * @return the value mapped to <code>attribute</code> or <code>null</code> if it does not exist +     * @throws NullPointerException if the <code>attribute</code> is <code>null</code> +     * @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 <code>null</code> if it does not exist +     * @see #getOrNull(Attribute) +     * @see #getOr(String) +     */ +    public Value getOrNull(String name) { +        return getOrNull(new Attribute(name)); +    } + +    /** +     * Removes the specified <code>attribute</code> and its value from this map. If <code>attribute</code> does not +     * exist, this method doesn't do anything. +     * +     * @param attribute the attribute to remove +     * @throws NullPointerException if <code>attribute</code> is <code>null</code> +     * @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<Entry<Attribute, Value>> iterator() { +        return map.entrySet().iterator(); +    } + +    /** +     * Creates a copy of this map. Since <code>Value</code> and <code>Attribute</code> 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<String> components; +    private final String name; + +    /** +     * Creates a <code>PathName</code> object representing the specified path. For the root zone, there are three +     * accepted forms: <code>null</code> 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: <code>/warsaw/uw/violet07</code> +     * @throws IllegalArgumentException if the <code>name</code> 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<String>() : Arrays.asList(name.substring(1).split("/")); +    } + +    /** +     * Creates a <code>PathName</code> 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<String> components) { +        this.components = new ArrayList<String>(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<String> 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 <code>PathName</code> object representing a zone one level up in the hierarchy +     */ +    public PathName levelUp() { +        List<String> componentsUp = new ArrayList<String>(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 <code>PathName</code> 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 <code>PathName</code> object is equal to other objects of +     * the same class representing identical path names. +     * +     * @param object the object to check +     * @return whether <code>object</code>'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 <code>PathName</code>. 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 <code>Type</code> 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 <code>TypeCollection</code>) +     */ +    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<Value> 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 <code>Value</code> reference that is <code>null</code> +     * 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 <code>ValueBoolean</code> 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 <code>ValueBoolean</code> 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 <code>ValueBoolean</code> 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 <code>type</code> +     * @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 <code>ValueString</code>. +     * +     * @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 <code>0</code> for integer types, +     * <code>false</code> for boolean, <code>null</code> 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 <code>Boolean</code> object. + */ +public class ValueBoolean extends ValueSimple<Boolean> { +    /** +     * Constructs a new <code>ValueBoolean</code> object wrapping the specified <code>value</code>. +     * +     * @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. + * <p> + * This class is immutable. + */ +public class ValueContact extends Value { +    private final PathName name; +    private final InetAddress address; + +    /** +     * Constructs a new <code>ValueContact</code> 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 <code>Double</code> object. + */ +public class ValueDouble extends ValueSimple<Double> { +    /** +     * Constructs a new <code>ValueDouble</code> object wrapping the specified <code>value</code>. +     * +     * @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 + * <code>Long</code> object. + */ +public class ValueDuration extends ValueSimple<Long> { +    public static class InvalidFormatException extends IllegalArgumentException { +    } + +    /** +     * Regex pattern for duration strings. +     */ +    private static final Pattern DURATION_PATTERN = Pattern.compile( +        "(?<sign>[+-])(?<days>\\d+) " + +        "(?<hours>[0-1][0-9]|2[0-3]):(?<minutes>[0-5][0-9]):(?<seconds>[0-5][0-9])." + +        "(?<milliseconds>[0-9]{3})" +    ); + +    /** +     * Constructs a new <code>ValueDuration</code> object wrapping the specified <code>value</code>. +     * +     * @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 <code>ValueDuration</code> 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 <code>ValueDuration</code> 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 <code>ValueDuration</code> 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 <code>ValueDuration</code> 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 <code>ValueDuration</code> object from its textual representation. The representation has +     * format: <code>sd hh:mm:ss.lll</code> where: +     * <ul> +     * <li><code>s</code> is a sign (<code>+</code> or <code>-</code>),</li> +     * <li><code>d</code> is a number of days,</li> +     * <li><code>hh</code> is a number of hours (between <code>00</code> and <code>23</code>),</li> +     * <li><code>mm</code> is a number of minutes (between <code>00</code> and <code>59</code>),</li> +     * <li><code>ss</code> is a number of seconds (between <code>00</code> and <code>59</code>),</li> +     * <li><code>lll</code> is a number of milliseconds (between <code>000</code> and <code>999</code>).</li> +     * </ul> +     * <p> +     * All fields are obligatory. +     * +     * @param value a textual representation of a duration +     * @throws IllegalArgumentException if <code>value</code> 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 <code>Long</code> object. + */ +public class ValueInt extends ValueSimple<Long> { +    /** +     * Constructs a new <code>ValueInt</code> object wrapping the specified <code>value</code>. +     * +     * @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 <code>List</code> interface. + * <p> + * All constructors take a type of elements stored in this list. This type is checked when adding elements to the list + * and an <code>IllegalArgumentException</code> is thrown in case of a mismatch. + * + * @see java.util.List + */ +public class ValueList extends ValueSimple<List<Value>> implements List<Value> { +    private TypeCollection type; + +    /** +     * Creates a new <code>ValueList</code> 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> 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<Value>()); +        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 <code>List</code> containing all the objects stored in this value. Modifying the returned list will cause an +     * exception. +     */ +    @Override +    public List<Value> 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<Value> result = new ArrayList<Value>(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<Value> set = new HashSet<Value>(); +                    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<Value> list) { +        if(list == null) +            super.setValue(null); +        else { +            super.setValue(new ArrayList<Value>()); +            for(Value e : list) +                add(e); +        } +    } + +    private List<Value> 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<? extends Value> c) { +        for(Value e : c) +            checkElement(e); +        return getList().addAll(c); +    } + +    @Override +    public boolean addAll(int index, Collection<? extends Value> 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<Value> iterator() { +        return getList().iterator(); +    } + +    @Override +    public int lastIndexOf(Object o) { +        return getList().lastIndexOf(o); +    } + +    @Override +    public ListIterator<Value> listIterator() { +        return getList().listIterator(); +    } + +    @Override +    public ListIterator<Value> 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<Value> subList(int fromIndex, int toIndex) { +        return new ValueList(getList().subList(fromIndex, toIndex), type.getElementType()); +    } + +    @Override +    public Object[] toArray() { +        return getList().toArray(); +    } + +    @Override +    public <Y> 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 <code>ValueNull</code> class. Every call to this method returns the same +     * reference. +     * +     * @return an instance of <code>ValueNull</code> +     */ +    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 <code>Set</code> interface. + * <p> + * All constructors take a type of elements stored in this set. This type is checked when adding elements to the set and + * an <code>IllegalArgumentException</code> is thrown in case of a mismatch. + * + * @see java.util.Set + */ +public class ValueSet extends ValueSimple<Set<Value>> implements Set<Value> { +    private TypeCollection type; + +    /** +     * Creates a new <code>ValueSet</code> 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> 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<Value>()); +        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 <code>Set</code> containing all the objects stored in this value. Modifying the returned list will cause an +     * exception. +     */ +    @Override +    public Set<Value> 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<Value> result = new HashSet<Value>(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<Value> set) { +        if(set == null) +            super.setValue(null); +        else { +            super.setValue(new HashSet<Value>()); +            for(Value e : set) +                add(e); +        } +    } + +    private Set<Value> 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<? extends Value> 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<Value> 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> 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<Value> list = new ArrayList<Value>(); +                    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 <code>Value</code> objects. + * <p> + * This class is immutable. + * + * @param <T> a wrapped type + */ +abstract class ValueSimple<T> extends Value { +    private T value; + +    /** +     * Constructs a new <code>Value</code> wrapping the specified <code>value</code>. +     * +     * @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<T>)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 <code>String</code> object. + */ +public class ValueString extends ValueSimple<String> { +    /** +     * Result of converting values representing null to <code>ValueString</code>. +     */ +    protected static final ValueString NULL_STRING = new ValueString("NULL"); + +    /** +     * Constructs a new <code>ValueString</code> object wrapping the specified <code>value</code>. +     * +     * @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 <code>Long</code> object. + */ +public class ValueTime extends ValueSimple<Long> { +    /** +     * A format string for constructing from or converting to a <code>String</code> object. +     */ +    public static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); + +    /** +     * Constructs a new <code>ValueTime</code> 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 <code>ValueTime</code> object from its textual representation. +     * +     * @param time a time formatted according to {@link #TIME_FORMAT} +     * @throws ParseException if the <code>time</code> 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<ZMI> sons = new ArrayList<ZMI>(); +    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 <code>father</code>. In particular, setting this object <code>father</code>'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 <code>null</code> 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 +     * <code>father</code>. In particular, setting this object as <code>father</code>'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<ZMI> 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 +     * <code>son</code>. In particular, setting this object as <code>son</code>'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 +     * <code>son</code>. 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<Attribute, Value> 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 <code>null</code>. +     * +     * @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(); +    } +}  |