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.datamodel;
025
026import java.io.Reader;
027import java.io.StringReader;
028import java.sql.Clob;
029import java.sql.Connection;
030import java.sql.PreparedStatement;
031import java.sql.ResultSet;
032import java.sql.SQLException;
033import java.util.Iterator;
034import java.util.List;
035
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039import dk.netarkivet.common.exceptions.ArgumentNotValid;
040import dk.netarkivet.common.exceptions.IOFailure;
041import dk.netarkivet.common.exceptions.PermissionDenied;
042import dk.netarkivet.common.exceptions.UnknownID;
043import dk.netarkivet.common.utils.DBUtils;
044import dk.netarkivet.common.utils.ExceptionUtils;
045
046/**
047 * Implements the TemplateDAO with databases.
048 * <p>
049 * The statements to create the tables are now in scripts/sql/createfullhddb.sql
050 */
051
052public class TemplateDBDAO extends TemplateDAO {
053
054    /** the log. */
055    private static final Logger log = LoggerFactory.getLogger(TemplateDBDAO.class);
056
057    /**
058     * Default constructor. Only used by TemplateDAO,getInstance().
059     */
060    TemplateDBDAO() {
061        Connection connection = HarvestDBConnection.get();
062        try {
063            HarvesterDatabaseTables.checkVersion(connection, HarvesterDatabaseTables.ORDERTEMPLATES);
064        } finally {
065            HarvestDBConnection.release(connection);
066        }
067    }
068
069    /**
070     * Read an XML order file for the named order XML.
071     *
072     * @param orderXmlName The name of the order.xml document
073     * @return The contents of this order.xml document
074     */
075    public synchronized HeritrixTemplate read(String orderXmlName) {
076        ArgumentNotValid.checkNotNullOrEmpty(orderXmlName, "String orderXmlName");
077        Connection c = HarvestDBConnection.get();
078        PreparedStatement s = null;
079        try {
080            s = c.prepareStatement("SELECT orderxml FROM ordertemplates WHERE name = ?");
081            s.setString(1, orderXmlName);
082            ResultSet res = s.executeQuery();
083            if (!res.next()) {
084                throw new UnknownID("Can't find template " + orderXmlName);
085            }
086            Reader orderTemplateReader = null;
087            if (DBSpecifics.getInstance().supportsClob()) {
088                Clob clob = res.getClob(1);
089                
090                orderTemplateReader = clob.getCharacterStream();
091            } else {
092                String string = res.getString(1);
093                // log.debug("clob=" + string);
094                orderTemplateReader = new StringReader(string);
095            } 
096            System.out.println("Calling HeritrixTemplate.read() w/ arg:" + orderTemplateReader);
097            return HeritrixTemplate.read(orderTemplateReader);
098        } catch (SQLException e) {
099            final String message = "SQL error finding order.xml for " + orderXmlName + "\n"
100                    + ExceptionUtils.getSQLExceptionCause(e);
101            log.warn(message, e);
102            throw new IOFailure(message, e);
103       /*
104        } catch (DocumentException e) {
105            final String message = "Error parsing order.xml string for " + orderXmlName;
106            log.warn(message, e);
107            throw new IOFailure(message, e);
108            */
109        }
110         finally {
111            DBUtils.closeStatementIfOpen(s);
112            HarvestDBConnection.release(c);
113        }
114    }
115
116    /**
117     * Returns an iterator with all names of order.xml-templates.
118     *
119     * @return Iterator<String> with all names of templates (without .xml).
120     */
121    public synchronized Iterator<String> getAll() {
122        Connection c = HarvestDBConnection.get();
123        try {
124            List<String> names = DBUtils.selectStringList(c, "SELECT name FROM ordertemplates ORDER BY name");
125            return names.iterator();
126        } finally {
127            HarvestDBConnection.release(c);
128        }
129    }
130
131    /**
132     * Return true if the database contains a template with the given name.
133     *
134     * @param orderXmlName Name of an order.xml template (without .xml).
135     * @return True if such a template exists.
136     * @throws ArgumentNotValid If the orderXmlName is null or an empty String
137     */
138    public synchronized boolean exists(String orderXmlName) {
139        ArgumentNotValid.checkNotNullOrEmpty(orderXmlName, "String orderXmlName");
140
141        Connection c = HarvestDBConnection.get();
142        try {
143            return exists(c, orderXmlName);
144        } finally {
145            HarvestDBConnection.release(c);
146        }
147    }
148
149    /**
150     * Return true if the database contains a template with the given name.
151     *
152     * @param orderXmlName Name of an order.xml template (without .xml).
153     * @return True if such a template exists.
154     * @throws ArgumentNotValid If the orderXmlName is null or an empty String
155     */
156    private synchronized boolean exists(Connection c, String orderXmlName) {
157        int count = DBUtils.selectIntValue(c, "SELECT COUNT(*) FROM ordertemplates WHERE name = ?", orderXmlName);
158        return count == 1;
159    }
160
161    /**
162     * Create a template. The template must not already exist.
163     *
164     * @param orderXmlName Name of the template.
165     * @param orderXml XML documents that is a Heritrix order.xml template.
166     * @throws ArgumentNotValid If the orderXmlName is null or an empty String, or the orderXml is null.
167     */
168    public synchronized void create(String orderXmlName, HeritrixTemplate orderXml) {
169        ArgumentNotValid.checkNotNullOrEmpty(orderXmlName, "String orderXmlName");
170        ArgumentNotValid.checkNotNull(orderXml, "HeritrixTemplate orderXml");
171
172        Connection c = HarvestDBConnection.get();
173        PreparedStatement s = null;
174        try {
175            if (exists(c, orderXmlName)) {
176                throw new PermissionDenied("An order template called " + orderXmlName + " already exists");
177            }
178
179            s = c.prepareStatement("INSERT INTO ordertemplates " + "( name, orderxml ) VALUES ( ?, ? )");
180            DBUtils.setStringMaxLength(s, 1, orderXmlName, Constants.MAX_NAME_SIZE, orderXmlName, "length");
181            DBUtils.setClobMaxLength(s, 2, orderXml.getXML(), Constants.MAX_ORDERXML_SIZE, "size", orderXmlName);
182            s.executeUpdate();
183        } catch (SQLException e) {
184            throw new IOFailure("SQL error creating template " + orderXmlName + "\n"
185                    + ExceptionUtils.getSQLExceptionCause(e), e);
186        } finally {
187            HarvestDBConnection.release(c);
188        }
189    }
190
191    /**
192     * Update a template. The template must already exist.
193     *
194     * @param orderXmlName Name of the template.
195     * @param orderXml XML document that is a Heritrix order.xml template.
196     * @throws PermissionDenied If the template does not exist
197     * @throws IOFailure If the template could not be
198     * @throws ArgumentNotValid If the orderXmlName is null or an empty String, or the orderXml is null.
199     */
200    public synchronized void update(String orderXmlName, HeritrixTemplate orderXml) {
201        ArgumentNotValid.checkNotNullOrEmpty(orderXmlName, "String orderXmlName");
202        ArgumentNotValid.checkNotNull(orderXml, "HeritrixTemplate orderXml");
203
204        Connection c = HarvestDBConnection.get();
205        PreparedStatement s = null;
206        try {
207            if (!exists(c, orderXmlName)) {
208                throw new PermissionDenied("No order template called " + orderXmlName + " exists");
209            }
210
211            s = c.prepareStatement("UPDATE ordertemplates SET orderxml = ? WHERE name = ?");
212            DBUtils.setClobMaxLength(s, 1, orderXml.getXML(), Constants.MAX_ORDERXML_SIZE, "size", orderXmlName);
213            s.setString(2, orderXmlName);
214            s.executeUpdate();
215        } catch (SQLException e) {
216            throw new IOFailure("SQL error updating template " + orderXmlName + "\n"
217                    + ExceptionUtils.getSQLExceptionCause(e), e);
218        } finally {
219            HarvestDBConnection.release(c);
220        }
221    }
222
223}