Package org.socialmusicdiscovery.server.plugins.mediaimport

Source Code of org.socialmusicdiscovery.server.plugins.mediaimport.AbstractTagImporter$TypeIdentity

/*
*  Copyright 2010-2011, Social Music Discovery project
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions are met:
*      * Redistributions of source code must retain the above copyright
*        notice, this list of conditions and the following disclaimer.
*      * Redistributions in binary form must reproduce the above copyright
*        notice, this list of conditions and the following disclaimer in the
*        documentation and/or other materials provided with the distribution.
*      * Neither the name of Social Music Discovery project nor the
*        names of its contributors may be used to endorse or promote products
*        derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED. IN NO EVENT SHALL SOCIAL MUSIC DISCOVERY PROJECT BE LIABLE FOR ANY
*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.socialmusicdiscovery.server.plugins.mediaimport;

import com.google.inject.Inject;
import liquibase.Liquibase;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.socialmusicdiscovery.server.api.mediaimport.AbstractProcessingModule;
import org.socialmusicdiscovery.server.api.mediaimport.InitializationFailedException;
import org.socialmusicdiscovery.server.api.mediaimport.ProcessingStatusCallback;
import org.socialmusicdiscovery.server.business.logic.ImageProviderManager;
import org.socialmusicdiscovery.server.business.logic.InjectHelper;
import org.socialmusicdiscovery.server.business.logic.injections.database.DatabaseProvider;
import org.socialmusicdiscovery.server.business.model.GlobalIdentity;
import org.socialmusicdiscovery.server.business.model.GlobalIdentityEntity;
import org.socialmusicdiscovery.server.business.model.SMDIdentity;
import org.socialmusicdiscovery.server.business.model.SMDIdentityReference;
import org.socialmusicdiscovery.server.business.model.classification.Classification;
import org.socialmusicdiscovery.server.business.model.classification.ClassificationEntity;
import org.socialmusicdiscovery.server.business.model.classification.ClassificationReferenceEntity;
import org.socialmusicdiscovery.server.business.model.config.ConfigurationParameter;
import org.socialmusicdiscovery.server.business.model.config.ConfigurationParameterEntity;
import org.socialmusicdiscovery.server.business.model.core.*;
import org.socialmusicdiscovery.server.business.repository.GlobalIdentityRepository;
import org.socialmusicdiscovery.server.business.repository.SMDIdentityRepository;
import org.socialmusicdiscovery.server.business.repository.classification.ClassificationReferenceRepository;
import org.socialmusicdiscovery.server.business.repository.classification.ClassificationRepository;
import org.socialmusicdiscovery.server.business.repository.core.*;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public abstract class AbstractTagImporter extends AbstractProcessingModule {
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy");
    private static final DateFormat DATE_FORMAT_WITH_DATE = new SimpleDateFormat("yyyy-MM-dd");

    class TypeIdentity {
        String type;
        String id;

        TypeIdentity(String type, String id) {
            this.type = type;
            this.id = id;
        }

        @Override
        public int hashCode() {
            return HashCodeBuilder.reflectionHashCode(this);
        }

        @Override
        public boolean equals(Object o) {
            return EqualsBuilder.reflectionEquals(this, o);
        }
    }

    private Map<TypeIdentity, Collection<String>> classificationCache = new HashMap<TypeIdentity, Collection<String>>();
    private Map<String, Collection<String>> artistCache = new HashMap<String, Collection<String>>();
    private Set<String> artistMusicbrainzCache = new HashSet<String>();
    private Map<String, Collection<String>> releaseCache = new HashMap<String, Collection<String>>();
    private Set<String> releaseMusicbrainzCache = new HashSet<String>();
    private Set<String> releaseDiscogsCache = new HashSet<String>();
    private javax.validation.Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Inject
    protected PlayableElementRepository playableElementRepository;

    @Inject
    private MediumRepository mediumRepository;

    @Inject
    private TrackRepository trackRepository;

    @Inject
    protected ReleaseRepository releaseRepository;

    @Inject
    private RecordingRepository recordingRepository;

    @Inject
    private ArtistRepository artistRepository;

    @Inject
    private ClassificationRepository classificationRepository;

    @Inject
    private ClassificationReferenceRepository classificationReferenceRepository;

    @Inject
    private ContributorRepository contributorRepository;

    @Inject
    private WorkRepository workRepository;

    @Inject
    private GlobalIdentityRepository globalIdentityRepository;

    @Inject
    private ImageRepository imageRepository;

    @Inject
    private ImageProviderManager imageProviderManager;

    /**
     * @inherit
     */
    @Override
    public void init(Map<String, String> executionParameters) throws InitializationFailedException {
        classificationCache = new HashMap<TypeIdentity, Collection<String>>();
        artistCache = new HashMap<String, Collection<String>>();
        artistMusicbrainzCache = new HashSet<String>();
        releaseCache = new HashMap<String, Collection<String>>();
        releaseMusicbrainzCache = new HashSet<String>();
        releaseDiscogsCache = new HashSet<String>();
        super.init(executionParameters);
    }

    protected abstract void executeImport(ProcessingStatusCallback progressHandler);

    /**
     * @inherit
     */
    public void execute(ProcessingStatusCallback progressHandler) {
        if (getExecutionConfiguration().getBooleanParameter("deletePrevious", Boolean.FALSE)) {
            String database = InjectHelper.instanceWithName(String.class, "org.socialmusicdiscovery.server.database");
            DatabaseProvider provider = InjectHelper.instanceWithName(DatabaseProvider.class, database);
            try {
                Connection connection = provider.getConnection();
                Liquibase liquibase = new Liquibase("org/socialmusicdiscovery/server/database/smd-database-drop.xml", new
                        ClassLoaderResourceAccessor(),
                        new JdbcConnection(connection));
                liquibase.update("");
                liquibase = new Liquibase("org/socialmusicdiscovery/server/database/smd-database.changelog.xml", new
                        ClassLoaderResourceAccessor(),
                        new JdbcConnection(connection));
                liquibase.update("");
            } catch (LiquibaseException e) {
                e.printStackTrace();
                progressHandler.failed(getId(), e.getLocalizedMessage());
                return;
            } catch (SQLException e) {
                e.printStackTrace();
                progressHandler.failed(getId(), e.getLocalizedMessage());
                return;
            }
        }
        artistCache.clear();
        artistMusicbrainzCache.clear();
        releaseCache.clear();
        releaseMusicbrainzCache.clear();
        releaseDiscogsCache.clear();
        classificationCache.clear();

        executeImport(progressHandler);

        artistCache.clear();
        artistMusicbrainzCache.clear();
        classificationCache.clear();
        releaseCache.clear();
        releaseMusicbrainzCache.clear();
        releaseDiscogsCache.clear();
    }

    /**
     * Import a new playable element with related meta data
     *
     * @param data Data about the playable element to create
     */
    protected void importNewPlayableElement(TrackData data) {
        importNewPlayableElementLogic(data);
    }

    protected ImageEntity getReleaseImage(TrackData data) {
        return null;
    }

    void importNewPlayableElementLogic(TrackData data) {
        Collection<PlayableElementEntity> playableElements = playableElementRepository.findBySmdID(data.getSmdID());
        if (playableElements.size() > 0) {
            // Update URI for previously imported playable elements of same format
            for (PlayableElementEntity playableElement : playableElements) {
                if (playableElement.getFormat().equals(data.getFormat()) &&
                        !playableElement.getUri().equals(data.getUrl())) {
                    playableElement.setUri(data.getUrl());
                    playableElement.setLastModified(data.getLastModified());
                    playableElement.setLastUpdated(new Date());
                    playableElement.setLastUpdatedBy(getId());
                    validate(playableElement);
                }
            }
        } else {
            // This playable element doesn't exist, yet, let's create it
            PlayableElementEntity playableElement = new PlayableElementEntity();
            playableElement.setUri(data.getUrl());
            playableElement.setFormat(data.getFormat());
            playableElement.setSmdID(data.getSmdID());
            playableElement.setLastModified(data.getLastModified());
            playableElement.setLastUpdated(new Date());
            playableElement.setLastUpdatedBy(getId());
            validate(playableElement);
            playableElementRepository.create(playableElement);
            playableElements.add(playableElement);

            // Convert list of tags to a map to make them easier to handle
            Map<String, Collection<String>> tags = new HashMap<String, Collection<String>>();
            Map<String, String> sortTags = new HashMap<String, String>();
            for (TagData tagData : data.getTags()) {
                if (tags.containsKey(tagData.getName())) {
                    tags.get(tagData.getName()).add(tagData.getValue());
                } else {
                    tags.put(tagData.getName(), new ArrayList<String>(Arrays.asList(tagData.getValue())));
                }
                if (tagData.getSortValue() != null) {
                    String tagName = tagData.getName();
                    if (tagName.equals(TagData.COMPOSER) || tagName.equals(TagData.CONDUCTOR) || tagName.contains(TagData.ARTIST)) {
                        tagName = TagData.ARTIST;
                    }
                    sortTags.put(tagName + ":" + tagData.getValue(), tagData.getSortValue());
                }
            }
            // We need a TITLE tag, tracks without titles isn't currenlty imported
            if (tags.containsKey(TagData.TITLE)) {
                String title = tags.get(TagData.TITLE).iterator().next();

                WorkEntity work = null;
                Collection<WorkEntity> existingWorks = new ArrayList<WorkEntity>();
                if (tags.containsKey((TagData.WORK))) {
                    String workName = tags.get(TagData.WORK).iterator().next();
                    existingWorks = workRepository.findByName(workName);
                    if (existingWorks.size() == 0) {
                        // Create a Work entity based on the WORK tag
                        work = new WorkEntity();
                        work.setName(workName);
                        if (sortTags.containsKey(TagData.WORK + ":" + workName)) {
                            work.setSortAs(sortTags.get(TagData.WORK + ":" + workName));
                        }
                        work.setLastUpdated(new Date());
                        work.setLastUpdatedBy(getId());
                        validate(work);
                    } else {
                        work = (WorkEntity) existingWorks.iterator().next();
                        if (work.getLastUpdatedBy().equals(getId()) && sortTags.containsKey(TagData.WORK + ":" + workName)) {
                            work.setSortAs(sortTags.get(TagData.WORK + ":" + workName));
                        }
                        validate(work);
                    }
                } else {
                    // Create a Work entity based on the TITLE tag
                    work = new WorkEntity();
                    work.setName(title);
                    if (sortTags.containsKey(TagData.TITLE + ":" + title)) {
                        work.setSortAs(sortTags.get(TagData.TITLE + ":" + title));
                    }
                    work.setLastUpdated(new Date());
                    work.setLastUpdatedBy(getId());
                    validate(work);
                }

                // Create Work entity and add composers to it if it didn't already exist
                if (existingWorks.size() == 0) {
                    workRepository.create(work);
                    if (getConfiguration().getBooleanParameter("composers")) {
                        Set<Contributor> workContributors = getContributorsForTag(tags.get(TagData.COMPOSER), TagData.ARTIST + ":", sortTags, Contributor.COMPOSER);
                        if (workContributors.size() > 0) {
                            saveContributors(work, workContributors);
                        }
                    }
                }


                // Create a Recording entity represented by the Work and various Contributors
                RecordingEntity recording = new RecordingEntity();
                recording.setLastUpdated(new Date());
                recording.setLastUpdatedBy(getId());
                recording.getWorks().add(work);

                Set<Contributor> albumArtistContributors = getContributorsForTag(tags.get(TagData.ALBUMARTIST), TagData.ARTIST + ":", sortTags, Contributor.PERFORMER);
                Set<Contributor> artistContributors = getContributorsForTag(tags.get(TagData.ARTIST), TagData.ARTIST + ":", sortTags, Contributor.PERFORMER);
                Set<Contributor> trackArtistContributors = getContributorsForTag(tags.get(TagData.TRACKARTIST), TagData.ARTIST + ":", sortTags, Contributor.PERFORMER);
                Set<Contributor> performerContributors = getContributorsForTag(tags.get(TagData.PERFORMER), TagData.ARTIST + ":", sortTags, Contributor.PERFORMER);
                Set<Contributor> conductorContributors = new HashSet<Contributor>();
                if (getConfiguration().getBooleanParameter("conductors")) {
                    conductorContributors = getContributorsForTag(tags.get(TagData.CONDUCTOR), TagData.ARTIST + ":", sortTags, Contributor.CONDUCTOR);
                }
                Set<Contributor> recordingContributors = new HashSet<Contributor>();

                handleArtistIdentities(tags, artistContributors);
                handleAlbumArtistIdentities(tags, albumArtistContributors);

                // Don't use ARTIST contributors on Recording if they are exactly the same as those on Release level
                if (!equalContributors(albumArtistContributors, artistContributors)) {
                    recordingContributors.addAll(artistContributors);
                }
                // Don't use TRACKARTIST contributors if they are exactly the same as those on Release level
                if (!equalContributors(albumArtistContributors, trackArtistContributors)) {
                    recordingContributors.addAll(trackArtistContributors);
                }
                recordingContributors.addAll(conductorContributors);
                recordingContributors.addAll(performerContributors);

                recordingRepository.create(recording);
                if (recordingContributors.size() > 0) {
                    saveContributors(recording, recordingContributors);
                }

                // Add GENRE, STYLE and MOOD Classification entities and related them to the created Recording entity
                if (tags.containsKey(TagData.GENRE) && getConfiguration().getBooleanParameter("genres")) {
                    createClassificationsForTag(tags.get(TagData.GENRE), TagData.GENRE + ":", sortTags, Classification.GENRE, recording.getReference());
                }
                if (tags.containsKey(TagData.STYLE) && getConfiguration().getBooleanParameter("styles")) {
                    createClassificationsForTag(tags.get(TagData.STYLE), TagData.STYLE + ":", sortTags, Classification.STYLE, recording.getReference());
                }
                if (tags.containsKey(TagData.MOOD) && getConfiguration().getBooleanParameter("moods")) {
                    createClassificationsForTag(tags.get(TagData.MOOD), TagData.MOOD + ":", sortTags, Classification.MOOD, recording.getReference());
                }

                // Create a Release entity based on the ALBUM tag
                if (tags.containsKey(TagData.ALBUM)) {
                    String albumName = tags.get(TagData.ALBUM).iterator().next();

                    // YEAR tag is optional but we use it if it exists
                    String year = null;
                    if (tags.containsKey(TagData.YEAR)) {
                        year = tags.get(TagData.YEAR).iterator().next();
                    }

                    // Create a new Release entity if it isn't already available
                    //TODO: We need to implement handling of greatest hits album here which might have exactly the same name
                    Collection<ReleaseEntity> releases = lookup(this.releaseCache.get(albumName.toLowerCase()), releaseRepository);
                    if (releases == null) {
                        releases = releaseRepository.findByName(albumName);
                        if (releases.size() > 0) {
                            this.releaseCache.put(albumName.toLowerCase(), idList(releases));
                        }
                    }
                    ReleaseEntity release = null;
                    if (releases.size() == 0) {
                        release = new ReleaseEntity();
                        release.setName(albumName);
                        if (sortTags.containsKey(TagData.ALBUM + ":" + albumName)) {
                            release.setSortAs(sortTags.get(TagData.ALBUM + ":" + albumName));
                        }
                        release.setLastUpdated(new Date());
                        release.setLastUpdatedBy(getId());
                        if (year != null) {
                            try {
                                if (year.length() == 10) {
                                    release.setDate(DATE_FORMAT_WITH_DATE.parse(year.substring(10)));
                                } else if (year.length() >= 4) {
                                    release.setDate(DATE_FORMAT.parse(year.substring(4)));
                                }
                            } catch (ParseException e) {
                                // Just ignore year if it can't be parsed
                            }
                        }
                        validate(release);
                        releaseRepository.create(release);
                        if (albumArtistContributors.size() > 0) {
                            saveContributors(release, albumArtistContributors);
                        }
                        this.releaseCache.put(albumName.toLowerCase(), Arrays.asList(release.getId()));

                        ImageEntity defaultImage = getReleaseImage(data);
                        if (defaultImage != null) {
                            defaultImage.setLastUpdated(new Date());
                            defaultImage.setLastUpdatedBy(getId());
                            defaultImage.setRelatedTo(release.getReference());
                            validate(defaultImage);
                            imageRepository.create(defaultImage);
                            release.setDefaultImage(defaultImage);
                        }
                    } else {
                        // We use the first Release entity found if it already existsted
                        release = releases.iterator().next();
                        if (release.getLastUpdatedBy().equals(getId()) && sortTags.containsKey(TagData.ALBUM + ":" + albumName)) {
                            release.setSortAs(sortTags.get(TagData.ALBUM + ":" + albumName));
                        }
                        validate(release);
                    }

                    handleReleaseIdentities(tags, release);

                    // Create a Track entity if there is a TRACKNUM tag
                    TrackEntity track = new TrackEntity();
                    track.setLastUpdated(new Date());
                    track.setLastUpdatedBy(getId());
                    if (tags.containsKey(TagData.TRACKNUM)) {
                        String trackNum = tags.get(TagData.TRACKNUM).iterator().next();

                        // Sometimes TRACKNUM is represented as 1/10
                        if (trackNum.contains("/")) {
                            trackNum = trackNum.substring(0, trackNum.indexOf("/"));
                        }
                        try {
                            track.setNumber(Integer.parseInt(trackNum));
                        } catch (NumberFormatException e) {
                            // Ignore the track number if we can't parse it
                            System.err.println("Unable to parse track number: " + tags.get(TagData.TRACKNUM).iterator().next());
                        }
                    }
                    track.getPlayableElements().addAll(playableElements);
                    track.setRecording(recording);
                    release.addTrack(track);
                    validate(track);
                    trackRepository.create(track);

                    handleTrackIdentities(tags, track);

                    // Create a Media entity if there is a DISC tag
                    if (tags.containsKey(TagData.DISC)) {
                        String discNo = tags.get(TagData.DISC).iterator().next();

                        // DISC tags can sometimes have the syntax 1/3
                        if (discNo.contains("/")) {
                            discNo = discNo.substring(0, discNo.indexOf("/"));
                        }

                        // Use existing Media entity if there is one already for this disc number
                        List<Medium> mediums = release.getMediums();
                        MediumEntity medium = null;
                        for (Medium m : mediums) {
                            if (m.getNumber() != null) {
                                try {
                                    if (m.getNumber().equals(Integer.parseInt(discNo))) {
                                        medium = (MediumEntity) m;
                                    }
                                } catch (NumberFormatException e) {
                                    // Ignore this and try with name instead
                                }
                            }
                            if (m.getName() != null && m.getName().equals(discNo)) {
                                medium = (MediumEntity) m;
                            }
                        }

                        // Create a new Media entity if we don't already have one
                        if (medium == null) {
                            medium = new MediumEntity();
                            medium.setLastUpdated(new Date());
                            medium.setLastUpdatedBy(getId());
                            try {
                                medium.setNumber(Integer.parseInt(discNo));
                            } catch (NumberFormatException e) {
                                medium.setName(discNo);
                            }
                            medium.addTrack(track);
                            release.addMedium(medium);
                            validate(medium);
                            mediumRepository.create(medium);
                        } else {
                            medium.addTrack(track);
                        }
                    }
                }
            }
        }
    }

    protected void handleTrackIdentities(Map<String, Collection<String>> tags, TrackEntity track) {
        if (tags.containsKey(TagData.MUSICBRAINZ_TRACK_ID)) {
            GlobalIdentityEntity identity = new GlobalIdentityEntity();
            identity.setSource(GlobalIdentity.SOURCE_MUSICBRAINZ);
            identity.setEntityId(track.getId());
            identity.setUri(tags.get(TagData.MUSICBRAINZ_TRACK_ID).iterator().next());
            identity.setLastUpdated(new Date());
            identity.setLastUpdatedBy(getId());
            validate(identity);
            globalIdentityRepository.create(identity);
        }
    }

    protected void handleReleaseIdentities(Map<String, Collection<String>> tags, ReleaseEntity release) {
        if (tags.containsKey(TagData.MUSICBRAINZ_ALBUM_ID)) {
            String releaseId = tags.get(TagData.MUSICBRAINZ_ALBUM_ID).iterator().next();
            if (!releaseMusicbrainzCache.contains(releaseId)) {
                GlobalIdentityEntity identity = globalIdentityRepository.findBySourceAndEntity(GlobalIdentity.SOURCE_MUSICBRAINZ, release);
                if (identity == null) {
                    identity = new GlobalIdentityEntity();
                    identity.setSource(GlobalIdentity.SOURCE_MUSICBRAINZ);
                    identity.setEntityId(release.getId());
                    identity.setUri(releaseId);
                    identity.setLastUpdated(new Date());
                    identity.setLastUpdatedBy(getId());
                    validate(identity);
                    globalIdentityRepository.create(identity);
                }
                releaseMusicbrainzCache.add(releaseId);
            }
        }
        if (tags.containsKey(TagData.DISCOGS_RELEASE_ID)) {
            String releaseId = tags.get(TagData.DISCOGS_RELEASE_ID).iterator().next();
            if (!releaseDiscogsCache.contains(releaseId)) {
                GlobalIdentityEntity identity = globalIdentityRepository.findBySourceAndEntity(GlobalIdentity.SOURCE_DISCOGS, release);
                if (identity == null) {
                    identity = new GlobalIdentityEntity();
                    identity.setSource(GlobalIdentity.SOURCE_DISCOGS);
                    identity.setEntityId(release.getId());
                    identity.setUri(releaseId);
                    identity.setLastUpdated(new Date());
                    identity.setLastUpdatedBy(getId());
                    validate(identity);
                    globalIdentityRepository.create(identity);
                }
                releaseDiscogsCache.add(releaseId);
            }
        }
    }

    protected void handleAlbumArtistIdentities(Map<String, Collection<String>> tags, Set<Contributor> albumArtistContributors) {
        if (albumArtistContributors.size() == 1 && tags.containsKey(TagData.MUSICBRAINZ_ALBUMARTIST_ID)) {
            String artistId = tags.get(TagData.MUSICBRAINZ_ALBUMARTIST_ID).iterator().next();
            if (!artistMusicbrainzCache.contains(artistId)) {
                Artist artist = artistRepository.findById(artistCache.get(tags.get(TagData.ALBUMARTIST).iterator().next().toLowerCase()).iterator().next());
                GlobalIdentityEntity identity = globalIdentityRepository.findBySourceAndEntity(GlobalIdentity.SOURCE_MUSICBRAINZ, artist);
                if (identity == null) {
                    identity = new GlobalIdentityEntity();
                    identity.setSource(GlobalIdentity.SOURCE_MUSICBRAINZ);
                    identity.setEntityId(artist.getId());
                    identity.setUri(artistId);
                    identity.setLastUpdated(new Date());
                    identity.setLastUpdatedBy(getId());
                    validate(identity);
                    globalIdentityRepository.create(identity);
                }
                artistMusicbrainzCache.add(artistId);
            }
        }
    }

    protected void handleArtistIdentities(Map<String, Collection<String>> tags, Set<Contributor> artistContributors) {
        if (artistContributors.size() == 1 && tags.containsKey(TagData.MUSICBRAINZ_ARTIST_ID)) {
            String artistId = tags.get(TagData.MUSICBRAINZ_ARTIST_ID).iterator().next();
            if (!artistMusicbrainzCache.contains(artistId)) {
                Artist artist = artistRepository.findById(artistCache.get(tags.get(TagData.ARTIST).iterator().next().toLowerCase()).iterator().next());
                GlobalIdentityEntity identity = globalIdentityRepository.findBySourceAndEntity(GlobalIdentity.SOURCE_MUSICBRAINZ, artist);
                if (identity == null) {
                    identity = new GlobalIdentityEntity();
                    identity.setSource(GlobalIdentity.SOURCE_MUSICBRAINZ);
                    identity.setEntityId(artist.getId());
                    identity.setUri(artistId);
                    identity.setLastUpdated(new Date());
                    identity.setLastUpdatedBy(getId());
                    validate(identity);
                    globalIdentityRepository.create(identity);
                }
                artistMusicbrainzCache.add(artistId);
            }
        }
    }

    /**
     * Checks if two sets of Contributor contains the same artists/role combinations
     *
     * @param contributors1 The first set of contributors
     * @param contributors2 The second set of contributors
     * @return true if the sets are equal, false if they aren't
     */
    private Boolean equalContributors(Set<Contributor> contributors1, Set<Contributor> contributors2) {
        if (contributors1.size() == contributors2.size()) {
            for (Contributor contributor1 : contributors1) {
                boolean found = false;
                for (Contributor contributor2 : contributors2) {
                    if (contributor1.getArtist().getId().equals(contributor2.getArtist().getId()) &&
                            contributor1.getType().equals(contributor2.getType())) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * Get contributors represented by the list of artist names
     * The Artist entities will be created if they don't already exists, the Contributor entities returned will just be prepared so you will have to
     * store them manually after this call
     *
     * @param artistNames     The list of artist names to search contributors for
     * @param sortPrefix      A prefix string which is used as prefix in the key of the sortValues input parameter
     * @param sortValues      A map with sort values which should be used for respective artist name
     * @param contributorType The type of contributors to create
     * @return A list of contributors representing the specified artist names and contributor type, empty list if no contributors are returned
     */
    private Set<Contributor> getContributorsForTag(Collection<String> artistNames, String sortPrefix, Map<String, String> sortValues, String contributorType) {
        Set<Contributor> contributors = new HashSet<Contributor>();
        if (artistNames != null) {
            Collection<Artist> artists = new ArrayList<Artist>();
            for (String artistName : artistNames) {
                Collection<ArtistEntity> existingArtists = lookup(this.artistCache.get(artistName.toLowerCase()), artistRepository);
                if (existingArtists == null) {
                    existingArtists = artistRepository.findByName(artistName);
                    if (existingArtists.size() > 0) {
                        this.artistCache.put(artistName.toLowerCase(), idList(existingArtists));
                        for (ArtistEntity existingArtist : existingArtists) {
                            if (existingArtist.getLastUpdatedBy().equals(getId()) && sortValues.containsKey(sortPrefix + artistName)) {
                                existingArtist.setSortAs(sortValues.get(sortPrefix + artistName));
                            }
                            validate(existingArtist);
                        }
                    }
                }
                if (existingArtists.size() == 0) {
                    ArtistEntity artist = new ArtistEntity();
                    artist.setName(artistName);
                    if (sortValues.containsKey(sortPrefix + artistName)) {
                        artist.setSortAs(sortValues.get(sortPrefix + artistName));
                    }
                    artist.setLastUpdated(new Date());
                    artist.setLastUpdatedBy(getId());
                    validate(artist);
                    artistRepository.create(artist);
                    artists.add(artist);
                    this.artistCache.put(artistName.toLowerCase(), Arrays.asList(artist.getId()));
                } else {
                    artists.addAll(existingArtists);
                }
            }
            for (Artist artist : artists) {
                ContributorEntity contributor = new ContributorEntity();
                contributor.setArtist(artist);
                contributor.setType(contributorType);
                contributor.setLastUpdated(new Date());
                contributor.setLastUpdatedBy(getId());
                validate(contributor);
                contributors.add(contributor);
            }
        }
        return contributors;
    }

    private Collection<String> idList(Collection<? extends SMDIdentity> entityList) {
        if (entityList == null || entityList.size() == 0) {
            return null;
        }
        List<String> idList = new ArrayList<String>(entityList.size());
        for (SMDIdentity artist : entityList) {
            idList.add(artist.getId());
        }
        return idList;
    }

    private <T> Collection<T> lookup(Collection<String> idList, SMDIdentityRepository<T> repository) {
        if (idList == null || idList.size() == 0) {
            return null;
        }
        List<T> result = new ArrayList<T>(idList.size());
        for (String id : idList) {
            result.add(repository.findById(id));
        }
        return result;
    }

    /**
     * Store Contributor entities for the set of contributors specified
     *
     * @param owner        The owning entity
     * @param contributors The list of contributors to create
     */
    private void saveContributors(ContributorOwner owner, Set<Contributor> contributors) {
        for (Contributor contributor : contributors) {
            owner.addContributor((ContributorEntity) contributor);
            contributorRepository.create((ContributorEntity) contributor);
        }
    }

    /**
     * Create and save Classification entities for the specified list of classification names and classification type
     * The created Classification entities is also related to the provided SMDIdentity reference.
     * If a Classification entity of the same name and type already exists, it is reused.
     *
     * @param classificationNames The list of classification names to create entities for
     * @param sortPrefix          The prefix which is used as prefix in key value in sortValues map
     * @param sortValues          A map with sort values for each classification
     * @param classificationType  Type of classification to create
     * @param reference           The reference to relate the created Classification entities to
     */
    private void createClassificationsForTag(Collection<String> classificationNames, String sortPrefix, Map<String, String> sortValues, String classificationType, SMDIdentityReference reference) {
        if (classificationNames != null) {
            for (String classificationName : classificationNames) {
                TypeIdentity classificationId = new TypeIdentity(classificationType.toLowerCase(), classificationName.toLowerCase());
                Collection<ClassificationEntity> existingClassifications = lookup(this.classificationCache.get(classificationId), classificationRepository);
                if (existingClassifications == null) {
                    existingClassifications = classificationRepository.findByNameAndType(classificationName, classificationType);
                    if (existingClassifications.size() > 0) {
                        this.classificationCache.put(classificationId, idList(existingClassifications));
                        for (ClassificationEntity existingClassification : existingClassifications) {
                            if (existingClassification.getLastUpdatedBy().equals(getId()) && sortValues.containsKey(sortPrefix + classificationName)) {
                                existingClassification.setSortAs(sortValues.get(sortPrefix + classificationName));
                            }
                            validate(existingClassification);
                        }
                    }
                }
                ClassificationReferenceEntity classificationReference = new ClassificationReferenceEntity();
                classificationReference.setReferenceTo(reference);
                classificationReference.setLastUpdated(new Date());
                classificationReference.setLastUpdatedBy(getId());
                if (existingClassifications.size() == 0) {
                    ClassificationEntity classification = new ClassificationEntity();
                    classification.setName(classificationName);
                    if (sortValues.containsKey(sortPrefix + classificationName)) {
                        classification.setSortAs(sortValues.get(sortPrefix + classificationName));
                    }
                    classification.setType(classificationType);
                    classification.setLastUpdated(new Date());
                    classification.setLastUpdatedBy(getId());
                    validate(classification);
                    classificationRepository.create(classification);
                    classification.addReference(classificationReference);
                    classificationReferenceRepository.create(classificationReference);
                    this.classificationCache.put(classificationId, Arrays.asList(classification.getId()));
                } else {
                    for (ClassificationEntity classification : existingClassifications) {
                        classification.addReference(classificationReference);
                        classificationReferenceRepository.create(classificationReference);
                    }
                }
            }
        }
    }

    protected <T extends SMDIdentity> void validate(T entity) {
        Set<ConstraintViolation<T>> errors = validator.validate(entity);
        if (errors.size() > 0) {
            throw new ConstraintViolationException(new HashSet<ConstraintViolation<?>>(errors));
        }
    }

    @Override
    public Collection<ConfigurationParameter> getDefaultConfiguration() {
        return new ArrayList<ConfigurationParameter>(Arrays.asList(
                (ConfigurationParameter) new ConfigurationParameterEntity("genres", ConfigurationParameter.Type.BOOLEAN, "true"),
                (ConfigurationParameter) new ConfigurationParameterEntity("styles", ConfigurationParameter.Type.BOOLEAN, "true"),
                (ConfigurationParameter) new ConfigurationParameterEntity("moods", ConfigurationParameter.Type.BOOLEAN, "true"),
                (ConfigurationParameter) new ConfigurationParameterEntity("composers", ConfigurationParameter.Type.BOOLEAN, "true"),
                (ConfigurationParameter) new ConfigurationParameterEntity("conductors", ConfigurationParameter.Type.BOOLEAN, "true")
        ));
    }
}
TOP

Related Classes of org.socialmusicdiscovery.server.plugins.mediaimport.AbstractTagImporter$TypeIdentity

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.