package org.keycloak.exportimport.util;
import org.jboss.logging.Logger;
import org.keycloak.Version;
import org.keycloak.exportimport.ExportImportConfig;
import org.keycloak.exportimport.ExportProvider;
import org.keycloak.exportimport.UsersExportStrategy;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation;
import java.io.IOException;
import java.util.List;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public abstract class MultipleStepsExportProvider implements ExportProvider {
protected final Logger logger = Logger.getLogger(getClass());
@Override
public void exportModel(KeycloakSessionFactory factory) throws IOException {
final RealmsHolder holder = new RealmsHolder();
KeycloakModelUtils.runJobInTransaction(factory, new KeycloakSessionTask() {
@Override
public void run(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms();
holder.realms = realms;
}
});
for (RealmModel realm : holder.realms) {
exportRealmImpl(factory, realm.getName());
}
writeVersion("version.json", Version.SINGLETON);
}
@Override
public void exportRealm(KeycloakSessionFactory factory, String realmName) throws IOException {
exportRealmImpl(factory, realmName);
writeVersion("version.json", Version.SINGLETON);
}
protected void exportRealmImpl(KeycloakSessionFactory factory, final String realmName) throws IOException {
final UsersExportStrategy usersExportStrategy = ExportImportConfig.getUsersExportStrategy();
final int usersPerFile = ExportImportConfig.getUsersPerFile();
final UsersHolder usersHolder = new UsersHolder();
final boolean exportUsersIntoRealmFile = usersExportStrategy == UsersExportStrategy.REALM_FILE;
KeycloakModelUtils.runJobInTransaction(factory, new ExportImportSessionTask() {
@Override
protected void runExportImportTask(KeycloakSession session) throws IOException {
RealmModel realm = session.realms().getRealmByName(realmName);
RealmRepresentation rep = ExportUtils.exportRealm(session, realm, exportUsersIntoRealmFile);
writeRealm(realmName + "-realm.json", rep);
logger.info("Realm '" + realmName + "' - data exported");
// Count total number of users
if (!exportUsersIntoRealmFile) {
usersHolder.totalCount = session.users().getUsersCount(realm);
}
}
});
if (usersExportStrategy != UsersExportStrategy.SKIP && !exportUsersIntoRealmFile) {
// We need to export users now
usersHolder.currentPageStart = 0;
// usersExportStrategy==SAME_FILE means exporting all users into single file (but separate to realm)
final int countPerPage = (usersExportStrategy == UsersExportStrategy.SAME_FILE) ? usersHolder.totalCount : usersPerFile;
while (usersHolder.currentPageStart < usersHolder.totalCount) {
if (usersHolder.currentPageStart + countPerPage < usersHolder.totalCount) {
usersHolder.currentPageEnd = usersHolder.currentPageStart + countPerPage;
} else {
usersHolder.currentPageEnd = usersHolder.totalCount;
}
KeycloakModelUtils.runJobInTransaction(factory, new ExportImportSessionTask() {
@Override
protected void runExportImportTask(KeycloakSession session) throws IOException {
RealmModel realm = session.realms().getRealmByName(realmName);
usersHolder.users = session.users().getUsers(realm, usersHolder.currentPageStart, usersHolder.currentPageEnd - usersHolder.currentPageStart);
writeUsers(realmName + "-users-" + (usersHolder.currentPageStart / countPerPage) + ".json", session, realm, usersHolder.users);
logger.info("Users " + usersHolder.currentPageStart + "-" + (usersHolder.currentPageEnd -1) + " exported");
}
});
usersHolder.currentPageStart = usersHolder.currentPageEnd;
}
}
}
protected abstract void writeRealm(String fileName, RealmRepresentation rep) throws IOException;
protected abstract void writeUsers(String fileName, KeycloakSession session, RealmModel realm, List<UserModel> users) throws IOException;
protected abstract void writeVersion(String fileName, Version version) throws IOException;
public static class RealmsHolder {
List<RealmModel> realms;
}
public static class UsersHolder {
List<UserModel> users;
int totalCount;
int currentPageStart;
int currentPageEnd;
}
}