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

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

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.RealmHistoryLockService;
import dk.grinn.keycloak.migration.entities.RealmHistory;
import dk.grinn.keycloak.migration.entities.RealmHistoryLock;
import dk.grinn.keycloak.migration.entities.Session;
import java.nio.ByteBuffer;
import static java.util.Arrays.asList;
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.OptimisticLockException;
import javax.persistence.PessimisticLockException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

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

    private static final Integer HISTORY_LOCK_MASTER_ID = 1;

    protected EntityManager em;

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

    /**
     * Get all history locks.
     *
     * @return
     */
    public List getAll() {
        TypedQuery q = em.createNamedQuery("RealmHistoryLock.findAll", RealmHistoryLock.class);
        return q.getResultList();
    }

    /**
     * Get all history locks as sessions.
     * 
     * @param onlyActive
     * @return 
     */
    public List getSessions(boolean onlyActive) {
        TypedQuery q = em.createNamedQuery("RealmHistoryLock.findSessions", Session.class);
        q.setParameter("onlyActive", onlyActive);
        List result = q.getResultList();
        return result;
    }
    
    /**
     * 
     * @param session
     * @return 
     * @throws NoResultException
     */
    public RealmHistoryLock get(UUID session) {
        TypedQuery q = em.createNamedQuery("RealmHistoryLock.findBySession", RealmHistoryLock.class);
        q.setParameter("session", getBinary(session));
        return q.getSingleResult();
    }

    /**
     *
     * @param realm
     * @param lockUser
     * @return
     * @throws OptimisticLockException Realm all ready in session use.
     * @throws PessimisticLockException Could not lock the master entry (30
     * seconds timeout).
     */
    @Override
    public UUID createSession(String realm, String lockUser) {
        // Need exclusive access to the whole history while creating the session
        lockMaster(lockUser);

        // Create or update session
        TypedQuery q = em.createNamedQuery(
                "RealmHistoryLock.findByRealm", RealmHistoryLock.class
        );
        q.setParameter("realm", realm);
        List realmLocks = q.getResultList();

        RealmHistoryLock realmLock;
        if (realmLocks.size() == 1) {
            realmLock = realmLocks.get(0);
            if (realmLock.getSession() != null) {
                throw new OptimisticLockException("Realm allready locked by: " + realmLock.getLockedBy());
            }
            realmLock.setSession(lockUser);
        } else {
            // The lock entry
            realmLock = new RealmHistoryLock(realm, lockUser);
            em.persist(realmLock);

            // The first migration - 
            realmLock.getHistory().add(
                    new RealmHistory(
                            realmLock, asList(realm), "<>", lockUser
                    )
            );
        }
        em.merge(realmLock);
        em.flush();
        return realmLock.getSession();
    }

    /**
     * Release the session.
     *
     * @param session
     * @return
     */
    @Override
    public int releaseSession(UUID session) {
        Query stmt = em.createNamedQuery("RealmHistoryLock.releaseSession");
        stmt.setParameter("session", getBinary(session));
        int result = stmt.executeUpdate();
        em.clear();
        return result;
    }

    /**
     * Abort any session on the realm.
     * 

* Only to be used in an abnormal situation where the session id has been * lost (caused by an error on a previous run, etc.). * * @param realm * @param abortedBy * @return */ @Override public int abortSession(String realm, String abortedBy) { Query stmt = em.createNamedQuery("RealmHistoryLock.releaseSessionByRealm"); stmt.setParameter("realm", realm); int result = stmt.executeUpdate(); em.clear(); return result; } /** * {@inheritDoc} */ @Override public void removeSession(UUID sessionId) { em.remove(get(sessionId)); } /** * Get a write lock on the master history lock element. * * @param lockUser * @return * @throws NoResultException If no master entry is found. * @throws PessimisticLockException Didn't get the lock (30 seconds * timeout). */ public RealmHistoryLock lockMaster(String lockUser) { RealmHistoryLock result = em.find(RealmHistoryLock.class, HISTORY_LOCK_MASTER_ID, PESSIMISTIC_WRITE); if (result == null) { throw new NoResultException("Unable to find the master history lock element"); } return result; } public static byte[] getBinary(UUID id) { ByteBuffer bb = ByteBuffer.allocate(16); bb.putLong(id.getMostSignificantBits()); bb.putLong(id.getLeastSignificantBits()); return bb.array(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy