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.harvester.webinterface;
025
026import java.sql.SQLException;
027import java.util.ArrayList;
028import java.util.List;
029
030import javax.servlet.ServletRequest;
031import javax.servlet.jsp.PageContext;
032
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import com.antiaction.raptor.dao.AttributeBase;
037import com.antiaction.raptor.dao.AttributeTypeBase;
038
039import dk.netarkivet.common.exceptions.ArgumentNotValid;
040import dk.netarkivet.common.exceptions.ForwardedToErrorPage;
041import dk.netarkivet.common.utils.I18n;
042import dk.netarkivet.common.webinterface.HTMLUtils;
043import dk.netarkivet.harvester.datamodel.Domain;
044import dk.netarkivet.harvester.datamodel.DomainConfiguration;
045import dk.netarkivet.harvester.datamodel.DomainDAO;
046import dk.netarkivet.harvester.datamodel.Password;
047import dk.netarkivet.harvester.datamodel.SeedList;
048import dk.netarkivet.harvester.datamodel.TemplateDAO;
049import dk.netarkivet.harvester.datamodel.eav.EAV;
050import dk.netarkivet.harvester.datamodel.eav.EAV.AttributeAndType;
051
052/**
053 * Utility class containing methods for processing a GUI-request to update the details of a domain-configuration.
054 */
055
056public class DomainConfigurationDefinition {
057        
058        private static final Logger log = LoggerFactory.getLogger(DomainConfigurationDefinition.class);
059        
060    /**
061     * Extracts all required parameters from the request, checks for any inconsistencies, and passes the requisite data
062     * to the updateDomain method for processing. The specified domain configuration is then updated and the result
063     * stored in the database.
064     * <p>
065     * update: This method does nothing if update is not set
066     * <p>
067     * name: must be the name of a known domain
068     * <p>
069     * default: the defaultconfig is set to this value. Must be non-null and a known configuration of this domain.
070     * <p>
071     * edition: The edition number the config was originally read as, if any.
072     * <p>
073     * (configName, order_xml, maxRate, maxObjects, maxBytes, urlListList[], passwordList): group specifying a
074     * configuration to update or add. If configName is non null then order_xml must be a known order-xml and
075     * urlListList must contain only known seedlists, (and at least one such). load, maxObjects, maxBytes, edition must
076     * be parsable as integers if present. passwordList is currently ignored.
077     *
078     * @param context The context of this request
079     * @param i18n I18n information
080     * @throws ForwardedToErrorPage if a user error has caused forwarding to the error page, in which case processing
081     * should abort.
082     */
083    public static void processRequest(PageContext context, I18n i18n) {
084        ArgumentNotValid.checkNotNull(context, "PageContext context");
085        ArgumentNotValid.checkNotNull(i18n, "I18n i18n");
086
087        ServletRequest request = context.getRequest();
088        String update = request.getParameter(Constants.UPDATE_PARAM);
089        if (update == null) {
090            return; // no need to continue
091        }
092
093        HTMLUtils.forwardOnEmptyParameter(context, Constants.DOMAIN_PARAM, Constants.CONFIG_NAME_PARAM, 
094                Constants.ORDER_XML_NAME_PARAM, Constants.SEEDLIST_LIST_PARAM);
095        String name = request.getParameter(Constants.DOMAIN_PARAM).trim();
096        String configName = request.getParameter(Constants.CONFIG_NAME_PARAM).trim();
097        String configOldName = request.getParameter(Constants.CONFIG_OLDNAME_PARAM);
098        if (configOldName != null) {
099            configOldName = configOldName.trim();
100        } else {
101            configOldName = "";
102        }
103        String order_xml = request.getParameter(Constants.ORDER_XML_NAME_PARAM).trim();
104        String[] urlListList = request.getParameterValues(Constants.SEEDLIST_LIST_PARAM);
105
106        if (!DomainDAO.getInstance().exists(name)) {
107            HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;unknown.domain.0", name);
108            throw new ForwardedToErrorPage("Domain " + name + " does not exist");
109        }
110
111        Domain domain = DomainDAO.getInstance().read(name);
112
113        long edition = HTMLUtils.parseOptionalLong(context, Constants.EDITION_PARAM, -1L);
114
115        // check the edition number before updating
116        if (domain.getEdition() != edition) {
117            HTMLUtils.forwardWithRawErrorMessage(
118                    context,
119                    i18n,
120                    "errormsg;domain.definition.changed.0.retry.1",
121                    "<br/><a href=\"Definitions-edit-domain.jsp?" + Constants.DOMAIN_PARAM + "="
122                            + HTMLUtils.escapeHtmlValues(HTMLUtils.encode(name)) + "\">", "</a>");
123            throw new ForwardedToErrorPage("Domain '" + name + "' has changed");
124        }
125
126        if (!TemplateDAO.getInstance().exists(order_xml)) {
127            HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;harvest.template.0.does.not.exist", order_xml);
128            throw new ForwardedToErrorPage("Unknown template " + order_xml);
129        }
130
131        for (String s : urlListList) {
132            s = s.trim();
133            if (s.length() == 0 || !domain.hasSeedList(s)) {
134                HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;unknown.seed.list.0", s);
135                throw new ForwardedToErrorPage("Unknown seed list " + s);
136            }
137        }
138
139        int load = HTMLUtils.parseOptionalLong(context, Constants.MAX_RATE_PARAM,
140                (long) dk.netarkivet.harvester.datamodel.Constants.DEFAULT_MAX_REQUEST_RATE).intValue();
141        long maxObjects = HTMLUtils.parseOptionalLong(context, Constants.MAX_OBJECTS_PARAM,
142                dk.netarkivet.harvester.datamodel.Constants.DEFAULT_MAX_OBJECTS);
143        long maxBytes = HTMLUtils.parseOptionalLong(context, Constants.MAX_BYTES_PARAM,
144                dk.netarkivet.harvester.datamodel.Constants.DEFAULT_MAX_BYTES);
145
146        String comments = request.getParameter(Constants.COMMENTS_PARAM);
147
148        DomainConfiguration domainConf = null;
149
150        if (!configOldName.isEmpty() && !configOldName.equals(configName)){
151            // Are we allowed to rename to the new name? or does it already exist?
152            if (domain.hasConfiguration(configName)) {
153                HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;configuration.exists.0", configName);
154                throw new ForwardedToErrorPage("Configuration " + configName + " already exist");
155            } else {
156                domainConf = domain.getConfiguration(configOldName);
157                String defaultConfigName = DomainDAO.getInstance().getDefaultDomainConfigurationName(domain.getName());
158                if (defaultConfigName.equals(configName)){      
159                    HTMLUtils.forwardWithErrorMessage(context, i18n, "errormsg;cannot.rename.defaultconfiguration.0", configOldName);
160                    throw new ForwardedToErrorPage("Configuration " + configOldName + " cannot be renamed. It is the defaultconfiguration");
161                } else {
162                    List<SeedList> seedlistList = new ArrayList<SeedList>();
163                    for (String seedlistName : urlListList) {
164                        seedlistList.add(domain.getSeedList(seedlistName));
165                    }
166                    domainConf.setName(configName);
167                    domainConf.setOrderXmlName(order_xml);
168                    domainConf.setMaxObjects(maxObjects);
169                    domainConf.setMaxBytes(maxBytes);
170                    domainConf.setMaxRequestRate(load);
171                    domainConf.setSeedLists(domain, seedlistList);
172                    if (comments != null) {
173                        domainConf.setComments(comments);
174                    }
175                    DomainDAO.getInstance().renameAndUpdateConfig(domain, domainConf, configOldName);
176                }
177            }
178        } else {
179                domainConf = updateDomainConfig(domain, configName, order_xml, load, maxObjects, maxBytes, urlListList, comments);
180        }
181
182        // EAV
183        try {
184                long entity_id = domainConf.getID();
185                log.info("Saving attributes for domain config id {} and name {}", entity_id, domainConf.getName());
186            EAV eav = EAV.getInstance();
187            List<AttributeAndType> attributeTypes = eav.getAttributesAndTypes(EAV.DOMAIN_TREE_ID, (int)entity_id);
188            AttributeAndType attributeAndType;
189            AttributeTypeBase attributeType;
190            AttributeBase attribute;
191            for (int i=0; i<attributeTypes.size(); ++i) {
192                attributeAndType = attributeTypes.get(i);
193                attributeType = attributeAndType.attributeType;
194                attribute = attributeAndType.attribute;
195                if (attribute == null) {
196                        attribute = attributeType.instanceOf();
197                        attribute.entity_id = (int)entity_id;
198                }
199                switch (attributeType.viewtype) {
200                case 1:
201                        long longValue = HTMLUtils.parseOptionalLong(context, attributeType.name, (long)attributeType.def_int);
202                        log.info("Setting attribute {} to value {}", attributeType.name, longValue);
203                        attribute.setInteger((int)longValue);
204                        break;
205                case 5:
206                case 6:
207                    String paramValue = context.getRequest().getParameter(attributeType.name);
208                    int intVal = 0;
209                    if (paramValue != null && !"0".equals(paramValue)) {
210                        log.debug("Set intVal = 1 for attribute {} when receiving paramValue={}", attributeType.name, paramValue);
211                        intVal = 1;
212                    }
213                        attribute.setInteger(intVal);
214                        break;
215                }
216                eav.saveAttribute(attribute);
217            }
218        } catch (SQLException e) {
219                throw new RuntimeException("Unable to store EAV data!", e);
220        }
221    }
222
223    /**
224     * Given the parsed values, update or create a configuration in the domain.
225     *
226     * @param domain The domain
227     * @param configName Name of config - if this exists we update, otherwise we create a new. 
228     * @param orderXml Order-template name
229     * @param load Request rate
230     * @param maxObjects Max objects
231     * @param maxBytes Max bytes
232     * @param urlListList List of url list names
233     * @param comments Comments, or null for none.
234     */
235    private static DomainConfiguration updateDomainConfig(Domain domain, String configName, String orderXml, int load, long maxObjects,
236            long maxBytes, String[] urlListList, String comments) {
237        // Update/create new configuration      
238        List<SeedList> seedlistList = new ArrayList<SeedList>();
239        for (String seedlistName : urlListList) {
240                seedlistList.add(domain.getSeedList(seedlistName));
241        }
242        DomainConfiguration domainConf;
243        if (domain.hasConfiguration(configName)) {
244                domainConf = domain.getConfiguration(configName);
245        } else { // new DomainConfiguration
246                domainConf = new DomainConfiguration(configName, domain, seedlistList, new ArrayList<Password>());
247                domain.addConfiguration(domainConf);
248        }
249        domainConf.setOrderXmlName(orderXml);
250        domainConf.setMaxObjects(maxObjects);
251        domainConf.setMaxBytes(maxBytes);
252        domainConf.setMaxRequestRate(load);
253        domainConf.setSeedLists(domain, seedlistList);
254        if (comments != null) {
255                domainConf.setComments(comments);
256        }
257        DomainDAO.getInstance().update(domain);
258        return domainConf;
259    }
260}