@Override
	public ProgramDB getDomainObject(FolderItem item, FileSystem userfs, long checkoutId,
			boolean okToUpgrade, boolean recover, Object consumer, TaskMonitor monitor)
			throws IOException, VersionException, CancelledException {

		String contentType = item.getContentType();
		if (contentType != null && !contentType.equals(PROGRAM_CONTENT_TYPE)) {
			throw new IOException("Unsupported content type: " + contentType);
		}
		DatabaseItem dbItem = (DatabaseItem) item;
		ManagedBufferFile bf = null;
		DBHandle dbh = null;
		ProgramDB program = null;
		boolean success = false;
		try {
			bf = dbItem.openForUpdate(checkoutId);
			dbh = new DBHandle(bf, recover, monitor);
			OpenMode openMode = okToUpgrade ? OpenMode.UPGRADE : OpenMode.UPDATE;
			program = new ProgramDB(dbh, openMode, monitor, consumer);
			if (checkoutId == FolderItem.DEFAULT_CHECKOUT_ID) {
				loadProgramChangeSet(program, bf);
			}
			if (recover) {
				recoverChangeSet(program, dbh);
				program.setChanged(true);
			}
			program.setProgramUserData(getProgramUserData(program, dbItem, userfs, monitor));
			success = true;
			return program;
		}
		catch (Field.UnsupportedFieldException e) {
			throw new VersionException(false);
		}
		catch (VersionException | IOException | CancelledException e) {
			throw e;
		}
		catch (Throwable t) {
			Msg.error(this, "getDomainObject failed", t);
			String msg = t.getMessage();
			if (msg == null) {
				msg = t.toString();
			}
			throw new IOException("Open failed: " + msg, t);
		}
		finally {
			if (!success) {
				if (program != null) {
					program.release(consumer);
				}
				if (dbh != null) {
					dbh.close();
				}
				if (bf != null) {
					bf.dispose();
				}
			}
		}
	}
<code>ProgramContentHandler</code> converts between Program instantiations
and FolderItem storage.  This class also produces the appropriate Icon for 
Program files.
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramContentHandler.java