All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencastproject.assetmanager.impl.persistence.Database Maven / Gradle / Ivy

There is a newer version: 16.7
Show newest version
/**
 * Licensed to The Apereo Foundation under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 *
 * The Apereo Foundation licenses this file to you under the Educational
 * Community License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License
 * at:
 *
 *   http://opensource.org/licenses/ecl2.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package org.opencastproject.assetmanager.impl.persistence;

import org.opencastproject.assetmanager.api.Availability;
import org.opencastproject.assetmanager.api.Property;
import org.opencastproject.assetmanager.api.PropertyId;
import org.opencastproject.assetmanager.api.Snapshot;
import org.opencastproject.assetmanager.impl.PartialMediaPackage;
import org.opencastproject.assetmanager.impl.VersionImpl;
import org.opencastproject.assetmanager.impl.persistence.AssetDtos.Full;
import org.opencastproject.assetmanager.impl.persistence.AssetDtos.Medium;
import org.opencastproject.mediapackage.MediaPackageElement;
import org.opencastproject.util.persistencefn.PersistenceEnv;
import org.opencastproject.util.persistencefn.PersistenceEnvs;
import org.opencastproject.util.persistencefn.Queries;

import com.entwinemedia.fn.Fn;
import com.entwinemedia.fn.Fx;
import com.entwinemedia.fn.data.Opt;
import com.mysema.query.Tuple;
import com.mysema.query.jpa.EclipseLinkTemplates;
import com.mysema.query.jpa.JPQLTemplates;
import com.mysema.query.jpa.impl.JPADeleteClause;
import com.mysema.query.jpa.impl.JPAQuery;
import com.mysema.query.jpa.impl.JPAQueryFactory;
import com.mysema.query.jpa.impl.JPAUpdateClause;
import com.mysema.query.types.expr.BooleanExpression;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;

import javax.annotation.ParametersAreNonnullByDefault;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

/**
 * Data access object.
 */
@ParametersAreNonnullByDefault
public class Database implements EntityPaths {
  private static final Logger logger = LoggerFactory.getLogger(Database.class);

  public static final JPQLTemplates TEMPLATES = EclipseLinkTemplates.DEFAULT;

  private final PersistenceEnv penv;
  private final EntityManagerFactory entityManagerFactory;

  public Database(EntityManagerFactory emf, PersistenceEnv persistenceEnv) {
    penv = persistenceEnv;
    entityManagerFactory = emf;
  }

  public Database(EntityManagerFactory emf) {
    penv = PersistenceEnvs.mk(emf);
    entityManagerFactory = emf;
  }

  /**
   * Run a Queryldsl query inside a persistence context/transaction.
   *
   * @param q the query function to run
   */
  public  A run(final Fn q) {
    return penv.tx(new Fn() {
      @Override public A apply(final EntityManager em) {
        return q.apply(new JPAQueryFactory(TEMPLATES, new Provider() {
          @Override public EntityManager get() {
            return em;
          }
        }));
      }
    });
  }

  public void logQuery(JPAQuery q) {
    logger.debug("\n---\nQUERY\n{}\n---", q);
  }

  public void logDelete(String queryName, JPADeleteClause q) {
    logger.debug("\n---\nDELETE {}\n{}\n---", queryName, q);
  }

  /**
   * Save a property to the database. This is either an insert or an update operation.
   */
  public boolean saveProperty(final Property property) {
    return penv.tx(new Fn() {
      @Override public Boolean apply(EntityManager em) {
        final PropertyId pId = property.getId();
        // check the existence of both the media package and the property in one query
        //
        // either the property matches or it does not exist <- left outer join
        final BooleanExpression eitherMatchOrNull =
            Q_PROPERTY.namespace.eq(pId.getNamespace())
                .and(Q_PROPERTY.propertyName.eq(pId.getName())).or(Q_PROPERTY.namespace.isNull());
        final Tuple result = new JPAQuery(em, TEMPLATES)
                .from(Q_SNAPSHOT)
                .leftJoin(Q_PROPERTY).on(Q_SNAPSHOT.mediaPackageId.eq(Q_PROPERTY.mediaPackageId).and(eitherMatchOrNull))
                .where(Q_SNAPSHOT.mediaPackageId.eq(pId.getMediaPackageId()))
                        // only one result is interesting, no need to fetch all versions of the media package
                .singleResult(Q_SNAPSHOT.id, Q_PROPERTY);
        if (result != null) {
          // media package exists, now check if the property exists
          final PropertyDto exists = result.get(Q_PROPERTY);
          Queries.persistOrUpdate(em, exists == null
                  ? PropertyDto.mk(property)
                  : exists.update(property.getValue()));
          return true;
        } else {
          // media package does not exist
          return false;
        }
      }
    });
  }

  /**
   * Claim a new version for media package mpId.
   */
  public VersionImpl claimVersion(final String mpId) {
    return penv.tx(new Fn() {
      @Override public VersionImpl apply(final EntityManager em) {
        final Opt lastOpt = VersionClaimDto.findLast(em, mpId);
        if (lastOpt.isSome()) {
          final VersionImpl claim = VersionImpl.next(lastOpt.get().getLastClaimed());
          VersionClaimDto.update(em, mpId, claim.value());
          return claim;
        } else {
          final VersionImpl first = VersionImpl.FIRST;
          em.persist(VersionClaimDto.mk(mpId, first.value()));
          return first;
        }
      }
    });
  }

  /**
   * Save a snapshot and all of its assets.
   */
  public SnapshotDto saveSnapshot(
          final String orgId,
          final PartialMediaPackage pmp,
          final Date archivalDate,
          final VersionImpl version,
          final Availability availability,
          final String storageId,
          final String owner) {
    final SnapshotDto snapshotDto = SnapshotDto.mk(
            pmp.getMediaPackage(),
            version,
            orgId,
            archivalDate,
            availability,
            storageId,
            owner);
    return penv.tx(new Fn() {
      @Override public SnapshotDto apply(EntityManager em) {
        // persist snapshot
        em.persist(snapshotDto);
        // persist assets
        for (MediaPackageElement e : pmp.getElements()) {
          final AssetDto a = AssetDto.mk(
                  e.getIdentifier(),
                  snapshotDto,
                  e.getChecksum().toString(),
                  Opt.nul(e.getMimeType()),
                  storageId,
                  e.getSize());
          em.persist(a);
        }
        return snapshotDto;
      }
    });
  }

  public void setStorageLocation(Snapshot snapshot, final String storageId) {
    setStorageLocation(
        VersionImpl.mk(snapshot.getVersion()),
        snapshot.getMediaPackage().getIdentifier().toString(),
        storageId
    );
  }

  public void setStorageLocation(final VersionImpl version, final String mpId, final String storageId) {
    penv.tx(new Fx() {
      @Override public void apply(EntityManager em) {
        final QSnapshotDto q = QSnapshotDto.snapshotDto;
        final QAssetDto a = QAssetDto.assetDto;
        //Update the snapshot
        new JPAUpdateClause(em, q, TEMPLATES)
                .where(q.version.eq(version.value()).and(q.mediaPackageId.eq(mpId)))
                .set(q.storageId, storageId)
                .execute();
        //Get the snapshot (to get its database ID)
        Opt s = getSnapshot(version, mpId);
        //Update the assets
        new JPAUpdateClause(em, a, TEMPLATES)
                .where(a.snapshot.id.eq(s.get().getSnapshotDto().getId()))
                .set(a.storageId, storageId)
                .execute();
      }
    }.toFn());
  }

  public void setAssetStorageLocation(final VersionImpl version, final String mpId, final String mpeId,
          final String storageId) {
    penv.tx(new Fx() {
      @Override
      public void apply(EntityManager em) {
        final QAssetDto a = QAssetDto.assetDto;
        Opt s = getSnapshot(version, mpId);
        // Update the asset store id
        new JPAUpdateClause(em, a, TEMPLATES)
                .where(a.snapshot.id.eq(s.get().getSnapshotDto().getId()).and(a.mediaPackageElementId.eq(mpeId)))
                .set(a.storageId, storageId).execute();
      }
    }.toFn());
  }

  public void setAvailability(final VersionImpl version, final String mpId, final Availability availability) {
    penv.tx(new Fx() {
      @Override public void apply(EntityManager em) {
        final QSnapshotDto q = QSnapshotDto.snapshotDto;
        new JPAUpdateClause(em, q, TEMPLATES)
            .where(q.version.eq(version.value()).and(q.mediaPackageId.eq(mpId)))
            .set(q.availability, availability.name())
            .execute();
      }
    }.toFn());
  }

  /**
   * Get an asset. If no version is specified return the latest version.
   *
   * @return the asset or none, if no asset can be found
   */
  public Opt getAsset(final VersionImpl version, final String mpId, final String mpeId) {
    return penv.tx(new Fn>() {
      @Override public Opt apply(EntityManager em) {
        final QAssetDto assetDto = QAssetDto.assetDto;
        final Tuple result = AssetDtos.baseJoin(em)
                .where(assetDto.snapshot.mediaPackageId.eq(mpId)
                               .and(assetDto.mediaPackageElementId.eq(mpeId))
                               .and(assetDto.snapshot.version.eq(version.value())))
                        // if no version has been specified make sure to get the latest by ordering
                .orderBy(assetDto.snapshot.version.desc())
                .uniqueResult(Medium.select);
        return Opt.nul(result).map(AssetDtos.Medium.fromTuple);
      }
    });
  }

  public Opt getSnapshot(final VersionImpl version, final String mpId) {
    return penv.tx(new Fn>() {
      @Override public Opt apply(EntityManager em) {
        final QSnapshotDto snapshotDto = QSnapshotDto.snapshotDto;
        final Tuple result = SnapshotDtos.baseQuery(em)
                .where(snapshotDto.mediaPackageId.eq(mpId)
                  .and(snapshotDto.version.eq(version.value())))
                // if no version has been specified make sure to get the latest by ordering
                .orderBy(snapshotDto.version.desc())
                .uniqueResult(SnapshotDtos.Medium.select);
        return Opt.nul(result).map(SnapshotDtos.Medium.fromTuple);
      }
    });
  }

  public Opt findAssetByChecksum(final String checksum) {
    return penv.tx(new Fn>() {
      @Override public Opt apply(EntityManager em) {
        final Tuple result = AssetDtos.baseJoin(em)
            .where(QAssetDto.assetDto.checksum.eq(checksum))
            .singleResult(Full.select);
        return Opt.nul(result).map(Full.fromTuple);
      }
    });
  }

  /**
   * Delete all properties for a given media package identifier
   *
   * @param mediaPackageId
   *          Media package identifier
   * @return Number of deleted rows
   */
  public int deleteProperties(final String mediaPackageId) {
    return PropertyDto.delete(entityManagerFactory.createEntityManager(), mediaPackageId);
  }

  /**
   * Delete all properties for a given media package identifier and namespace.
   *
   * @param mediaPackageId
   *          Media package identifier
   * @param namespace
   *          A namespace prefix to use for deletion
   * @return Number of deleted rows
   */
  public int deleteProperties(final String mediaPackageId, final String namespace) {
    if (StringUtils.isBlank(namespace)) {
      return PropertyDto.delete(entityManagerFactory.createEntityManager(), mediaPackageId);
    }
    return PropertyDto.delete(entityManagerFactory.createEntityManager(), mediaPackageId, namespace);
  }

  /**
   * Check if any snapshot with the given media package identifier exists.
   *
   * @param mediaPackageId
   *          The media package identifier to check for
   * @return If a snapshot exists for the given media package
   */
  public boolean snapshotExists(final String mediaPackageId) {
    return SnapshotDto.exists(entityManagerFactory.createEntityManager(), mediaPackageId);
  }

  /**
   * Check if any snapshot with the given media package identifier exists.
   *
   * @param mediaPackageId
   *          The media package identifier to check for
   * @param organization
   *          The organization to filter for
   * @return If a snapshot exists for the given media package
   */
  public boolean snapshotExists(final String mediaPackageId, final String organization) {
    return SnapshotDto.exists(entityManagerFactory.createEntityManager(), mediaPackageId, organization);
  }

  /**
   * Select all properties for a specific media package.
   *
   * @param mediaPackageId
   *          Media package identifier to check for
   * @param namespace
   *          Namespace to limit the search to
   * @return List of properties
   */
  public List selectProperties(final String mediaPackageId, final String namespace) {
    return PropertyDto.select(entityManagerFactory.createEntityManager(), mediaPackageId, namespace);
  }

  /**
   * Count events with snapshots in the asset manager
   *
   * @param organization
   *          An organization to count in
   * @return Number of events
   */
  public long countEvents(final String organization) {
    return SnapshotDto.countEvents(entityManagerFactory.createEntityManager(), organization);
  }

  public Opt findAssetByChecksumAndStore(final String checksum, final String storeId) {
    return penv.tx(new Fn>() {
      @Override
      public Opt apply(EntityManager em) {
        final Tuple result = AssetDtos.baseJoin(em)
                .where(QAssetDto.assetDto.checksum.eq(checksum).and(QAssetDto.assetDto.storageId.eq(storeId)))
                .singleResult(Full.select);
        return Opt.nul(result).map(Full.fromTuple);
      }
    });
  }

  //
  // Utility
  //

  public static  A insidePersistenceContextCheck(A a) {
    if (a != null) {
      return a;
    } else {
      throw new RuntimeException(
          "Used DTO outside of a persistence context or the DTO has not been assigned an ID yet.");
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy