001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.db.oracle;
029
030import org.opencms.db.CmsDbContext;
031import org.opencms.db.CmsDbEntryNotFoundException;
032import org.opencms.db.CmsDbIoException;
033import org.opencms.db.CmsDbSqlException;
034import org.opencms.db.generic.CmsSqlManager;
035import org.opencms.db.generic.Messages;
036import org.opencms.file.CmsDataAccessException;
037import org.opencms.file.CmsProject;
038import org.opencms.main.OpenCms;
039import org.opencms.util.CmsUUID;
040
041import java.io.IOException;
042import java.io.OutputStream;
043import java.sql.Connection;
044import java.sql.PreparedStatement;
045import java.sql.ResultSet;
046import java.sql.SQLException;
047
048/**
049 * Oracle implementation of the VFS driver methods.<p>
050 *
051 * @since 6.0.0
052 */
053public class CmsVfsDriver extends org.opencms.db.generic.CmsVfsDriver {
054
055    /**
056     * @see org.opencms.db.I_CmsVfsDriver#createContent(CmsDbContext, CmsUUID, CmsUUID, byte[])
057     */
058    @Override
059    public void createContent(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId, byte[] content)
060    throws CmsDataAccessException {
061
062        Connection conn = null;
063        PreparedStatement stmt = null;
064
065        try {
066            conn = m_sqlManager.getConnection(dbc);
067            stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ORACLE_OFFLINE_CONTENTS_WRITE");
068
069            // first insert new file without file_content, then update the file_content
070            // these two steps are necessary because of using BLOBs in the Oracle DB
071            stmt.setString(1, resourceId.toString());
072
073            stmt.executeUpdate();
074        } catch (SQLException e) {
075            throw new CmsDbSqlException(
076                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
077                e);
078        } finally {
079            m_sqlManager.closeAll(dbc, conn, stmt, null);
080        }
081
082        // now update the file content
083        internalWriteContent(dbc, projectId, resourceId, content, -1);
084    }
085
086    /**
087     * @see org.opencms.db.generic.CmsVfsDriver#createOnlineContent(CmsDbContext, CmsUUID, byte[], int, boolean, boolean)
088     */
089    @Override
090    public void createOnlineContent(
091        CmsDbContext dbc,
092        CmsUUID resourceId,
093        byte[] contents,
094        int publishTag,
095        boolean keepOnline,
096        boolean needToUpdateContent)
097    throws CmsDataAccessException {
098
099        Connection conn = null;
100        PreparedStatement stmt = null;
101
102        try {
103            conn = m_sqlManager.getConnection(dbc);
104            boolean dbcHasProjectId = (dbc.getProjectId() != null) && !dbc.getProjectId().isNullUUID();
105            if (needToUpdateContent || dbcHasProjectId) {
106                if (dbcHasProjectId || !OpenCms.getSystemInfo().isHistoryEnabled()) {
107                    // remove the online content for this resource id
108                    stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_DELETE");
109                    stmt.setString(1, resourceId.toString());
110                    stmt.executeUpdate();
111                    m_sqlManager.closeAll(dbc, null, stmt, null);
112                } else {
113                    // put the online content in the history
114                    stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_HISTORY");
115                    stmt.setString(1, resourceId.toString());
116                    stmt.executeUpdate();
117                    m_sqlManager.closeAll(dbc, null, stmt, null);
118                }
119
120                // create new empty online content entry
121                stmt = m_sqlManager.getPreparedStatement(conn, "C_ORACLE_ONLINE_CONTENTS_WRITE");
122                stmt.setString(1, resourceId.toString());
123                stmt.setInt(2, publishTag);
124                stmt.setInt(3, publishTag);
125                stmt.setInt(4, keepOnline ? 1 : 0);
126                stmt.executeUpdate();
127                m_sqlManager.closeAll(dbc, conn, stmt, null);
128
129                // now update the file content
130                internalWriteContent(dbc, CmsProject.ONLINE_PROJECT_ID, resourceId, contents, publishTag);
131            } else {
132                // update old content entry
133                stmt = m_sqlManager.getPreparedStatement(conn, "C_HISTORY_CONTENTS_UPDATE");
134                stmt.setInt(1, publishTag);
135                stmt.setString(2, resourceId.toString());
136                stmt.executeUpdate();
137                m_sqlManager.closeAll(dbc, null, stmt, null);
138
139                if (!keepOnline) {
140                    // put the online content in the history
141                    stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_HISTORY");
142                    stmt.setString(1, resourceId.toString());
143                    stmt.executeUpdate();
144                    m_sqlManager.closeAll(dbc, null, stmt, null);
145                }
146            }
147        } catch (SQLException e) {
148            throw new CmsDbSqlException(
149                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
150                e);
151        } finally {
152            m_sqlManager.closeAll(dbc, conn, stmt, null);
153        }
154    }
155
156    /**
157     * @see org.opencms.db.I_CmsVfsDriver#initSqlManager(String)
158     */
159    @Override
160    public org.opencms.db.generic.CmsSqlManager initSqlManager(String classname) {
161
162        return CmsSqlManager.getInstance(classname);
163    }
164
165    /**
166     * @see org.opencms.db.I_CmsVfsDriver#writeContent(CmsDbContext, CmsUUID, byte[])
167     */
168    @Override
169    public void writeContent(CmsDbContext dbc, CmsUUID resourceId, byte[] content) throws CmsDataAccessException {
170
171        internalWriteContent(dbc, dbc.currentProject().getUuid(), resourceId, content, -1);
172    }
173
174    /**
175     * Writes the resource content with the specified resource id.<p>
176     *
177     * @param dbc the current database context
178     * @param projectId the id of the current project
179     * @param resourceId the id of the resource used to identify the content to update
180     * @param contents the new content of the file
181     * @param publishTag the publish tag if to be written to the online content
182     *
183     * @throws CmsDataAccessException if something goes wrong
184     */
185    protected void internalWriteContent(
186        CmsDbContext dbc,
187        CmsUUID projectId,
188        CmsUUID resourceId,
189        byte[] contents,
190        int publishTag)
191    throws CmsDataAccessException {
192
193        PreparedStatement stmt = null;
194        PreparedStatement commit = null;
195        Connection conn = null;
196        ResultSet res = null;
197
198        boolean wasInTransaction = false;
199        try {
200            conn = m_sqlManager.getConnection(dbc);
201            if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
202                stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ORACLE_ONLINE_CONTENTS_UPDATECONTENT");
203            } else {
204                stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ORACLE_OFFLINE_CONTENTS_UPDATECONTENT");
205            }
206
207            wasInTransaction = !conn.getAutoCommit();
208            if (!wasInTransaction) {
209                conn.setAutoCommit(false);
210            }
211
212            // update the file content in the contents table
213            stmt.setString(1, resourceId.toString());
214            if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
215                stmt.setInt(2, publishTag);
216                stmt.setInt(3, publishTag);
217            }
218            res = stmt.executeQuery();
219            if (!res.next()) {
220                throw new CmsDbEntryNotFoundException(
221                    Messages.get().container(Messages.LOG_READING_RESOURCE_1, resourceId));
222            }
223            // write file content
224            OutputStream output = CmsUserDriver.getOutputStreamFromBlob(res, "FILE_CONTENT");
225            output.write(contents, 0, contents.length);
226            output.close();
227
228            if (!wasInTransaction) {
229                commit = m_sqlManager.getPreparedStatement(conn, "C_COMMIT");
230                commit.execute();
231                m_sqlManager.closeAll(dbc, null, commit, null);
232            }
233
234            m_sqlManager.closeAll(dbc, null, stmt, res);
235
236            // this is needed so the finally block works correctly
237            commit = null;
238            stmt = null;
239            res = null;
240
241            if (!wasInTransaction) {
242                conn.setAutoCommit(true);
243            }
244        } catch (IOException e) {
245            throw new CmsDbIoException(
246                Messages.get().container(Messages.ERR_WRITING_TO_OUTPUT_STREAM_1, resourceId),
247                e);
248        } catch (SQLException e) {
249            throw new CmsDbSqlException(
250                org.opencms.db.generic.Messages.get().container(
251                    org.opencms.db.generic.Messages.ERR_GENERIC_SQL_1,
252                    CmsDbSqlException.getErrorQuery(stmt)),
253                e);
254        } finally {
255            org.opencms.db.oracle.CmsSqlManager.closeAllInTransaction(
256                m_sqlManager,
257                dbc,
258                conn,
259                stmt,
260                res,
261                commit,
262                wasInTransaction);
263        }
264    }
265}