001/*
002 * #%L
003 * Netarchivesuite - harvester
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.viewerproxy;
025
026import java.net.URI;
027import java.util.ArrayList;
028import java.util.Collections;
029import java.util.HashSet;
030import java.util.List;
031import java.util.Locale;
032import java.util.Set;
033
034import dk.netarkivet.common.distribute.indexserver.Index;
035import dk.netarkivet.common.distribute.indexserver.JobIndexCache;
036import dk.netarkivet.common.exceptions.ArgumentNotValid;
037import dk.netarkivet.common.utils.I18n;
038import dk.netarkivet.common.utils.StringUtils;
039
040/**
041 * Control of viewer proxy. Delegates URL-methods to a missing URL recorder, and cdx control to a JobIndexCache instance
042 * combined with an ARCArchiveAccess instance.
043 */
044
045public class DelegatingController implements Controller {
046    /**
047     * The missing URL recorder which handles missing URL collection.
048     */
049    private MissingURIRecorder mur;
050    /**
051     * The JobIndexCache which generates a CDX from a list of jobs on changeIndex command.
052     */
053    private JobIndexCache cc;
054    /**
055     * The ARCArchiveAccess instance to receive new cdx on changeIndex command.
056     */
057    private ARCArchiveAccess aaa;
058    /**
059     * Remembers the last joblist used for setting index for status purposes.
060     */
061    private Set<Long> jobSet;
062    /**
063     * Remembers the jobs that were available from the last index job list for status purposes.
064     */
065    private Set<Long> availableSet;
066
067    /**
068     * Remembers the label of the index for status purposes.
069     */
070    private String indexLabel;
071    /**
072     * Internationalisation context.
073     */
074    private static final I18n I18N = new I18n(Constants.TRANSLATIONS_BUNDLE);
075
076    /**
077     * Initialise a controller with the relevant instances to control.
078     *
079     * @param mur The missing URL recorder which handles missing URL collection.
080     * @param cc The JobIndexCache which generates an index from a list of jobs on changeIndex command.
081     * @param aaa The ARCArchiveAccess instance to receive new cdx on changeIndex command.
082     * @throws ArgumentNotValid if any argument is null.
083     */
084    public DelegatingController(MissingURIRecorder mur, JobIndexCache cc, ARCArchiveAccess aaa) {
085        ArgumentNotValid.checkNotNull(mur, "MissingURIRecorder mur");
086        ArgumentNotValid.checkNotNull(cc, "JobIndexCache cc");
087        ArgumentNotValid.checkNotNull(aaa, "ARCArchiveAccess aaa");
088        this.mur = mur;
089        this.cc = cc;
090        this.aaa = aaa;
091    }
092
093    /**
094     * Start collecting missing URLs.
095     */
096    public void startRecordingURIs() {
097        mur.startRecordingURIs();
098    }
099
100    /**
101     * Stop collecting missing URLs.
102     */
103    public void stopRecordingURIs() {
104        mur.stopRecordingURIs();
105    }
106
107    /**
108     * Clear list of missing URLs.
109     */
110    public void clearRecordedURIs() {
111        mur.clearRecordedURIs();
112    }
113
114    /**
115     * Get list of missing URLs.
116     *
117     * @return The list of missing URLs.
118     */
119    public Set<URI> getRecordedURIs() {
120        return mur.getRecordedURIs();
121    }
122
123    /**
124     * Change index to use an index based on a list of jobs. Note: Does not check arguments. This is a task for the
125     * mediated classes, ArcArchiveAccess and JobIndexCache.
126     *
127     * @param jobSet List of jobs to get an index for.
128     * @param label The label this index should be known as
129     */
130    public void changeIndex(Set<Long> jobSet, String label) {
131        Index<Set<Long>> jobindex = cc.getIndex(jobSet);
132        aaa.setIndex(jobindex.getIndexFile());
133        this.availableSet = jobindex.getIndexSet();
134        this.jobSet = jobSet;
135        this.indexLabel = label;
136    }
137
138    /**
139     * Get a human readable status of the viewer proxy.
140     *
141     * @param locale The locale used to generate the string
142     * @return A human readable status string.
143     */
144    public String getStatus(Locale locale) {
145        ArgumentNotValid.checkNotNull(locale, "locale");
146        StringBuilder status = new StringBuilder();
147        if (mur.isRecordingURIs()) {
148            status.append(I18N.getString(locale, "currently.collecting.urls"));
149        } else {
150            status.append(I18N.getString(locale, "currently.not.collecting.urls"));
151        }
152        status.append('\n');
153        status.append(I18N.getString(locale, "current.list.contains.0.urls", mur.getRecordedURIs().size()));
154        status.append('\n');
155        if (jobSet == null) {
156            status.append(I18N.getString(locale, "no.index.set"));
157        } else {
158            List<Long> availableList = new ArrayList<Long>(availableSet);
159            Collections.sort(availableList);
160            status.append(I18N.getString(locale, "index.0.built.on.jobs.1", indexLabel,
161                    StringUtils.conjoin(", ", availableList)));
162            if (!availableSet.containsAll(jobSet)) {
163                // Generate a status message that lists
164                // - what was requested
165                // - what is available
166                // - what is missing
167                Set<Long> missingSet = new HashSet<Long>(jobSet);
168                missingSet.removeAll(availableSet);
169                List<Long> jobList = new ArrayList<Long>(jobSet);
170                Collections.sort(jobList);
171                List<Long> missingList = new ArrayList<Long>(missingSet);
172                Collections.sort(missingList);
173                status.append('\n');
174                status.append(I18N.getString(locale, "errormsg;request.was.for.0.but.got.1.missing.2",
175                        StringUtils.conjoin(", ", jobList), StringUtils.conjoin(", ", availableList),
176                        StringUtils.conjoin(", ", missingList)));
177            }
178        }
179        return status.toString();
180    }
181}