/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */

UI Endpoints for Update Process

1. Get list of update archives in openidm/update:

	ACTION openidm/maintenance/update?_action=available

	returns:
    {
        "updates":
            [
                {
                    "archive": "OpenIDM-4.2.0.zip",
                    "fileSize": 80681980,
                    "fileDate": "Wed Feb 24 12:51:05 PST 2016",
                    "checksum": "D754CCCFAF336509D20DA66D6ECC74FB",
                    "fromProduct": "OpenIDM",
                    "fromVersion": [
                        "4.1.0"
                    ],
                    "toProduct": "OpenIDM",
                    "toVersion": "4.2.0",
                    "description": "Full product installation",
                    "resource": "https://forgerock.org/openidm/doc/bootstrap/integrators-guide/",
                    "restartRequired": true
                }, {
                    ...
                }
	        ],
        "rejects":
            [
                {
                  "archive": "update.xyz",
                  "reason": "File does not have '.zip' extension."
                },
                {
                  "archive": "update.zip",
                  "reason": "The archive update.zip can be used only to upgrade version '8.8.8' and you are running
                  version 4.1.0-SNAPSHOT"
                },
                {
                  "archive": "update_bad.zip",
                  "reason": "Unable to read or find package.properties within update_bad.zip",
                  "errorMessage": "Possible exception message."
                },
                {
                  "archive": "update_XXX.zip",
                  "reason": "The archive update_XXX.zip can be used only to upgrade product 'OpenXXX' and you are
                  running product OpenIDM"
                }
            ]
        }
    }

2. Get list of file changes for a given update archive:

	ACTION openidm/maintenance/update?_action=preview&archive=OpenIDM-4.5.0.zip

	returns:
	[
		{
			"filePath" : "bin/defaults/script/access.js",
			"fileState" : "UNEXPECTED" (states from FileState.java, see below)
		}, {
			...
		}
	]

2a. Get applicable license for an update archive:

	ACTION openidm/maintenance/update?_action=getLicense&archive=OpenIDM-4.5.0.zip

	returns:
    {
        "license" : "<WALL O' TEXT>"
    }

2b. Get list of repo updates (for the current db type) for a given update archive
    ACTION openidm/maintenance/update?_action=listRepoUpdates&archive=OpenIDM-4.5.0.zip

    returns:
    [
        {
            "file": "v1_shorten_link_columns.sql",
            "path": "db/postgresql/scripts/updates/v1_shorten_link_columns.sql"
        },
        {
            "file": "v2_some_change.sql",
            "path": "db/postgresql/scripts/updates/v2_some_change.sql"
        },
        {
            "file": "v3_more_changes.sql",
            "path": "db/postgresql/scripts/updates/v3_more_changes.sql"
        }
    ]

2c. Get repo update file(s) from archive
    GET openidm/maintenance/update/archives/{archive}/{path...}
    GET openidm/maintenance/update/archives/OpenIDM-4.5.0.zip/db/postgresql/scripts/updates/v1_shorten_link_columns.sql?_fields=/contents&_mimeType=text/plain

    returns:

        -- Column lengths are stored as N+4 for legacy reasons
        -- Much faster way of updating column length in postgres
        -- Instant change vs full-rewrite with ALTER
        UPDATE pg_attribute SET atttypmod = 54 WHERE attrelid = 'links'::regclass AND attname = 'linktype';
        UPDATE pg_attribute SET atttypmod = 54 WHERE attrelid = 'links'::regclass AND attname = 'linkqualifier';

3. Perform update using a given update archive

	ACTION openidm/maintenance/update?_action=update&archive=OpenIDM-4.5.0.zip

	returns:
	{
		"_id" : "someIDstring",
		"status" : "IN_PROGRESS" (see below for possible states),
		"statusMessage" : "Initializing",
		"completedTasks" : 0,
		"totalTasks" : 350,
		"startDate" : "2016-04-01 12:00:00",
		"user" : "openidm-admin"
	}

3a. List pending repo updates for the currently running update (identical to 2a sans archive)
    ACTION openidm/maintenance/update?_action=listRepoUpdates

    returns:
    [
        {
            "file": "v1_shorten_link_columns.sql",
            "path": "db/postgresql/scripts/updates/v1_shorten_link_columns.sql"
        },
        {
            "file": "v2_some_change.sql",
            "path": "db/postgresql/scripts/updates/v2_some_change.sql"
        },
        {
            "file": "v3_more_changes.sql",
            "path": "db/postgresql/scripts/updates/v3_more_changes.sql"
        }
    ]

3b. Get the repo update script (see 2c)

3c. Mark repo updates as complete for a PENDING_REPO_UPDATES update

    ACTION openidm/maintenance/update?_action=markComplete&updateId=someIDstring

	returns:
	{
		"_id" : "someIDstring",
		"status" : "COMPLETE",
		"statusMessage" : "All done!",
		"completedTasks" : 350,
		"totalTasks" : 350,
		"startDate" : "2016-04-01 12:00:00",
		"user" : "openidm-admin"
	}

4. Get status of running update

	QUERY openidm/maintenance/update/log?_queryFilter=_id+eq+%22someIDstring%22

	returns (while still in progress):
	{
		"_id" : "someIDstring",
		"status" : "IN_PROGRESS",
		"statusMessage" : "Doing something",
		"completedTasks" : 150,
		"totalTasks" : 350,
		"startDate" : "2016-04-01 12:00:00",
		"user" : "openidm-admin"
	}

	(while main update complete but repo updates must be run):
    {
        "_id" : "someIDstring",
        "status" : "PENDING_REPO_UPDATES",
        "statusMessage" : "Repo updates required",
        "completedTasks" : 350,
        "totalTasks" : 350,
        "startDate" : "2016-04-01 12:00:00",
        "endDate" : "2016-04-01 13:00:00",
        "user" : "openidm-admin",
        "nodeId" : "node3",
        "files" : [
            {
                "filePath" : "bin/defaults/script/access.js",
                "fileState" : "REPLACED" (see Post-Update File States below),
                "backup" : "bin/defaults/script/access.js.<update id>"
            },
            ...
        ]
    }

	(while in terminal state):
	{
		"_id" : "someIDstring",
		"status" : "COMPLETE",
		"statusMessage" : "Something went horribly wrong",
		"completedTasks" : 15,
		"totalTasks" : 350,
		"startDate" : "2016-04-01 12:00:00",
		"endDate" : "2016-04-01 13:00:00",
		"user" : "openidm-admin",
		"nodeId" : "node3",
		"files" : [
			{
				"filePath" : "bin/defaults/script/access.js",
				"fileState" : "REPLACED" (see Post-Update File States below),
				"backup" : "bin/defaults/script/access.js.<update id>"
			},
			...
		]
	}

5. Get list of updates

	QUERY openidm/maintenance/update/log/?_queryFilter=true

	returns:
	[
		{
			"archive" : "OpenIDM-4.1.0.zip",
			"_id" : "someIDstring",
			"status" : "COMPLETED",
    		"statusMessage" : "Rainbows and unicorns",
    		"completedTasks" : 350,
	    	"totalTasks" : 350,
    		"startDate" : "2016-04-01 12:00:00",
    		"endDate" : "2016-04-01 13:00:00",
    		"user" : "openidm-admin",
    		"nodeId" : "node1"
		},
		...
	]

	The id can be passed to READ openidm/maintenance/update/log/someIDstring to fetch the log if terminal or just status
	otherwise.

6. Optionally restart IDM immediately.  IDM can be restarted at any time with this call.  If an update has completed
    and is sleeping prior to the automatic restart this method call will interrupt that sleep to restart immediately.

    POST openidm/maintenance/update?_action=restart

    returns:
    {}

7. Return the id of the most recently successfully installed update

    POST openidm/maintenance/update?_action=lastUpdateId

    returns:
    {
        "lastUpdateId" : "<value>"
    }

8. Fetch a summary list of all installed updates

    POST openidm/maintenance/update?_action=installed

    returns:
    [
      {
        "archive": "OpenIDM-4.1.0.zip",
        "status": "FAILED",
        "completedTasks": 523,
        "totalTasks": 2821,
        "startDate": "2016-02-23T12:46:30.8-08:00",
        "endDate": "2016-02-23T12:46:56.478-08:00",
        "userName": "openidm-admin",
        "statusMessage": "Update failed."
      }, {
        ...
      }
    ]


FileState States:

    These states are described from the perspective of the existing installation, not that of the update archive.

    /** The file exists on disk but not in the list of known files for the original distribution. */
    UNEXPECTED,
    /** The file does not exist on disk nor in the list of known files for the original distribution. */
    NONEXISTENT,
    /** The file should exist but does not. */
    DELETED,
    /** The file on disk has been changed since the original deployment in a read-only directory. */
    DIFFERS,
    /** The file is unchanged from the original distribution. */
    UNCHANGED

Update Statuses:

    IN_PROGRESS             Update has started, not yet completed
    PENDING_REPO_UPDATES    Update is completed, repo updates pending
    COMPLETE                Update is complete
    FAILED                  Update failed

    Note that it is possible an update could remain in IN_PROGRESS or FAILED state forever if the thread/process
    died before the update could reach COMPLETE, the "terminal state".  Updates are not reentrant at this time.

Post-Update File States:

    REPLACED        Original file was replaced with new file. If original file had user changes it was renamed with
                    a -old extension.
    PRESERVED       Original file contained user changes and was preserved. New file added with -new extension.
    APPLIED         A patch was applied to the configuration of the same name.



Other

Backups should be named after the original file plus the update id as a suffix. Thus script/access.js backed up as
part of an update assign the id "123foo" named script/access.js.123foo.

Requests for update history against repo/update can use queryFilter to filter the history results.
