All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dk.grinn.keycloak.migration.boundary.RealmHistoryController Maven / Gradle / Ivy

Go to download

Keycloak migrate extending the keycloak jpa model to include migrate versioning. And addtional REST end-points for migration purposes.

There is a newer version: 15.0.0.1
Show newest version
package dk.grinn.keycloak.migration.boundary;

/*-
 * #%L
 * Keycloak : Migrate : Spi
 * %%
 * Copyright (C) 2019 Jonas Grann & Kim Jersin
 * %%
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * #L%
 */
import dk.grinn.keycloak.migration.services.RealmHistoryService;
import static dk.grinn.keycloak.migration.boundary.RealmHistoryLockController.getBinary;
import dk.grinn.keycloak.migration.entities.RealmHistory;
import dk.grinn.keycloak.migration.entities.RealmHistoryLock;
import dk.grinn.keycloak.migration.entities.RealmHistoryPK;
import dk.grinn.keycloak.migration.entities.ScriptHistory;
import dk.grinn.keycloak.migration.entities.ScriptHistoryKey;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import static javax.persistence.LockModeType.PESSIMISTIC_WRITE;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

/**
 *
 * @author @author Kim Jersin <[email protected]>
 */
public class RealmHistoryController implements RealmHistoryService {

    protected EntityManager em;

    @Inject
    public RealmHistoryController(EntityManager em) {
        this.em = em;
    }

    /**
     * Register begin of the script.
     *
     * @param session
     * @param version
     * @param description
     * @param type
     * @param installedBy
     * @param repeatable
     * @return
     * @throws NoResultException Not a valid session.
     * @throws NonUniqueResultException A script is all ready being processed
     * @see RealmHistoryLockController#createSession
     */
    @Override
    public ScriptHistoryKey scriptBegin(UUID session, String version, String description, String type, String installedBy, boolean repeatable) {
        // Get session lock (happens on a realm basis)
        // And check that no current script is in progress (open)
        RealmHistoryLock lock = getLock(session);
        TypedQuery countOpen = em.createNamedQuery(
                "RealmHistory.countOpen", Long.class
        );
        countOpen.setParameter("session", getBinary(session));
        if (countOpen.getSingleResult() != 0) {
            throw new NonUniqueResultException("A script is all ready being processed");
        }

        RealmHistory script = null;
        if (repeatable) {
            TypedQuery q = em.createNamedQuery("RealmHistory.findBySessionAndVersion", RealmHistory.class);
            q.setParameter("version", version);
            q.setParameter("session", getBinary(session));
            List scripts = q.getResultList();
            script = scripts.isEmpty() ? null : scripts.get(0);
        }

        // New or update
        if (script != null) {
            script.setDescription(description);
            script.setType(type);
            script.setInstalledBy(installedBy);
            script.setScript(null);
            em.merge(script);
        } else {
            // Create the next script entry in the migration history of the realm
            script = new RealmHistory(
                    lock, version, description, type, installedBy
            );
            lock.getHistory().add(script);
            em.merge(lock);
        }
        em.flush();

        return script.getPk().asScriptHistoryKey();
    }

    /**
     * (Re)open an existing script.
     *
     * @param session
     * @param version
     * @param openedBy
     * @return
     * @throws NoResultException Not a valid session or the script does not exists.
     * @throws NonUniqueResultException A script is all ready being processed
     * @see RealmHistoryLockController#createSession
     */
    @Override
    public ScriptHistoryKey scriptOpen(UUID session, String version, String openedBy) {
        // Get session lock (happens on a realm basis)
        // And check that no current script is in progress (open)
        RealmHistoryLock lock = getLock(session);
        TypedQuery countOpen = em.createNamedQuery(
                "RealmHistory.countOpen", Long.class
        );
        countOpen.setParameter("session", getBinary(session));
        if (countOpen.getSingleResult() != 0) {
            throw new NonUniqueResultException("A script is all ready being processed");
        }

        // Get the script
        TypedQuery q = em.createNamedQuery("RealmHistory.findBySessionAndVersion", RealmHistory.class);
        q.setParameter("version", version);
        q.setParameter("session", getBinary(session));
        RealmHistory script = q.getSingleResult();

        // And open it!
        script.setInstalledBy(openedBy);
        script.setScript(null);
        em.merge(script);
        em.flush();
        return script.getPk().asScriptHistoryKey();
    }

    /**
     * Commit (close) the history script entry.
     * 

* The history entry is updated with the information collected by the client * responsible of the migration. * * @param session * @param key As obtained by {@link #scriptBegin} * @param script (Not null) Typically the name of the script. * @param checksum Checksum * @param executionTime In milliseconds - how long time the migration took. * @throws NoResultException Unable to find the open history script entry. * @see RealmHistoryLockController#createSession */ @Override public void scriptCommit(UUID session, ScriptHistoryKey key, String script, Long checksum, int executionTime) { // Get session lock (happens on a realm basis) // And get the open script entry RealmHistoryLock lock = getLock(session); TypedQuery q = em.createNamedQuery( "RealmHistory.findBySessionAndKey", RealmHistory.class ); q.setParameter("pk", new RealmHistoryPK(key)); q.setParameter("session", getBinary(session)); RealmHistory scriptHistory = q.getSingleResult(); // Apply the closing properties scriptHistory.setScript(script); scriptHistory.setChecksum(checksum); scriptHistory.setExecutionTime(executionTime); em.merge(scriptHistory); em.flush(); } /** * Remove the history script entry. * * @param session * @param key As obtained by {@link #scriptBegin} * @throws NoResultException Unable to find the open history script entry. * @see RealmHistoryLockController#createSession */ @Override public void scriptRemove(UUID session, ScriptHistoryKey key) { // Get session lock (happens on a realm basis) // And get the open script entry RealmHistoryLock lock = getLock(session); Query stmt = em.createNamedQuery("RealmHistory.removeBySessionAndKey"); stmt.setParameter("pk", new RealmHistoryPK(lock.getId(), key.getRank())); if (stmt.executeUpdate() != 1) { throw new NoResultException("Unable to locate the script to be remove"); } em.flush(); } /** * Get the script history of the realm currently associated with the * session. * * @param session * @return Script history. Ranked (ordered) by the initial creation order. * @throws NoResultException No history on the session or session not found. * @see RealmHistoryLockController#createSession */ @Override public List getHistory(UUID session) { TypedQuery q = em.createNamedQuery( "RealmHistory.findScriptHistoryBySession", ScriptHistory.class ); q.setParameter("session", getBinary(session)); return q.getResultList(); } /** * {@inheritDoc} */ @Override public ScriptHistory getHistory(UUID session, int id, int installedRank) { TypedQuery q = em.createNamedQuery( "RealmHistory.findScriptHistoryBySessionIdAndRank", ScriptHistory.class ); q.setParameter("session", getBinary(session)); q.setParameter("id", id); q.setParameter("installedRank", installedRank); return q.getSingleResult(); } /** * {@inheritDoc} */ @Override public ScriptHistory getHistory(String realm, String version) { TypedQuery q = em.createNamedQuery( "RealmHistory.findScriptHistoryByRealmAndVersion", ScriptHistory.class ); q.setParameter("realm", realm); q.setParameter("version", version); return q.getSingleResult(); } /** * Get the script history of the realm. * * @param realm * @return Script history. Ranked (ordered) by initial creation order. */ @Override public List getHistory(String realm) { TypedQuery q = em.createNamedQuery( "RealmHistory.findScriptHistoryByRealm", ScriptHistory.class ); q.setParameter("realm", realm); return q.getResultList(); } /** * * @param session * @return * @throws NoResultException No valid session. */ private RealmHistoryLock getLock(UUID session) { TypedQuery q = this.em.createNamedQuery( "RealmHistoryLock.findBySession", RealmHistoryLock.class ); q.setParameter("session", getBinary(session)); q.setLockMode(PESSIMISTIC_WRITE); return q.getSingleResult(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy