/******************************************************************************* * Copyright (c) 2010-2014 SAP AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * SAP AG - initial API and implementation *******************************************************************************/ package org.eclipse.skalli.services.rest; import java.io.IOException; import java.util.Collection; import java.util.UUID; import org.restlet.data.MediaType; /** * Interface for a writer for hierarchically structured REST formats like XML and JSON. * The interface is inspired by the <a href="http://json.org">JSON syntax</a> since * it distinguishes between arrays and objects as basic structures. However, it * supports also typical XML features like attributes and arrays with named elements. * <p> * Implementations of this interface should be derived from {@link RestWriterBase} * and must be registered as OSGI service. */ public interface RestWriter { /** * Enables the rendering of links with relative URLs (without web locator part) * instead of absolute URLs, which is the default. */ public static long RELATIVE_LINKS = 0x0001L; /** * Enables the rendering of blank object members, i.e. object members * with value equal to <code>null</code> or the empty string. * By default, such members are surpressed. */ public static long ALL_MEMBERS = 0x0002L; /** * Returns the {@link MediaType} this REST writer is able to produce. */ public MediaType getMediaType(); /** * Checks whether this writer is able to produce output for a given {@link MediaType}. * @param mediaType the media type to check. * @return <code>true</<code>, if this writer supports the given media type. */ public boolean isMediaType(MediaType mediaType); /** * Returns the web locator used to generated absolute URIs. * @return a web locator including protocol, host and port, or <code>null</code> * if no web locator has been specified. */ public String getHost(); /** * Concatenates the given path segments to a resource path. * Unless the option {@link #RELATIVE_LINKS} is set, the path is converted * to an absolute URL. * * @param pathSegments a list of path segments. * * @return either a relative path or the absolute URL of a resource. */ public String hrefOf(Object... pathSegments); /** * Checks if a given set of options is active. * * @param optionsMask an OR-combination of option flags. * @return <code>true</code> if all given options are active. */ public boolean isSet(long optionsMask); /** * Sets the given options. * * @param optionsMask an OR-combination of option flags to set. */ public RestWriter set(long optionsMask); /** * Resets the given options. * * @param optionsMask an OR-combination of option flags to reset. */ public RestWriter reset(long optionsMask); /** * Checks that all structures (arrays/objects) have been * closed properly and flushes the underlying writer. * All subsequent attempts to create new structures will fail. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the writer is not yet in the final state, * because there are structures that have not been closed properly. */ public void flush() throws IOException; /** * Defines the name for a subsequent structure, i.e. for an array or object. * * @param key the name to define, or <code>null</code>. */ public RestWriter key(String key) throws IOException; /** * Begins an array. * <p> * If a name has previously been defined with {@link #key(String)} the array is * rendered as named array. Otherwise depending on the requirements of the media type * a suitable default name is choosen. If the media type requires names for array elements, * a suitable default name is choosen for the elements. * <p> * Note, element names can be overriden individually with {@link #item(String)}. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter array() throws IOException; /** * Begins an array and defines the name for elements of that array * given the media type supports named array elements. * <p> * If a name has previously been defined with {@link #key(String)} the array is * rendered as named array. Otherwise depending on the requirements of the media type * a suitable default name is choosen. * <p> * Note, element names can be overriden individually with {@link #item(String)}. * * @param itemKey the default name to assign to the array elements, or <code>null</code>. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter array(String itemKey) throws IOException; /** * Begins a named array and defines the name for elements of that array * given the media type supports named array elements. * <p> * Note, element names can be overriden individually with {@link #item(String)}. * * @param key the name of the array, or <code>null</code>. Overrides any name that * has previously been defined with {@link #key(String)}. * @param itemKey the default name to assign to the array elements, or <code>null</code>. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter array(String key, String itemKey) throws IOException; /** * Begins the next element of an array ("item"). If the media type requires named * array elements a suitable default name is choosen. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached, * or the method was called outside of an array. */ public RestWriter item() throws IOException; /** * Begins the next element of an array (item) and defines the name for that and * all subsequent array elements given the media type supports named array elements. * * @param itemKey the name to assign to the next and all subsequent array elements, * or <code>null</code>. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached, * or the method was called outside of an array. */ public RestWriter item(String itemKey) throws IOException; /** * Begins an object. * <p> * If a name has previously been defined with {@link #key(String)} the object is * rendered as named object. Otherwise depending on the requirements of the media type * a suitable default name is choosen. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter object() throws IOException; /** * Begins a named object. * * @param key the name of the object, or <code>null</code>. Overrides any name that * has previously been defined with {@link #key(String)}. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter object(String key) throws IOException; /** * Ends an object, array or array element (item). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached, * or the method is used outside of an object, array or array element. */ public RestWriter end() throws IOException; /** * Begins a list of {@link #link(String, String) links}. * If the media type requires a name for the list, <tt>"links"</tt> is assumed. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter links() throws IOException; /** * Begins a named list of {@link #link(String, String) links}. * * @param key the name to assign to the link list. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter links(String key) throws IOException; /** * Appends a link with given relation type and target URL. * * @param rel the type of link relation. * @param href the absolute URL of the linked resource. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached, * or the method was used outside of an object, array or {@link #links() link list}. */ public RestWriter link(String rel, String href) throws IOException; /** * Appends a link with given relation type and resource path. * * @param rel the type of link relation. * @param pathSegments a list of path segments that are concatenated * by this method to form a relative resource path. Unless the option * {@link #RELATIVE_LINKS} is set, the path is converted to an absolute URL * before rendering. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached, * or the method was used outside of an object, array or {@link #links() link list}. */ public RestWriter link(String rel, Object... pathSegments) throws IOException; /** * Appends a string as next element to an array or as value to an object. * If the media type requires a name for the value of an object, <tt>"value"</tt> is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param s the string to append. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter value(String s) throws IOException; /** * Appends a long number as next element to an array or as value to an object. * If the media type requires a name for the value of an object, <tt>"value"</tt> is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param l the number to append. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter value(long l) throws IOException; /** * Appends a floating point number as next element to an array or as value to an object. * If the media type requires a name for the value of an object, <tt>"value"</tt> is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param d the floating point number to append. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter value(double d) throws IOException; /** * Appends a numerical value as next element to an array or as value to an object. * If the media type requires a name for the text value of an object, <tt>"value"</tt> is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param n the numerical value to append. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter value(Number n) throws IOException; /** * Appends a boolean value as next element to an array or as value to an object. * If the media type requires a name for the value of an object, <tt>"value"</tt> is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param b the boolean to append. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter value(boolean b) throws IOException; /** * Appends the string representation of a universally unique identifier (UUID) as next * element to an array or as value to an object. If the media type requires a name * for the value of an object, <tt>"value"</tt> is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param uuid the universally unique identifier (UUID) to append * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter value(UUID uuid) throws IOException; /** * Appends the string representation of a date given by the time in milliseconds * since January 1, 1970 as next element to an array or as value to an object. * The string representation contains the date and time as specified by ISO 8601 * following the pattern <tt>"yyyy-MM-dd'T'HH:mm:ss'Z'"</tt>. Timezone is always UTC. * This is compatible with the XML Schema type <tt>xsd:dateTime</tt>. * If the media type requires a name for the value of an object, <tt>"value"</tt> * is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param millis the date in milliseconds since January 1, 1970. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter datetime(long millis) throws IOException; /** * Appends the string representation of a date given by the time in milliseconds * since January 1, 1970 as next element to an array or as value to an object. * The string representation contains the date without the time as specified by ISO 8601 * following the pattern <tt>""yyyy-MM-dd""</tt>. Timezone is always UTC. * This is compatible with the XML Schema type <tt>xsd:date</tt>. * If the media type requires a name for the value of an object, <tt>"value"</tt> * is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param millis the date in milliseconds since January 1, 1970. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter date(long millis) throws IOException; /** * Appends the string representation of a time intervall given in milliseconds * as next element to an array or as value to an object. * The string representation follows ISO8601 period format. * If the media type requires a name for the value of an object, <tt>"value"</tt> * is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param millis the duration in milliseconds. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter duration(long millis) throws IOException; /** * Append an URL as next element to an array or as value to an object. * If the media type requires a name for the value of an object, <tt>"value"</tt> * is assumed. * <p> * Note, once a value has been appended to an object, no further members or attributes * can be appended to that object afterwards. * * @param pathSegments a list of path segments that are concatenated * by this method to form a relative resource path. Unless the option * {@link #RELATIVE_LINKS} is set, the path is converted to an absolute URL * before rendering. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object or array, * or the surrounding object already has a text value. */ public RestWriter href(Object... pathSegments) throws IOException; /** * Appends an object member with a string value. * * @param key the name the object member, never <code>null</code>. * @param value the value of the object member, or <code>null</code>. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter pair(String key, String value) throws IOException; /** * Appends an object member with a numerical value. * * @param key the name the object member, never <code>null</code>. * @param l the numerical value of the object member. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter pair(String key, long l) throws IOException; /** * Appends an object member with a floating point value. * * @param key the name the object member, never <code>null</code>. * @param d the floating point value of the object member. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter pair(String key, double d) throws IOException; /** * Appends an object member with a numerical value. * * @param key the name the object member, never <code>null</code>. * @param n the numerical value of the object member. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter pair(String key, Number n) throws IOException; /** * Appends an object member with a boolean value. * * @param key the name the object member, never <code>null</code>. * @param b the boolean value of the object member. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter pair(String key, boolean b) throws IOException; /** * Appends an object member with a universally unique identifier (UUID) as value. * * @param key the name the object member, never <code>null</code>. * @param uuid a universally unique identifier (UUID). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter pair(String key, UUID uuid) throws IOException; /** * Appends an object member with a date value. * * @param key the name the object member, never <code>null</code>. * @param millis a timestamp in milliseconds. The timestamp is converted * to ISO 8601 date representation (see {@link #date(long)}). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter date(String key, long millis) throws IOException; /** * Appends an object member with a date and time value. * * @param key the name the object member, never <code>null</code>. * @param millis a timestamp in milliseconds. The timestamp is converted * to ISO 8601 date/time representation (see {@link #datetime(long)}). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter datetime(String key, long millis) throws IOException; /** * Appends an object member representing a time intervall. * * @param key the name the object member, never <code>null</code>. * @param millis the time intervall in milliseconds. The time intervall is converted * to ISO 8601 time intervall representation (see {@link #duration(long)}). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter duration(String key, long millis) throws IOException; /** * Appends an object member with a <tt>"millis"</tt> attribute * followed by the ISO 8601 representation of the timestamp as text value. * * @param key the name the object member, never <code>null</code>. * @param millis a timestamp in milliseconds. The timestamp is converted * to ISO 8601 date/time representation (see {@link #datetime(long)}). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter timestamp(String key, long millis) throws IOException; /** * Appends an object member with an URL as value. * * @param key the name the object member, never <code>null</code>. * @param pathSegments a list of path segments that are concatenated * by this method to form a relative resource path. Unless the option * {@link #RELATIVE_LINKS} is set, the path is converted to an absolute URL * before rendering. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the key was <code>null</code>. */ public RestWriter href(String key, Object... pathSegments) throws IOException; /** * Appends an object attribute with a string value. * <p> * Note, attributes must be appended to an object before any other members * or text values. * * @param key the name of the attribute, never <code>null</code>. * @param value the value of the attribute, or <code>null</code>. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter attribute(String key, String value) throws IOException; /** * Appends an object attribute with a numerical value. * <p> * Note, attributes must be appended to an object before any other members * or text values. * * @param key the name of the attribute, never <code>null</code>. * @param l the numerical value of the attribute. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter attribute(String key, long l) throws IOException; /** * Appends an object attribute with a floating point value. * <p> * Note, attributes must be appended to an object before any other members * or text values. * * @param key the name of the attribute, never <code>null</code>. * @param d the floating point value of the attribute. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter attribute(String key, double d) throws IOException; /** * Appends an object attribute with a numerical value. * <p> * Note, attributes must be appended to an object before any other members * or text values. * * @param key the name of the attribute, never <code>null</code>. * @param n the numerical value of the attribute. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter attribute(String name, Number n) throws IOException; /** * Appends an object attribute with a boolean value. * <p> * Note, attributes must be appended to an object before any other members * or text values. * * @param key the name of the attribute, never <code>null</code>. * @param d the boolean value of the attribute. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter attribute(String key, boolean b) throws IOException; /** * Appends an object attribute with a boolean value. * <p> * Note, attributes must be appended to an object before any other members * or text values. * * @param key the name of the attribute, never <code>null</code>. * @param uuid a universally unique identifier (UUID). * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter attribute(String key, UUID uuid) throws IOException; /** * Appends a namespace attribute. * <p> * Note, namespace attributes must be appended to an object before any other members * or text values. * * @param key the namespace identifier including the namespace prefix, e.g. <tt>"xmlns:xsi"</tt>. * @param value the value of the namespace attribute, usually an URI. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the method was used outside of an object, * or the object has already members, or the key was <code>null</code>. */ public RestWriter namespace(String name, String value) throws IOException; /** * Appends the given collection as array of strings with given name and element name. * * @param key the name of the array, or <code>null</code>. Overrides any name that * has previously been defined with {@link #key(String)}. * @param itemKey the default name to assign to the array elements, or <code>null</code>. * @param values the collection to append. * * @throws IOException if an i/o error occured when writing to the underlying writer. * @throws IllegalStateException if the final state of this writer was already reached. */ public RestWriter collection(String key, String itemKey, Collection<String> values) throws IOException; }