diff --git a/.gitignore b/.gitignore index f837fd9..4c88021 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ target/* +/target/ diff --git a/README.md b/README.md index 5dad463..6b11b20 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Content page = new Content(); page.setType(Type.Page); page.setSpace( new Space("DEV")); page.setTitle("A page in DEV"); -page.setBody(new Body(new Storage(Storage.Representation.STORAGE, content))); +page.setBody(new Body(new Storage(content, Storage.Representation.STORAGE))); // post page to confluence. client.postContent(page); @@ -37,4 +37,4 @@ ContentResultList search ### Disclaimer -This library is currently still under active development, a MAVEN repository will be published when complete. \ No newline at end of file +This library is currently still under active development, a MAVEN repository will be published when complete. diff --git a/src/main/java/com/softwareleaf/confluence/ConfluenceAPI.java b/src/main/java/com/softwareleaf/confluence/ConfluenceAPI.java index 5d0da85..c2eccae 100644 --- a/src/main/java/com/softwareleaf/confluence/ConfluenceAPI.java +++ b/src/main/java/com/softwareleaf/confluence/ConfluenceAPI.java @@ -1,123 +1,134 @@ -package com.softwareleaf.confluence; - -import com.softwareleaf.confluence.model.*; -import retrofit.Callback; -import retrofit.http.*; -import retrofit.http.Body; - -import java.util.Map; - -/** - * Specifies the API paths that are so far supported with this confluence client. - * - * @author Jonathon Hope - * @since 29/05/2015 - */ -public interface ConfluenceAPI -{ - - /** - * Fetch a results object containing a paginated list of content. - * - * @return an instance of {@code getContentResults} wrapping the list - * of {@code Content} instances obtained from the API call. - */ - @GET("/rest/api/content") - ContentResultList getContentResults(); - - /** - * Perform a search for content, by space key and title. - * - * @param key the space key to search under. - * @param title the title of the piece of content to search for. - * @return an instance of {@code getContentResults} wrapping the list - * of {@code Content} instances obtained from the API call. - */ - @GET("/rest/api/content") - ContentResultList getContentBySpaceKeyAndTitle(@Query("key") String key, @Query("title") String title); - - /** - * GET Content - * - * @param id the id of the page or blog post to fetch. - * @return the Content instance representing the JSON response. - */ - @GET("/rest/api/content/{id}" + QueryParams.EXPAND_BODY_STORAGE) - Content getContentById(@Path("id") String id); - - /** - * POST Conversion request. Used for converting between storage formats. - * - * @param storage the storage instance to convert. - * @param convertToFormat the representation to convert to. - * @return an instance of {@code Storage} that contains the result of - * the conversion request. - */ - @POST("/rest/api/contentbody/convert/{to}") - Storage postContentConverstion(@Body Storage storage, @Path("to") String convertToFormat); - - /** - * POST Content. - * - * @param content the piece of Content to be included in the body of the request. - */ - @POST("/rest/api/content") - Content postContent(@Body Content content); - - /** - * Same as {@link #postContent} but clients can provide a callback with success - * and failure hooks. - * - * @param content the piece of Content to be included in the body of the request. - * @param callback this handle provides a means of inquiring about - * the success or failure of the invocation. - */ - @POST("/rest/api/content") - void postContentWithCallback(@Body Content content, Callback callback); - - /** - * DELETE Content - *

- * Trashes or purges a piece of Content, based on its {@literal ContentType} and {@literal ContentStatus}. - *

- * There are three cases: - * If the content is trashable and its status is {@literal ContentStatus#CURRENT}, it will be trashed. - * If the content is trashable, its status is {@literal ContentStatus#TRASHED} and the "status" query parameter in - * the request is "trashed", the content will be purged from the trash and deleted permanently. - * If the content is not trashable it will be deleted permanently without being trashed. - * - * @param id the id of the page of blog post to be deleted. - */ - @DELETE("/rest/api/content/{id}") - NoContent deleteContentById(@Path("id") String id); - - /** - * Obtain a result list of available spaces. - * - * @return an instance of {@code SpaceResultList} that can be used to - * obtain a list of spaces available on confluence. - */ - @GET("/rest/api/space") - SpaceResultList getSpaces(); - - /** - * Fetch all content from a confluence space. - * - * @param spaceKey the key that identifies the target Space. - * @param params the query parameters. - * @return a list of all content in the given Space identified by {@param spaceKey}. - */ - @GET("/rest/api/space/{spaceKey}/content/page") - ContentResultList getAllSpaceContent(@Path("spaceKey") String spaceKey, @QueryMap Map params); - - /** - * Obtain paginated results of root content available from a given space. - * - * @param spaceKey the space key of the space to search. - * @param contentType the type of content to return. - * @return a wrapper model around the {@link ContentResultList} resulting from this call. - */ - @GET("/rest/api/space/{spaceKey}/content/{type}") - ContentResultList getRootContentBySpaceKey(@Path("spaceKey") String spaceKey, @Path("type") String contentType); - -} +package com.softwareleaf.confluence; + +import java.util.Map; + +import retrofit.Callback; +import retrofit.http.Body; +import retrofit.http.DELETE; +import retrofit.http.GET; +import retrofit.http.POST; +import retrofit.http.Path; +import retrofit.http.Query; +import retrofit.http.QueryMap; + +import com.softwareleaf.confluence.model.Content; +import com.softwareleaf.confluence.model.ContentResultList; +import com.softwareleaf.confluence.model.NoContent; +import com.softwareleaf.confluence.model.SpaceResultList; +import com.softwareleaf.confluence.model.Storage; + +/** + * Specifies the API paths that are so far supported with this confluence client. + * + * @author Jonathon Hope + * @since 29/05/2015 + */ +public interface ConfluenceAPI +{ + /** + * Fetch a results object containing a paginated list of content. + * + * @return an instance of {@code getContentResults} wrapping the list + * of {@code Content} instances obtained from the API call. + */ + @GET("/rest/api/content") + ContentResultList getContentResults(); + + /** + * Perform a search for content, by space key and title. + * + * @param key the space key to search under. + * @param title the title of the piece of content to search for. + * @return an instance of {@code getContentResults} wrapping the list + * of {@code Content} instances obtained from the API call. + */ + @GET("/rest/api/content") + ContentResultList getContentBySpaceKeyAndTitle(@Query("key") String key, + @Query("title") String title); + + /** + * GET Content + * + * @param id the id of the page or blog post to fetch. + * @return the Content instance representing the JSON response. + */ + @GET("/rest/api/content/{id}" + QueryParams.EXPAND_BODY_STORAGE) + Content getContentById(@Path("id") String id); + + /** + * POST Conversion request. Used for converting between storage formats. + * + * @param storage the storage instance to convert. + * @param convertToFormat the representation to convert to. + * @return an instance of {@code Storage} that contains the result of + * the conversion request. + */ + @POST("/rest/api/contentbody/convert/{to}") + Storage postContentConverstion(@Body Storage storage, @Path("to") String convertToFormat); + + /** + * POST Content. + * + * @param content the piece of Content to be included in the body of the request. + */ + @POST("/rest/api/content") + Content postContent(@Body Content content); + + /** + * Same as {@link #postContent} but clients can provide a callback with success + * and failure hooks. + * + * @param content the piece of Content to be included in the body of the request. + * @param callback this handle provides a means of inquiring about + * the success or failure of the invocation. + */ + @POST("/rest/api/content") + void postContentWithCallback(@Body Content content, Callback callback); + + /** + * DELETE Content + *

+ * Trashes or purges a piece of Content, based on its {@literal ContentType} and {@literal ContentStatus}. + *

+ * There are three cases: + * If the content is trashable and its status is {@literal ContentStatus#CURRENT}, it will be trashed. + * If the content is trashable, its status is {@literal ContentStatus#TRASHED} and the "status" query parameter in + * the request is "trashed", the content will be purged from the trash and deleted permanently. + * If the content is not trashable it will be deleted permanently without being trashed. + * + * @param id the id of the page of blog post to be deleted. + */ + @DELETE("/rest/api/content/{id}") + NoContent deleteContentById(@Path("id") String id); + + /** + * Obtain a result list of available spaces. + * + * @return an instance of {@code SpaceResultList} that can be used to + * obtain a list of spaces available on confluence. + */ + @GET("/rest/api/space") + SpaceResultList getSpaces(); + + /** + * Fetch all content from a confluence space. + * + * @param spaceKey the key that identifies the target Space. + * @param params the query parameters. + * @return a list of all content in the given Space identified by {@param spaceKey}. + */ + @GET("/rest/api/space/{spaceKey}/content/page") + ContentResultList getAllSpaceContent(@Path("spaceKey") String spaceKey, + @QueryMap Map params); + + /** + * Obtain paginated results of root content available from a given space. + * + * @param spaceKey the space key of the space to search. + * @param contentType the type of content to return. + * @return a wrapper model around the {@link ContentResultList} resulting from this call. + */ + @GET("/rest/api/space/{spaceKey}/content/{type}") + ContentResultList getRootContentBySpaceKey(@Path("spaceKey") String spaceKey, + @Path("type") String contentType); +} \ No newline at end of file diff --git a/src/main/java/com/softwareleaf/confluence/ConfluenceClient.java b/src/main/java/com/softwareleaf/confluence/ConfluenceClient.java index 0de4e44..f3659d8 100644 --- a/src/main/java/com/softwareleaf/confluence/ConfluenceClient.java +++ b/src/main/java/com/softwareleaf/confluence/ConfluenceClient.java @@ -1,18 +1,24 @@ package com.softwareleaf.confluence; -import com.google.common.collect.ImmutableMap; -import com.google.gson.GsonBuilder; -import com.softwareleaf.confluence.model.*; -import retrofit.Callback; -import retrofit.RestAdapter; -import retrofit.converter.GsonConverter; - import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; +import retrofit.Callback; +import retrofit.RestAdapter; +import retrofit.converter.GsonConverter; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.GsonBuilder; +import com.softwareleaf.confluence.model.Content; +import com.softwareleaf.confluence.model.ContentResultList; +import com.softwareleaf.confluence.model.NoContent; +import com.softwareleaf.confluence.model.Space; +import com.softwareleaf.confluence.model.Storage; +import com.softwareleaf.confluence.model.Type; + /** * A class that is capable of making requests to the confluence API. *

@@ -49,19 +55,19 @@ public class ConfluenceClient /** * the Logger instance used by this class. */ - private static final Logger theLogger = Logger.getLogger( ConfluenceClient.class.getName() ); + private static final Logger theLogger = Logger.getLogger(ConfluenceClient.class.getName()); /** * The ConfluenceAPI endpoint. */ - private ConfluenceAPI myConfluenceAPI; + private final ConfluenceAPI myConfluenceAPI; /** * Constructor. */ - private ConfluenceClient( Builder builder ) + private ConfluenceClient(final Builder builder) { - this.myConfluenceAPI = builder.myConfluenceAPI; + myConfluenceAPI = builder.myConfluenceAPI; } /** @@ -70,9 +76,9 @@ private ConfluenceClient( Builder builder ) * @param id the id of the page or blog post to fetch. * @return the Content instance. */ - public Content getContentById( String id ) + public Content getContentById(final String id) { - return myConfluenceAPI.getContentById( id ); + return myConfluenceAPI.getContentById(id); } /** @@ -94,9 +100,9 @@ public ContentResultList getContentResults() * @return an instance of {@code getContentResults} wrapping the list * of {@code Content} instances obtained from the API call. */ - public ContentResultList getContentBySpaceKeyAndTitle( String key, String title ) + public ContentResultList getContentBySpaceKeyAndTitle(final String key, final String title) { - return myConfluenceAPI.getContentBySpaceKeyAndTitle( key, title ); + return myConfluenceAPI.getContentBySpaceKeyAndTitle(key, title); } /** @@ -109,9 +115,9 @@ public ContentResultList getContentBySpaceKeyAndTitle( String key, String title * @see * Confluence Storage Format */ - public Storage convertContent( Storage storage, Storage.Representation convertTo ) + public Storage convertContent(final Storage storage, final Storage.Representation convertTo) { - return myConfluenceAPI.postContentConverstion( storage, convertTo.toString() ); + return myConfluenceAPI.postContentConverstion(storage, convertTo.toString()); } /** @@ -122,9 +128,9 @@ public Storage convertContent( Storage storage, Storage.Representation convertTo * @param callback this handle provides a means of inquiring about * the success or failure of the invocation. */ - public void postContentWithCallback( Content content, Callback callback ) + public void postContentWithCallback(final Content content, final Callback callback) { - myConfluenceAPI.postContentWithCallback( content, callback ); + myConfluenceAPI.postContentWithCallback(content, callback); } /** @@ -133,10 +139,9 @@ public void postContentWithCallback( Content content, Callback callback * * @param content the content to post to confluence. */ - public Content postContent( Content content ) + public Content postContent(final Content content) { - System.out.println( content.toString() ); - return myConfluenceAPI.postContent( content ); + return myConfluenceAPI.postContent(content); } /** @@ -152,10 +157,10 @@ public Content postContent( Content content ) * * @param id the id of the page of blog post to be deleted. */ - public void deleteContentById( String id ) + public void deleteContentById(final String id) { - NoContent noContent = myConfluenceAPI.deleteContentById( id ); - theLogger.fine( "Response: " + noContent ); + final NoContent noContent = myConfluenceAPI.deleteContentById(id); + theLogger.fine("Response: " + noContent); } /** @@ -165,8 +170,8 @@ public void deleteContentById( String id ) */ public List getSpaces() { - Space[] results = myConfluenceAPI.getSpaces().getSpaces(); - return Arrays.stream( results ).collect( Collectors.toList() ); + final Space[] results = myConfluenceAPI.getSpaces().getSpaces(); + return Arrays.stream(results).collect(Collectors.toList()); } /** @@ -175,14 +180,14 @@ public List getSpaces() * @param spaceKey the key that identifies the target Space. * @return a list of all content in the given Space identified by {@param spaceKey}. */ - public List getAllSpaceContent( String spaceKey ) + public List getAllSpaceContent(final String spaceKey) { - Content[] results = myConfluenceAPI.getAllSpaceContent( spaceKey, + final Content[] results = myConfluenceAPI.getAllSpaceContent(spaceKey, ImmutableMap.of( "expand", "ancestors,body.storage", - "limit", "1000" ) ) + "limit", "1000" )) .getContents(); - return Arrays.stream( results ).collect( Collectors.toList() ); + return Arrays.stream(results).collect(Collectors.toList()); } /** @@ -192,12 +197,12 @@ public List getAllSpaceContent( String spaceKey ) * @param contentType the type of content to return. * @return a list of Content instances obtained from the root. */ - public List getRootContentBySpaceKey( String spaceKey, Type contentType ) + public List getRootContentBySpaceKey(final String spaceKey, final Type contentType) { - Content[] resultList = myConfluenceAPI + final Content[] resultList = myConfluenceAPI .getRootContentBySpaceKey( spaceKey, contentType.toString() ) .getContents(); - return Arrays.stream( resultList ).collect( Collectors.toList() ); + return Arrays.stream(resultList).collect(Collectors.toList()); } /** @@ -244,9 +249,9 @@ private Builder() * @param username the username. * @return {@code this}. */ - public Builder username( String username ) + public Builder username(final String username) { - this.myUsername = username; + myUsername = username; return this; } @@ -256,9 +261,9 @@ public Builder username( String username ) * @param password the password matching the username. * @return {@code this}. */ - public Builder password( String password ) + public Builder password(final String password) { - this.myPassword = password; + myPassword = password; return this; } @@ -269,9 +274,9 @@ public Builder password( String password ) * @param url the alternative Base url of the confluence instance to make requests to. * @return {@code this}. */ - public Builder baseURL( String url ) + public Builder baseURL(final String url) { - this.myAlternativeBaseURL = url; + myAlternativeBaseURL = url; return this; } @@ -285,8 +290,8 @@ public ConfluenceClient build() // determine if we are using the production confluence or not. final String URL = myAlternativeBaseURL == null ? THE_BASE_URL : myAlternativeBaseURL; // determine the user credentials to use. - String username = myUsername == null ? DEFAULT_USERNAME : myUsername; - String password = myPassword == null ? DEFAULT_PASSWORD : myPassword; + final String username = myUsername == null ? DEFAULT_USERNAME : myUsername; + final String password = myPassword == null ? DEFAULT_PASSWORD : myPassword; /* * The Confluence REST API requires HTTP Basic authentication using a * username and password pair, for a given Confluence user. @@ -297,25 +302,23 @@ public ConfluenceClient build() // encode in base64. final String encodedCredentials = "Basic " + Base64.getEncoder().encodeToString( credentials.getBytes() ); - RestAdapter restAdapter = new RestAdapter.Builder() - .setEndpoint( URL ) - .setConverter( new GsonConverter( new GsonBuilder().disableHtmlEscaping().create() ) ) - .setLogLevel( RestAdapter.LogLevel.FULL ) - .setLog( System.out::println ) + final RestAdapter restAdapter = new RestAdapter.Builder() + .setEndpoint(URL) + .setConverter(new GsonConverter(new GsonBuilder().disableHtmlEscaping().create())) + .setLogLevel(RestAdapter.LogLevel.FULL) + .setLog(System.out::println) .setRequestInterceptor( request -> { - request.addHeader( "Accept", "application/json" ); - request.addHeader( "Authorization", encodedCredentials ); + request.addHeader("Accept", "application/json"); + request.addHeader("Authorization", encodedCredentials); } ) .build(); // Create an implementation of the API defined by the specified ConfluenceAPI interface - this.myConfluenceAPI = restAdapter.create( ConfluenceAPI.class ); + myConfluenceAPI = restAdapter.create(ConfluenceAPI.class); - return new ConfluenceClient( this ); + return new ConfluenceClient(this); } - } - -} +} \ No newline at end of file diff --git a/src/main/java/com/softwareleaf/confluence/QueryParams.java b/src/main/java/com/softwareleaf/confluence/QueryParams.java index 5f989b8..c3e45c3 100644 --- a/src/main/java/com/softwareleaf/confluence/QueryParams.java +++ b/src/main/java/com/softwareleaf/confluence/QueryParams.java @@ -1,23 +1,22 @@ -package com.softwareleaf.confluence; - -/** - * An easy way to access common query params. - * - * @author Jonathon Hope - * @since 29/05/2015 - */ -public interface QueryParams -{ - /** - * This will expand the body.storage object of a request for particular content. - *

- * For example: - *

{@literal
-     *     GET /rest/api/content/757575775?expand=body.storage
-     * }
-     * 
- *

would expand the actual content stored in the page or blog post with the id 757575775. - */ - String EXPAND_BODY_STORAGE = "?expand=body.storage"; - -} +package com.softwareleaf.confluence; + +/** + * An easy way to access common query params. + * + * @author Jonathon Hope + * @since 29/05/2015 + */ +public interface QueryParams +{ + /** + * This will expand the body.storage object of a request for particular content. + *

+ * For example: + *

{@literal
+     *     GET /rest/api/content/757575775?expand=body.storage
+     * }
+     * 
+ *

would expand the actual content stored in the page or blog post with the id 757575775. + */ + String EXPAND_BODY_STORAGE = "?expand=body.storage"; +} diff --git a/src/main/java/com/softwareleaf/confluence/macro/CodeBlockMacro.java b/src/main/java/com/softwareleaf/confluence/macro/CodeBlockMacro.java index 99e4941..39f0899 100644 --- a/src/main/java/com/softwareleaf/confluence/macro/CodeBlockMacro.java +++ b/src/main/java/com/softwareleaf/confluence/macro/CodeBlockMacro.java @@ -1,333 +1,331 @@ -package com.softwareleaf.confluence.macro; - -import java.util.EnumMap; -import java.util.Map; - -/** - * Represents a confluence Code Block Macro. - * - * @author Jonathon Hope - * @see - * Confluence Page describing the Macro - * @since 28/05/2015 - */ -public class CodeBlockMacro -{ - - /** - * Stores the parameters of this code block macro. - */ - private EnumMap myParameters; - /** - * The code of this CodeBlockMacro. - */ - private String myBody; - - /** - * Parameters are options that you can set to control the content or format of the macro output. - */ - public enum Parameters - { - /** - * Can be either {@literal true} or {@literal false} - * Default: false - */ - COLLAPSE, - /** - * When Show line numbers is selected, this value defines the number of the first line of code. - * Default: 1 - */ - FIRSTlINE, - /** - * Specifies the language (or environment) for syntax highlighting. The default language is Java but you can - * choose from one of the following languages/environments: - * - * @see CodeBlockMacro.Languages - */ - LANGUAGE, - /** - * If selected, line numbers will be shown to the left of the lines of code. - * Default: false - */ - LINENUMBERS, - /** - * Specifies the colour scheme used for displaying your code block. Many of these themes are based on the - * default colour schemes of popular integrated development environments (IDEs). The default theme is - * Confluence (also known as Default), which is typically black and coloured text on a blank background. - * However, you can also choose from one of the following other popular themes: - * - * @see CodeBlockMacro.Themes - */ - THEME, - /** - * Adds a title to the code block. If specified, the title will be displayed in a header row at the top - * of the code block. - * Default: none - */ - TITLE; - - @Override - public String toString() - { - // replace the underscore with a slash and print as lower case - return this.name().replace("_", "/").toLowerCase(); - } - - } - - /** - * The enumerated list of languages supported by the confluence code macro. - */ - public enum Languages - { - ACTION_SCRIPT_3("actionscript3"), - BASH("bash"), - C_SHARP("c#"), // (C#) - COLD_FUSION("coldfusion"), - CPP("cpp"), //(C++) - CSS("css"), - DELPHI("delphi"), - DIFF("diff"), - ERLANG("erlang"), - GROOVY("groovy"), - HTML_XML("xml"), // html/xml - JAVA("java"), - JAVA_FX("javafx"), - JAVA_SCRIPT("js"), // JavaScript - NONE("none"), // (no syntax highlighting) - PERL("perl"), - PHP("php"), - POWER_SHELL("powershell"), - PYTHON("python"), - RUBY("ruby"), - SCALA("scala"), - SQL("sql"), - VB("vb"); - - public final String value; - - Languages(String value) - { - this.value = value; - } - - @Override - public String toString() - { - return this.value; - } - } - - /** - * The available values for the Theme parameter. - * - * @see CodeBlockMacro.Parameters#THEME - */ - public enum Themes - { - D_JANGO, - EMACS, - FADE_TO_GREY, - MIDNIGHT, - R_DARK, - ECLIPSE, - CONFLUENCE; - - /** - * Motivation: Necessary to keep consistent with UPPER CASE naming convention for enums, - * whilst outputting the expected format of the macro value. - * - * @param theme the String to convert. - * @return a String in Upper Camel Case format. - */ - private String convertToUpperCamel(String theme) - { - StringBuilder sb = new StringBuilder(); - for (String s : theme.split("_")) - { - sb.append(Character.toUpperCase(s.charAt(0))); - if (s.length() > 1) - { - sb.append(s.substring(1, s.length()).toLowerCase()); - } - } - return sb.toString(); - } - - @Override - public String toString() - { - return convertToUpperCamel(super.toString()); - } - } - - - /** - * Constructor. - * - * @param builder the builder instance to use as a factory. - * @see CodeBlockMacro.Builder - */ - protected CodeBlockMacro(Builder builder) - { - this.myParameters = builder.myParameters; - this.myBody = builder.myCode; - } - - /** - * Converts this CodeBlockMacro into confluence markup form. - * - * @see Confluence Page describing the Macro - */ - public String toMarkup() - { - StringBuilder sb = new StringBuilder(); - sb.append(""); - for (Map.Entry entry : myParameters.entrySet()) - { - sb.append(""); - sb.append(entry.getValue()); - sb.append(""); - } - sb.append(""); - sb.append(myBody); - sb.append(""); - sb.append(""); - return sb.toString(); - } - - /** - * Builder factory method. - * - * @return a {@code Builder} instance for chain-building a CodeBlockMacro. - */ - public static Builder builder() - { - return new Builder(); - } - - /** - * A class for implementing the Builder Pattern for {@code CodeBlockMacro}. - */ - public static class Builder - { - private EnumMap myParameters; - private String myCode; - - /** - * Constructor. - */ - private Builder() - { - myParameters = new EnumMap<>(Parameters.class); - } - - /** - * @return a new instance of {@code CodeBlockMacro}. - */ - public CodeBlockMacro build() - { - return new CodeBlockMacro(this); - } - - /** - *

Example - *

{@literal
-         *      xml
-         * }
- *

would be represented as: - *

{@code
-         *      CodeBlockMacro.builder().language(Languages.HTML_XML)
-         * }
- * - * @param l the Languages enum. - * @see CodeBlockMacro.Languages - */ - public Builder language(Languages l) - { - myParameters.putIfAbsent(Parameters.LANGUAGE, l.value); - return this; - } - - /** - *

Makes the macro collapsible: - *

{@literal
-         *      true
-         * }
- */ - public Builder collapse() - { - myParameters.putIfAbsent(Parameters.COLLAPSE, "true"); - return this; - } - - /** - *

Enables linenumbers: - *

{@literal
-         *      true
-         * }
- */ - public Builder showLineNumbers() - { - myParameters.putIfAbsent(Parameters.LINENUMBERS, "true"); - return this; - } - - /** - *

If {@code Parameters.LINENUMBERS} is set, sets the first line number to start at {@param first}: - *

{@literal
-         *      true1
-         * }
- */ - public Builder firstline(int first) - { - - if (myParameters.containsKey(Parameters.LINENUMBERS)) - { - myParameters.putIfAbsent(Parameters.FIRSTlINE, Integer.toString(first)); - } - - return this; - } - - /** - *

Adds a theme, for example; adding eclipse theme: - *

{@literal
-         *      Eclipse
-         * }
- */ - public Builder theme(Themes theme) - { - myParameters.putIfAbsent(Parameters.THEME, theme.toString()); - return this; - } - - /** - *

Sets the title for the code block, for example, here we call it {@literal "Request"}: - *

{@literal
-         *      Request
-         * }
- */ - public Builder title(String title) - { - myParameters.putIfAbsent(Parameters.TITLE, title); - return this; - } - - /** - * The code to be displayed by this code body. - * - * @param code the code contents, as a String. - * @return {@code this}. - */ - public Builder code(String code) - { - // escape code in wrapper - this.myCode = ""; - return this; - } - } - -} +package com.softwareleaf.confluence.macro; + +import java.util.EnumMap; +import java.util.Map; + +/** + * Represents a confluence Code Block Macro. + * + * @author Jonathon Hope + * @see + * Confluence Page describing the Macro + * @since 28/05/2015 + */ +public class CodeBlockMacro +{ + /** + * Stores the parameters of this code block macro. + */ + private final EnumMap myParameters; + /** + * The code of this CodeBlockMacro. + */ + private final String myBody; + + /** + * Parameters are options that you can set to control the content or format of the macro output. + */ + public enum Parameters + { + /** + * Can be either {@literal true} or {@literal false} + * Default: false + */ + COLLAPSE, + /** + * When Show line numbers is selected, this value defines the number of the first line of code. + * Default: 1 + */ + FIRSTlINE, + /** + * Specifies the language (or environment) for syntax highlighting. The default language is Java but you can + * choose from one of the following languages/environments: + * + * @see CodeBlockMacro.Languages + */ + LANGUAGE, + /** + * If selected, line numbers will be shown to the left of the lines of code. + * Default: false + */ + LINENUMBERS, + /** + * Specifies the colour scheme used for displaying your code block. Many of these themes are based on the + * default colour schemes of popular integrated development environments (IDEs). The default theme is + * Confluence (also known as Default), which is typically black and coloured text on a blank background. + * However, you can also choose from one of the following other popular themes: + * + * @see CodeBlockMacro.Themes + */ + THEME, + /** + * Adds a title to the code block. If specified, the title will be displayed in a header row at the top + * of the code block. + * Default: none + */ + TITLE; + + @Override + public String toString() + { + // replace the underscore with a slash and print as lower case + return name().replace("_", "/").toLowerCase(); + } + + } + + /** + * The enumerated list of languages supported by the confluence code macro. + */ + public enum Languages + { + ACTION_SCRIPT_3("actionscript3"), + BASH("bash"), + C_SHARP("c#"), // (C#) + COLD_FUSION("coldfusion"), + CPP("cpp"), //(C++) + CSS("css"), + DELPHI("delphi"), + DIFF("diff"), + ERLANG("erlang"), + GROOVY("groovy"), + HTML_XML("xml"), // html/xml + JAVA("java"), + JAVA_FX("javafx"), + JAVA_SCRIPT("js"), // JavaScript + NONE("none"), // (no syntax highlighting) + PERL("perl"), + PHP("php"), + POWER_SHELL("powershell"), + PYTHON("python"), + RUBY("ruby"), + SCALA("scala"), + SQL("sql"), + VB("vb"); + + public final String value; + + Languages(final String value) + { + this.value = value; + } + + @Override + public String toString() + { + return value; + } + } + + /** + * The available values for the Theme parameter. + * + * @see CodeBlockMacro.Parameters#THEME + */ + public enum Themes + { + D_JANGO, + EMACS, + FADE_TO_GREY, + MIDNIGHT, + R_DARK, + ECLIPSE, + CONFLUENCE; + + /** + * Motivation: Necessary to keep consistent with UPPER CASE naming convention for enums, + * whilst outputting the expected format of the macro value. + * + * @param theme the String to convert. + * @return a String in Upper Camel Case format. + */ + private static String convertToUpperCamel(final String theme) + { + final StringBuilder sb = new StringBuilder(); + for (final String s : theme.split("_")) + { + sb.append(Character.toUpperCase(s.charAt(0))); + if (s.length() > 1) + { + sb.append(s.substring(1, s.length()).toLowerCase()); + } + } + return sb.toString(); + } + + @Override + public String toString() + { + return convertToUpperCamel(super.toString()); + } + } + + + /** + * Constructor. + * + * @param builder the builder instance to use as a factory. + * @see CodeBlockMacro.Builder + */ + protected CodeBlockMacro(final Builder builder) + { + myParameters = builder.myParameters; + myBody = builder.myCode; + } + + /** + * Converts this CodeBlockMacro into confluence markup form. + * + * @see Confluence Page describing the Macro + */ + public String toMarkup() + { + final StringBuilder sb = new StringBuilder(); + sb.append(""); + for (final Map.Entry entry : myParameters.entrySet()) + { + sb.append(""); + sb.append(entry.getValue()); + sb.append(""); + } + sb.append(""); + sb.append(myBody); + sb.append(""); + sb.append(""); + return sb.toString(); + } + + /** + * Builder factory method. + * + * @return a {@code Builder} instance for chain-building a CodeBlockMacro. + */ + public static Builder builder() + { + return new Builder(); + } + + /** + * A class for implementing the Builder Pattern for {@code CodeBlockMacro}. + */ + public static class Builder + { + private final EnumMap myParameters; + private String myCode; + + /** + * Constructor. + */ + private Builder() + { + myParameters = new EnumMap<>(Parameters.class); + } + + /** + * @return a new instance of {@code CodeBlockMacro}. + */ + public CodeBlockMacro build() + { + return new CodeBlockMacro(this); + } + + /** + *

Example + *

{@literal
+         *      xml
+         * }
+ *

would be represented as: + *

{@code
+         *      CodeBlockMacro.builder().language(Languages.HTML_XML)
+         * }
+ * + * @param l the Languages enum. + * @see CodeBlockMacro.Languages + */ + public Builder language(final Languages l) + { + myParameters.putIfAbsent(Parameters.LANGUAGE, l.value); + return this; + } + + /** + *

Makes the macro collapsible: + *

{@literal
+         *      true
+         * }
+ */ + public Builder collapse() + { + myParameters.putIfAbsent(Parameters.COLLAPSE, "true"); + return this; + } + + /** + *

Enables linenumbers: + *

{@literal
+         *      true
+         * }
+ */ + public Builder showLineNumbers() + { + myParameters.putIfAbsent(Parameters.LINENUMBERS, "true"); + return this; + } + + /** + *

If {@code Parameters.LINENUMBERS} is set, sets the first line number to start at {@param first}: + *

{@literal
+         *      true1
+         * }
+ */ + public Builder firstline(final int first) + { + + if (myParameters.containsKey(Parameters.LINENUMBERS)) + { + myParameters.putIfAbsent(Parameters.FIRSTlINE, Integer.toString(first)); + } + + return this; + } + + /** + *

Adds a theme, for example; adding eclipse theme: + *

{@literal
+         *      Eclipse
+         * }
+ */ + public Builder theme(final Themes theme) + { + myParameters.putIfAbsent(Parameters.THEME, theme.toString()); + return this; + } + + /** + *

Sets the title for the code block, for example, here we call it {@literal "Request"}: + *

{@literal
+         *      Request
+         * }
+ */ + public Builder title(final String title) + { + myParameters.putIfAbsent(Parameters.TITLE, title); + return this; + } + + /** + * The code to be displayed by this code body. + * + * @param code the code contents, as a String. + * @return {@code this}. + */ + public Builder code(final String code) + { + // escape code in wrapper + myCode = ""; + return this; + } + } +} diff --git a/src/main/java/com/softwareleaf/confluence/macro/ExpandMacro.java b/src/main/java/com/softwareleaf/confluence/macro/ExpandMacro.java index 7563bf7..1b09e03 100644 --- a/src/main/java/com/softwareleaf/confluence/macro/ExpandMacro.java +++ b/src/main/java/com/softwareleaf/confluence/macro/ExpandMacro.java @@ -1,87 +1,85 @@ -package com.softwareleaf.confluence.macro; - -/** - * Represents an expandable body of rich text. - * - * @author Jonathon Hope - * @see Expand Macro docs - * @since 3/07/2015 - */ -public class ExpandMacro -{ - - /** - * The title of the expandable. - */ - private String myTitle; - /** - * The contents of the expandable. - */ - private String myBody; - - /** - * @param builder the builder factory to use. - */ - protected ExpandMacro(Builder builder) - { - this.myTitle = builder.myTitle; - this.myBody = builder.myBody; - } - - /** - * @return converts this instance to confluence markup. - */ - public String toMarkup() - { - StringBuilder sb = new StringBuilder(); - sb.append(""); - sb.append(""); - sb.append(myTitle); - sb.append(""); - - sb.append(""); - sb.append(myBody); - sb.append(""); - sb.append(""); - return sb.toString(); - } - - /** - * Builder factory method. - * - * @return a {@code Builder} instance for chain-building a {@code ExpandMacro}. - */ - public static Builder builder() - { - return new Builder(); - } - - /** - * A class for implementing the Builder Pattern for {@code ExpandMacro}. - */ - public static class Builder - { - - private String myTitle; - private String myBody; - - public Builder title(String title) - { - this.myTitle = title; - return this; - } - - public Builder body(String body) - { - this.myBody = body; - return this; - } - - public ExpandMacro build() - { - return new ExpandMacro(this); - } - - } - -} +package com.softwareleaf.confluence.macro; + +/** + * Represents an expandable body of rich text. + * + * @author Jonathon Hope + * @see Expand Macro docs + * @since 3/07/2015 + */ +public class ExpandMacro +{ + /** + * The title of the expandable. + */ + private final String myTitle; + /** + * The contents of the expandable. + */ + private final String myBody; + + /** + * @param builder the builder factory to use. + */ + protected ExpandMacro(final Builder builder) + { + myTitle = builder.myTitle; + myBody = builder.myBody; + } + + /** + * @return converts this instance to confluence markup. + */ + public String toMarkup() + { + final StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append(""); + sb.append(myTitle); + sb.append(""); + + sb.append(""); + sb.append(myBody); + sb.append(""); + sb.append(""); + return sb.toString(); + } + + /** + * Builder factory method. + * + * @return a {@code Builder} instance for chain-building a {@code ExpandMacro}. + */ + public static Builder builder() + { + return new Builder(); + } + + /** + * A class for implementing the Builder Pattern for {@code ExpandMacro}. + */ + public static class Builder + { + + private String myTitle; + private String myBody; + + public Builder title(final String title) + { + myTitle = title; + return this; + } + + public Builder body(final String body) + { + myBody = body; + return this; + } + + public ExpandMacro build() + { + return new ExpandMacro(this); + } + + } +} diff --git a/src/main/java/com/softwareleaf/confluence/macro/HtmlMacro.java b/src/main/java/com/softwareleaf/confluence/macro/HtmlMacro.java index e493d83..41612a3 100644 --- a/src/main/java/com/softwareleaf/confluence/macro/HtmlMacro.java +++ b/src/main/java/com/softwareleaf/confluence/macro/HtmlMacro.java @@ -1,45 +1,44 @@ -package com.softwareleaf.confluence.macro; - -/** - * The HTML macro allows you to add HTML code to a Confluence page. - * - * @author Jonathon Hope - * @see HTML Macro Documentation - * @since 11/06/2015 - */ -public class HtmlMacro -{ - /** - * The HTML source. - */ - private final String content; - - /** - * Constructor. - * - * @param content the HTML source. - * NOTE: This cannot contain a {@literal } tag. - */ - public HtmlMacro(String content) - { - this.content = content; - } - - /** - * @return a structured macro (XML formatted) String, according to the confluence HTML Macro documentation. - */ - public String toMarkup() - { - final StringBuilder sb = new StringBuilder(content.length() + 140); - sb.append(""); - sb.append(""); - sb.append(""); - sb.append(""); - - return sb.toString(); - } - -} +package com.softwareleaf.confluence.macro; + +/** + * The HTML macro allows you to add HTML code to a Confluence page. + * + * @author Jonathon Hope + * @see HTML Macro Documentation + * @since 11/06/2015 + */ +public class HtmlMacro +{ + /** + * The HTML source. + */ + private final String content; + + /** + * Constructor. + * + * @param content the HTML source. + * NOTE: This cannot contain a {@literal } tag. + */ + public HtmlMacro(final String content) + { + this.content = content; + } + + /** + * @return a structured macro (XML formatted) String, according to the confluence HTML Macro documentation. + */ + public String toMarkup() + { + final StringBuilder sb = new StringBuilder(content.length() + 140); + sb.append(""); + sb.append(""); + sb.append(""); + sb.append(""); + + return sb.toString(); + } +} diff --git a/src/main/java/com/softwareleaf/confluence/macro/JiraIssuesMacro.java b/src/main/java/com/softwareleaf/confluence/macro/JiraIssuesMacro.java index 50e99fd..8aa1df0 100644 --- a/src/main/java/com/softwareleaf/confluence/macro/JiraIssuesMacro.java +++ b/src/main/java/com/softwareleaf/confluence/macro/JiraIssuesMacro.java @@ -1,8 +1,5 @@ package com.softwareleaf.confluence.macro; -import com.softwareleaf.confluence.ConfluenceClient; -import com.softwareleaf.confluence.model.Storage; - import java.net.URL; import java.util.Arrays; import java.util.EnumMap; @@ -10,6 +7,9 @@ import java.util.Objects; import java.util.stream.Collectors; +import com.softwareleaf.confluence.ConfluenceClient; +import com.softwareleaf.confluence.model.Storage; + /** * A class for building the requisite markup for a JIRA Issues Macro. * @@ -19,7 +19,6 @@ */ public class JiraIssuesMacro { - /** * Parameters are options that you can set to control the content or format of the macro output. */ @@ -109,10 +108,10 @@ public enum Parameters * @param string the String to convert. * @return a String in Camel Case format. */ - private String convertToCamelCase(String string) + private static String convertToCamelCase(final String string) { - StringBuilder sb = new StringBuilder(); - String[] parts = string.split("_"); + final StringBuilder sb = new StringBuilder(); + final String[] parts = string.split("_"); sb.append(parts[0].toLowerCase()); for (int i = 1; i <= parts.length - 1; i++) { @@ -121,7 +120,7 @@ private String convertToCamelCase(String string) return sb.toString(); } - private String toProperCase(String s) + private static String toProperCase(final String s) { return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); @@ -192,16 +191,16 @@ public String toString() /** * Stores the parameters of this code block macro. */ - private EnumMap parameters; + private final EnumMap parameters; /** * Constructor * * @param builder the builder factory used to build this {@code JiraIssuesMacro} */ - protected JiraIssuesMacro(Builder builder) + protected JiraIssuesMacro(final Builder builder) { - this.parameters = builder.myParameters; + parameters = builder.myParameters; } /** @@ -211,9 +210,9 @@ protected JiraIssuesMacro(Builder builder) */ public String toWikiMarkup() { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append("{jiraissues:"); - for (Map.Entry entry : parameters.entrySet()) + for (final Map.Entry entry : parameters.entrySet()) { sb.append(entry.getKey().toString()); sb.append("="); @@ -235,7 +234,7 @@ public String toWikiMarkup() public String toStorageRepresentation(ConfluenceClient client) { client = Objects.requireNonNull(client); - Storage wikiStorage = new Storage(toWikiMarkup(), Storage.Representation.WIKI.toString()); + final Storage wikiStorage = new Storage(toWikiMarkup(), Storage.Representation.WIKI); return client.convertContent(wikiStorage, Storage.Representation.STORAGE).getValue(); } @@ -254,7 +253,7 @@ public static Builder builder() */ public static class Builder { - private EnumMap myParameters; + private final EnumMap myParameters; // constructor private Builder() @@ -279,9 +278,9 @@ public JiraIssuesMacro build() * @return {@code this}. * @see JiraIssuesMacro.Columns */ - public Builder columns(Columns[] columns) + public Builder columns(final Columns[] columns) { - String cols = Arrays.stream(columns) + final String cols = Arrays.stream(columns) .map(Columns::toString).collect(Collectors.joining(",")); myParameters.putIfAbsent(Parameters.COLUMNS, cols); return this; @@ -292,7 +291,7 @@ public Builder columns(Columns[] columns) * @return {@code this}. * @see Parameters#COUNT */ - public Builder count(boolean count) + public Builder count(final boolean count) { myParameters.putIfAbsent(Parameters.COUNT, Boolean.toString(count)); return this; @@ -303,7 +302,7 @@ public Builder count(boolean count) * @return {@code this} * @see JiraIssuesMacro.Parameters#CACHE */ - public Builder cache(Cache cache) + public Builder cache(final Cache cache) { myParameters.putIfAbsent(Parameters.CACHE, cache.toString()); return this; @@ -315,7 +314,7 @@ public Builder cache(Cache cache) * @param height the height value. * @return {@code this} */ - public Builder height(int height) + public Builder height(final int height) { if (height >= 200) { @@ -328,7 +327,7 @@ public Builder height(int height) * @param renderMode the {@link JiraIssuesMacro.RenderMode} to set. * @return {@code this} */ - public Builder renderMode(RenderMode renderMode) + public Builder renderMode(final RenderMode renderMode) { myParameters.putIfAbsent(Parameters.RENDER_MODE, renderMode.toString()); return this; @@ -343,7 +342,7 @@ public Builder renderMode(RenderMode renderMode) * @param title the title to set. * @return {@code this}. */ - public Builder title(String title) + public Builder title(final String title) { myParameters.putIfAbsent(Parameters.TITLE, title); return this; @@ -355,7 +354,7 @@ public Builder title(String title) * @param url the URL to set. * @return {@code this}. */ - public Builder url(URL url) + public Builder url(final URL url) { myParameters.putIfAbsent(Parameters.URL, url.toString()); return this; @@ -367,7 +366,7 @@ public Builder url(URL url) * @param percentage a value must be greater or equal to {@code 500}. * @return {@code this}. */ - public Builder width(int percentage) + public Builder width(final int percentage) { if (percentage >= 500) { @@ -388,5 +387,4 @@ private void checkParameters() } } - } diff --git a/src/main/java/com/softwareleaf/confluence/macro/TableOfContentsMacro.java b/src/main/java/com/softwareleaf/confluence/macro/TableOfContentsMacro.java index e7a2c7c..9b42eba 100644 --- a/src/main/java/com/softwareleaf/confluence/macro/TableOfContentsMacro.java +++ b/src/main/java/com/softwareleaf/confluence/macro/TableOfContentsMacro.java @@ -1,485 +1,484 @@ -package com.softwareleaf.confluence.macro; - -import java.util.EnumMap; -import java.util.Map; - -/** - * Represents a confluence Table of Contents Macro. - *

- * Usage - *

{@literal
- * String macro = TableOfContentsMacro.builder()
- *      .enableNumbering()
- *      .outputType(OutputType.LIST)
- *      .bulletPointStyle(ListStyle.NONE)
- *      .build()
- *      .toWikiMarkup();
- * }
- * - * @author Jonathon Hope - * @see table of Contents - * Macro Documentation - * @since 16/06/2015 - */ -public class TableOfContentsMacro -{ - - /** - * Parameters are options that you can set to control the content or format of the macro output. - */ - public enum Parameters - { - /** - * Enables section numbering. - *
{@literal
-         *      true
-         * }
- */ - OUTLINE, - /** - * @see TableOfContentsMacro.OutputType - */ - TYPE, - /** - * The style of bullet point to use. - * - * @see TableOfContentsMacro.ListStyle - */ - STYLE, - /** - * Sets the indent for a list according to CSS quantities. Entering 10px - * will successively indent heading groups by 10px. For example, level 1 - * headings will be indented 10px and level 2 headings will be indented - * an additional 10px. - * - * @see TableOfContentsMacro.Indentation - */ - INDENT, - /** - * This parameter applies to flat lists only. Configures the separator used - * for separating content items. - * - * @see TableOfContentsMacro.Separator - */ - SEPARATOR, - /** - * Select the highest heading level to start your TOC list. For example, entering - * {@code 2} will include levels {@literal

} and lower levels, but - * will not include level {@literal

} headings and below. - */ - MIN_LEVEL, - /** - * Select the lowest heading level to include. For example, entering - * {@code 2} will include levels {@literal

} and {@literal

}, but - * will not include level {@literal

} headings and below. - */ - MAX_LEVEL, - /** - * By default, the TOC is set to print. If you clear the check box, the - * TOC will not be visible when you print the page. - */ - PRINTABLE; - - /** - * Motivation: Necessary to keep consistent with UPPER CASE naming convention for enums, - * whilst outputting the expected format of the macro value. - * - * @param string the String to convert. - * @return a String in Camel Case format. - */ - private String convertToCamelCase(String string) - { - StringBuilder sb = new StringBuilder(); - String[] parts = string.split("_"); - sb.append(parts[0].toLowerCase()); - for (int i = 1; i <= parts.length - 1; i++) - { - sb.append(toProperCase(parts[i])); - } - return sb.toString(); - } - - private String toProperCase(String s) - { - return s.substring(0, 1).toUpperCase() + - s.substring(1).toLowerCase(); - } - - @Override - public String toString() - { - return convertToCamelCase(this.name()); - } - } - - /** - * The output style of the table of contents. - */ - public enum OutputType - { - /** - * Causes the output style of the table of contents - * to be laid out in a flat series of links separated - * by square brackets. - *

- * For Example: - *

{@literal
-         *      [ 1 Summary ] [ 2 Cacheable HTTPS response ] [ 2.1 Issue Background ] ...
-         * }
- */ - FLAT, - /** - * Causes the output style of the table of contents to be laid out - * as an indented list. - *

- * For example: - *

{@literal
-         *  1 Summary
-         *  2 Cacheable HTTPS response
-         *      2.1 Issue Background
-         *          2.1.1 quickstreamdev3/
-         *          2.1.2 quickstreamdev3/PreregisteredAccountsReportActionServlet
-         * }
-         * 
- */ - LIST; - - @Override - public String toString() - { - return this.name().toLowerCase(); - } - } - - /** - * The bullet point style to use for each list item. - */ - public enum ListStyle - { - /** - * none — no list style is displayed - */ - NONE, - /** - * circle — the list style is a circle - */ - CIRCLE, - /** - * disc — the list style is a filled circle. This is the typical - * bullet list, and is used for this example list. - */ - DISC, - /** - * square — the list style is a square - */ - SQUARE, - /** - * decimal — the list is numbered (1, 2, 3, 4, 5) - */ - DECIMAL, - /** - * lower-alpha — the list is lower-case, alphabetised (a, b, c, d, e) - */ - LOWER_ALPHA, - /** - * lower-roman — the list style is lower roman numerals (i, ii, iii, iv, v, vi) - */ - LOWER_ROMAN, - /** - * upper-roman — the list style is upper roman numerals (I, II, III, IV, V, VI) - */ - UPPER_ROMAN; - - @Override - public String toString() - { - // replace the underscore with a dash and print as lower case - return this.name().replace('_', '-').toLowerCase(); - } - } - - /** - * The available indentation levels. - */ - public enum Indentation - { - TEN_PX, - TWENTY_PX, - THIRTY_PX, - FORTY_PX; - - private String convert() - { - switch (name()) - { - case "TEN_PX": - return "10px"; - case "TWENTY_PX": - return "20px"; - case "THIRTY_PX": - return "30px"; - default: - return "40px"; - } - } - - @Override - public String toString() - { - return convert(); - } - } - - /** - * This parameter applies to flat lists only. You can enter any of the following values: - */ - public enum Separator - { - /** - * brackets — Each item is enclosed by square brackets: [ ]. - */ - BRACKETS, - /** - * braces — Each item is enclosed by braces: { }. - */ - BRACES, - /** - * parens — Each item is enclosed by parentheses: ( ). - */ - PARENS, - /** - * pipe — Each item is separated by a pipe: - */ - PIPE; - - @Override - public String toString() - { - return super.toString().toLowerCase(); - } - } - - // API - - /** - * Stores the parameters of this code block macro. - */ - private EnumMap parameters; - - /** - * Constructor. - * - * @param builder the factory object used to build an instance of this class. - */ - public TableOfContentsMacro(Builder builder) - { - this.parameters = builder.parameters; - } - - /** - * @return a String containing the XML markup for the confluence storage format. - */ - public String toMarkup() - { - StringBuilder sb = new StringBuilder(); - sb.append(""); - for (Map.Entry entry : parameters.entrySet()) - { - sb.append(""); - sb.append(entry.getValue()); - sb.append(""); - } - sb.append(""); - return sb.toString(); - } - - /** - * Builder factory method. - * - * @return a {@code Builder} instance for chain-building a CodeBlockMacro. - */ - public static Builder builder() - { - return new Builder(); - } - - /** - * A class for implementing the Builder Pattern for {@code CodeBlockMacro}. - */ - public static class Builder - { - private EnumMap parameters; - - // check if a parameter has already been set. - private boolean parameterNotSet(Parameters p) - { - return !parameters.containsKey(p); - } - - // Constructor. - private Builder() - { - parameters = new EnumMap<>(Parameters.class); - } - - /** - * Creates an instance of {@code TableOfContentsMacro}. - * - * @return an instance {@code TableOfContentsMacro} that was configured - * by this Builder. - */ - public TableOfContentsMacro build() - { - return new TableOfContentsMacro(this); - } - - /** - * Enables numbering of sections. - * - * @return {@code this}. - */ - public Builder enableNumbering() - { - if (parameterNotSet(Parameters.OUTLINE)) - { - parameters.put(Parameters.OUTLINE, "true"); - } - return this; - } - - /** - * Sets the output type, which is really the style of Table of Contents. - * - * @param outputType the style of Table of Contents to produce. - * @return {@code this}. - */ - public Builder outputType(OutputType outputType) - { - if (parameterNotSet(Parameters.TYPE)) - { - parameters.put(Parameters.TYPE, outputType.toString()); - } - return this; - } - - /** - * Set the bullet point style to use for each list item. - * - * @param listStyle the style to set. - * @return {@code this}. - */ - public Builder bulletPointStyle(ListStyle listStyle) - { - if (parameterNotSet(Parameters.TYPE)) - { - parameters.put(Parameters.STYLE, listStyle.toString()); - } - return this; - } - - /** - * Set the indentation level. - * - * @param indentation the indentation level to use. - * @return {@code this}. - */ - public Builder indentation(Indentation indentation) - { - if (parameterNotSet(Parameters.INDENT)) - { - parameters.put(Parameters.INDENT, indentation.toString()); - } - return this; - } - - /** - * Set builtin separator. - * - * @param separator the builtin separator to use. - * @return {@code this}. - */ - public Builder separator(Separator separator) - { - if (parameterNotSet(Parameters.SEPARATOR)) - { - parameters.put(Parameters.SEPARATOR, separator.toString()); - } - return this; - } - - /** - * Set a custom separator. Each item is separated by the value you enter. - * You can enter any text as a separator, for example "***". - * If using a custom separator, be aware that text displays - * exactly as entered, with no additional white space to further - * separate the characters. - * - * @param separator the custom separator to use. - * @return {@code this}. - */ - public Builder separator(String separator) - { - if (parameterNotSet(Parameters.SEPARATOR)) - { - parameters.put(Parameters.SEPARATOR, separator); - } - return this; - } - - /** - * Set the minimum heading level to include in the table of contents - * - * @param i the number between 1 and 6 corresponding to the {@literal

-

}. - * For example: {@code 1} for {@literal

}. - * @return {@code this}. - */ - public Builder minHeadingLevel(int i) - { - if (i <= 6 && i > 0) // h1 - h6 - { - if (parameterNotSet(Parameters.MIN_LEVEL)) - { - parameters.put(Parameters.MIN_LEVEL, Integer.toString(i)); - } - } - return this; - } - - - /** - * Set the maximum heading level to include in the table of contents - * - * @param i the number between 1 and 6 corresponding to the {@literal

-

}. - * For example: {@code 1} for {@literal

}. - * @return {@code this}. - */ - public Builder maxHeadingLevel(int i) - { - if (i <= 6 && i > 0) // h1 - h6 - { - if (parameterNotSet(Parameters.MAX_LEVEL)) - { - parameters.put(Parameters.MAX_LEVEL, Integer.toString(i)); - } - } - return this; - } - - /** - * Disables inclusion of the TOC when the page is printed. - * - * @return {@code this}. - */ - public Builder disablePrinting() - { - if (parameterNotSet(Parameters.PRINTABLE)) - { - parameters.put(Parameters.PRINTABLE, "false"); - } - return this; - } - - } -} +package com.softwareleaf.confluence.macro; + +import java.util.EnumMap; +import java.util.Map; + +/** + * Represents a confluence Table of Contents Macro. + *

+ * Usage + *

{@literal
+ * String macro = TableOfContentsMacro.builder()
+ *      .enableNumbering()
+ *      .outputType(OutputType.LIST)
+ *      .bulletPointStyle(ListStyle.NONE)
+ *      .build()
+ *      .toWikiMarkup();
+ * }
+ * + * @author Jonathon Hope + * @see table of Contents + * Macro Documentation + * @since 16/06/2015 + */ +public class TableOfContentsMacro +{ + /** + * Parameters are options that you can set to control the content or format of the macro output. + */ + public enum Parameters + { + /** + * Enables section numbering. + *
{@literal
+         *      true
+         * }
+ */ + OUTLINE, + /** + * @see TableOfContentsMacro.OutputType + */ + TYPE, + /** + * The style of bullet point to use. + * + * @see TableOfContentsMacro.ListStyle + */ + STYLE, + /** + * Sets the indent for a list according to CSS quantities. Entering 10px + * will successively indent heading groups by 10px. For example, level 1 + * headings will be indented 10px and level 2 headings will be indented + * an additional 10px. + * + * @see TableOfContentsMacro.Indentation + */ + INDENT, + /** + * This parameter applies to flat lists only. Configures the separator used + * for separating content items. + * + * @see TableOfContentsMacro.Separator + */ + SEPARATOR, + /** + * Select the highest heading level to start your TOC list. For example, entering + * {@code 2} will include levels {@literal

} and lower levels, but + * will not include level {@literal

} headings and below. + */ + MIN_LEVEL, + /** + * Select the lowest heading level to include. For example, entering + * {@code 2} will include levels {@literal

} and {@literal

}, but + * will not include level {@literal

} headings and below. + */ + MAX_LEVEL, + /** + * By default, the TOC is set to print. If you clear the check box, the + * TOC will not be visible when you print the page. + */ + PRINTABLE; + + /** + * Motivation: Necessary to keep consistent with UPPER CASE naming convention for enums, + * whilst outputting the expected format of the macro value. + * + * @param string the String to convert. + * @return a String in Camel Case format. + */ + private static String convertToCamelCase(final String string) + { + final StringBuilder sb = new StringBuilder(); + final String[] parts = string.split("_"); + sb.append(parts[0].toLowerCase()); + for (int i = 1; i <= parts.length - 1; i++) + { + sb.append(toProperCase(parts[i])); + } + return sb.toString(); + } + + private static String toProperCase(final String s) + { + return s.substring(0, 1).toUpperCase() + + s.substring(1).toLowerCase(); + } + + @Override + public String toString() + { + return convertToCamelCase(name()); + } + } + + /** + * The output style of the table of contents. + */ + public enum OutputType + { + /** + * Causes the output style of the table of contents + * to be laid out in a flat series of links separated + * by square brackets. + *

+ * For Example: + *

{@literal
+         *      [ 1 Summary ] [ 2 Cacheable HTTPS response ] [ 2.1 Issue Background ] ...
+         * }
+ */ + FLAT, + /** + * Causes the output style of the table of contents to be laid out + * as an indented list. + *

+ * For example: + *

{@literal
+         *  1 Summary
+         *  2 Cacheable HTTPS response
+         *      2.1 Issue Background
+         *          2.1.1 quickstreamdev3/
+         *          2.1.2 quickstreamdev3/PreregisteredAccountsReportActionServlet
+         * }
+         * 
+ */ + LIST; + + @Override + public String toString() + { + return name().toLowerCase(); + } + } + + /** + * The bullet point style to use for each list item. + */ + public enum ListStyle + { + /** + * none � no list style is displayed + */ + NONE, + /** + * circle � the list style is a circle + */ + CIRCLE, + /** + * disc � the list style is a filled circle. This is the typical + * bullet list, and is used for this example list. + */ + DISC, + /** + * square � the list style is a square + */ + SQUARE, + /** + * decimal � the list is numbered (1, 2, 3, 4, 5) + */ + DECIMAL, + /** + * lower-alpha � the list is lower-case, alphabetised (a, b, c, d, e) + */ + LOWER_ALPHA, + /** + * lower-roman � the list style is lower roman numerals (i, ii, iii, iv, v, vi) + */ + LOWER_ROMAN, + /** + * upper-roman � the list style is upper roman numerals (I, II, III, IV, V, VI) + */ + UPPER_ROMAN; + + @Override + public String toString() + { + // replace the underscore with a dash and print as lower case + return name().replace('_', '-').toLowerCase(); + } + } + + /** + * The available indentation levels. + */ + public enum Indentation + { + TEN_PX, + TWENTY_PX, + THIRTY_PX, + FORTY_PX; + + private String convert() + { + switch (name()) + { + case "TEN_PX": + return "10px"; + case "TWENTY_PX": + return "20px"; + case "THIRTY_PX": + return "30px"; + default: + return "40px"; + } + } + + @Override + public String toString() + { + return convert(); + } + } + + /** + * This parameter applies to flat lists only. You can enter any of the following values: + */ + public enum Separator + { + /** + * brackets � Each item is enclosed by square brackets: [ ]. + */ + BRACKETS, + /** + * braces � Each item is enclosed by braces: { }. + */ + BRACES, + /** + * parens � Each item is enclosed by parentheses: ( ). + */ + PARENS, + /** + * pipe � Each item is separated by a pipe: + */ + PIPE; + + @Override + public String toString() + { + return super.toString().toLowerCase(); + } + } + + // API + + /** + * Stores the parameters of this code block macro. + */ + private final EnumMap parameters; + + /** + * Constructor. + * + * @param builder the factory object used to build an instance of this class. + */ + public TableOfContentsMacro(final Builder builder) + { + parameters = builder.parameters; + } + + /** + * @return a String containing the XML markup for the confluence storage format. + */ + public String toMarkup() + { + final StringBuilder sb = new StringBuilder(); + sb.append(""); + for (final Map.Entry entry : parameters.entrySet()) + { + sb.append(""); + sb.append(entry.getValue()); + sb.append(""); + } + sb.append(""); + return sb.toString(); + } + + /** + * Builder factory method. + * + * @return a {@code Builder} instance for chain-building a CodeBlockMacro. + */ + public static Builder builder() + { + return new Builder(); + } + + /** + * A class for implementing the Builder Pattern for {@code CodeBlockMacro}. + */ + public static class Builder + { + private final EnumMap parameters; + + // check if a parameter has already been set. + private boolean parameterNotSet(final Parameters p) + { + return !parameters.containsKey(p); + } + + // Constructor. + private Builder() + { + parameters = new EnumMap<>(Parameters.class); + } + + /** + * Creates an instance of {@code TableOfContentsMacro}. + * + * @return an instance {@code TableOfContentsMacro} that was configured + * by this Builder. + */ + public TableOfContentsMacro build() + { + return new TableOfContentsMacro(this); + } + + /** + * Enables numbering of sections. + * + * @return {@code this}. + */ + public Builder enableNumbering() + { + if (parameterNotSet(Parameters.OUTLINE)) + { + parameters.put(Parameters.OUTLINE, "true"); + } + return this; + } + + /** + * Sets the output type, which is really the style of Table of Contents. + * + * @param outputType the style of Table of Contents to produce. + * @return {@code this}. + */ + public Builder outputType(final OutputType outputType) + { + if (parameterNotSet(Parameters.TYPE)) + { + parameters.put(Parameters.TYPE, outputType.toString()); + } + return this; + } + + /** + * Set the bullet point style to use for each list item. + * + * @param listStyle the style to set. + * @return {@code this}. + */ + public Builder bulletPointStyle(final ListStyle listStyle) + { + if (parameterNotSet(Parameters.TYPE)) + { + parameters.put(Parameters.STYLE, listStyle.toString()); + } + return this; + } + + /** + * Set the indentation level. + * + * @param indentation the indentation level to use. + * @return {@code this}. + */ + public Builder indentation(final Indentation indentation) + { + if (parameterNotSet(Parameters.INDENT)) + { + parameters.put(Parameters.INDENT, indentation.toString()); + } + return this; + } + + /** + * Set builtin separator. + * + * @param separator the builtin separator to use. + * @return {@code this}. + */ + public Builder separator(final Separator separator) + { + if (parameterNotSet(Parameters.SEPARATOR)) + { + parameters.put(Parameters.SEPARATOR, separator.toString()); + } + return this; + } + + /** + * Set a custom separator. Each item is separated by the value you enter. + * You can enter any text as a separator, for example "***". + * If using a custom separator, be aware that text displays + * exactly as entered, with no additional white space to further + * separate the characters. + * + * @param separator the custom separator to use. + * @return {@code this}. + */ + public Builder separator(final String separator) + { + if (parameterNotSet(Parameters.SEPARATOR)) + { + parameters.put(Parameters.SEPARATOR, separator); + } + return this; + } + + /** + * Set the minimum heading level to include in the table of contents + * + * @param i the number between 1 and 6 corresponding to the {@literal

-

}. + * For example: {@code 1} for {@literal

}. + * @return {@code this}. + */ + public Builder minHeadingLevel(final int i) + { + if (i <= 6 && i > 0) // h1 - h6 + { + if (parameterNotSet(Parameters.MIN_LEVEL)) + { + parameters.put(Parameters.MIN_LEVEL, Integer.toString(i)); + } + } + return this; + } + + + /** + * Set the maximum heading level to include in the table of contents + * + * @param i the number between 1 and 6 corresponding to the {@literal

-

}. + * For example: {@code 1} for {@literal

}. + * @return {@code this}. + */ + public Builder maxHeadingLevel(final int i) + { + if (i <= 6 && i > 0) // h1 - h6 + { + if (parameterNotSet(Parameters.MAX_LEVEL)) + { + parameters.put(Parameters.MAX_LEVEL, Integer.toString(i)); + } + } + return this; + } + + /** + * Disables inclusion of the TOC when the page is printed. + * + * @return {@code this}. + */ + public Builder disablePrinting() + { + if (parameterNotSet(Parameters.PRINTABLE)) + { + parameters.put(Parameters.PRINTABLE, "false"); + } + return this; + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/softwareleaf/confluence/model/Body.java b/src/main/java/com/softwareleaf/confluence/model/Body.java index 8bdc1bb..1c469da 100644 --- a/src/main/java/com/softwareleaf/confluence/model/Body.java +++ b/src/main/java/com/softwareleaf/confluence/model/Body.java @@ -1,65 +1,65 @@ -package com.softwareleaf.confluence.model; - -import java.util.Objects; - -/** - * This object represents the Body of some {@code Content}. - * - * @author Jonathon Hope - * @since 29/05/2015 - */ -public class Body -{ - private Storage storage; - - /** - * Constructor. - * - * @param storage the instance of {@code Storage} to wrap. - */ - public Body(final Storage storage) - { - this.storage = storage; - } - - /** - * Getter for this Body.storage. - * - * @return the storage object encapsulated by this Body. - */ - public Storage getStorage() - { - return storage; - } - - /** - * Setter for this Body.storage. - * - * @param storage the instance of storage. - */ - public void setStorage(Storage storage) - { - this.storage = storage; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - Body body = (Body) o; - return Objects.equals(storage, body.storage); - } - - @Override - public int hashCode() - { - return Objects.hash(storage); - } -} +package com.softwareleaf.confluence.model; + +import java.util.Objects; + +/** + * This object represents the Body of some {@code Content}. + * + * @author Jonathon Hope + * @since 29/05/2015 + */ +public class Body +{ + private Storage storage; + + /** + * Constructor. + * + * @param storage the instance of {@code Storage} to wrap. + */ + public Body(final Storage storage) + { + this.storage = storage; + } + + /** + * Getter for this Body.storage. + * + * @return the storage object encapsulated by this Body. + */ + public Storage getStorage() + { + return storage; + } + + /** + * Setter for this Body.storage. + * + * @param storage the instance of storage. + */ + public void setStorage(final Storage storage) + { + this.storage = storage; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + final Body body = (Body) o; + return Objects.equals(storage, body.storage); + } + + @Override + public int hashCode() + { + return Objects.hash(storage); + } +} diff --git a/src/main/java/com/softwareleaf/confluence/model/Content.java b/src/main/java/com/softwareleaf/confluence/model/Content.java index 09d00fb..7fb7ea4 100644 --- a/src/main/java/com/softwareleaf/confluence/model/Content.java +++ b/src/main/java/com/softwareleaf/confluence/model/Content.java @@ -1,187 +1,184 @@ -package com.softwareleaf.confluence.model; - -import com.google.gson.GsonBuilder; - -import java.util.Objects; - -/** - * Represents a piece of content. - *

- *

Example - *

{@literal
- *      {
- *          "id": "22217244",
- *          "type": "page",
- *          "space": {
- *              "key": "TST"
- *          },
- *          "title": "A title",
- *          "body": {
- *              "storage": {
- *                  "value": "

This is a new page

", - * "representation": "storage" - * } - * } - * } - * } - *
- * - * @author Jonathon Hope - * @since 28/05/2015 - */ -public class Content -{ - /** - * The id of the page or blog post. - */ - private String id; - /** - * The type of content: blog post or page. - */ - private String type; - /** - * The ancestors of this blog post or page. - */ - private Parent[] ancestors; - - /** - * The space object holds the space key, that is used to identify the location of - * the piece of content. - */ - private Space space; - /** - * The title of the page or blog post. - */ - private String title; - /** - * The body object holds the stored data of the page or blog post. - */ - private Body body; - - /** - * Default Constructor. - */ - - public Content() - { - } - - /** - * Constructor. - * - * @param id the id of the piece of content. - * @param type the type of piece of content. - * @param space the space object for the piece of content. - * @param title the title of the piece of content. - * @param body the body of the piece of content. - */ - public Content(String id, - String type, - Space space, - String title, - Body body) - { - this.id = id; - this.type = type; - this.title = title; - this.space = space; - this.body = body; - } - - // getters and setters - - public String getType() - { - return type; - } - - public void setType(Type type) - { - this.type = type.toString(); - } - - public Parent[] getAncestors() - { - return ancestors; - } - - public void setAncestors(Parent[] ancestors) - { - this.ancestors = ancestors; - } - - public Space getSpace() - { - return space; - } - - public void setSpace(Space space) - { - this.space = space; - } - - public String getTitle() - { - return title; - } - - public void setTitle(String title) - { - this.title = title; - } - - public Body getBody() - { - return body; - } - - public void setBody(Body body) - { - this.body = body; - } - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - @Override - public String toString() - { - return new GsonBuilder().disableHtmlEscaping().create().toJson(this); - } - - // equals and hashcode - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || !(o instanceof Content)) - { - return false; - } - Content content = (Content) o; - return Objects.equals(id, content.id) && - Objects.equals(type, content.type) && - Objects.equals(ancestors, content.ancestors) && - Objects.equals(space, content.space) && - Objects.equals(title, content.title) && - Objects.equals(body, content.body); - } - - @Override - public int hashCode() - { - return Objects.hash(id, type, ancestors, space, title, body); - } -} - +package com.softwareleaf.confluence.model; + +import java.util.Objects; + +import com.google.gson.GsonBuilder; + +/** + * Represents a piece of content. + *

+ *

Example + *

{@literal
+ *      {
+ *          "id": "22217244",
+ *          "type": "page",
+ *          "space": {
+ *              "key": "TST"
+ *          },
+ *          "title": "A title",
+ *          "body": {
+ *              "storage": {
+ *                  "value": "

This is a new page

", + * "representation": "storage" + * } + * } + * } + * } + *
+ * + * @author Jonathon Hope + * @since 28/05/2015 + */ +public class Content +{ + /** + * The id of the page or blog post. + */ + private String id; + /** + * The type of content: blog post or page. + */ + private String type; + /** + * The ancestors of this blog post or page. + */ + private Parent[] ancestors; + + /** + * The space object holds the space key, that is used to identify the location of + * the piece of content. + */ + private Space space; + /** + * The title of the page or blog post. + */ + private String title; + /** + * The body object holds the stored data of the page or blog post. + */ + private Body body; + + /** + * Default Constructor. + */ + + public Content() + { + } + + /** + * Constructor. + * + * @param id the id of the piece of content. + * @param type the type of piece of content. + * @param space the space object for the piece of content. + * @param title the title of the piece of content. + * @param body the body of the piece of content. + */ + public Content(final String id, + final String type, + final Space space, + final String title, + final Body body) + { + this.id = id; + this.type = type; + this.title = title; + this.space = space; + this.body = body; + } + + // getters and setters + + public String getType() + { + return type; + } + + public void setType(final Type type) + { + this.type = type.toString(); + } + + public Parent[] getAncestors() + { + return ancestors; + } + + public void setAncestors(final Parent[] ancestors) + { + this.ancestors = ancestors; + } + + public Space getSpace() + { + return space; + } + + public void setSpace(final Space space) + { + this.space = space; + } + + public String getTitle() + { + return title; + } + + public void setTitle(final String title) + { + this.title = title; + } + + public Body getBody() + { + return body; + } + + public void setBody(final Body body) + { + this.body = body; + } + + public String getId() + { + return id; + } + + public void setId(final String id) + { + this.id = id; + } + + @Override + public String toString() + { + return new GsonBuilder().disableHtmlEscaping().create().toJson(this); + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || !(o instanceof Content)) + { + return false; + } + final Content content = (Content) o; + return Objects.equals(id, content.id) && + Objects.equals(type, content.type) && + Objects.equals(ancestors, content.ancestors) && + Objects.equals(space, content.space) && + Objects.equals(title, content.title) && + Objects.equals(body, content.body); + } + + @Override + public int hashCode() + { + return Objects.hash(id, type, ancestors, space, title, body); + } +} \ No newline at end of file diff --git a/src/main/java/com/softwareleaf/confluence/model/ContentResultList.java b/src/main/java/com/softwareleaf/confluence/model/ContentResultList.java index 8f81f53..92b3447 100644 --- a/src/main/java/com/softwareleaf/confluence/model/ContentResultList.java +++ b/src/main/java/com/softwareleaf/confluence/model/ContentResultList.java @@ -1,38 +1,36 @@ -package com.softwareleaf.confluence.model; - -import com.google.gson.annotations.SerializedName; - -/** - * A representation of the results object returned by the - * GET {@literal /rest/api/content/} API call. - * - * @author Jonathon Hope - * @since 9/06/2015 - */ -public class ContentResultList -{ - @SerializedName("results") - private Content[] contents; - - /** - * Constructor. - * - * @param contents the array of Content instances. - */ - public ContentResultList(Content[] contents) - { - this.contents = contents; - } - - // getter and setter - - public Content[] getContents() - { - return contents; - } - - public void setContents(Content[] contents) - { - this.contents = contents; - } -} +package com.softwareleaf.confluence.model; + +import com.google.gson.annotations.SerializedName; + +/** + * A representation of the results object returned by the + * GET {@literal /rest/api/content/} API call. + * + * @author Jonathon Hope + * @since 9/06/2015 + */ +public class ContentResultList +{ + @SerializedName("results") + private Content[] contents; + + /** + * Constructor. + * + * @param contents the array of Content instances. + */ + public ContentResultList(final Content[] contents) + { + this.contents = contents; + } + + public Content[] getContents() + { + return contents; + } + + public void setContents(final Content[] contents) + { + this.contents = contents; + } +} diff --git a/src/main/java/com/softwareleaf/confluence/model/NoContent.java b/src/main/java/com/softwareleaf/confluence/model/NoContent.java index 5a1d58f..9ce81c2 100644 --- a/src/main/java/com/softwareleaf/confluence/model/NoContent.java +++ b/src/main/java/com/softwareleaf/confluence/model/NoContent.java @@ -1,45 +1,45 @@ -package com.softwareleaf.confluence.model; - -import com.google.gson.GsonBuilder; - -/** - * Represents the JSON response when Content is not found. - * - * @author Jonathon Hope - * @since 11/06/2015 - */ -public class NoContent -{ - private int statusCode; - private String message; - - public NoContent() - { - } - - public int getStatusCode() - { - return statusCode; - } - - public void setStatusCode(int statusCode) - { - this.statusCode = statusCode; - } - - public String getMessage() - { - return message; - } - - public void setMessage(String message) - { - this.message = message; - } - - @Override - public String toString() - { - return new GsonBuilder().disableHtmlEscaping().create().toJson(this); - } -} +package com.softwareleaf.confluence.model; + +import com.google.gson.GsonBuilder; + +/** + * Represents the JSON response when Content is not found. + * + * @author Jonathon Hope + * @since 11/06/2015 + */ +public class NoContent +{ + private int statusCode; + private String message; + + public NoContent() + { + } + + public int getStatusCode() + { + return statusCode; + } + + public void setStatusCode(final int statusCode) + { + this.statusCode = statusCode; + } + + public String getMessage() + { + return message; + } + + public void setMessage(final String message) + { + this.message = message; + } + + @Override + public String toString() + { + return new GsonBuilder().disableHtmlEscaping().create().toJson(this); + } +} diff --git a/src/main/java/com/softwareleaf/confluence/model/Parent.java b/src/main/java/com/softwareleaf/confluence/model/Parent.java index 526b462..9564090 100644 --- a/src/main/java/com/softwareleaf/confluence/model/Parent.java +++ b/src/main/java/com/softwareleaf/confluence/model/Parent.java @@ -1,84 +1,84 @@ -package com.softwareleaf.confluence.model; - -import java.util.Objects; - -/** - * Represents the ancestors nested json object, used to set the parents of a - * piece of content. - * - * @author Jonathon Hope - * @since 18/06/2015 - */ -public class Parent -{ - /** - * The id of the parent. - */ - private String id; - /** - * The type of the parent. - */ - private String type; - - /** - * Constructor. - */ - public Parent() - { - } - - /** - * Constructor. - * - * @param id the id of the parent. - * @param type the type of the parent. - */ - public Parent(String id, String type) - { - this.id = id; - this.type = type; - } - - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getType() - { - return type; - } - - public void setType(String type) - { - this.type = type; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - Parent parent = (Parent) o; - return Objects.equals(id, parent.id) && - Objects.equals(type, parent.type); - } - - @Override - public int hashCode() - { - return Objects.hash(id, type); - } -} +package com.softwareleaf.confluence.model; + +import java.util.Objects; + +/** + * Represents the ancestors nested json object, used to set the parents of a + * piece of content. + * + * @author Jonathon Hope + * @since 18/06/2015 + */ +public class Parent +{ + /** + * The id of the parent. + */ + private String id; + /** + * The type of the parent. + */ + private String type; + + /** + * Constructor. + */ + public Parent() + { + } + + /** + * Constructor. + * + * @param id the id of the parent. + * @param type the type of the parent. + */ + public Parent(final String id, final String type) + { + this.id = id; + this.type = type; + } + + + public String getId() + { + return id; + } + + public void setId(final String id) + { + this.id = id; + } + + public String getType() + { + return type; + } + + public void setType(final String type) + { + this.type = type; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + final Parent parent = (Parent) o; + return Objects.equals(id, parent.id) && + Objects.equals(type, parent.type); + } + + @Override + public int hashCode() + { + return Objects.hash(id, type); + } +} diff --git a/src/main/java/com/softwareleaf/confluence/model/Space.java b/src/main/java/com/softwareleaf/confluence/model/Space.java index a075f37..5031d3a 100644 --- a/src/main/java/com/softwareleaf/confluence/model/Space.java +++ b/src/main/java/com/softwareleaf/confluence/model/Space.java @@ -1,94 +1,103 @@ -package com.softwareleaf.confluence.model; - -import com.google.gson.GsonBuilder; - -/** - * Represents the type of a piece of content. - *

Example - *

{@literal
- *  {
- *      ...
- *      "space": {
- *          "key": "KEY"
- *      }
- *      ...
- *  }
- * }
- * - * @author Jonathon Hope - * @since 28/05/2015 - */ -public class Space -{ - /** - * The space key. For example: {@literal "DEV"}. - */ - private String key; - /** - * The space name. For example: {@literal "Development"}. - */ - private String name; - - /** - * Default constructor. - */ - public Space() {} - - /** - * Constructor. - */ - public Space(String key) - { - this.key = key; - } - - public String getKey() - { - return key; - } - - public void setKey(String key) - { - this.key = key; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - @Override - public String toString() - { - return new GsonBuilder().disableHtmlEscaping().create().toJson(this); - } - - // equals and hashcode - - @Override - public int hashCode() - { - int result = 17; - result = 31 * result + key.hashCode(); - result = 31 * result + name.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (obj == this) return true; - if (obj == null) return false; - if (!(obj instanceof Space)) return false; - Space that = (Space) obj; - return ((name == null) ? that.name == null : that.name.equals(this.name)) && - ((key == null) ? that.key == null : that.key.equals(this.key)); - } - -} - +package com.softwareleaf.confluence.model; + +import com.google.gson.GsonBuilder; + +/** + * Represents the type of a piece of content. + *

Example + *

{@literal
+ *  {
+ *      ...
+ *      "space": {
+ *          "key": "KEY"
+ *      }
+ *      ...
+ *  }
+ * }
+ * + * @author Jonathon Hope + * @since 28/05/2015 + */ +public class Space +{ + /** + * The space key. For example: {@literal "DEV"}. + */ + private String key; + /** + * The space name. For example: {@literal "Development"}. + */ + private String name; + + /** + * Default constructor. + */ + public Space() {} + + /** + * Constructor. + */ + public Space(final String key) + { + this.key = key; + } + + public String getKey() + { + return key; + } + + public void setKey(final String key) + { + this.key = key; + } + + public String getName() + { + return name; + } + + public void setName(final String name) + { + this.name = name; + } + + @Override + public String toString() + { + return new GsonBuilder().disableHtmlEscaping().create().toJson(this); + } + + // equals and hashcode + + @Override + public int hashCode() + { + int result = 17; + result = 31 * result + key.hashCode(); + result = 31 * result + name.hashCode(); + return result; + } + + @Override + public boolean equals(final Object obj) + { + if (obj == this) + { + return true; + } + if (obj == null) + { + return false; + } + if (!(obj instanceof Space)) + { + return false; + } + final Space that = (Space) obj; + return (name == null ? that.name == null : that.name.equals(name)) && + (key == null ? that.key == null : that.key.equals(key)); + } + +} + diff --git a/src/main/java/com/softwareleaf/confluence/model/SpaceResultList.java b/src/main/java/com/softwareleaf/confluence/model/SpaceResultList.java index 3166864..a4a3ae5 100644 --- a/src/main/java/com/softwareleaf/confluence/model/SpaceResultList.java +++ b/src/main/java/com/softwareleaf/confluence/model/SpaceResultList.java @@ -1,38 +1,38 @@ -package com.softwareleaf.confluence.model; - -import com.google.gson.annotations.SerializedName; - -/** - * Represents a result set of confluence spaces. - * - * @author Jonathon Hope - * @see Space REST API - * @since 25/06/2015 - */ -public class SpaceResultList -{ - @SerializedName("results") - private Space[] spaces; - - /** - * Constructor. - * - * @param spaces the array of {@code Space} instances. - */ - public SpaceResultList(Space[] spaces) - { - this.spaces = spaces; - } - - // getter and setter - - public Space[] getSpaces() - { - return spaces; - } - - public void setSpaces(Space[] spaces) - { - this.spaces = spaces; - } -} +package com.softwareleaf.confluence.model; + +import com.google.gson.annotations.SerializedName; + +/** + * Represents a result set of confluence spaces. + * + * @author Jonathon Hope + * @see Space REST API + * @since 25/06/2015 + */ +public class SpaceResultList +{ + @SerializedName("results") + private Space[] spaces; + + /** + * Constructor. + * + * @param spaces the array of {@code Space} instances. + */ + public SpaceResultList(final Space[] spaces) + { + this.spaces = spaces; + } + + // getter and setter + + public Space[] getSpaces() + { + return spaces; + } + + public void setSpaces(final Space[] spaces) + { + this.spaces = spaces; + } +} diff --git a/src/main/java/com/softwareleaf/confluence/model/Storage.java b/src/main/java/com/softwareleaf/confluence/model/Storage.java index a5b493f..609185d 100644 --- a/src/main/java/com/softwareleaf/confluence/model/Storage.java +++ b/src/main/java/com/softwareleaf/confluence/model/Storage.java @@ -1,99 +1,99 @@ -package com.softwareleaf.confluence.model; - -import java.util.Objects; - -/** - * Represents the storage container within a {@code Content.body} - * - * @author Jonathon Hope - * @see - * Confluence Storage Format - * @since 28/05/2015 - */ -public class Storage -{ - /** - * The markup or html of this {@code Storage}. - */ - private String value; - - /** - * The representation. The confluence REST API docs are unclear as to what the - * full set of possible values for this are; but so far {@literal "view","page","storage"}. - *

- * NOTE: {@literal "storage"} should almost always be used. - */ - private String representation = "storage"; - - /** - * @see - * Confluence Storage Format - */ - public enum Representation - { - VIEW, - PAGE, - STORAGE, - WIKI; - - @Override - public String toString() - { - return name().toLowerCase(); - } - } - - /** - * Constructor. - * - * @param value the markup of HTML. - * @param representation the type of representation. - */ - public Storage(String value, String representation) - { - this.value = value; - this.representation = representation; - } - - public String getValue() - { - return value; - } - - public void setValue(String value) - { - this.value = value; - } - - public String getRepresentation() - { - return representation; - } - - public void setRepresentation(String representation) - { - this.representation = representation; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - Storage storage = (Storage) o; - return Objects.equals(value, storage.value) && - Objects.equals(representation, storage.representation); - } - - @Override - public int hashCode() - { - return Objects.hash(value, representation); - } -} +package com.softwareleaf.confluence.model; + +import java.util.Objects; + +/** + * Represents the storage container within a {@code Content.body} + * + * @author Jonathon Hope + * @see + * Confluence Storage Format + * @since 28/05/2015 + */ +public class Storage +{ + /** + * The markup or html of this {@code Storage}. + */ + private String value; + + /** + * The representation. The confluence REST API docs are unclear as to what the + * full set of possible values for this are; but so far {@literal "view","page","storage"}. + *

+ * NOTE: {@literal "storage"} should almost always be used. + */ + private Representation representation = Representation.STORAGE; + + /** + * @see + * Confluence Storage Format + */ + public enum Representation + { + VIEW, + PAGE, + STORAGE, + WIKI; + + @Override + public String toString() + { + return name().toLowerCase(); + } + } + + /** + * Constructor. + * + * @param value the markup of HTML. + * @param representation the type of representation. + */ + public Storage(final String value, final Representation representation) + { + this.value = value; + this.representation = representation; + } + + public String getValue() + { + return value; + } + + public void setValue(final String value) + { + this.value = value; + } + + public Representation getRepresentation() + { + return representation; + } + + public void setRepresentation(final Representation representation) + { + this.representation = representation; + } + + @Override + public boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + final Storage storage = (Storage) o; + return Objects.equals(value, storage.value) && + Objects.equals(representation, storage.representation); + } + + @Override + public int hashCode() + { + return Objects.hash(value, representation); + } +} diff --git a/src/main/java/com/softwareleaf/confluence/model/Type.java b/src/main/java/com/softwareleaf/confluence/model/Type.java index c6b5e86..53e8715 100644 --- a/src/main/java/com/softwareleaf/confluence/model/Type.java +++ b/src/main/java/com/softwareleaf/confluence/model/Type.java @@ -1,33 +1,33 @@ -package com.softwareleaf.confluence.model; - -/** - * Represents the type of a piece of content. - *

Example - *

{@literal
- *  {
- *      "id": "2345678",
- *      "type": "page",
- *      "space": {
- *          ...
- *      }
- *      ...
- *  }
- * }
- * - * @author Jonathon Hope - * @since 28/05/2015 - */ -public enum Type -{ - BLOGPOST, - PAGE; - - /** - * We override this here to - */ - @Override - public String toString() - { - return super.toString().toLowerCase(); - } -} +package com.softwareleaf.confluence.model; + +/** + * Represents the type of a piece of content. + *

Example + *

{@literal
+ *  {
+ *      "id": "2345678",
+ *      "type": "page",
+ *      "space": {
+ *          ...
+ *      }
+ *      ...
+ *  }
+ * }
+ * + * @author Jonathon Hope + * @since 28/05/2015 + */ +public enum Type +{ + BLOGPOST, + PAGE; + + /** + * We override this here to + */ + @Override + public String toString() + { + return super.toString().toLowerCase(); + } +} diff --git a/src/main/java/com/softwareleaf/confluence/util/Pair.java b/src/main/java/com/softwareleaf/confluence/util/Pair.java index 8bdd117..bbe483a 100644 --- a/src/main/java/com/softwareleaf/confluence/util/Pair.java +++ b/src/main/java/com/softwareleaf/confluence/util/Pair.java @@ -1,22 +1,20 @@ -package com.softwareleaf.confluence.util; - -/** - * An immutable tuple structure, that can hold two - * different types. - * - * @author Jonathon Hope - * @since 7/07/2015 - */ -public class Pair -{ - - public final U p1; - public final V p2; - - public Pair( U p1, V p2 ) - { - this.p1 = p1; - this.p2 = p2; - } - -} +package com.softwareleaf.confluence.util; + +/** + * An immutable tuple structure, that can hold two + * different types. + * + * @author Jonathon Hope + * @since 7/07/2015 + */ +public class Pair +{ + public final U p1; + public final V p2; + + public Pair( final U p1, final V p2 ) + { + this.p1 = p1; + this.p2 = p2; + } +} diff --git a/src/main/java/com/softwareleaf/confluence/util/Tree.java b/src/main/java/com/softwareleaf/confluence/util/Tree.java index cb93111..39588ba 100644 --- a/src/main/java/com/softwareleaf/confluence/util/Tree.java +++ b/src/main/java/com/softwareleaf/confluence/util/Tree.java @@ -1,222 +1,225 @@ -package com.softwareleaf.confluence.util; - -import java.util.*; - -/** - * A generic recursive, immutable Tree structure, used to implement a - * {@code "n-ary"} Tree. Contains a {@link #isVisited()} query method - * useful for depth first search and breadth first search algorithms. - * - * @author Jonathon Hope - * @since 8/07/2015 - */ -public class Tree -{ - - /** - * The element stored in this Tree. - */ - private E myElement; - /** - * The child elements of this node. - */ - private List> myChildren; - /** - * A predicate for this tree node having been visited. - */ - private boolean myVisited; - - /** - * Constructor. - * - * @param element the element stored in this {@code Tree} - * @param children the child nodes of this {@code Tree} - */ - public Tree( E element, List> children ) - { - myVisited = false; - myElement = element; - myChildren = children; - } - - /** - * Construct a Tree using a TreeBuilder. - * - * @param treeBuilder the {@code TreeBuilder} instance to use. - */ - protected Tree( TreeBuilder treeBuilder ) - { - myVisited = false; - myElement = treeBuilder.myRootElement; - final Map>> locator = treeBuilder.myLocator; - myChildren = locator.get( treeBuilder.myRootElement ); - - // add all children that would otherwise not be reached from the parent. - List> visitedChildren = myChildren; - while ( visitedChildren != null ) - { - for ( Tree subTree : visitedChildren ) - { - final E root = subTree.myElement; - final List> children = locator.get( root ); - subTree.myChildren = children; - visitedChildren = children; - } - } - } - - /** - * Attempts to find a {@code Tree} with the {@param parent} element, - * and subsequently return the children of that {@code Tree}. - * - * @param parent the parent node to find. - * @return the list of children or {@code null} - */ - public List> findChildrenOf( E parent ) - { - List> visitedChildren = myChildren; - while ( visitedChildren != null ) - { - for ( Tree subTree : visitedChildren ) - { - final E root = subTree.myElement; - if ( root.equals( parent ) ) - { - return subTree.myChildren; - } - visitedChildren = subTree.myChildren; - } - } - return Collections.emptyList(); - } - - /** - * Fetch the element stored in this node. - * - * @return the element stored in this node. - */ - public E getElement() - { - return myElement; - } - - /** - * @return {@code true} if this {@code Tree} has been - * visited or not. - */ - public boolean isVisited() - { - return myVisited; - } - - /** - * Mark or un-mark this node as visited. - * - * @param isVisited the predicate for being visited. - */ - public void setVisited( boolean isVisited ) - { - myVisited = isVisited; - } - - /** - * @return the children of this {@code Tree} - */ - public List> getChildren() - { - return myChildren; - } - - /** - * Construct a Tree by builder pattern. - * - * @param the type of the resulting Tree. - * @param rootElement the root element of the Tree. - * @return the TreeBuilder instance for building the Tree. - */ - public static TreeBuilder builder( E rootElement ) - { - return new TreeBuilder<>( rootElement ); - } - - /** - * The builder of a {@code Tree}. This enables us to make - * {@code Tree} instances immutable. - */ - public static class TreeBuilder - { - /** - * Used to track the root element. - */ - private T myRootElement; - /** - * We use a map to to locate {@literal "parent"} {@code Tree}. We rely on - * the {@code } type overriding {@link Object#hashCode()}. - */ - private Map>> myLocator; - - /** - * Constructor. - * - * @param rootElement the root element to establish a guarantee - * that the tree will not be empty. - */ - public TreeBuilder( T rootElement ) - { - if ( rootElement == null ) - { - throw new NullPointerException( "Root element of the tree cannot be null." ); - } - myRootElement = rootElement; - myLocator = new HashMap<>(); - myLocator.put( rootElement, new ArrayList<>() ); - } - - /** - * Adds a child in the {@code Tree}, given the {@param parent}. - * - * @param parent the parent element. - * @param child the child of the parent. - * @return {@code this}. - */ - public TreeBuilder addChild( T parent, T child ) - { - if ( Objects.equals( parent, child ) ) - { - throw new IllegalArgumentException( "A child element cannot be equal to its parent." ); - } - List> children = myLocator.get( parent ); - if ( children == null ) - { - children = new ArrayList<>(); - } - children.add( new Tree<>( child, null ) ); - myLocator.put( parent, children ); - return this; - } - - /** - * Adds all children given in a list, to a {@code Tree}, given the {@param parent}. - * - * @param parent the parent element. - * @param children the intended list of children of the parent. - * @return {@code this}. - */ - public TreeBuilder addAllChildren( T parent, List children ) - { - children.stream().forEachOrdered( child -> addChild( parent, child ) ); - return this; - } - - /** - * @return a new {@code Tree} instance with all the - * elements added by this {@code Builder}. - */ - public Tree build() - { - return new Tree<>( this ); - } - - } - -} +package com.softwareleaf.confluence.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * A generic recursive, immutable Tree structure, used to implement a + * {@code "n-ary"} Tree. Contains a {@link #isVisited()} query method + * useful for depth first search and breadth first search algorithms. + * + * @author Jonathon Hope + * @since 8/07/2015 + */ +public class Tree +{ + /** + * The element stored in this Tree. + */ + private final E myElement; + /** + * The child elements of this node. + */ + private List> myChildren; + /** + * A predicate for this tree node having been visited. + */ + private boolean myVisited; + + /** + * Constructor. + * + * @param element the element stored in this {@code Tree} + * @param children the child nodes of this {@code Tree} + */ + public Tree( final E element, final List> children ) + { + myVisited = false; + myElement = element; + myChildren = children; + } + + /** + * Construct a Tree using a TreeBuilder. + * + * @param treeBuilder the {@code TreeBuilder} instance to use. + */ + protected Tree( final TreeBuilder treeBuilder ) + { + myVisited = false; + myElement = treeBuilder.myRootElement; + final Map>> locator = treeBuilder.myLocator; + myChildren = locator.get( treeBuilder.myRootElement ); + + // add all children that would otherwise not be reached from the parent. + List> visitedChildren = myChildren; + while ( visitedChildren != null ) + { + for ( final Tree subTree : visitedChildren ) + { + final E root = subTree.myElement; + final List> children = locator.get( root ); + subTree.myChildren = children; + visitedChildren = children; + } + } + } + + /** + * Attempts to find a {@code Tree} with the {@param parent} element, + * and subsequently return the children of that {@code Tree}. + * + * @param parent the parent node to find. + * @return the list of children or {@code null} + */ + public List> findChildrenOf( final E parent ) + { + List> visitedChildren = myChildren; + while ( visitedChildren != null ) + { + for ( final Tree subTree : visitedChildren ) + { + final E root = subTree.myElement; + if ( root.equals( parent ) ) + { + return subTree.myChildren; + } + visitedChildren = subTree.myChildren; + } + } + return Collections.emptyList(); + } + + /** + * Fetch the element stored in this node. + * + * @return the element stored in this node. + */ + public E getElement() + { + return myElement; + } + + /** + * @return {@code true} if this {@code Tree} has been + * visited or not. + */ + public boolean isVisited() + { + return myVisited; + } + + /** + * Mark or un-mark this node as visited. + * + * @param isVisited the predicate for being visited. + */ + public void setVisited( final boolean isVisited ) + { + myVisited = isVisited; + } + + /** + * @return the children of this {@code Tree} + */ + public List> getChildren() + { + return myChildren; + } + + /** + * Construct a Tree by builder pattern. + * + * @param the type of the resulting Tree. + * @param rootElement the root element of the Tree. + * @return the TreeBuilder instance for building the Tree. + */ + public static TreeBuilder builder( final E rootElement ) + { + return new TreeBuilder<>( rootElement ); + } + + /** + * The builder of a {@code Tree}. This enables us to make + * {@code Tree} instances immutable. + */ + public static class TreeBuilder + { + /** + * Used to track the root element. + */ + private final T myRootElement; + /** + * We use a map to to locate {@literal "parent"} {@code Tree}. We rely on + * the {@code } type overriding {@link Object#hashCode()}. + */ + private final Map>> myLocator; + + /** + * Constructor. + * + * @param rootElement the root element to establish a guarantee + * that the tree will not be empty. + */ + public TreeBuilder( final T rootElement ) + { + if ( rootElement == null ) + { + throw new NullPointerException( "Root element of the tree cannot be null." ); + } + myRootElement = rootElement; + myLocator = new HashMap<>(); + myLocator.put( rootElement, new ArrayList<>() ); + } + + /** + * Adds a child in the {@code Tree}, given the {@param parent}. + * + * @param parent the parent element. + * @param child the child of the parent. + * @return {@code this}. + */ + public TreeBuilder addChild( final T parent, final T child ) + { + if ( Objects.equals( parent, child ) ) + { + throw new IllegalArgumentException( "A child element cannot be equal to its parent." ); + } + List> children = myLocator.get( parent ); + if ( children == null ) + { + children = new ArrayList<>(); + } + children.add( new Tree<>( child, null ) ); + myLocator.put( parent, children ); + return this; + } + + /** + * Adds all children given in a list, to a {@code Tree}, given the {@param parent}. + * + * @param parent the parent element. + * @param children the intended list of children of the parent. + * @return {@code this}. + */ + public TreeBuilder addAllChildren( final T parent, final List children ) + { + children.stream().forEachOrdered( child -> addChild( parent, child ) ); + return this; + } + + /** + * @return a new {@code Tree} instance with all the + * elements added by this {@code Builder}. + */ + public Tree build() + { + return new Tree<>( this ); + } + + } +} \ No newline at end of file