public <T extends RootEntity> void write(T entity, Callback cb) {
   if (entity == null) return;
   ModelType type = ModelType.forModelClass(entity.getClass());
   if (type == null || entity.getRefId() == null) {
     warn(cb, "no refId, or type is unknown", entity);
     return;
   }
   if (conf.hasVisited(type, entity.getId())) return;
   Writer<T> writer = getWriter(entity, conf);
   if (writer == null) {
     warn(cb, "no writer found for type " + type, entity);
     return;
   }
   try {
     conf.refFn =
         ref -> {
           write(ref, cb);
         };
     JsonObject obj = writer.write(entity);
     conf.store.put(type, obj);
     if (writer.isExportExternalFiles()) writeExternalFiles(entity, type, cb);
     if (cb != null) cb.apply(Message.info("data set exported"), entity);
   } catch (Exception e) {
     e.printStackTrace();
     if (cb != null) cb.apply(Message.error("failed to export data set", e), entity);
   }
 }
 private void writeExternalFiles(RootEntity entity, ModelType type, Callback cb) {
   if (entity == null
       || conf.db == null
       || conf.db.getFileStorageLocation() == null
       || conf.store == null) return;
   FileStore fs = new FileStore(conf.db.getFileStorageLocation());
   File dir = fs.getFolder(entity);
   if (dir == null || !dir.exists()) return;
   try {
     Path dbDir = dir.toPath();
     Copy copy = new Copy(entity.getRefId(), type, dbDir);
     Files.walkFileTree(dir.toPath(), copy);
   } catch (Exception e) {
     cb.apply(Message.error("failed to copy external files", e), entity);
   }
 }
 private void warn(Callback cb, String message, RootEntity entity) {
   if (cb == null) return;
   cb.apply(Message.warn(message), entity);
 }