package dk.kb.yggdrasil.preservation; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import dk.kb.yggdrasil.exceptions.ArgumentCheck; import dk.kb.yggdrasil.exceptions.YggdrasilException; /** * This class describes all the system states of the Yggdrasil preservation service. * It is the intention, that these states are reported back to the Valhal system after * each state change. * Step 1: Message is received from valhal results in either state PRESERVATION_REQUEST_RECEIVED * or the failstate PRESERVATION_REQUEST_RECEIVED_BUT_INCOMPLETE * Step 2: If metadata download succesfully, package the metadata . This can result in either failstate * PRESERVATION_METADATA_PACKAGED_FAILURE or successtate PRESERVATION_METADATA_PACKAGED_SUCCESSFULLY * Step 3: If still no failstate, we continue with fetching the resources associated with this metadata. * This can result in the failstate PRESERVATION_RESOURCES_DOWNLOAD_FAILURE or the OK-state * PRESERVATION_RESOURCES_DOWNLOAD_SUCCESS * Step 4: If still good to go, we package the data in the warc-format. No failstate here (need one), * but if more data required before upload to bitrepository we go to wait-state * PRESERVATION_PACKAGE_WAITING_FOR_MORE_DATA * otherwise we change state to PRESERVATION_PACKAGE_COMPLETE (is this state necessary?). If in * PRESERVATION_PACKAGE_COMPLETE remember to check * if status for other requests can be changed from PRESERVATION_PACKAGE_WAITING_FOR_MORE_DATA to * PRESERVATION_PACKAGE_COMPLETE. * Step 5: Initiate upload to Bitrepository. If initiation fails, go to the failstate * PRESERVATION_PACKAGE_UPLOAD_FAILURE. * Step 6: Wait for Bitrepository upload to complete. This can result in the failstate * PRESERVATION_PACKAGE_UPLOAD_FAILURE or final OK-state PRESERVATION_PACKAGE_UPLOAD_SUCCESS. */ public enum PreservationState implements Serializable { /** Preservation request received and understood (i.e. the message is complete). */ PRESERVATION_REQUEST_RECEIVED("Preservation request received and validated"), /** Preservation request incomplete. Something is missing. Failstate. */ PRESERVATION_REQUEST_RECEIVED_BUT_INCOMPLETE("Preservation request incomplete. Something is missing"), /** Resources downloaded successfully. */ PRESERVATION_RESOURCES_DOWNLOAD_SUCCESS("Resources downloaded successfully"), /** Resources downloaded unsuccessfully. Failstate. */ PRESERVATION_RESOURCES_DOWNLOAD_FAILURE("Resources downloaded unsuccessfully"), /** Metadata packaged successfully. */ PRESERVATION_METADATA_PACKAGED_SUCCESSFULLY("Metadata packaged successfully."), /** Metadata packaged unsuccessfully (eg. METS error or similar). Failstate. */ PRESERVATION_METADATA_PACKAGED_FAILURE("Metadata packaged unsuccessfully (eg. METS error or similarly)"), /** Resources packaged successfully. */ PRESERVATION_RESOURCES_PACKAGE_SUCCESS("Resources packaged successfully."), /** Resources not package successfully. Failstate. */ PRESERVATION_RESOURCES_PACKAGE_FAILURE("Resources not packaged successfully."), /** Package complete (metadata and ressources written to the WARC format). * and ready to initiate upload. */ PRESERVATION_PACKAGE_COMPLETE("metadata and ressources has been written to the WARC format"), /** Waiting for more requests before upload is initiated. * If the request does not have the requirement, that it should be packaged in its own package. * Then it arrives into this state. However, we can only package data together with * the same bitrepository profile. So each profile must have its own waiting queue. */ PRESERVATION_PACKAGE_WAITING_FOR_MORE_DATA( "Waiting for more requests before upload to bitrepository is initiated"), /** Initiated upload to Bitrepository. */ PRESERVATION_PACKAGE_UPLOAD_INITIATED("Upload to bitrepository initiated"), /** Upload to Bitrepository failed. Failstate. */ PRESERVATION_PACKAGE_UPLOAD_FAILURE("Upload to bitrepository failed."), /** Upload to Bitrepository was successful. */ PRESERVATION_PACKAGE_UPLOAD_SUCCESS("Upload to bitrepository was successful"), /** Preservation request failed */ PRESERVATION_REQUEST_FAILED("The preservation request failed"); private PreservationState(String description) { this.defaultDescription = description; } /** * @return The default description of this state. */ public String getDescription() { return this.defaultDescription; } /** Default description. */ private String defaultDescription; /** Set with the failstates in this enum class. */ private static final Set<PreservationState> FAIL_STATES = new HashSet<PreservationState>(Arrays.asList( PRESERVATION_PACKAGE_UPLOAD_FAILURE, PRESERVATION_METADATA_PACKAGED_FAILURE, PRESERVATION_REQUEST_RECEIVED_BUT_INCOMPLETE, PRESERVATION_RESOURCES_DOWNLOAD_FAILURE, PRESERVATION_REQUEST_FAILED)); /** * @return set of failure states. */ public static Set<PreservationState> getFailStates() { return FAIL_STATES; } /** * Method for finding out whether the state is a failstate or not. * @return true, if the state is a failstate; otherwise it returns false. */ public boolean isOkState() { return !FAIL_STATES.contains(this); } /** * Verify if state change is valid. Throws an Exception if not valid change * @param oldState the old state * @param newState the new state * @throws YggdrasilException If not a valid state change. */ public static void verifyIfValidStateChange(PreservationState oldState, PreservationState newState) throws YggdrasilException { ArgumentCheck.checkNotNull(oldState, "State oldState"); ArgumentCheck.checkNotNull(newState, "State newState"); if (!oldState.isOkState()) { throw new YggdrasilException("Cannot change from state '" + oldState + "' to '" + newState + "', since the current state is a fail-state."); } if (oldState.ordinal() > newState.ordinal()) { throw new YggdrasilException("Cannot change from state '" + oldState + "' to '" + newState + "', since we cannot go back to previous states."); } } /** * Check, if the state change from oldState to newState is valid. * @param oldState The existing state * @param newState The new state * @return true, if the transition from oldState to newState is valid; otherwise false is returned. */ public static boolean isValidStateChange(PreservationState oldState, PreservationState newState){ ArgumentCheck.checkNotNull(oldState, "State oldState"); ArgumentCheck.checkNotNull(newState, "State newState"); try { verifyIfValidStateChange(oldState, newState); return true; } catch (YggdrasilException e) { return false; } } /** * @param aState A given state * @return true, if the current state equals the given state, otherwise false. */ public boolean hasState(PreservationState aState) { return this.equals(aState); } }