class UpgradeRestService {

    @POST
    public Response upgrade( OobUpgradeSpec upgradeSpec )
        throws HMSRestException
    {

        String message = null;

        // validate upgrade request.
        Response validationResponse = UpgradeUtil.validateUpgradeRequest( upgradeSpec );
        if ( validationResponse != null )
        {
            // delete upgrade scripts and upgrade bundle files
            if ( upgradeSpec != null )
            {
                UpgradeUtil.deleteUpgradeFiles( upgradeSpec.getId() );
            }
            return validationResponse;
        }

        final String upgradeId = upgradeSpec.getId();
        final String upgradeDir = UpgradeUtil.getUpgradeDir( upgradeId );

        UpgradeStatus status = new UpgradeStatus();
        status.setId( upgradeId );

        boolean scriptsExecutable = FileUtil.setFilesExecutable( upgradeDir, "sh" );
        if ( !scriptsExecutable )
        {

            // delete upgrade scripts and upgrade bundle files
            UpgradeUtil.deleteUpgradeFiles( upgradeId );

            message = String.format( "Failed to grant execute rights to upgrade scripts at '%s'.", upgradeDir );
            logger.error( message );

            status.setStatusCode( UpgradeStatusCode.HMS_OOB_UPGRADE_INTERNAL_ERROR );
            status.setStatusMessage( UpgradeStatusCode.HMS_OOB_UPGRADE_INTERNAL_ERROR.getStatusMessage() );
            status.setMoreInfo( message );
            return Response.status( Status.INTERNAL_SERVER_ERROR ).entity( status ).build();
        }

        /*
         * 1. Put Service under maintenance 2. Drain/Post all events in queue 3. Shut off monitoring threads
         */
        boolean serviceInMaintenance = ServiceManager.putServiceInMaintenance();
        if ( serviceInMaintenance )
        {

            // Invoke upgrade-hms-oob script
            boolean upgradeInitiated = UpgradeUtil.initiateUpgrade( upgradeId, upgradeSpec.getFileName() );

            if ( upgradeInitiated )
            {

                if ( ( ServiceManager.getServiceState().equals( ServiceState.NORMAL_MAINTENANCE ) )
                    && ( ServiceManager.getActiveRequests() == 1 ) )
                {

                    message =
                        "Upgrade initiated after Out-of-band agent in " + ServiceState.NORMAL_MAINTENANCE.toString();

                }
                else if ( ( ServiceManager.getServiceState().equals( ServiceState.FORCE_MAINTENANCE ) )
                    && ( ServiceManager.getActiveRequests() > 1 ) )
                {

                    message =
                        String.format( "Upgrade initiated after Out-of-band agent " + "in %s with %s active requests.",
                                       ServiceState.FORCE_MAINTENANCE.toString(), ServiceManager.getActiveRequests() );
                }

                logger.info( message );

                // save upgradeStatus to json file.
                status.setStatusCode( UpgradeStatusCode.HMS_OOB_UPGRADE_INITIATED );

                final String hmsUpgradeDir = UpgradeUtil.getHmsUpgradeDir();
                String upgradeStatusFileAbsPath = String.format( "%1$s/%2$s.json", hmsUpgradeDir, upgradeId );
                boolean saved = HmsUpgradeUtil.saveUpgradeStatus( upgradeStatusFileAbsPath, status );
                if ( saved )
                {
                    logger.info( "Saved upgrade status to '{}'", upgradeStatusFileAbsPath );
                }
                else
                {
                    logger.warn( "Unable to save upgrade status to '{}'.", upgradeStatusFileAbsPath );
                }

                status.setStatusMessage( UpgradeStatusCode.HMS_OOB_UPGRADE_INITIATED.getStatusMessage() );
                status.setMoreInfo( message );
                return Response.status( Status.ACCEPTED ).entity( status ).build();

            }
            else
            {

                // delete upgrade scripts and upgrade bundle files
                UpgradeUtil.deleteUpgradeFiles( upgradeId );

                message = "Executing Out-of-band Agent upgrade script failed.";
                logger.error( message );

                /*
                 * put back service in running state and reset activeRequests and restart monitoring.
                 */
                ServiceManager.putServiceInRunning();

                status.setStatusCode( UpgradeStatusCode.HMS_OOB_UPGRADE_INTERNAL_ERROR );
                status.setStatusMessage( UpgradeStatusCode.HMS_OOB_UPGRADE_INTERNAL_ERROR.getStatusMessage() );
                status.setMoreInfo( message );
                return Response.status( Status.INTERNAL_SERVER_ERROR ).entity( status ).build();
            }
        }
        else
        {

            // delete upgrade scripts and upgrade bundle files
            UpgradeUtil.deleteUpgradeFiles( upgradeId );

            message = "Setting Out-of-band Agent Service in MAINTENANCE failed.";
            logger.error( message );
            status.setStatusCode( UpgradeStatusCode.HMS_OOB_UPGRADE_INTERNAL_ERROR );
            status.setStatusMessage( UpgradeStatusCode.HMS_OOB_UPGRADE_INTERNAL_ERROR.getStatusMessage() );
            status.setMoreInfo( message );
            return Response.status( Status.INTERNAL_SERVER_ERROR ).entity( status ).build();
        }
    }

}