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.io.Serializable;
026
027import javax.servlet.jsp.PageContext;
028
029import dk.netarkivet.common.exceptions.ArgumentNotValid;
030import dk.netarkivet.common.utils.I18n;
031
032/**
033 * Harvest channels are used to dispatch harvest jobs to specific pools of crawlers. Channels can accept either only
034 * snapshot jobs or only focused jobs. Snapshot crawls all use a single hard-coded channel.
035 * <p>
036 * Harvest channels names must only contain alphanumeric characters, the constraint is enforced at creation time.
037 * <p>
038 * {@link HarvestDefinition}s are mapped to a {@link HarvestChannel}, and HarvestControllers listen to jobs sent
039 * on a specific channel.
040 * <p>
041 * Harvest channels are stored in the harvest database, as well as mappings to {@link HarvestDefinition}s and
042 * HarvestControllers through two association tables.
043 * <p>
044 * There must be exactly one channel defined as default for every type of job (snapshot and focused). This constraint
045 * will be enforced by the DAO.
046 *
047 * @author ngiraud
048 */
049@SuppressWarnings("serial")
050public class HarvestChannel implements Serializable {
051
052    /** The unique {@link dk.netarkivet.harvester.datamodel.HarvestChannel} for snapshot harvests. */
053    // public static final HarvestChannel SNAPSHOT = new HarvestChannel();
054
055    /** Defines acceptable channel names: at least one word character. */
056    public static final String ACCEPTABLE_NAME_PATTERN = "^\\w+$";
057
058    /** The unique numeric id. */
059    private long id;
060
061    /**
062     * The unique name of the channel. Accepts only alpha numeric characters.
063     *
064     * @see #ACCEPTABLE_NAME_PATTERN
065     * @see #isAcceptableName(String)
066     */
067    private String name;
068
069    /* Whether this channels type is snapshot or focused. */
070    private boolean isSnapshot;
071
072    /** Whether this channel is the default one for the given type (snapshot or focused). */
073    private boolean isDefault;
074
075    /** Comments. */
076    private String comments;
077
078    /**
079     * Used to build the {@link #SNAPSHOT} singleton only.
080     */
081    /*
082     * private HarvestChannel() { this.name = Settings.get(HarvesterSettings.SNAPSHOT_HARVEST_CHANNEL_ID);
083     * this.isSnapshot = true; this.isDefault = true; this.comments = ""; }
084     */
085
086    /**
087     * Constructor from name and comments
088     *
089     * @param name channel name
090     * @param isSnapshot whether this channels type is snapshot or focused
091     * @param isDefault whether this channel is the default one
092     * @param comments user comments (snapshot or focused)
093     * @throws ArgumentNotValid if the name is incorrect.
094     */
095    public HarvestChannel(String name, boolean isSnapshot, boolean isDefault, String comments) {
096        if (!isAcceptableName(name)) {
097            throw new ArgumentNotValid("'" + name + "' does not match pattern '" + ACCEPTABLE_NAME_PATTERN + "'");
098        }
099        this.name = name;
100        this.isSnapshot = isSnapshot;
101        this.isDefault = isDefault;
102        this.comments = comments;
103    }
104
105    /**
106     * Constructor from persistent storage
107     *
108     * @param id the channel id
109     * @param name channel name
110     * @param isSnapshot whether this channels type is snapshot or focused
111     * @param isDefault whether this channel is the default one for the given type
112     * @param comments user comments
113     * @throws ArgumentNotValid if the name is incorrect.
114     */
115    public HarvestChannel(long id, String name, boolean isSnapshot, boolean isDefault, String comments) {
116        ArgumentNotValid.checkNotNullOrEmpty(name, "name");
117        if (!isAcceptableName(name)) {
118            throw new ArgumentNotValid("'" + name + "' does not match pattern '" + ACCEPTABLE_NAME_PATTERN + "'");
119        }
120        this.id = id;
121        this.name = name;
122        this.isSnapshot = isSnapshot;
123        this.isDefault = isDefault;
124        this.comments = comments;
125    }
126
127    /**
128     * @return the unique identifier in the persistent storage
129     */
130    public long getId() {
131        return id;
132    }
133
134    /**
135     * @return the harvest channel name.
136     */
137    public String getName() {
138        return name;
139    }
140
141    /**
142     * Sets the harvest channel name
143     *
144     * @param name the name to set
145     */
146    public void setName(String name) {
147        this.name = name;
148    }
149
150    /**
151     * @return true if this channel is intended for snaphsot harvests, false if it is intended for focused ones.
152     */
153    public boolean isSnapshot() {
154        return isSnapshot;
155    }
156
157    /**
158     * Set the harvest type to snapshot or focused.
159     *
160     * @param isSnapshot true if snapshot, false if focused
161     */
162    public void setSnapshot(boolean isSnapshot) {
163        this.isSnapshot = isSnapshot;
164    }
165
166    /**
167     * @return true if the channel is the default one for the harvest type (snapshot or focused), false otherwise.
168     */
169    public boolean isDefault() {
170        return isDefault;
171    }
172
173    /**
174     * Set whether if the channel is the default one for the harvest type (snapshot or focused).
175     *
176     * @param isDefault true if default, false otherwise
177     */
178    public void setDefault(boolean isDefault) {
179        this.isDefault = isDefault;
180    }
181
182    /**
183     * @return the associated comments.
184     */
185    public String getComments() {
186        return comments;
187    }
188
189    /**
190     * Sets the associated comments
191     *
192     * @param comments the comments to set
193     */
194    public void setComments(String comments) {
195        this.comments = comments;
196    }
197
198    /**
199     * Renders a localized description for the singleton.
200     *
201     * @param context
202     * @return a localized description.
203     */
204    public static String getSnapshotDescription(PageContext context) {
205        return I18n.getString(dk.netarkivet.harvester.Constants.TRANSLATIONS_BUNDLE, context.getResponse().getLocale(),
206                "harvest.channel.snapshot.desc");
207    }
208
209    /**
210     * Returns true if the given input is an acceptable channel name.
211     *
212     * @param input the candidate name.
213     * @return true if the name complies to the defined {@link #ACCEPTABLE_NAME_PATTERN}, false otherwise
214     */
215    public static boolean isAcceptableName(String input) {
216        return input.matches(ACCEPTABLE_NAME_PATTERN);
217    }
218
219    @Override
220    public String toString() {
221        return "HarvestChannel [id=" + id + ", name=" + name + ", comments=" + comments + ", isSnapShot=" + isSnapshot
222                + ", isDefault=" + isDefault + "]";
223    }
224
225}