dk.grinn.keycloak.migration.boundary.RealmHistoryController Maven / Gradle / Ivy
Show all versions of keycloak-migrate-spi Show documentation
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();
}
}