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