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 */
023package dk.netarkivet.harvester.datamodel;
024
025import java.util.Date;
026import java.util.Iterator;
027import java.util.List;
028
029import javax.inject.Provider;
030
031import dk.netarkivet.common.exceptions.ArgumentNotValid;
032import dk.netarkivet.common.utils.Named;
033import dk.netarkivet.harvester.datamodel.dao.DAOProviderFactory;
034import dk.netarkivet.harvester.datamodel.extendedfield.ExtendableEntity;
035import dk.netarkivet.harvester.datamodel.extendedfield.ExtendedFieldDAO;
036import dk.netarkivet.harvester.datamodel.extendedfield.ExtendedFieldTypes;
037import dk.netarkivet.harvester.datamodel.extendedfield.ExtendedFieldValue;
038
039/**
040 * This abstract class models the general properties of a harvest definition, i.e. object id , name, comments, and
041 * submission date
042 * <p>
043 * The specializing classes FullHarvest and PartielHarvest contains the specific properties and operations of snapshot
044 * harvestdefinitions and all other kinds of harvestdefinitions, respectively.
045 * <p>
046 * Methods exist to generate jobs from this harvest definition.
047 */
048public abstract class HarvestDefinition extends ExtendableEntity implements Named {
049
050    protected Long oid;
051    protected String harvestDefName;
052    /** The intended audience for the harvest. */
053    protected String audience;
054
055    /** The time this harvest definition was first written. */
056    protected Date submissionDate;
057    protected String comments;
058
059    /** Edition is used by the DAO to keep track of changes. */
060    protected long edition = -1;
061
062    /**
063     * Determines if the harvest definition is active and ready for scheduling. When true the jobs should be scheduled
064     * otherwise the scheduler should ignore the definition. Initially a definition is assumed active - the original
065     * behaviour before the isActive flag was introduced.
066     */
067    protected boolean isActive = true;
068
069    /** The number of times this event has already run. */
070    protected int numEvents;
071
072    /** The id of the associated harvest channel, or null if the default one is to be used. */
073    protected Long channelId;
074
075    protected HarvestDefinition(Provider<ExtendedFieldDAO> extendedFieldDAO) {
076        super(extendedFieldDAO);
077    }
078
079    /**
080     * Create new instance of a PartialHavest configured according to the properties of the supplied
081     * DomainConfiguration.
082     *
083     * @param domainConfigurations a list of domain configurations
084     * @param schedule the harvest definition schedule
085     * @param harvestDefName the name of the harvest definition
086     * @param comments comments
087     * @return the newly created PartialHarvest
088     */
089    public static PartialHarvest createPartialHarvest(List<DomainConfiguration> domainConfigurations,
090            Schedule schedule, String harvestDefName, String comments, String audience) {
091
092        return new PartialHarvest(domainConfigurations, schedule, harvestDefName, comments, audience);
093    }
094
095    /**
096     * Create snapshot harvestdefinition. A snapshot harvestdefinition creates jobs for all domains, using the default
097     * configuration for each domain. The HarvestDefinition is scheduled to run once as soon as possible.
098     * <p>
099     * When a previous harvest definition is supplied, only domains not completely harvested by the previous
100     * harvestdefinition are included in this harvestdefinition. indexready set to false.
101     *
102     * @param harvestDefName the name of the harvest definition
103     * @param comments description of the harvestdefinition
104     * @param prevHarvestOid an id of a previous harvest to use as basis for this definition, ignored when null.
105     * @param maxCountObjects the maximum number of objects harvested from any domain
106     * @param maxBytes the maximum number of bytes harvested from any domain
107     * @param maxJobRunningTime The maximum running time for each job
108     * @return a snapshot harvestdefinition
109     */
110    public static FullHarvest createFullHarvest(String harvestDefName, String comments, Long prevHarvestOid,
111            long maxCountObjects, long maxBytes, long maxJobRunningTime) {
112
113        return new FullHarvest(harvestDefName, comments, prevHarvestOid, maxCountObjects, maxBytes, maxJobRunningTime,
114                false, DAOProviderFactory.getHarvestDefinitionDAOProvider(), DAOProviderFactory.getJobDAOProvider(),
115                DAOProviderFactory.getExtendedFieldDAOProvider(), DAOProviderFactory.getDomainDAOProvider());
116    }
117
118    /**
119     * Set the object ID of this harvest definition.
120     *
121     * @param oid The oid
122     * @throws ArgumentNotValid if the oid is null
123     */
124    public void setOid(Long oid) {
125        ArgumentNotValid.checkNotNull(oid, "oid");
126        this.oid = oid;
127    }
128
129    /**
130     * Return the object ID of this harvest definition.
131     *
132     * @return The object id, or null if none.
133     */
134    public Long getOid() {
135        return oid;
136    }
137
138    /**
139     * Check if this harvestdefinition has an ID set yet (doesn't happen until the DBDAO persists it).
140     *
141     * @return true, if this harvestdefinition has an ID set
142     */
143    boolean hasID() {
144        return oid != null;
145    }
146
147    /**
148     * Set the submission date.
149     *
150     * @param submissionDate the time when the harvestdefinition was created
151     */
152    public void setSubmissionDate(Date submissionDate) {
153        this.submissionDate = submissionDate;
154    }
155
156    /**
157     * Returns the submission date.
158     *
159     * @return the submission date
160     */
161    public Date getSubmissionDate() {
162        return submissionDate;
163    }
164
165    /**
166     * Returns the name of the harvest definition.
167     *
168     * @return the harvest definition name
169     */
170    public String getName() {
171        return harvestDefName;
172    }
173
174    /**
175     * Returns the comments for this harvest definition.
176     *
177     * @return the comments for this harvest definition.
178     */
179    public String getComments() {
180        return comments;
181    }
182
183    /**
184     * Set the comments for this harvest definition.
185     *
186     * @param comments A user-entered string.
187     */
188    public void setComments(String comments) {
189        ArgumentNotValid.checkNotNull(comments, "comments");
190        this.comments = comments;
191    }
192
193    /**
194     * Get the edition number.
195     *
196     * @return The edition number
197     */
198    public long getEdition() {
199        return edition;
200    }
201
202    /**
203     * Set the edition number.
204     *
205     * @param theEdition the new edition of the harvestdefinition
206     */
207    public void setEdition(long theEdition) {
208        edition = theEdition;
209    }
210
211    /**
212     * Get the number of times this harvest definition has been run so far.
213     *
214     * @return That number
215     */
216    public int getNumEvents() {
217        return numEvents;
218    }
219
220    /**
221     * Set the number of times this harvest definition has been run so far.
222     *
223     * @param numEvents The number.
224     * @throws ArgumentNotValid if numEvents is negative
225     */
226    public void setNumEvents(int numEvents) {
227        ArgumentNotValid.checkNotNegative(numEvents, "numEvents");
228        this.numEvents = numEvents;
229    }
230
231    /**
232     * Set's activation status. Only active harvestdefinitions should be scheduled.
233     *
234     * @param active new activation status
235     */
236    public void setActive(boolean active) {
237        isActive = active;
238    }
239
240    /**
241     * Returns the activation status.
242     *
243     * @return activation status
244     */
245    public boolean getActive() {
246        return isActive;
247    }
248
249    /**
250     * Returns a iterator of domain configurations for this harvest definition.
251     *
252     * @return Iterator containing information about the domain configurations
253     */
254    public abstract Iterator<DomainConfiguration> getDomainConfigurations();
255
256    /**
257     * Return a human-readable string representation of this object.
258     *
259     * @return A human-readable string representation of this object
260     */
261    public String toString() {
262        return "HD #" + oid + ": '" + getName() + "'";
263    }
264
265    /**
266     * Tests whether some other object is "equal to" this HarvestDefinition. Cfr. documentation of
267     * java.lang.Object.equals()
268     *
269     * @param o
270     * @return True or false, indicating equality.
271     */
272    public boolean equals(Object o) {
273        if (this == o) {
274            return true;
275        }
276        if (!(o instanceof HarvestDefinition)) {
277            return false;
278        }
279
280        final HarvestDefinition harvestDefinition = (HarvestDefinition) o;
281
282        if (!comments.equals(harvestDefinition.comments)) {
283            return false;
284        }
285        if (!harvestDefName.equals(harvestDefinition.harvestDefName)) {
286            return false;
287        }
288        if (oid != null ? !oid.equals(harvestDefinition.oid) : harvestDefinition.oid != null) {
289            return false;
290        }
291
292        if ((extendedFieldValues == null && harvestDefinition.getExtendedFieldValues() != null)
293                || (extendedFieldValues != null && harvestDefinition.getExtendedFieldValues() == null)) {
294            return false;
295        }
296
297        if (extendedFieldValues != null && harvestDefinition.getExtendedFieldValues() != null) {
298            if (extendedFieldValues.size() != harvestDefinition.getExtendedFieldValues().size()) {
299                return false;
300            }
301
302            for (int i = 0; i < extendedFieldValues.size(); i++) {
303                ExtendedFieldValue e1 = extendedFieldValues.get(i);
304                ExtendedFieldValue e2 = harvestDefinition.getExtendedFieldValues().get(i);
305
306                if ((e1 == null && e2 != null) || (e1 != null && e2 == null)) {
307                    return false;
308                }
309
310                if (e1 != null && e2 != null) {
311                    if (!e1.equals(e2)) {
312                        return false;
313                    }
314                }
315            }
316        }
317
318        return true;
319    }
320
321    /**
322     * Returns a hashcode of this object generated on fields oid, harvestDefName, and comments.
323     *
324     * @return the hashCode
325     */
326    public int hashCode() {
327        int result;
328        result = (oid != null ? oid.hashCode() : 0);
329        result = 29 * result + harvestDefName.hashCode();
330        result = 29 * result + comments.hashCode();
331        return result;
332    }
333
334    /**
335     * Check if this harvest definition should be run, given the time now.
336     *
337     * @param now The current time
338     * @return true if harvest definition should be run
339     */
340    public abstract boolean runNow(Date now);
341
342    /**
343     * Used to check if a harvestdefinition is a snapshot harvestdefinition.
344     *
345     * @return true if this harvestdefinition defines a snapshot harvest
346     */
347    public abstract boolean isSnapShot();
348
349    /**
350     * Returns how many objects to harvest per domain, or 0 for no limit.
351     *
352     * @return how many objects to harvest per domain
353     */
354    public abstract long getMaxCountObjects();
355
356    /**
357     * Returns how many bytes to harvest per domain, or -1 for no limit.
358     *
359     * @return how many bytes to harvest per domain
360     */
361    public abstract long getMaxBytes();
362
363    /**
364     * @return the intended audience for this harvest.
365     */
366    public String getAudience() {
367        return this.audience;
368    }
369
370    /**
371     * Set the audience.
372     *
373     * @param audience the audience.
374     */
375    public void setAudience(String audience) {
376        this.audience = audience;
377    }
378
379    public Long getChannelId() {
380        return channelId;
381    }
382
383    protected void setChannelId(Long channelId) {
384        this.channelId = channelId;
385    }
386
387    /**
388     * All derived classes allow ExtendedFields from Type ExtendedFieldTypes.HARVESTDEFINITION
389     *
390     * @return ExtendedFieldTypes.HARVESTDEFINITION
391     */
392    protected int getExtendedFieldType() {
393        return ExtendedFieldTypes.HARVESTDEFINITION;
394    }
395    
396    /**
397     * Change the name of the Harvestdefinition to newName. 
398     * @param newName The new name of the Harvestdefinition
399     */
400    public void setName(String newName) {
401        this.harvestDefName = newName;
402    }
403}