class BrowseNodeEntityAdapter extends IterableEntityAdapter<OrientBrowseNode> {

  public void createAssetNode(final ODatabaseDocumentTx db,
                              final String repositoryName,
                              final String format,
                              final List<? extends BrowsePath> paths,
                              final Asset asset)
  {
    //create any parent folder nodes for this asset if not already existing
    maybeCreateParentNodes(db, repositoryName, format, paths.subList(0, paths.size() - 1));

    //now create the asset node
    OrientBrowseNode node = newNode(repositoryName, format, paths);
    ODocument document = findNodeRecord(db, node);
    if (document == null) {
      // complete the new entity before persisting
      node.setAssetId(EntityHelper.id(asset));
      addEntity(db, node);
    }
    else {
      ORID oldAssetId = document.field(P_ASSET_ID, ORID.class);
      ORID newAssetId = assetEntityAdapter.recordIdentity(asset);
      if (oldAssetId == null) {
        // shortcut: merge new information directly into existing record
        document.field(P_ASSET_ID, newAssetId);
        String path = document.field(P_PATH, OType.STRING);

        //if this node is now an asset, we don't want a trailing slash
        if (!asset.name().endsWith("/") && path.endsWith("/")) {
          path = path.substring(0, path.length() - 1);
          document.field(P_PATH, path);
        }
        document.save();
      }
      else if (!oldAssetId.equals(newAssetId)) {
        // retry in case this is due to an out-of-order delete event
        throw new BrowseNodeCollisionException("Node already has an asset");
      }
    }
  }

  @Inject public  BrowseNodeEntityAdapter(final ComponentEntityAdapter componentEntityAdapter,
                                 final AssetEntityAdapter assetEntityAdapter,
                                 final PackageUrlService packageUrlService);

}