001package com.box.sdk;
002
003import com.eclipsesource.json.JsonArray;
004import com.eclipsesource.json.JsonObject;
005import com.eclipsesource.json.JsonValue;
006
007/**
008 * The Metadata class represents one type instance of Box metadata.
009 *
010 * Learn more about Box metadata:
011 * https://developers.box.com/metadata-api/
012 */
013public class Metadata {
014    private final JsonObject values;
015    private JsonArray operations;
016
017    /**
018     * Creates an empty metadata.
019     */
020    public Metadata() {
021        this.values = new JsonObject();
022    }
023
024    /**
025     * Creates a new metadata.
026     * @param values the initial metadata values.
027     */
028    Metadata(JsonObject values) {
029        this.values = values;
030    }
031
032    /**
033     * Creates a copy of another metadata.
034     * @param other the other metadata object to copy.
035     */
036    public Metadata(Metadata other) {
037        this.values = new JsonObject(other.values);
038    }
039
040    /**
041     * Returns the 36 character UUID to identify the metadata object.
042     * @return the metadata ID.
043     */
044    public String getID() {
045        return this.get("/$id");
046    }
047
048    /**
049     * Returns the metadata type.
050     * @return the metadata type.
051     */
052    public String getTypeName() {
053        return this.get("/$type");
054    }
055
056    /**
057     * Returns the parent object ID (typically the file ID).
058     * @return the parent object ID.
059     */
060    public String getParentID() {
061        return this.get("/$parent");
062    }
063
064    /**
065     * Returns the scope.
066     * @return the scope.
067     */
068    public String getScope() {
069        return this.get("/$scope");
070    }
071
072    /**
073     * Returns the template name.
074     * @return the template name.
075     */
076    public String getTemplateName() {
077        return this.get("/$template");
078    }
079
080    /**
081     * Adds a new metdata value.
082     * @param path the path that designates the key. Must be prefixed with a "/".
083     * @param value the value.
084     * @return this metadata object.
085     */
086    public Metadata add(String path, String value) {
087        this.values.add(this.pathToProperty(path), value);
088        this.addOp("add", path, value);
089        return this;
090    }
091
092    /**
093     * Replaces an existing metdata value.
094     * @param path the path that designates the key. Must be prefixed with a "/".
095     * @param value the value.
096     * @return this metadata object.
097     */
098    public Metadata replace(String path, String value) {
099        this.values.set(this.pathToProperty(path), value);
100        this.addOp("replace", path, value);
101        return this;
102    }
103
104    /**
105     * Removes an existing metadata value.
106     * @param path the path that designates the key. Must be prefixed with a "/".
107     * @return this metadata object.
108     */
109    public Metadata remove(String path) {
110        this.values.remove(this.pathToProperty(path));
111        this.addOp("remove", path, null);
112        return this;
113    }
114
115    /**
116     * Tests that a property has the expected value.
117     * @param path the path that designates the key. Must be prefixed with a "/".
118     * @param value the expected value.
119     * @return this metadata object.
120     */
121    public Metadata test(String path, String value) {
122        this.addOp("test", path, value);
123        return this;
124    }
125
126    /**
127     * Returns a value.
128     * @param path the path that designates the key. Must be prefixed with a "/".
129     * @return the metadata property value.
130     */
131    public String get(String path) {
132        final JsonValue value = this.values.get(this.pathToProperty(path));
133        if (value == null) {
134            return null;
135        }
136        return value.asString();
137    }
138
139    /**
140     * Returns the JSON patch string with all operations.
141     * @return the JSON patch string.
142     */
143    public String getPatch() {
144        if (this.operations == null) {
145            return "[]";
146        }
147        return this.operations.toString();
148    }
149
150    /**
151     * Returns the JSON representation of this metadata.
152     * @return the JSON representation of this metadata.
153     */
154    @Override
155    public String toString() {
156        return this.values.toString();
157    }
158
159    /**
160     * Converts a JSON patch path to a JSON property name.
161     * Currently the metadata API only supports flat maps.
162     * @param path the path that designates the key.  Must be prefixed with a "/".
163     * @return the JSON property name.
164     */
165    private String pathToProperty(String path) {
166        if (path == null || !path.startsWith("/")) {
167            throw new IllegalArgumentException("Path must be prefixed with a \"/\".");
168        }
169        return path.substring(1);
170    }
171
172    /**
173     * Adds a patch operation.
174     * @param op the operation type. Must be add, replace, remove, or test.
175     * @param path the path that designates the key. Must be prefixed with a "/".
176     * @param value the value to be set.
177     */
178    private void addOp(String op, String path, String value) {
179        if (this.operations == null) {
180            this.operations = new JsonArray();
181        }
182
183        this.operations.add(new JsonObject()
184                .add("op", op)
185                .add("path", path)
186                .add("value", value));
187    }
188}