@NotNull
  @Override
  public SModel load(@NotNull DataSource dataSource, @NotNull Map<String, String> options)
      throws IOException {
    if (!(dataSource instanceof StreamDataSource)) {
      throw new UnsupportedDataSourceException(dataSource);
    }

    StreamDataSource source = (StreamDataSource) dataSource;
    SModelHeader binaryModelHeader;
    try {
      binaryModelHeader = BinaryPersistence.readHeader(source);
    } catch (ModelReadException e) {
      if (e.getCause() instanceof IOException) {
        throw (IOException) e.getCause();
      }
      throw new IOException(e.getMessageEx(), e);
    }
    if (Boolean.parseBoolean(options.get(MetaModelInfoProvider.OPTION_KEEP_READ_METAINFO))) {
      binaryModelHeader.setMetaInfoProvider(
          new StuffedMetaModelInfo(
              new RegularMetaModelInfo(binaryModelHeader.getModelReference())));
    }
    return new DefaultSModelDescriptor(new PersistenceFacility(this, source), binaryModelHeader);
  }
 /**
  * This is provisional workaround to deal with performance tuning in jps/plugin (see
  * CachedRepositoryData, CachedModelData) where header is serialized to get passed to another
  * process, where model is instantiated without need to read model file.
  *
  * <p>If there's real benefit in this optimization (commit comment suggests it's 0.5 second in
  * process startup time, which doesn't look too much, imo) this serialization shall be addressed
  * with an object supplied by descriptor itself, rather than by external means, so that full
  * control over serialize/restore is inside implementation, and all the internal stuff (like model
  * header) doesn't get exposed. FIXME revisit, reconsider approach
  */
 public static SModel createFromHeader(
     @NotNull SModelHeader header, @NotNull StreamDataSource dataSource) {
   final ModelFactory modelFactory =
       PersistenceFacade.getInstance().getModelFactory(MPSExtentions.MODEL_BINARY);
   assert modelFactory instanceof BinaryModelPersistence;
   return new DefaultSModelDescriptor(
       new PersistenceFacility((BinaryModelPersistence) modelFactory, dataSource),
       header.createCopy());
 }
 public static Map<String, String> getDigestMap(@NotNull StreamDataSource source) {
   try {
     SModelHeader binaryModelHeader = BinaryPersistence.readHeader(source);
     binaryModelHeader.setMetaInfoProvider(
         new StuffedMetaModelInfo(
             new RegularMetaModelInfo(binaryModelHeader.getModelReference())));
     final ModelLoadResult loadedModel =
         BinaryPersistence.readModel(binaryModelHeader, source, false);
     Map<String, String> result =
         BinaryPersistence.getDigestMap(
             loadedModel.getModel(), binaryModelHeader.getMetaInfoProvider());
     result.put(GeneratableSModel.FILE, ModelDigestUtil.hashBytes(source.openInputStream()));
     return result;
   } catch (ModelReadException ignored) {
     /* ignore */
   } catch (IOException e) {
     /* ignore */
   }
   return null;
 }
  @NotNull
  @Override
  public SModel create(DataSource dataSource, @NotNull Map<String, String> options)
      throws IOException {
    if (!(dataSource instanceof StreamDataSource)) {
      throw new UnsupportedDataSourceException(dataSource);
    }

    StreamDataSource source = (StreamDataSource) dataSource;
    String modelName = options.get(OPTION_MODELNAME);
    if (modelName == null) {
      throw new IOException("modelName is not provided");
    }
    String modulRef = options.get(OPTION_MODULEREF);
    if (modulRef == null) {
      throw new IOException("moduleRef is not provided");
    }

    final SModelHeader header = new SModelHeader();
    header.setModelReference(
        PersistenceFacade.getInstance()
            .createModelReference(null, jetbrains.mps.smodel.SModelId.generate(), modelName));
    return new DefaultSModelDescriptor(new PersistenceFacility(this, source), header);
  }