private IfcModel realCheckout(
      Project project, Revision revision, DatabaseSession databaseSession, User user)
      throws BimserverLockConflictException, BimserverDatabaseException, UserException {
    SerializerPluginConfiguration serializerPluginConfiguration =
        getDatabaseSession()
            .get(
                StorePackage.eINSTANCE.getSerializerPluginConfiguration(),
                serializerOid,
                Query.getDefault());
    final long totalSize = revision.getSize();
    final AtomicLong total = new AtomicLong();

    IfcModelSet ifcModelSet = new IfcModelSet();
    for (ConcreteRevision subRevision : revision.getConcreteRevisions()) {
      IfcModel subModel = new IfcModel();
      int highestStopId = findHighestStopRid(project, subRevision);
      Query query =
          new Query(
              subRevision.getProject().getId(), subRevision.getId(), null, Deep.YES, highestStopId);
      subModel.addChangeListener(
          new IfcModelChangeListener() {
            @Override
            public void objectAdded() {
              total.incrementAndGet();
              if (totalSize == 0) {
                setProgress("Preparing checkout...", 0);
              } else {
                setProgress(
                    "Preparing checkout...", (int) Math.round(100.0 * total.get() / totalSize));
              }
            }
          });
      getDatabaseSession().getMap(subModel, query);
      try {
        checkGeometry(
            serializerPluginConfiguration,
            getBimServer().getPluginManager(),
            subModel,
            project,
            subRevision,
            revision);
      } catch (GeometryGeneratingException e) {
        throw new UserException(e);
      }
      subModel.getModelMetaData().setDate(subRevision.getDate());
      ifcModelSet.add(subModel);
    }

    IfcModelInterface ifcModel = new IfcModel();
    if (ifcModelSet.size() > 1) {
      try {
        ifcModel =
            getBimServer()
                .getMergerFactory()
                .createMerger(getDatabaseSession(), getAuthorization().getUoid())
                .merge(revision.getProject(), ifcModelSet, new ModelHelper(ifcModel));
      } catch (MergeException e) {
        throw new UserException(e);
      }
    } else {
      ifcModel = ifcModelSet.iterator().next();
    }

    ifcModel.getModelMetaData().setName(project.getName() + "." + revision.getId());
    ifcModel.getModelMetaData().setRevisionId(project.getRevisions().indexOf(revision) + 1);
    ifcModel.getModelMetaData().setAuthorizedUser(user.getName());
    ifcModel.getModelMetaData().setDate(new Date());
    return (IfcModel) ifcModel;
  }
  @Override
  public IfcModelInterface execute()
      throws UserException, BimserverLockConflictException, BimserverDatabaseException {
    User user = getUserByUoid(getAuthorization().getUoid());
    Set<String> foundNames = new HashSet<String>();
    IfcModelSet ifcModelSet = new IfcModelSet();
    Project project = null;
    long incrSize = 0L;

    SerializerPluginConfiguration serializerPluginConfiguration =
        getDatabaseSession()
            .get(
                StorePackage.eINSTANCE.getSerializerPluginConfiguration(),
                serializerOid,
                Query.getDefault());

    for (Long roid : roids) {
      Revision virtualRevision = getRevisionByRoid(roid);
      project = virtualRevision.getProject();
      if (!getAuthorization().hasRightsOnProjectOrSuperProjectsOrSubProjects(user, project)) {
        throw new UserException(
            "User has insufficient rights to download revisions from this project");
      }
      Map<ConcreteRevision, Set<Long>> map = new HashMap<ConcreteRevision, Set<Long>>();
      for (String name : names) {
        if (!foundNames.contains(name)) {
          for (ConcreteRevision concreteRevision : virtualRevision.getConcreteRevisions()) {
            for (ObjectIdentifier objectIdentifier :
                getDatabaseSession()
                    .getOidsOfName(
                        name, concreteRevision.getProject().getId(), concreteRevision.getId())) {
              foundNames.add(name);
              if (!map.containsKey(concreteRevision)) {
                map.put(concreteRevision, new HashSet<Long>());
                incrSize += concreteRevision.getSize();
              }
              map.get(concreteRevision).add(objectIdentifier.getOid());
            }
          }
        }
      }
      final long totalSize = incrSize;
      final AtomicLong total = new AtomicLong();

      for (ConcreteRevision concreteRevision : map.keySet()) {
        IfcModel subModel = new IfcModel();
        int highestStopId = findHighestStopRid(project, concreteRevision);
        Query query =
            new Query(
                concreteRevision.getProject().getId(),
                concreteRevision.getId(),
                objectIDM,
                deep,
                highestStopId);
        subModel.addChangeListener(
            new IfcModelChangeListener() {
              @Override
              public void objectAdded() {
                total.incrementAndGet();
                progress = (int) Math.round(100.0 * total.get() / totalSize);
              }
            });
        Set<Long> oids = map.get(concreteRevision);
        getDatabaseSession().getMapWithOids(subModel, oids, query);
        subModel.getModelMetaData().setDate(concreteRevision.getDate());

        try {
          checkGeometry(
              serializerPluginConfiguration,
              bimServer.getPluginManager(),
              subModel,
              project,
              concreteRevision,
              virtualRevision);
        } catch (GeometryGeneratingException e) {
          throw new UserException(e);
        }

        ifcModelSet.add(subModel);
      }
    }
    IfcModelInterface ifcModel = new IfcModel();
    try {
      ifcModel =
          bimServer
              .getMergerFactory()
              .createMerger(getDatabaseSession(), getAuthorization().getUoid())
              .merge(project, ifcModelSet, new ModelHelper(ifcModel));
      ifcModel.getModelMetaData().setName("query");
      for (String name : names) {
        if (!foundNames.contains(name)) {
          throw new UserException("Name " + name + " not found");
        }
      }
      ifcModel.getModelMetaData().setRevisionId(1);
      ifcModel
          .getModelMetaData()
          .setAuthorizedUser(getUserByUoid(getAuthorization().getUoid()).getName());
      ifcModel.getModelMetaData().setDate(new Date());
      return ifcModel;
    } catch (MergeException e) {
      throw new UserException(e);
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  public Set<T> execute()
      throws UserException, BimserverLockConflictException, BimserverDatabaseException {
    Map<Long, Revision> oidToRoidMap = new HashMap<Long, Revision>();

    // Look in the cache
    Set<EidClash> clashDetections =
        bimServer.getClashDetectionCache().getClashDetection(clashDetectionSettings);
    if (clashDetections != null) {
      return (Set<T>) clashDetections;
    }

    Project project = null;
    IfcModelSet ifcModelSet = new IfcModelSet();
    for (Revision revision : clashDetectionSettings.getRevisions()) {
      project = revision.getProject();
      for (ConcreteRevision concreteRevision : revision.getConcreteRevisions()) {
        IfcModel source = new IfcModel();
        getDatabaseSession()
            .getMap(
                source,
                concreteRevision.getProject().getId(),
                concreteRevision.getId(),
                true,
                null);
        source.setDate(concreteRevision.getDate());
        ifcModelSet.add(source);
        for (Long oid : source.keySet()) {
          oidToRoidMap.put(oid, revision);
        }
      }
    }
    IfcModelInterface ifcModel =
        bimServer.getMergerFactory().createMerger().merge(project, ifcModelSet, false);
    IfcModel newModel = new IfcModel();
    Map<IdEObject, IdEObject> converted = new HashMap<IdEObject, IdEObject>();
    for (IdEObject idEObject : ifcModel.getValues()) {
      if (!clashDetectionSettings.getIgnoredClasses().contains(idEObject.eClass().getName())) {
        cleanupModel(idEObject.eClass(), idEObject, newModel, ifcModel, converted);
      }
    }
    Collection<SerializerPlugin> allSerializerPlugins =
        bimServer.getPluginManager().getAllSerializerPlugins("application/ifc", true);
    if (!allSerializerPlugins.isEmpty()) {
      SerializerPlugin serializerPlugin = allSerializerPlugins.iterator().next();
      EmfSerializer ifcSerializer = serializerPlugin.createSerializer();
      try {
        try {
          ifcSerializer.init(
              newModel,
              null,
              bimServer.getPluginManager(),
              bimServer.getPluginManager().requireIfcEngine().createIfcEngine());
          byte[] bytes = ifcSerializer.getBytes();
          Plugin plugin =
              bimServer
                  .getPluginManager()
                  .getPlugin("org.bimserver.ifcengine.TNOIfcEnginePlugin", true);
          if (plugin != null && plugin instanceof IfcEnginePlugin) {
            IfcEnginePlugin ifcEnginePlugin = (IfcEnginePlugin) plugin;
            IfcEngine ifcEngine = ifcEnginePlugin.createIfcEngine();
            ifcEngine.init();
            IfcEngineModel ifcEngineModel = ifcEngine.openModel(bytes);
            try {
              Set<IfcEngineClash> clashes =
                  ifcEngineModel.findClashesWithEids(clashDetectionSettings.getMargin());

              Set<EidClash> eidClashes = new HashSet<EidClash>();
              for (IfcEngineClash clash : clashes) {
                EidClash eidClash = StoreFactory.eINSTANCE.createEidClash();
                eidClash.setEid1(clash.getEid1());
                eidClash.setEid2(clash.getEid2());
                eidClash.setName1(clash.getName1());
                eidClash.setName2(clash.getName2());
                eidClash.setType1(clash.getType1());
                eidClash.setType2(clash.getType2());
                eidClashes.add(eidClash);
              }

              // Store in cache
              bimServer
                  .getClashDetectionCache()
                  .storeClashDetection(clashDetectionSettings, eidClashes);

              for (EidClash clash : eidClashes) {
                IfcRoot object1 = (IfcRoot) newModel.get(clash.getEid1());
                clash.setName1(object1.getName());
                clash.setType1(object1.eClass().getName());
                clash.setRevision1(oidToRoidMap.get(clash.getEid1()));
                IfcRoot object2 = (IfcRoot) newModel.get(clash.getEid2());
                clash.setName2(object2.getName());
                clash.setType2(object2.eClass().getName());
                clash.setRevision2(oidToRoidMap.get(clash.getEid2()));
              }
              return (Set<T>) eidClashes;
            } finally {
              ifcEngineModel.close();
              ifcEngine.close();
            }
          }
        } catch (PluginException e) {
          LOGGER.error("", e);
        }
      } catch (SerializerException e) {
        LOGGER.error("", e);
      }
    }
    return null;
  }