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.extendedfield;
024
025import java.sql.Connection;
026import java.sql.PreparedStatement;
027import java.sql.ResultSet;
028import java.sql.SQLException;
029
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032
033import dk.netarkivet.common.exceptions.ArgumentNotValid;
034import dk.netarkivet.common.exceptions.IOFailure;
035import dk.netarkivet.common.exceptions.UnknownID;
036import dk.netarkivet.common.utils.DBUtils;
037import dk.netarkivet.harvester.datamodel.HarvestDBConnection;
038import dk.netarkivet.harvester.datamodel.HarvesterDatabaseTables;
039
040/**
041 * Implementation class for the ExtendedFieldValueDAO interface.
042 */
043public class ExtendedFieldValueDBDAO extends ExtendedFieldValueDAO {
044
045    /** The logger. */
046    private static final Logger log = LoggerFactory.getLogger(ExtendedFieldValueDBDAO.class);
047
048    /**
049     * Constructor for the ExtendedFieldValueDBDAO class.
050     */
051    public ExtendedFieldValueDBDAO() {
052        Connection connection = HarvestDBConnection.get();
053        try {
054            HarvesterDatabaseTables.checkVersion(connection, HarvesterDatabaseTables.EXTENDEDFIELD);
055            HarvesterDatabaseTables.checkVersion(connection, HarvesterDatabaseTables.EXTENDEDFIELDTYPE);
056            HarvesterDatabaseTables.checkVersion(connection, HarvesterDatabaseTables.EXTENDEDFIELDVALUE);
057        } finally {
058            HarvestDBConnection.release(connection);
059        }
060    }
061
062    /**
063     * Create a ExtendedFieldValue in persistent storage.
064     *
065     * @param aConnection an open connection to the HarvestDatabase.
066     * @param aExtendedFieldValue The ExtendedFieldValue to create in persistent storage
067     * @param aCommit Should we commit this or not
068     * @throws SQLException In case of Database access problems.
069     */
070    public void create(Connection aConnection, ExtendedFieldValue aExtendedFieldValue, boolean aCommit)
071            throws SQLException {
072        ArgumentNotValid.checkNotNull(aExtendedFieldValue, "aExtendedFieldValue");
073
074        if (aExtendedFieldValue.getExtendedFieldValueID() != null) {
075            log.warn("The extendedFieldValueID for this extendedField Value is already set. "
076                    + "This should probably never happen.");
077        } else {
078            aExtendedFieldValue.setExtendedFieldValueID(generateNextID(aConnection));
079        }
080
081        log.debug("Creating {}", aExtendedFieldValue.toString());
082
083        PreparedStatement statement = null;
084        aConnection.setAutoCommit(false);
085        statement = aConnection.prepareStatement("INSERT INTO extendedfieldvalue ("
086                + "extendedfieldvalue_id, extendedfield_id, content, instance_id) " + "VALUES (?, ?, ?, ?)");
087
088        statement.setLong(1, aExtendedFieldValue.getExtendedFieldValueID());
089        statement.setLong(2, aExtendedFieldValue.getExtendedFieldID());
090        statement.setString(3, aExtendedFieldValue.getContent());
091        statement.setLong(4, aExtendedFieldValue.getInstanceID());
092
093        statement.executeUpdate();
094        if (aCommit) {
095            aConnection.commit();
096        }
097    }
098
099    @Override
100    public void create(ExtendedFieldValue aExtendedFieldValue) {
101        Connection connection = HarvestDBConnection.get();
102
103        try {
104            create(connection, aExtendedFieldValue, true);
105        } catch (SQLException e) {
106            String message = "SQL error creating extendedfield value " + aExtendedFieldValue + " in database" + "\n";
107            log.warn(message, e);
108            throw new IOFailure(message, e);
109        } finally {
110            DBUtils.rollbackIfNeeded(connection, "create extendedfield value", aExtendedFieldValue);
111            HarvestDBConnection.release(connection);
112        }
113    }
114
115    /**
116     * @param c an open connection to the HarvestDatabase.
117     * @return the ID for next extendedvFieldValue inserted.
118     */
119    private Long generateNextID(Connection c) {
120        // FIXME synchronize or use identity row or generator.
121        Long maxVal = DBUtils.selectLongValue(c, "SELECT max(extendedfieldvalue_id) FROM extendedfieldvalue");
122
123        if (maxVal == null) {
124            maxVal = 0L;
125        }
126        return maxVal + 1L;
127    }
128
129    @Override
130    public void delete(long aExtendedfieldValueID) throws IOFailure {
131        ArgumentNotValid.checkNotNull(aExtendedfieldValueID, "aExtendedfieldValueID");
132
133        Connection c = HarvestDBConnection.get();
134        PreparedStatement stm = null;
135        try {
136            c.setAutoCommit(false);
137
138            stm = c.prepareStatement("DELETE FROM extendedfieldvalue WHERE extendedfieldvalue_id = ?");
139            stm.setLong(1, aExtendedfieldValueID);
140            stm.executeUpdate();
141
142            c.commit();
143        } catch (SQLException e) {
144            String message = "SQL error deleting extendedfieldvalue for ID " + aExtendedfieldValueID + "\n";
145            log.warn(message, e);
146        } finally {
147            DBUtils.closeStatementIfOpen(stm);
148            DBUtils.rollbackIfNeeded(c, "delete extendedfield value", aExtendedfieldValueID);
149            HarvestDBConnection.release(c);
150        }
151    }
152
153    @Override
154    public boolean exists(Long aExtendedFieldValueID) {
155        ArgumentNotValid.checkNotNull(aExtendedFieldValueID, "Long aExtendedFieldValueID");
156
157        Connection c = HarvestDBConnection.get();
158        try {
159            return exists(c, aExtendedFieldValueID);
160        } finally {
161            HarvestDBConnection.release(c);
162        }
163
164    }
165
166    /**
167     * Find out if there already exists in persistent storage a ExtendedFieldValue with the given id.
168     *
169     * @param c an open connection to the HarvestDatabase.
170     * @param aExtendedFieldValueID An id associated with a ExtendedFieldValue
171     * @return true, if there already exists in persistent storage a ExtendedFieldValue with the given id.
172     */
173    private synchronized boolean exists(Connection c, Long aExtendedFieldValueID) {
174        return 1 == DBUtils.selectLongValue(c, "SELECT COUNT(*) FROM extendedfieldvalue "
175                + "WHERE extendedfieldvalue_id = ?", aExtendedFieldValueID);
176    }
177
178    @Override
179    public synchronized ExtendedFieldValue read(Long aExtendedFieldID, Long aInstanceID) {
180        ArgumentNotValid.checkNotNull(aExtendedFieldID, "aExtendedFieldID");
181        ArgumentNotValid.checkNotNull(aInstanceID, "aInstanceID");
182        Connection connection = HarvestDBConnection.get();
183        try {
184            return read(connection, aExtendedFieldID, aInstanceID);
185        } finally {
186            HarvestDBConnection.release(connection);
187        }
188    }
189
190    /**
191     * Read the ExtendedFieldValue with the given extendedFieldID.
192     *
193     * @param connection an open connection to the HarvestDatabase
194     * @param aExtendedFieldID A given ID for a ExtendedFieldValue
195     * @param aInstanceID A given instanceID
196     * @return the ExtendedFieldValue with the given extendedFieldID.
197     */
198    private synchronized ExtendedFieldValue read(Connection connection, Long aExtendedFieldID, Long aInstanceID) {
199        ExtendedFieldValue extendedFieldValue = null;
200        PreparedStatement statement = null;
201        try {
202            statement = connection.prepareStatement("" + "SELECT extendedfieldvalue_id, " + "       extendedfield_id, "
203                    + "       content " + "FROM extendedfieldvalue "
204                    + "WHERE  extendedfield_id = ? and instance_id = ?");
205
206            statement.setLong(1, aExtendedFieldID);
207            statement.setLong(2, aInstanceID);
208            ResultSet result = statement.executeQuery();
209            if (!result.next()) {
210                return null;
211            }
212
213            long extendedfieldvalueId = result.getLong(1);
214            long extendedfieldId = result.getLong(2);
215            long instanceId = aInstanceID;
216            String content = result.getString(3);
217
218            extendedFieldValue = new ExtendedFieldValue(extendedfieldvalueId, extendedfieldId, instanceId, content);
219
220            return extendedFieldValue;
221        } catch (SQLException e) {
222            String message = "SQL error reading extended Field " + aExtendedFieldID + " in database" + "\n";
223            log.warn(message, e);
224            throw new IOFailure(message, e);
225        }
226    }
227
228    /**
229     * Read a ExtendedFieldValue in persistent storage.
230     *
231     * @param aConnection an open connection to the HarvestDatabase
232     * @param aExtendedFieldValue The ExtendedFieldValue to update
233     * @param aCommit Should we commit this or not
234     * @throws SQLException In case of database problems.
235     */
236    public void update(Connection aConnection, ExtendedFieldValue aExtendedFieldValue, boolean aCommit)
237            throws SQLException {
238        PreparedStatement statement = null;
239        final Long extendedfieldvalueId = aExtendedFieldValue.getExtendedFieldID();
240        if (!exists(aConnection, extendedfieldvalueId)) {
241            throw new UnknownID("Extended Field Value id " + extendedfieldvalueId + " is not known in "
242                    + "persistent storage");
243        }
244
245        aConnection.setAutoCommit(false);
246
247        statement = aConnection.prepareStatement("" + "UPDATE extendedfieldvalue " + "SET    extendedfield_id = ?, "
248                + "       instance_id = ?, " + "       content = ? "
249                + "WHERE  extendedfieldvalue_id = ? and instance_id = ?");
250
251        statement.setLong(1, aExtendedFieldValue.getExtendedFieldID());
252        statement.setLong(2, aExtendedFieldValue.getInstanceID());
253        statement.setString(3, aExtendedFieldValue.getContent());
254        statement.setLong(4, aExtendedFieldValue.getExtendedFieldValueID());
255        statement.setLong(5, aExtendedFieldValue.getInstanceID());
256
257        statement.executeUpdate();
258
259        if (aCommit) {
260            aConnection.commit();
261        }
262    }
263
264    @Override
265    public void update(ExtendedFieldValue aExtendedFieldValue) throws IOFailure {
266        Connection connection = HarvestDBConnection.get();
267
268        try {
269            update(connection, aExtendedFieldValue, true);
270        } catch (SQLException e) {
271            String message = "SQL error updating extendedfield Value " + aExtendedFieldValue + " in database" + "\n";
272            log.warn(message, e);
273            throw new IOFailure(message, e);
274        } finally {
275            DBUtils.rollbackIfNeeded(connection, "update extendedfield Value", aExtendedFieldValue);
276            HarvestDBConnection.release(connection);
277        }
278    }
279
280}