001/** 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 * 006 */ 007package org.fcrepo.migration.handlers; 008 009import java.util.ArrayList; 010import java.util.Comparator; 011import java.util.HashMap; 012import java.util.List; 013import java.util.Map; 014import java.util.Collections; 015 016import org.fcrepo.migration.DatastreamVersion; 017import org.fcrepo.migration.ObjectInfo; 018import org.fcrepo.migration.ObjectProperties; 019import org.fcrepo.migration.ObjectReference; 020import org.fcrepo.migration.ObjectVersionReference; 021import org.fcrepo.migration.FedoraObjectVersionHandler; 022import org.fcrepo.migration.StreamingFedoraObjectHandler; 023 024/** 025 * A StreamingFedoraObjectHandler implementation that caches all the references to 026 * the Fedora 3 object and provides them to a FedoraObjectHandler implementation 027 * which in turn can process the object as a whole in a random-access fashion rather 028 * than as a stream. 029 * @author mdurbin 030 */ 031public class ObjectAbstractionStreamingFedoraObjectHandler implements StreamingFedoraObjectHandler { 032 033 private FedoraObjectVersionHandler versionHandler; 034 035 private ObjectInfo objectInfo; 036 037 private ObjectProperties objectProperties; 038 039 private List<String> dsIds; 040 041 private Map<String, List<DatastreamVersion>> dsIdToVersionListMap; 042 043 /** 044 * the object abstraction streaming fedora object handler. 045 * @param versionHandler the fedora object version handler 046 */ 047 public ObjectAbstractionStreamingFedoraObjectHandler(final FedoraObjectVersionHandler versionHandler) { 048 this.versionHandler = versionHandler; 049 this.dsIds = new ArrayList<String>(); 050 this.dsIdToVersionListMap = new HashMap<String, List<DatastreamVersion>>(); 051 } 052 053 @Override 054 public void beginObject(final ObjectInfo object) { 055 this.objectInfo = object; 056 } 057 058 @Override 059 public void processObjectProperties(final ObjectProperties properties) { 060 this.objectProperties = properties; 061 } 062 063 @Override 064 public void processDatastreamVersion(final DatastreamVersion dsVersion) { 065 List<DatastreamVersion> versions = dsIdToVersionListMap.get(dsVersion.getDatastreamInfo().getDatastreamId()); 066 if (versions == null) { 067 dsIds.add(dsVersion.getDatastreamInfo().getDatastreamId()); 068 versions = new ArrayList<DatastreamVersion>(); 069 dsIdToVersionListMap.put(dsVersion.getDatastreamInfo().getDatastreamId(), versions); 070 } 071 versions.add(dsVersion); 072 } 073 074 @Override 075 public void completeObject(final ObjectInfo object) { 076 final var objectReference = getObjectReference(); 077 try { 078 final Map<String, List<DatastreamVersion>> versionMap = buildVersionMap(); 079 final List<String> versionDates = new ArrayList<String>(versionMap.keySet()); 080 Collections.sort(versionDates); 081 final List<ObjectVersionReference> versions = new ArrayList<ObjectVersionReference>(); 082 for (final String versionDate : versionDates) { 083 versions.add(getObjectVersionReference(versionDate, versionDates, objectReference, versionMap)); 084 } 085 086 // Need to sort the datastream versions because they may not appear in order in FOXML 087 dsIdToVersionListMap.forEach((dsId, dsVersions) -> { 088 dsVersions.sort(Comparator.comparing(DatastreamVersion::getCreatedInstant)); 089 }); 090 091 versionHandler.processObjectVersions(versions, object); 092 } finally { 093 cleanForReuse(); 094 } 095 } 096 097 @Override 098 public void abortObject(final ObjectInfo object) { 099 cleanForReuse(); 100 } 101 102 /** 103 * Removes any state that's specific to a Fedora 3 object that was processed 104 * so that this Handler may be reused for a different object. 105 */ 106 private void cleanForReuse() { 107 this.dsIds.clear(); 108 this.dsIdToVersionListMap.clear(); 109 } 110 111 private Map<String, List<DatastreamVersion>> buildVersionMap() { 112 final Map<String, List<DatastreamVersion>> versionMap = new HashMap<String, List<DatastreamVersion>>(); 113 for (final String dsId : dsIds) { 114 for (final DatastreamVersion v : dsIdToVersionListMap.get(dsId)) { 115 final String date = v.getCreated(); 116 List<DatastreamVersion> versionsForDate = versionMap.get(date); 117 if (versionsForDate == null) { 118 versionsForDate = new ArrayList<DatastreamVersion>(); 119 versionMap.put(date, versionsForDate); 120 } 121 versionsForDate.add(v); 122 } 123 } 124 return versionMap; 125 } 126 127 private ObjectReference getObjectReference() { 128 return new ObjectReference() { 129 @Override 130 public ObjectInfo getObjectInfo() { 131 return objectInfo; 132 } 133 134 @Override 135 public ObjectProperties getObjectProperties() { 136 return objectProperties; 137 } 138 139 @Override 140 public List<String> listDatastreamIds() { 141 return dsIds; 142 } 143 144 @Override 145 public List<DatastreamVersion> getDatastreamVersions(final String datastreamId) { 146 return dsIdToVersionListMap.get(datastreamId); 147 } 148 }; 149 } 150 151 private ObjectVersionReference getObjectVersionReference(final String versionDate, final List<String> versionDates, 152 final ObjectReference objectReference, 153 final Map<String, List<DatastreamVersion>> versionMap) { 154 return new ObjectVersionReference() { 155 @Override 156 public ObjectReference getObject() { 157 return objectReference; 158 } 159 160 @Override 161 public ObjectProperties getObjectProperties() { 162 return objectProperties; 163 } 164 165 @Override 166 public String getVersionDate() { 167 return versionDate; 168 } 169 170 @Override 171 public List<DatastreamVersion> listChangedDatastreams() { 172 return versionMap.get(versionDate); 173 } 174 175 @Override 176 public boolean isLastVersion() { 177 return versionDates.get(versionDates.size() - 1).equals(versionDate); 178 } 179 180 @Override 181 public boolean isFirstVersion() { 182 return versionDates.get(0).equals(versionDate); 183 } 184 185 @Override 186 public int getVersionIndex() { 187 return versionDates.indexOf(versionDate); 188 } 189 190 @Override 191 public boolean wasDatastreamChanged(final String dsId) { 192 for (final DatastreamVersion v : listChangedDatastreams()) { 193 if (v.getDatastreamInfo().getDatastreamId().equals(dsId)) { 194 return true; 195 } 196 } 197 return false; 198 } 199 }; 200 } 201}