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.generic;
029
030import org.opencms.configuration.CmsConfigurationManager;
031import org.opencms.configuration.CmsParameterConfiguration;
032import org.opencms.db.CmsAliasFilter;
033import org.opencms.db.CmsDbContext;
034import org.opencms.db.CmsDbEntryNotFoundException;
035import org.opencms.db.CmsDbIoException;
036import org.opencms.db.CmsDbSqlException;
037import org.opencms.db.CmsDriverManager;
038import org.opencms.db.CmsPreparedStatementIntParameter;
039import org.opencms.db.CmsPreparedStatementLongParameter;
040import org.opencms.db.CmsPreparedStatementStringParameter;
041import org.opencms.db.CmsPublishList;
042import org.opencms.db.CmsPublishedResource;
043import org.opencms.db.CmsResourceState;
044import org.opencms.db.CmsVisitEntryFilter;
045import org.opencms.db.I_CmsDriver;
046import org.opencms.db.I_CmsHistoryDriver;
047import org.opencms.db.I_CmsPreparedStatementParameter;
048import org.opencms.db.I_CmsProjectDriver;
049import org.opencms.db.I_CmsVfsDriver;
050import org.opencms.db.log.CmsLogEntry;
051import org.opencms.db.log.CmsLogEntryType;
052import org.opencms.db.log.CmsLogFilter;
053import org.opencms.db.userpublishlist.CmsUserPublishListEntry;
054import org.opencms.file.CmsDataAccessException;
055import org.opencms.file.CmsFile;
056import org.opencms.file.CmsFolder;
057import org.opencms.file.CmsGroup;
058import org.opencms.file.CmsProject;
059import org.opencms.file.CmsProperty;
060import org.opencms.file.CmsPropertyDefinition;
061import org.opencms.file.CmsResource;
062import org.opencms.file.CmsResourceFilter;
063import org.opencms.file.CmsUser;
064import org.opencms.file.CmsVfsResourceAlreadyExistsException;
065import org.opencms.file.CmsVfsResourceNotFoundException;
066import org.opencms.file.history.CmsHistoryFile;
067import org.opencms.file.types.CmsResourceTypeFolder;
068import org.opencms.i18n.CmsMessageContainer;
069import org.opencms.lock.CmsLock;
070import org.opencms.lock.CmsLockType;
071import org.opencms.main.CmsEvent;
072import org.opencms.main.CmsException;
073import org.opencms.main.CmsLog;
074import org.opencms.main.I_CmsEventListener;
075import org.opencms.main.OpenCms;
076import org.opencms.publish.CmsPublishJobInfoBean;
077import org.opencms.relations.CmsRelationFilter;
078import org.opencms.report.I_CmsReport;
079import org.opencms.security.CmsOrganizationalUnit;
080import org.opencms.security.I_CmsPrincipal;
081import org.opencms.staticexport.CmsStaticExportManager;
082import org.opencms.util.CmsPair;
083import org.opencms.util.CmsStringUtil;
084import org.opencms.util.CmsUUID;
085
086import java.io.ByteArrayInputStream;
087import java.io.ByteArrayOutputStream;
088import java.io.IOException;
089import java.io.ObjectInputStream;
090import java.io.ObjectOutputStream;
091import java.sql.Connection;
092import java.sql.PreparedStatement;
093import java.sql.ResultSet;
094import java.sql.SQLException;
095import java.util.ArrayList;
096import java.util.Collection;
097import java.util.Collections;
098import java.util.HashMap;
099import java.util.HashSet;
100import java.util.Iterator;
101import java.util.List;
102import java.util.Map;
103import java.util.Set;
104
105import org.apache.commons.logging.Log;
106
107import com.google.common.collect.Sets;
108
109/**
110 * Generic (ANSI-SQL) implementation of the project driver methods.<p>
111 *
112 * @since 6.0.0
113 */
114public class CmsProjectDriver implements I_CmsDriver, I_CmsProjectDriver {
115
116    /**
117     * This private class is a temporary storage for the method {@link CmsProjectDriver#readLocks(CmsDbContext)}.<p>
118     */
119    private class CmsTempResourceLock {
120
121        /** The lock type. */
122        private int m_lockType;
123
124        /** The project id. */
125        private CmsUUID m_projectId;
126
127        /** The resource path. */
128        private String m_resourcePath;
129
130        /** The user id. */
131        private CmsUUID m_userId;
132
133        /**
134         * The constructor.<p>
135         *
136         * @param resourcePath resource path
137         * @param userId user id
138         * @param projectId project id
139         * @param lockType lock type
140         */
141        public CmsTempResourceLock(String resourcePath, CmsUUID userId, CmsUUID projectId, int lockType) {
142
143            m_resourcePath = resourcePath;
144            m_userId = userId;
145            m_projectId = projectId;
146            m_lockType = lockType;
147        }
148
149        /**
150         * Returns the lockType.<p>
151         *
152         * @return the lockType
153         */
154        public int getLockType() {
155
156            return m_lockType;
157        }
158
159        /**
160         * Returns the projectId.<p>
161         *
162         * @return the projectId
163         */
164        public CmsUUID getProjectId() {
165
166            return m_projectId;
167        }
168
169        /**
170         * Returns the resourcePath.<p>
171         *
172         * @return the resourcePath
173         */
174        public String getResourcePath() {
175
176            return m_resourcePath;
177        }
178
179        /**
180         * Returns the userId.<p>
181         *
182         * @return the userId
183         */
184        public CmsUUID getUserId() {
185
186            return m_userId;
187        }
188
189    }
190
191    /** Attribute name for reading the project of a resource. */
192    public static final String DBC_ATTR_READ_PROJECT_FOR_RESOURCE = "DBC_ATTR_READ_PROJECT_FOR_RESOURCE";
193
194    /** The log object for this class. */
195    private static final Log LOG = CmsLog.getLog(org.opencms.db.generic.CmsProjectDriver.class);
196
197    /** The driver manager. */
198    protected CmsDriverManager m_driverManager;
199
200    /** The SQL manager. */
201    protected CmsSqlManager m_sqlManager;
202
203    /**
204     * @see org.opencms.db.I_CmsProjectDriver#cleanupPublishHistory(org.opencms.db.CmsDbContext, org.opencms.db.generic.CmsPublishHistoryCleanupFilter)
205     */
206    public int cleanupPublishHistory(CmsDbContext dbc, CmsPublishHistoryCleanupFilter filter)
207    throws CmsDataAccessException {
208
209        Connection conn = null;
210        PreparedStatement stmt = null;
211        int rowsAffected = 0;
212
213        try {
214            // get a JDBC connection from the OpenCms standard pool
215            conn = m_sqlManager.getConnection(dbc);
216            switch (filter.getMode()) {
217
218                case single:
219                default:
220                    stmt = m_sqlManager.getPreparedStatement(conn, "C_CLEANUP_PUBLISH_HISTORY_SINGLE");
221                    stmt.setString(1, filter.getHistoryId().toString());
222                    rowsAffected = stmt.executeUpdate();
223                    break;
224                case allUnreferenced:
225                    String statementText = m_sqlManager.readQuery("C_CLEANUP_PUBLISH_HISTORY_ALL");
226                    if (filter.getExceptions().size() > 0) {
227                        List<String> parts = new ArrayList<>();
228                        // it's safe to construct the clause as a string here because UUIDs can only contain dashes and hex digits
229                        parts.add("'" + CmsUUID.getNullUUID() + "'");
230                        for (CmsUUID id : filter.getExceptions()) {
231                            parts.add("'" + id.toString() + "'");
232                        }
233                        String exceptionListStr = "(" + CmsStringUtil.listAsString(parts, ",") + ")";
234                        statementText += " AND CMS_PUBLISH_HISTORY.HISTORY_ID NOT IN " + exceptionListStr;
235                    }
236                    stmt = m_sqlManager.getPreparedStatementForSql(conn, statementText);
237                    rowsAffected = stmt.executeUpdate();
238                    break;
239            }
240            LOG.info(
241                "executed publish list cleanup in mode " + filter.getMode() + ", " + rowsAffected + " rows deleted");
242            return rowsAffected;
243        } catch (SQLException e) {
244            throw new CmsDbSqlException(
245                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
246                e);
247        } finally {
248            m_sqlManager.closeAll(dbc, conn, stmt, null);
249
250        }
251
252    }
253
254    /**
255     * @see org.opencms.db.I_CmsProjectDriver#createProject(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsUser, org.opencms.file.CmsGroup, org.opencms.file.CmsGroup, java.lang.String, java.lang.String, int, CmsProject.CmsProjectType)
256     */
257    public CmsProject createProject(
258        CmsDbContext dbc,
259        CmsUUID id,
260        CmsUser owner,
261        CmsGroup group,
262        CmsGroup managergroup,
263        String projectFqn,
264        String description,
265        int flags,
266        CmsProject.CmsProjectType type)
267    throws CmsDataAccessException {
268
269        CmsProject project = null;
270
271        if ((description == null) || (description.length() < 1)) {
272            description = " ";
273        }
274
275        Connection conn = null;
276        PreparedStatement stmt = null;
277
278        try {
279            // get a JDBC connection from the OpenCms standard pool
280            conn = m_sqlManager.getConnection(dbc);
281            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_CREATE_10");
282
283            stmt.setString(1, id.toString());
284            stmt.setString(2, owner.getId().toString());
285            stmt.setString(3, group.getId().toString());
286            stmt.setString(4, managergroup.getId().toString());
287            stmt.setString(5, CmsOrganizationalUnit.getSimpleName(projectFqn));
288            stmt.setString(6, description);
289            stmt.setInt(7, flags);
290            stmt.setInt(9, type.getMode());
291            stmt.setString(10, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(projectFqn));
292
293            synchronized (this) {
294                long createTime = System.currentTimeMillis();
295                stmt.setLong(8, createTime);
296                stmt.executeUpdate();
297                try {
298                    // this is an ugly hack, but for MySQL (and maybe other DBs as well)
299                    // there is a UNIQUE INDEX constraint on the project name+createTime
300                    // so theoretically if 2 projects with the same name are created very fast, this
301                    // SQL restraint would be violated if we don't wait here
302                    Thread.sleep(50);
303                } catch (InterruptedException e) {
304                    // continue
305                }
306                project = new CmsProject(
307                    id,
308                    projectFqn,
309                    description,
310                    owner.getId(),
311                    group.getId(),
312                    managergroup.getId(),
313                    flags,
314                    createTime,
315                    type);
316            }
317        } catch (SQLException e) {
318            throw new CmsDbSqlException(
319                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
320                e);
321        } finally {
322            m_sqlManager.closeAll(dbc, conn, stmt, null);
323        }
324
325        return project;
326    }
327
328    /**
329     * @see org.opencms.db.I_CmsProjectDriver#createProjectResource(org.opencms.db.CmsDbContext, CmsUUID, java.lang.String)
330     */
331    public void createProjectResource(CmsDbContext dbc, CmsUUID projectId, String resourcePath)
332    throws CmsDataAccessException {
333
334        // do not create entries for online-project
335        PreparedStatement stmt = null;
336        Connection conn = null;
337
338        boolean projectResourceExists = false;
339        try {
340            readProjectResource(dbc, projectId, resourcePath);
341            projectResourceExists = true;
342        } catch (CmsVfsResourceNotFoundException e) {
343            // resource does not exist yet, everything is okay
344            projectResourceExists = false;
345        }
346
347        if (projectResourceExists) {
348            throw new CmsVfsResourceAlreadyExistsException(
349                Messages.get().container(
350                    Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1,
351                    dbc.removeSiteRoot(resourcePath)));
352        }
353
354        try {
355            conn = getSqlManager().getConnection(dbc);
356            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTRESOURCES_CREATE_2");
357
358            // write new resource to the database
359            stmt.setString(1, projectId.toString());
360            stmt.setString(2, resourcePath);
361
362            stmt.executeUpdate();
363        } catch (SQLException e) {
364            throw new CmsDbSqlException(
365                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
366                e);
367        } finally {
368            m_sqlManager.closeAll(dbc, conn, stmt, null);
369        }
370    }
371
372    /**
373     * @see org.opencms.db.I_CmsProjectDriver#createPublishJob(org.opencms.db.CmsDbContext, org.opencms.publish.CmsPublishJobInfoBean)
374     */
375    public void createPublishJob(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsDataAccessException {
376
377        Connection conn = null;
378        PreparedStatement stmt = null;
379
380        try {
381            CmsPublishJobInfoBean currentJob = readPublishJob(dbc, publishJob.getPublishHistoryId());
382            LOG.error("wanted to write: " + publishJob);
383            LOG.error("already on db: " + currentJob);
384            return;
385        } catch (CmsDbEntryNotFoundException e) {
386            // ok, this is the expected behavior
387        }
388        try {
389            conn = m_sqlManager.getConnection(dbc);
390            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_CREATE");
391
392            stmt.setString(1, publishJob.getPublishHistoryId().toString());
393            stmt.setString(2, publishJob.getProjectId().toString());
394            stmt.setString(3, publishJob.getProjectName());
395            stmt.setString(4, publishJob.getUserId().toString());
396            stmt.setString(5, publishJob.getLocale().toString());
397            stmt.setInt(6, publishJob.getFlags());
398            stmt.setInt(7, publishJob.getSize());
399            stmt.setLong(8, publishJob.getEnqueueTime());
400            stmt.setLong(9, publishJob.getStartTime());
401            stmt.setLong(10, publishJob.getFinishTime());
402
403            byte[] publishList = internalSerializePublishList(publishJob.getPublishList());
404            if (publishList.length < 2000) {
405                stmt.setBytes(11, publishList);
406            } else {
407                stmt.setBinaryStream(11, new ByteArrayInputStream(publishList), publishList.length);
408            }
409
410            stmt.executeUpdate();
411        } catch (SQLException e) {
412            throw new CmsDbSqlException(
413                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
414                e);
415        } catch (IOException e) {
416            throw new CmsDbIoException(
417                Messages.get().container(
418                    Messages.ERR_SERIALIZING_PUBLISHLIST_1,
419                    publishJob.getPublishHistoryId().toString()),
420                e);
421        } finally {
422            m_sqlManager.closeAll(dbc, conn, stmt, null);
423        }
424    }
425
426    /**
427     * @see org.opencms.db.I_CmsProjectDriver#deleteAllStaticExportPublishedResources(org.opencms.db.CmsDbContext, int)
428     */
429    public void deleteAllStaticExportPublishedResources(CmsDbContext dbc, int linkType) throws CmsDataAccessException {
430
431        Connection conn = null;
432        PreparedStatement stmt = null;
433
434        try {
435            conn = m_sqlManager.getConnection(dbc);
436            stmt = m_sqlManager.getPreparedStatement(conn, "C_STATICEXPORT_DELETE_ALL_PUBLISHED_LINKS");
437            stmt.setInt(1, linkType);
438            stmt.executeUpdate();
439        } catch (SQLException e) {
440            throw new CmsDbSqlException(
441                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
442                e);
443        } finally {
444            m_sqlManager.closeAll(dbc, conn, stmt, null);
445        }
446    }
447
448    /**
449     * @see org.opencms.db.I_CmsProjectDriver#deleteLog(org.opencms.db.CmsDbContext, org.opencms.db.log.CmsLogFilter)
450     */
451    public void deleteLog(CmsDbContext dbc, CmsLogFilter filter) throws CmsDataAccessException {
452
453        Connection conn = null;
454        PreparedStatement stmt = null;
455
456        try {
457            conn = m_sqlManager.getConnection(dbc);
458            // compose statement
459            StringBuffer queryBuf = new StringBuffer(256);
460            queryBuf.append(m_sqlManager.readQuery("C_LOG_DELETE_ENTRIES"));
461
462            CmsPair<String, List<I_CmsPreparedStatementParameter>> conditionsAndParams = prepareLogConditions(filter);
463            queryBuf.append(conditionsAndParams.getFirst());
464            if (LOG.isDebugEnabled()) {
465                LOG.debug(queryBuf.toString());
466            }
467            stmt = m_sqlManager.getPreparedStatementForSql(conn, queryBuf.toString());
468            List<I_CmsPreparedStatementParameter> params = conditionsAndParams.getSecond();
469            for (int i = 0; i < params.size(); i++) {
470                I_CmsPreparedStatementParameter param = conditionsAndParams.getSecond().get(i);
471                param.insertIntoStatement(stmt, i + 1);
472            }
473
474            // execute
475            stmt.executeUpdate();
476        } catch (SQLException e) {
477            throw new CmsDbSqlException(
478                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
479                e);
480        } finally {
481            m_sqlManager.closeAll(dbc, conn, stmt, null);
482        }
483    }
484
485    /**
486     * @see org.opencms.db.I_CmsProjectDriver#deleteProject(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject)
487     */
488    public void deleteProject(CmsDbContext dbc, CmsProject project) throws CmsDataAccessException {
489
490        // delete the resources from project_resources
491        deleteProjectResources(dbc, project);
492
493        // remove the project id form all resources within their project
494        unmarkProjectResources(dbc, project);
495
496        // finally delete the project
497        Connection conn = null;
498        PreparedStatement stmt = null;
499        try {
500            conn = m_sqlManager.getConnection(dbc);
501            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_DELETE_1");
502            // create the statement
503            stmt.setString(1, project.getUuid().toString());
504            stmt.executeUpdate();
505        } catch (SQLException e) {
506            throw new CmsDbSqlException(
507                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
508                e);
509        } finally {
510            m_sqlManager.closeAll(dbc, conn, stmt, null);
511        }
512    }
513
514    /**
515     * @see org.opencms.db.I_CmsProjectDriver#deleteProjectResource(org.opencms.db.CmsDbContext, CmsUUID, java.lang.String)
516     */
517    public void deleteProjectResource(CmsDbContext dbc, CmsUUID projectId, String resourceName)
518    throws CmsDataAccessException {
519
520        Connection conn = null;
521        PreparedStatement stmt = null;
522        try {
523            conn = m_sqlManager.getConnection(dbc);
524            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTRESOURCES_DELETE_2");
525            // delete resource from the database
526            stmt.setString(1, projectId.toString());
527            stmt.setString(2, resourceName);
528            stmt.executeUpdate();
529        } catch (SQLException e) {
530            throw new CmsDbSqlException(
531                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
532                e);
533        } finally {
534            m_sqlManager.closeAll(dbc, conn, stmt, null);
535        }
536    }
537
538    /**
539     * @see org.opencms.db.I_CmsProjectDriver#deleteProjectResources(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject)
540     */
541    public void deleteProjectResources(CmsDbContext dbc, CmsProject project) throws CmsDataAccessException {
542
543        Connection conn = null;
544        PreparedStatement stmt = null;
545
546        try {
547            conn = m_sqlManager.getConnection(dbc);
548            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTRESOURCES_DELETEALL_1");
549            stmt.setString(1, project.getUuid().toString());
550            stmt.executeUpdate();
551        } catch (SQLException e) {
552            throw new CmsDbSqlException(
553                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
554                e);
555        } finally {
556            m_sqlManager.closeAll(dbc, conn, stmt, null);
557        }
558    }
559
560    /**
561     * @see org.opencms.db.I_CmsProjectDriver#deletePublishHistory(org.opencms.db.CmsDbContext, CmsUUID, int)
562     */
563    public void deletePublishHistory(CmsDbContext dbc, CmsUUID projectId, int maxpublishTag)
564    throws CmsDataAccessException {
565
566        PreparedStatement stmt = null;
567        Connection conn = null;
568
569        try {
570            conn = m_sqlManager.getConnection(dbc);
571            stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_DELETE_PUBLISH_HISTORY");
572            stmt.setInt(1, maxpublishTag);
573            stmt.executeUpdate();
574        } catch (SQLException e) {
575            throw new CmsDbSqlException(
576                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
577                e);
578        } finally {
579            m_sqlManager.closeAll(dbc, conn, stmt, null);
580        }
581    }
582
583    /**
584     * @see org.opencms.db.I_CmsProjectDriver#deletePublishHistoryEntry(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, org.opencms.db.CmsPublishedResource)
585     */
586    public void deletePublishHistoryEntry(
587        CmsDbContext dbc,
588        CmsUUID publishHistoryId,
589        CmsPublishedResource publishedResource)
590    throws CmsDataAccessException {
591
592        Connection conn = null;
593        PreparedStatement stmt = null;
594
595        try {
596            conn = m_sqlManager.getConnection(dbc);
597            stmt = m_sqlManager.getPreparedStatement(conn, "C_RESOURCES_DELETE_PUBLISH_HISTORY_ENTRY");
598            stmt.setString(1, publishHistoryId.toString());
599            stmt.setInt(2, publishedResource.getPublishTag());
600            stmt.setString(3, publishedResource.getStructureId().toString());
601            stmt.setString(4, publishedResource.getRootPath());
602            stmt.executeUpdate();
603        } catch (SQLException e) {
604            throw new CmsDbSqlException(
605                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
606                e);
607        } finally {
608            m_sqlManager.closeAll(dbc, conn, stmt, null);
609        }
610    }
611
612    /**
613     * @see org.opencms.db.I_CmsProjectDriver#deletePublishJob(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
614     */
615    public void deletePublishJob(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsDataAccessException {
616
617        Connection conn = null;
618        PreparedStatement stmt = null;
619
620        try {
621            conn = m_sqlManager.getConnection(dbc);
622            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_DELETE");
623            stmt.setString(1, publishHistoryId.toString());
624            stmt.executeUpdate();
625        } catch (SQLException e) {
626            throw new CmsDbSqlException(
627                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
628                e);
629        } finally {
630            m_sqlManager.closeAll(dbc, conn, stmt, null);
631        }
632    }
633
634    /**
635     * @see org.opencms.db.I_CmsProjectDriver#deletePublishList(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
636     */
637    public void deletePublishList(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsDataAccessException {
638
639        Connection conn = null;
640        PreparedStatement stmt = null;
641
642        try {
643            conn = m_sqlManager.getConnection(dbc);
644            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_DELETE_PUBLISHLIST");
645            stmt.setString(1, publishHistoryId.toString());
646            stmt.executeUpdate();
647        } catch (SQLException e) {
648            throw new CmsDbSqlException(
649                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
650                e);
651        } finally {
652            m_sqlManager.closeAll(dbc, conn, stmt, null);
653        }
654    }
655
656    /**
657     * @see org.opencms.db.I_CmsProjectDriver#deleteStaticExportPublishedResource(org.opencms.db.CmsDbContext, java.lang.String, int, java.lang.String)
658     */
659    public void deleteStaticExportPublishedResource(
660        CmsDbContext dbc,
661        String resourceName,
662        int linkType,
663        String linkParameter)
664    throws CmsDataAccessException {
665
666        Connection conn = null;
667        PreparedStatement stmt = null;
668
669        try {
670            conn = m_sqlManager.getConnection(dbc);
671            stmt = m_sqlManager.getPreparedStatement(conn, "C_STATICEXPORT_DELETE_PUBLISHED_LINKS");
672            stmt.setString(1, resourceName);
673            stmt.setInt(2, linkType);
674            stmt.setString(3, linkParameter);
675            stmt.executeUpdate();
676        } catch (SQLException e) {
677            throw new CmsDbSqlException(
678                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
679                e);
680        } finally {
681            m_sqlManager.closeAll(dbc, conn, stmt, null);
682        }
683    }
684
685    /**
686     * @see org.opencms.db.I_CmsProjectDriver#deleteUserPublishListEntries(org.opencms.db.CmsDbContext, java.util.List)
687     */
688    public void deleteUserPublishListEntries(CmsDbContext dbc, List<CmsUserPublishListEntry> publishListDeletions)
689    throws CmsDbSqlException {
690
691        if (publishListDeletions.isEmpty()) {
692            return;
693        }
694        Connection conn = null;
695        PreparedStatement stmt = null;
696
697        try {
698            conn = m_sqlManager.getConnection(dbc);
699            String sql = m_sqlManager.readQuery("C_USER_PUBLISH_LIST_DELETE_3");
700            stmt = m_sqlManager.getPreparedStatementForSql(conn, sql);
701            for (CmsUserPublishListEntry entry : publishListDeletions) {
702                stmt.setString(1, entry.getStructureId().toString());
703                stmt.setString(2, entry.getUserId() != null ? entry.getUserId().toString() : null);
704                stmt.setInt(3, entry.getUserId() == null ? 1 : 0);
705                stmt.addBatch();
706            }
707            stmt.executeBatch();
708        } catch (SQLException e) {
709            throw new CmsDbSqlException(
710                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
711                e);
712        } finally {
713            m_sqlManager.closeAll(dbc, conn, stmt, null);
714        }
715
716    }
717
718    /**
719     * @see org.opencms.db.I_CmsProjectDriver#destroy()
720     */
721    public void destroy() throws Throwable {
722
723        m_sqlManager = null;
724        m_driverManager = null;
725
726        if (CmsLog.INIT.isInfoEnabled()) {
727            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_DRIVER_1, getClass().getName()));
728        }
729    }
730
731    /**
732     * @see org.opencms.db.I_CmsProjectDriver#fillDefaults(org.opencms.db.CmsDbContext)
733     */
734    public void fillDefaults(CmsDbContext dbc) throws CmsDataAccessException {
735
736        try {
737            if (readProject(dbc, CmsProject.ONLINE_PROJECT_ID) != null) {
738                // online-project exists - no need of filling defaults
739                return;
740            }
741        } catch (CmsDataAccessException exc) {
742            // ignore the exception - the project was not readable so fill in the defaults
743        }
744
745        if (CmsLog.INIT.isInfoEnabled()) {
746            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_FILL_DEFAULTS_0));
747        }
748
749        String adminUser = OpenCms.getDefaultUsers().getUserAdmin();
750        CmsUser admin = m_driverManager.readUser(dbc, adminUser);
751
752        String administratorsGroup = OpenCms.getDefaultUsers().getGroupAdministrators();
753        CmsGroup administrators = m_driverManager.readGroup(dbc, administratorsGroup);
754
755        String usersGroup = OpenCms.getDefaultUsers().getGroupUsers();
756        CmsGroup users = m_driverManager.readGroup(dbc, usersGroup);
757
758        ////////////////////////////////////////////////////////////////////////////////////////////
759        // online project stuff
760        ////////////////////////////////////////////////////////////////////////////////////////////
761
762        // create the online project
763        CmsProject onlineProject = createProject(
764            dbc,
765            CmsProject.ONLINE_PROJECT_ID,
766            admin,
767            users,
768            administrators,
769            CmsProject.ONLINE_PROJECT_NAME,
770            "The Online project",
771            I_CmsPrincipal.FLAG_ENABLED,
772            CmsProject.PROJECT_TYPE_NORMAL);
773
774        // create the root-folder for the online project
775        CmsFolder rootFolder = new CmsFolder(
776            new CmsUUID(),
777            new CmsUUID(),
778            "/",
779            CmsResourceTypeFolder.RESOURCE_TYPE_ID,
780            0,
781            onlineProject.getUuid(),
782            CmsResource.STATE_CHANGED,
783            0,
784            admin.getId(),
785            0,
786            admin.getId(),
787            CmsResource.DATE_RELEASED_DEFAULT,
788            CmsResource.DATE_EXPIRED_DEFAULT,
789            0);
790
791        m_driverManager.getVfsDriver(dbc).createResource(dbc, onlineProject.getUuid(), rootFolder, null);
792
793        // important: must access through driver manager to ensure proper cascading
794        m_driverManager.getProjectDriver(dbc).createProjectResource(
795            dbc,
796            onlineProject.getUuid(),
797            rootFolder.getRootPath());
798
799        // create the system-folder for the online project
800        CmsFolder systemFolder = new CmsFolder(
801            new CmsUUID(),
802            new CmsUUID(),
803            "/system",
804            CmsResourceTypeFolder.RESOURCE_TYPE_ID,
805            0,
806            onlineProject.getUuid(),
807            CmsResource.STATE_CHANGED,
808            0,
809            admin.getId(),
810            0,
811            admin.getId(),
812            CmsResource.DATE_RELEASED_DEFAULT,
813            CmsResource.DATE_EXPIRED_DEFAULT,
814            0);
815
816        m_driverManager.getVfsDriver(dbc).createResource(dbc, onlineProject.getUuid(), systemFolder, null);
817
818        ////////////////////////////////////////////////////////////////////////////////////////////
819        // setup project stuff
820        ////////////////////////////////////////////////////////////////////////////////////////////
821
822        // important: must access through driver manager to ensure proper cascading
823        CmsProject setupProject = m_driverManager.getProjectDriver(dbc).createProject(
824            dbc,
825            CmsUUID.getConstantUUID(SETUP_PROJECT_NAME),
826            admin,
827            administrators,
828            administrators,
829            SETUP_PROJECT_NAME,
830            "The Project for the initial import",
831            I_CmsPrincipal.FLAG_ENABLED,
832            CmsProject.PROJECT_TYPE_TEMPORARY);
833
834        rootFolder.setState(CmsResource.STATE_CHANGED);
835        // create the root-folder for the offline project
836        CmsResource offlineRootFolder = m_driverManager.getVfsDriver(
837            dbc).createResource(dbc, setupProject.getUuid(), rootFolder, null);
838
839        offlineRootFolder.setState(CmsResource.STATE_UNCHANGED);
840
841        m_driverManager.getVfsDriver(
842            dbc).writeResource(dbc, setupProject.getUuid(), offlineRootFolder, CmsDriverManager.NOTHING_CHANGED);
843
844        // important: must access through driver manager to ensure proper cascading
845        m_driverManager.getProjectDriver(dbc).createProjectResource(
846            dbc,
847            setupProject.getUuid(),
848            offlineRootFolder.getRootPath());
849
850        systemFolder.setState(CmsResource.STATE_CHANGED);
851        // create the system-folder for the offline project
852        CmsResource offlineSystemFolder = m_driverManager.getVfsDriver(
853            dbc).createResource(dbc, setupProject.getUuid(), systemFolder, null);
854
855        offlineSystemFolder.setState(CmsResource.STATE_UNCHANGED);
856
857        m_driverManager.getVfsDriver(
858            dbc).writeResource(dbc, setupProject.getUuid(), offlineSystemFolder, CmsDriverManager.NOTHING_CHANGED);
859    }
860
861    /**
862     * @see org.opencms.db.I_CmsProjectDriver#getSqlManager()
863     */
864    public CmsSqlManager getSqlManager() {
865
866        return m_sqlManager;
867    }
868
869    /**
870     * @see org.opencms.db.I_CmsProjectDriver#getUsersPubList(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
871     */
872    public List<CmsResource> getUsersPubList(CmsDbContext dbc, CmsUUID userId) throws CmsDataAccessException {
873
874        List<CmsResource> result = new ArrayList<CmsResource>();
875        Connection conn = null;
876        PreparedStatement stmt = null;
877        ResultSet res = null;
878        try {
879            conn = m_sqlManager.getConnection(dbc);
880            String sql = m_sqlManager.readQuery("C_USER_PUBLISH_LIST_READ_1");
881            sql = sql.replace("${PROJECT}", "OFFLINE");
882            stmt = m_sqlManager.getPreparedStatementForSql(conn, sql);
883            stmt.setString(1, userId.toString());
884            res = stmt.executeQuery();
885            while (res.next()) {
886                CmsResource resource = m_driverManager.getVfsDriver(dbc).createResource(
887                    res,
888                    dbc.currentProject().getUuid());
889                long date = res.getLong("DATE_CHANGED");
890                resource.setDateLastModified(date);
891                result.add(resource);
892            }
893            return result;
894        } catch (SQLException e) {
895            throw new CmsDbSqlException(
896                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
897                e);
898        } finally {
899            m_sqlManager.closeAll(dbc, conn, stmt, res);
900        }
901    }
902
903    /**
904     * @see org.opencms.db.I_CmsDriver#init(CmsDbContext, CmsConfigurationManager, List, CmsDriverManager)
905     */
906    public void init(
907        CmsDbContext dbc,
908        CmsConfigurationManager configurationManager,
909        List<String> successiveDrivers,
910        CmsDriverManager driverManager) {
911
912        CmsParameterConfiguration configuration = configurationManager.getConfiguration();
913        String poolUrl = configuration.get("db.project.pool");
914        String classname = configuration.get("db.project.sqlmanager");
915        m_sqlManager = initSqlManager(classname);
916        m_sqlManager.init(I_CmsProjectDriver.DRIVER_TYPE_ID, poolUrl);
917
918        m_driverManager = driverManager;
919
920        if (CmsLog.INIT.isInfoEnabled()) {
921            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ASSIGNED_POOL_1, poolUrl));
922        }
923
924        if ((successiveDrivers != null) && !successiveDrivers.isEmpty()) {
925            if (LOG.isWarnEnabled()) {
926                LOG.warn(
927                    Messages.get().getBundle().key(
928                        Messages.LOG_SUCCESSIVE_DRIVERS_UNSUPPORTED_1,
929                        getClass().getName()));
930            }
931        }
932    }
933
934    /**
935     * @see org.opencms.db.I_CmsProjectDriver#initSqlManager(String)
936     */
937    public org.opencms.db.generic.CmsSqlManager initSqlManager(String classname) {
938
939        return CmsSqlManager.getInstance(classname);
940    }
941
942    /**
943     * @see org.opencms.db.I_CmsProjectDriver#log(org.opencms.db.CmsDbContext, java.util.List)
944     */
945    public void log(CmsDbContext dbc, List<CmsLogEntry> logEntries) throws CmsDbSqlException {
946
947        Connection conn = null;
948        PreparedStatement stmt = null;
949
950        try {
951            conn = m_sqlManager.getConnection(dbc);
952            stmt = m_sqlManager.getPreparedStatement(conn, "C_LOG_CREATE_5");
953
954            for (CmsLogEntry logEntry : logEntries) {
955                stmt.setString(1, logEntry.getUserId().toString());
956                stmt.setLong(2, logEntry.getDate());
957                stmt.setString(3, logEntry.getStructureId() == null ? null : logEntry.getStructureId().toString());
958                stmt.setInt(4, logEntry.getType().getId());
959                stmt.setString(5, CmsStringUtil.arrayAsString(logEntry.getData(), "|"));
960                try {
961                    stmt.executeUpdate();
962                } catch (SQLException e) {
963                    // ignore, most likely a duplicate entry
964                    LOG.debug(
965                        Messages.get().container(
966                            Messages.ERR_GENERIC_SQL_1,
967                            CmsDbSqlException.getErrorQuery(stmt)).key(),
968                        e);
969                }
970            }
971        } catch (SQLException e) {
972            throw new CmsDbSqlException(
973                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
974                e);
975        } finally {
976            try {
977                m_sqlManager.closeAll(dbc, conn, stmt, null);
978            } catch (Throwable t) {
979                // this could happen during shutdown
980                LOG.debug(t.getLocalizedMessage(), t);
981            }
982        }
983    }
984
985    /**
986     * @see org.opencms.db.I_CmsProjectDriver#publishDeletedFolder(org.opencms.db.CmsDbContext, org.opencms.report.I_CmsReport, int, int, org.opencms.file.CmsProject, org.opencms.file.CmsFolder, org.opencms.util.CmsUUID, int)
987     */
988    public void publishDeletedFolder(
989        CmsDbContext dbc,
990        I_CmsReport report,
991        int m,
992        int n,
993        CmsProject onlineProject,
994        CmsFolder currentFolder,
995        CmsUUID publishHistoryId,
996        int publishTag)
997    throws CmsDataAccessException {
998
999        try {
1000            report.print(
1001                org.opencms.report.Messages.get().container(
1002                    org.opencms.report.Messages.RPT_SUCCESSION_2,
1003                    String.valueOf(m),
1004                    String.valueOf(n)),
1005                I_CmsReport.FORMAT_NOTE);
1006            report.print(Messages.get().container(Messages.RPT_DELETE_FOLDER_0), I_CmsReport.FORMAT_NOTE);
1007            report.print(
1008                org.opencms.report.Messages.get().container(
1009                    org.opencms.report.Messages.RPT_ARGUMENT_1,
1010                    dbc.removeSiteRoot(currentFolder.getRootPath())));
1011            report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1012
1013            CmsResourceState folderState = fixMovedResource(
1014                dbc,
1015                onlineProject,
1016                currentFolder,
1017                publishHistoryId,
1018                publishTag);
1019
1020            // read the folder online
1021            CmsFolder onlineFolder = m_driverManager.readFolder(
1022                dbc,
1023                currentFolder.getRootPath(),
1024                CmsResourceFilter.ALL);
1025
1026            // if the folder in the online-project contains any files, these need to be removed.
1027            // this can occur if these files were moved in the offline-project
1028            List<CmsResource> movedFiles = null;
1029            I_CmsVfsDriver vfsDriver = m_driverManager.getVfsDriver(dbc);
1030            movedFiles = vfsDriver.readResourceTree(
1031                dbc,
1032                onlineProject.getUuid(),
1033                currentFolder.getRootPath(),
1034                CmsDriverManager.READ_IGNORE_TYPE,
1035                null,
1036                CmsDriverManager.READ_IGNORE_TIME,
1037                CmsDriverManager.READ_IGNORE_TIME,
1038                CmsDriverManager.READ_IGNORE_TIME,
1039                CmsDriverManager.READ_IGNORE_TIME,
1040                CmsDriverManager.READ_IGNORE_TIME,
1041                CmsDriverManager.READ_IGNORE_TIME,
1042                CmsDriverManager.READMODE_INCLUDE_TREE);
1043
1044            for (CmsResource delFile : movedFiles) {
1045                try {
1046                    CmsResource offlineResource = vfsDriver.readResource(
1047                        dbc,
1048                        dbc.currentProject().getUuid(),
1049                        delFile.getStructureId(),
1050                        true);
1051                    if (offlineResource.isFile()) {
1052                        CmsFile offlineFile = new CmsFile(offlineResource);
1053                        offlineFile.setContents(
1054                            vfsDriver.readContent(dbc, dbc.currentProject().getUuid(), offlineFile.getResourceId()));
1055                        internalWriteHistory(
1056                            dbc,
1057                            offlineFile,
1058                            CmsResource.STATE_DELETED,
1059                            null,
1060                            publishHistoryId,
1061                            publishTag);
1062                        vfsDriver.deletePropertyObjects(
1063                            dbc,
1064                            onlineProject.getUuid(),
1065                            delFile,
1066                            CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
1067                        vfsDriver.removeFile(dbc, onlineProject.getUuid(), delFile);
1068                    } else if (offlineResource.isFolder()) {
1069
1070                        internalWriteHistory(
1071                            dbc,
1072                            offlineResource,
1073                            CmsResource.STATE_DELETED,
1074                            null,
1075                            publishHistoryId,
1076                            publishTag);
1077                        vfsDriver.deletePropertyObjects(
1078                            dbc,
1079                            onlineProject.getUuid(),
1080                            delFile,
1081                            CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
1082                        vfsDriver.removeFolder(dbc, onlineProject, delFile);
1083                    }
1084                } catch (CmsDataAccessException e) {
1085                    if (LOG.isWarnEnabled()) {
1086                        LOG.warn(
1087                            Messages.get().getBundle().key(Messages.LOG_REMOVING_RESOURCE_1, delFile.getName()),
1088                            e);
1089                    }
1090                }
1091            }
1092
1093            // write history before deleting
1094            internalWriteHistory(dbc, currentFolder, folderState, null, publishHistoryId, publishTag);
1095
1096            try {
1097                // delete the properties online and offline
1098                vfsDriver.deletePropertyObjects(
1099                    dbc,
1100                    onlineProject.getUuid(),
1101                    onlineFolder,
1102                    CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
1103                vfsDriver.deletePropertyObjects(
1104                    dbc,
1105                    dbc.currentProject().getUuid(),
1106                    currentFolder,
1107                    CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
1108            } catch (CmsDataAccessException e) {
1109                if (LOG.isErrorEnabled()) {
1110                    LOG.error(
1111                        Messages.get().getBundle().key(Messages.LOG_DELETING_PROPERTIES_1, currentFolder.getRootPath()),
1112                        e);
1113                }
1114                throw e;
1115            }
1116
1117            try {
1118                // remove the folder online and offline
1119                vfsDriver.removeFolder(dbc, dbc.currentProject(), currentFolder);
1120                vfsDriver.removeFolder(dbc, onlineProject, currentFolder);
1121            } catch (CmsDataAccessException e) {
1122                if (LOG.isErrorEnabled()) {
1123                    LOG.error(
1124                        Messages.get().getBundle().key(Messages.LOG_REMOVING_RESOURCE_1, currentFolder.getRootPath()),
1125                        e);
1126                }
1127                throw e;
1128            }
1129
1130            try {
1131                // remove the ACL online and offline
1132                m_driverManager.getUserDriver(dbc).removeAccessControlEntries(
1133                    dbc,
1134                    onlineProject,
1135                    onlineFolder.getResourceId());
1136                m_driverManager.getUserDriver(dbc).removeAccessControlEntries(
1137                    dbc,
1138                    dbc.currentProject(),
1139                    currentFolder.getResourceId());
1140            } catch (CmsDataAccessException e) {
1141                if (LOG.isErrorEnabled()) {
1142                    LOG.error(
1143                        Messages.get().getBundle().key(Messages.LOG_REMOVING_ACL_1, currentFolder.getRootPath()),
1144                        e);
1145                }
1146                throw e;
1147            }
1148
1149            // remove relations
1150            try {
1151                vfsDriver.deleteRelations(dbc, onlineProject.getUuid(), onlineFolder, CmsRelationFilter.TARGETS);
1152                vfsDriver.deleteRelations(
1153                    dbc,
1154                    dbc.currentProject().getUuid(),
1155                    currentFolder,
1156                    CmsRelationFilter.TARGETS);
1157            } catch (CmsDataAccessException e) {
1158                if (LOG.isErrorEnabled()) {
1159                    LOG.error(
1160                        Messages.get().getBundle().key(Messages.LOG_REMOVING_RELATIONS_1, currentFolder.getRootPath()),
1161                        e);
1162                }
1163                throw e;
1164            }
1165
1166            // remove project resources
1167            String deletedResourceRootPath = currentFolder.getRootPath();
1168            Iterator<CmsProject> itProjects = readProjectsForResource(dbc, deletedResourceRootPath).iterator();
1169            while (itProjects.hasNext()) {
1170                CmsProject project = itProjects.next();
1171                deleteProjectResource(dbc, project.getUuid(), deletedResourceRootPath);
1172            }
1173
1174            try {
1175                m_driverManager.getVfsDriver(dbc).deleteAliases(
1176                    dbc,
1177                    onlineProject,
1178                    new CmsAliasFilter(null, null, currentFolder.getStructureId()));
1179            } catch (CmsDataAccessException e) {
1180                LOG.error("Could not delete aliases: " + e.getLocalizedMessage(), e);
1181            }
1182
1183            report.println(
1184                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
1185                I_CmsReport.FORMAT_OK);
1186
1187            if (LOG.isDebugEnabled()) {
1188                if (LOG.isDebugEnabled()) {
1189                    LOG.debug(
1190                        Messages.get().getBundle().key(
1191                            Messages.LOG_DEL_FOLDER_3,
1192                            currentFolder.getRootPath(),
1193                            String.valueOf(m),
1194                            String.valueOf(n)));
1195                }
1196            }
1197        } finally {
1198            // notify the app. that the published folder and it's properties have been modified offline
1199            OpenCms.fireCmsEvent(
1200                new CmsEvent(
1201                    I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED,
1202                    Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFolder)));
1203        }
1204    }
1205
1206    /**
1207     * @see org.opencms.db.I_CmsProjectDriver#publishFile(org.opencms.db.CmsDbContext, org.opencms.report.I_CmsReport, int, int, org.opencms.file.CmsProject, org.opencms.file.CmsResource, java.util.Set, org.opencms.util.CmsUUID, int)
1208     */
1209    public void publishFile(
1210        CmsDbContext dbc,
1211        I_CmsReport report,
1212        int m,
1213        int n,
1214        CmsProject onlineProject,
1215        CmsResource offlineResource,
1216        Set<CmsUUID> publishedContentIds,
1217        CmsUUID publishHistoryId,
1218        int publishTag)
1219    throws CmsDataAccessException {
1220
1221        /*
1222         * Never use onlineResource.getState() here!
1223         * Only use offlineResource.getState() to determine the state of an offline resource!
1224         *
1225         * In case a resource has siblings, after a sibling was published the structure
1226         * and resource states are reset to UNCHANGED -> the state of the corresponding
1227         * onlineResource is still NEW, DELETED or CHANGED.
1228         * Thus, using onlineResource.getState() will inevitably result in unpublished resources!
1229         */
1230
1231        try {
1232            report.print(
1233                org.opencms.report.Messages.get().container(
1234                    org.opencms.report.Messages.RPT_SUCCESSION_2,
1235                    String.valueOf(m),
1236                    String.valueOf(n)),
1237                I_CmsReport.FORMAT_NOTE);
1238
1239            if (offlineResource.getState().isDeleted()) {
1240                report.print(Messages.get().container(Messages.RPT_DELETE_FILE_0), I_CmsReport.FORMAT_NOTE);
1241                report.print(
1242                    org.opencms.report.Messages.get().container(
1243                        org.opencms.report.Messages.RPT_ARGUMENT_1,
1244                        dbc.removeSiteRoot(offlineResource.getRootPath())));
1245                report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1246
1247                publishDeletedFile(dbc, onlineProject, offlineResource, publishHistoryId, publishTag);
1248
1249                dbc.pop();
1250                List<CmsProperty> props = m_driverManager.readPropertyObjects(dbc, offlineResource, true);
1251                boolean removeDeleted = Boolean.parseBoolean(
1252                    CmsProperty.get(CmsPropertyDefinition.PROPERTY_HISTORY_REMOVE_DELETED, props).getValue("false"));
1253                // delete old historical entries
1254                m_driverManager.getHistoryDriver(dbc).deleteEntries(
1255                    dbc,
1256                    new CmsHistoryFile(offlineResource),
1257                    removeDeleted ? 0 : OpenCms.getSystemInfo().getHistoryVersionsAfterDeletion(),
1258                    -1);
1259
1260                report.println(
1261                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
1262                    I_CmsReport.FORMAT_OK);
1263
1264                if (LOG.isDebugEnabled()) {
1265                    LOG.debug(
1266                        Messages.get().getBundle().key(
1267                            Messages.LOG_DEL_FILE_3,
1268                            String.valueOf(m),
1269                            String.valueOf(n),
1270                            offlineResource.getRootPath()));
1271                }
1272
1273            } else if (offlineResource.getState().isChanged()) {
1274                report.print(Messages.get().container(Messages.RPT_PUBLISH_FILE_0), I_CmsReport.FORMAT_NOTE);
1275                report.print(
1276                    org.opencms.report.Messages.get().container(
1277                        org.opencms.report.Messages.RPT_ARGUMENT_1,
1278                        dbc.removeSiteRoot(offlineResource.getRootPath())));
1279                report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1280
1281                publishChangedFile(
1282                    dbc,
1283                    onlineProject,
1284                    offlineResource,
1285                    publishedContentIds,
1286                    publishHistoryId,
1287                    publishTag);
1288
1289                dbc.pop();
1290                // delete old historical entries
1291                m_driverManager.getHistoryDriver(dbc).deleteEntries(
1292                    dbc,
1293                    new CmsHistoryFile(offlineResource),
1294                    OpenCms.getSystemInfo().getHistoryVersions(),
1295                    -1);
1296
1297                report.println(
1298                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
1299                    I_CmsReport.FORMAT_OK);
1300
1301                if (LOG.isDebugEnabled()) {
1302                    LOG.debug(
1303                        Messages.get().getBundle().key(
1304                            Messages.LOG_PUBLISHING_FILE_3,
1305                            offlineResource.getRootPath(),
1306                            String.valueOf(m),
1307                            String.valueOf(n)));
1308                }
1309            } else if (offlineResource.getState().isNew()) {
1310                report.print(Messages.get().container(Messages.RPT_PUBLISH_FILE_0), I_CmsReport.FORMAT_NOTE);
1311                report.print(
1312                    org.opencms.report.Messages.get().container(
1313                        org.opencms.report.Messages.RPT_ARGUMENT_1,
1314                        dbc.removeSiteRoot(offlineResource.getRootPath())));
1315                report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1316
1317                publishNewFile(dbc, onlineProject, offlineResource, publishedContentIds, publishHistoryId, publishTag);
1318
1319                dbc.pop();
1320                // delete old historical entries
1321                m_driverManager.getHistoryDriver(dbc).deleteEntries(
1322                    dbc,
1323                    new CmsHistoryFile(offlineResource),
1324                    OpenCms.getSystemInfo().getHistoryVersions(),
1325                    -1);
1326
1327                report.println(
1328                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
1329                    I_CmsReport.FORMAT_OK);
1330
1331                if (LOG.isDebugEnabled()) {
1332                    if (LOG.isDebugEnabled()) {
1333                        LOG.debug(
1334                            Messages.get().getBundle().key(
1335                                Messages.LOG_PUBLISHING_FILE_3,
1336                                offlineResource.getRootPath(),
1337                                String.valueOf(m),
1338                                String.valueOf(n)));
1339                    }
1340                }
1341            } else {
1342                // state == unchanged !!?? something went really wrong
1343                report.print(Messages.get().container(Messages.RPT_PUBLISH_FILE_0), I_CmsReport.FORMAT_NOTE);
1344                report.print(
1345                    org.opencms.report.Messages.get().container(
1346                        org.opencms.report.Messages.RPT_ARGUMENT_1,
1347                        dbc.removeSiteRoot(offlineResource.getRootPath())));
1348                report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1349                report.println(
1350                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0),
1351                    I_CmsReport.FORMAT_ERROR);
1352
1353                if (LOG.isErrorEnabled()) {
1354                    // the whole resource is printed out here
1355                    LOG.error(
1356                        Messages.get().getBundle().key(
1357                            Messages.LOG_PUBLISHING_FILE_3,
1358                            String.valueOf(m),
1359                            String.valueOf(n),
1360                            offlineResource));
1361                }
1362            }
1363            m_driverManager.publishUrlNameMapping(dbc, offlineResource);
1364            if (offlineResource.getState().isDeleted()) {
1365                m_driverManager.getVfsDriver(dbc).deleteAliases(
1366                    dbc,
1367                    onlineProject,
1368                    new CmsAliasFilter(null, null, offlineResource.getStructureId()));
1369            }
1370        } catch (CmsException e) {
1371            throw new CmsDataAccessException(e.getMessageContainer(), e);
1372        } finally {
1373            // notify the app. that the published file and it's properties have been modified offline
1374            Map<String, Object> data = new HashMap<String, Object>(2);
1375            data.put(I_CmsEventListener.KEY_RESOURCE, offlineResource);
1376            data.put(I_CmsEventListener.KEY_SKIPINDEX, new Boolean(true));
1377
1378            OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, data));
1379        }
1380    }
1381
1382    /**
1383     * @see org.opencms.db.I_CmsProjectDriver#publishFileContent(CmsDbContext, CmsProject, CmsProject, CmsResource, Set, boolean, int)
1384     */
1385    public CmsFile publishFileContent(
1386        CmsDbContext dbc,
1387        CmsProject offlineProject,
1388        CmsProject onlineProject,
1389        CmsResource offlineResource,
1390        Set<CmsUUID> publishedResourceIds,
1391        boolean needToUpdateContent,
1392        int publishTag)
1393    throws CmsDataAccessException {
1394
1395        CmsFile newFile = null;
1396        try {
1397            // read the file content offline
1398            CmsUUID projectId = dbc.getProjectId();
1399            boolean dbcHasProjectId = (projectId != null) && !projectId.isNullUUID();
1400            CmsUUID projectIdForReading = (!dbcHasProjectId ? offlineProject.getUuid() : CmsProject.ONLINE_PROJECT_ID);
1401            dbc.setProjectId(offlineProject.getUuid());
1402            byte[] offlineContent = m_driverManager.getVfsDriver(dbc).readContent(
1403                dbc,
1404                projectIdForReading,
1405                offlineResource.getResourceId());
1406            CmsFile offlineFile = new CmsFile(offlineResource);
1407            offlineFile.setContents(offlineContent);
1408            dbc.setProjectId(projectId);
1409
1410            // create the file online
1411            newFile = (CmsFile)offlineFile.clone();
1412            newFile.setState(CmsResource.STATE_UNCHANGED);
1413
1414            boolean createSibling = true;
1415            // check if we are facing with a create new sibling operation
1416            if (!offlineFile.getState().isNew()) {
1417                createSibling = false;
1418            } else {
1419                // check if the resource entry already exists
1420                if (!m_driverManager.getVfsDriver(dbc).validateResourceIdExists(
1421                    dbc,
1422                    onlineProject.getUuid(),
1423                    offlineFile.getResourceId())) {
1424                    // we are creating a normal resource and not a sibling
1425                    createSibling = false;
1426                }
1427            }
1428
1429            // only update the content if it was not updated before
1430            boolean alreadyPublished = publishedResourceIds.contains(offlineResource.getResourceId());
1431            needToUpdateContent &= !alreadyPublished;
1432
1433            if (createSibling) {
1434                if (!alreadyPublished) {
1435                    // create the file online, the first time a sibling is published also the resource entry has to be actualized
1436                    m_driverManager.getVfsDriver(dbc).createResource(dbc, onlineProject.getUuid(), newFile, null);
1437                } else {
1438                    // create the sibling online
1439                    m_driverManager.getVfsDriver(dbc).createSibling(dbc, onlineProject, offlineResource);
1440                }
1441                newFile = new CmsFile(offlineResource);
1442                newFile.setContents(offlineContent);
1443            } else {
1444                // update the online/offline structure and resource records of the file
1445                m_driverManager.getVfsDriver(dbc).publishResource(dbc, onlineProject, newFile, offlineFile);
1446            }
1447            // update version numbers
1448            m_driverManager.getVfsDriver(dbc).publishVersions(dbc, offlineResource, !alreadyPublished);
1449
1450            // create/update the content
1451            m_driverManager.getVfsDriver(dbc).createOnlineContent(
1452                dbc,
1453                offlineFile.getResourceId(),
1454                offlineFile.getContents(),
1455                publishTag,
1456                true,
1457                needToUpdateContent);
1458
1459            // mark the resource as written to avoid that the same content is written for each sibling instance
1460            publishedResourceIds.add(offlineResource.getResourceId());
1461        } catch (CmsDataAccessException e) {
1462            if (LOG.isErrorEnabled()) {
1463                LOG.error(
1464                    Messages.get().getBundle().key(Messages.LOG_PUBLISHING_FILE_CONTENT_1, offlineResource.toString()),
1465                    e);
1466            }
1467            throw e;
1468        }
1469        return newFile;
1470    }
1471
1472    /**
1473     * @see org.opencms.db.I_CmsProjectDriver#publishFolder(org.opencms.db.CmsDbContext, org.opencms.report.I_CmsReport, int, int, org.opencms.file.CmsProject, org.opencms.file.CmsFolder, org.opencms.util.CmsUUID, int)
1474     */
1475    public void publishFolder(
1476        CmsDbContext dbc,
1477        I_CmsReport report,
1478        int m,
1479        int n,
1480        CmsProject onlineProject,
1481        CmsFolder offlineFolder,
1482        CmsUUID publishHistoryId,
1483        int publishTag)
1484    throws CmsDataAccessException {
1485
1486        try {
1487            report.print(
1488                org.opencms.report.Messages.get().container(
1489                    org.opencms.report.Messages.RPT_SUCCESSION_2,
1490                    String.valueOf(m),
1491                    String.valueOf(n)),
1492                I_CmsReport.FORMAT_NOTE);
1493            report.print(Messages.get().container(Messages.RPT_PUBLISH_FOLDER_0), I_CmsReport.FORMAT_NOTE);
1494            report.print(
1495                org.opencms.report.Messages.get().container(
1496                    org.opencms.report.Messages.RPT_ARGUMENT_1,
1497                    dbc.removeSiteRoot(offlineFolder.getRootPath())));
1498            report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1499
1500            CmsResourceState resourceState = fixMovedResource(
1501                dbc,
1502                onlineProject,
1503                offlineFolder,
1504                publishHistoryId,
1505                publishTag);
1506
1507            CmsResource onlineFolder = null;
1508            if (offlineFolder.getState().isNew()) {
1509                try {
1510                    // create the folder online
1511                    CmsResource newFolder = (CmsFolder)offlineFolder.clone();
1512                    newFolder.setState(CmsResource.STATE_UNCHANGED);
1513
1514                    onlineFolder = m_driverManager.getVfsDriver(
1515                        dbc).createResource(dbc, onlineProject.getUuid(), newFolder, null);
1516                    m_driverManager.getVfsDriver(dbc).publishResource(dbc, onlineProject, onlineFolder, offlineFolder);
1517                    // update version numbers
1518                    m_driverManager.getVfsDriver(dbc).publishVersions(dbc, offlineFolder, true);
1519                } catch (CmsVfsResourceAlreadyExistsException e) {
1520                    if (!offlineFolder.getRootPath().equals("/")
1521                        && !offlineFolder.getRootPath().equals("/system/")
1522                        && LOG.isWarnEnabled()) {
1523                        LOG.warn(
1524                            Messages.get().getBundle().key(
1525                                Messages.LOG_WARN_FOLDER_WRONG_STATE_CN_1,
1526                                offlineFolder.getRootPath()));
1527                    }
1528                    try {
1529                        onlineFolder = m_driverManager.getVfsDriver(dbc).readFolder(
1530                            dbc,
1531                            onlineProject.getUuid(),
1532                            offlineFolder.getRootPath());
1533                        m_driverManager.getVfsDriver(
1534                            dbc).publishResource(dbc, onlineProject, onlineFolder, offlineFolder);
1535                        // update version numbers
1536                        m_driverManager.getVfsDriver(dbc).publishVersions(dbc, offlineFolder, true);
1537                    } catch (CmsDataAccessException e1) {
1538                        if (LOG.isErrorEnabled()) {
1539                            LOG.error(
1540                                Messages.get().getBundle().key(
1541                                    Messages.LOG_READING_RESOURCE_1,
1542                                    offlineFolder.getRootPath()),
1543                                e);
1544                        }
1545                        throw e1;
1546                    }
1547                } catch (CmsDataAccessException e) {
1548                    if (LOG.isErrorEnabled()) {
1549                        LOG.error(
1550                            Messages.get().getBundle().key(
1551                                Messages.LOG_PUBLISHING_RESOURCE_1,
1552                                offlineFolder.getRootPath()),
1553                            e);
1554                    }
1555                    throw e;
1556                }
1557            } else if (offlineFolder.getState().isChanged()) {
1558                try {
1559                    // read the folder online
1560                    onlineFolder = m_driverManager.getVfsDriver(dbc).readFolder(
1561                        dbc,
1562                        onlineProject.getUuid(),
1563                        offlineFolder.getStructureId());
1564                } catch (CmsVfsResourceNotFoundException e) {
1565                    if (LOG.isWarnEnabled()) {
1566                        LOG.warn(
1567                            Messages.get().getBundle().key(
1568                                Messages.LOG_WARN_FOLDER_WRONG_STATE_NC_1,
1569                                offlineFolder.getRootPath()));
1570                    }
1571                    try {
1572                        onlineFolder = m_driverManager.getVfsDriver(
1573                            dbc).createResource(dbc, onlineProject.getUuid(), offlineFolder, null);
1574                        internalResetResourceState(dbc, onlineFolder);
1575                    } catch (CmsDataAccessException e1) {
1576                        if (LOG.isErrorEnabled()) {
1577                            LOG.error(
1578                                Messages.get().getBundle().key(
1579                                    Messages.LOG_PUBLISHING_RESOURCE_1,
1580                                    offlineFolder.getRootPath()),
1581                                e);
1582                        }
1583                        throw e1;
1584                    }
1585                }
1586
1587                try {
1588                    // update the folder online
1589                    m_driverManager.getVfsDriver(dbc).publishResource(dbc, onlineProject, onlineFolder, offlineFolder);
1590                    // update version numbers
1591                    m_driverManager.getVfsDriver(dbc).publishVersions(dbc, offlineFolder, true);
1592                } catch (CmsDataAccessException e) {
1593                    if (LOG.isErrorEnabled()) {
1594                        LOG.error(
1595                            Messages.get().getBundle().key(
1596                                Messages.LOG_PUBLISHING_RESOURCE_1,
1597                                offlineFolder.getRootPath()),
1598                            e);
1599                    }
1600                    throw e;
1601                }
1602            }
1603
1604            if (onlineFolder != null) {
1605                try {
1606                    // write the ACL online
1607                    m_driverManager.getUserDriver(dbc).publishAccessControlEntries(
1608                        dbc,
1609                        dbc.currentProject(),
1610                        onlineProject,
1611                        offlineFolder.getResourceId(),
1612                        onlineFolder.getResourceId());
1613                } catch (CmsDataAccessException e) {
1614                    if (LOG.isErrorEnabled()) {
1615                        LOG.error(
1616                            Messages.get().getBundle().key(Messages.LOG_PUBLISHING_ACL_1, offlineFolder.getRootPath()),
1617                            e);
1618                    }
1619                    throw e;
1620                }
1621            }
1622
1623            List<CmsProperty> offlineProperties = null;
1624            try {
1625                // write the properties online
1626                m_driverManager.getVfsDriver(dbc).deletePropertyObjects(
1627                    dbc,
1628                    onlineProject.getUuid(),
1629                    onlineFolder,
1630                    CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
1631                offlineProperties = m_driverManager.getVfsDriver(dbc).readPropertyObjects(
1632                    dbc,
1633                    dbc.currentProject(),
1634                    offlineFolder);
1635                CmsProperty.setAutoCreatePropertyDefinitions(offlineProperties, true);
1636                m_driverManager.getVfsDriver(
1637                    dbc).writePropertyObjects(dbc, onlineProject, onlineFolder, offlineProperties);
1638            } catch (CmsDataAccessException e) {
1639                if (LOG.isErrorEnabled()) {
1640                    LOG.error(
1641                        Messages.get().getBundle().key(
1642                            Messages.LOG_PUBLISHING_PROPERTIES_1,
1643                            offlineFolder.getRootPath()),
1644                        e);
1645                }
1646                throw e;
1647            }
1648
1649            internalWriteHistory(dbc, offlineFolder, resourceState, offlineProperties, publishHistoryId, publishTag);
1650
1651            m_driverManager.getVfsDriver(dbc).updateRelations(dbc, onlineProject, offlineFolder);
1652
1653            report.println(
1654                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
1655                I_CmsReport.FORMAT_OK);
1656
1657            if (LOG.isDebugEnabled()) {
1658                LOG.debug(
1659                    Messages.get().getBundle().key(
1660                        Messages.LOG_PUBLISHING_FOLDER_3,
1661                        String.valueOf(m),
1662                        String.valueOf(n),
1663                        offlineFolder.getRootPath()));
1664            }
1665        } finally {
1666            // notify the app. that the published folder and it's properties have been modified offline
1667            OpenCms.fireCmsEvent(
1668                new CmsEvent(
1669                    I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED,
1670                    Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, offlineFolder)));
1671        }
1672    }
1673
1674    /**
1675     * @see org.opencms.db.I_CmsProjectDriver#publishProject(org.opencms.db.CmsDbContext, org.opencms.report.I_CmsReport, org.opencms.file.CmsProject, org.opencms.db.CmsPublishList, int)
1676     */
1677    public void publishProject(
1678        CmsDbContext dbc,
1679        I_CmsReport report,
1680        CmsProject onlineProject,
1681        CmsPublishList publishList,
1682        int publishTag)
1683    throws CmsException {
1684
1685        int publishedFolderCount = 0;
1686        int deletedFolderCount = 0;
1687        int publishedFileCount = 0;
1688        Set<CmsUUID> publishedContentIds = new HashSet<CmsUUID>();
1689        Set<CmsUUID> publishedIds = new HashSet<CmsUUID>();
1690
1691        try {
1692
1693            ////////////////////////////////////////////////////////////////////////////////////////
1694            // write the historical project entry
1695
1696            if (OpenCms.getSystemInfo().isHistoryEnabled()) {
1697                try {
1698                    // write an entry in the publish project log
1699                    m_driverManager.getHistoryDriver(dbc).writeProject(dbc, publishTag, System.currentTimeMillis());
1700                    dbc.pop();
1701                } catch (Throwable t) {
1702                    dbc.report(
1703                        report,
1704                        Messages.get().container(
1705                            Messages.ERR_WRITING_HISTORY_OF_PROJECT_1,
1706                            dbc.currentProject().getName()),
1707                        t);
1708                }
1709            }
1710
1711            ///////////////////////////////////////////////////////////////////////////////////////
1712            // publish new/changed folders
1713
1714            if (LOG.isDebugEnabled()) {
1715                LOG.debug(
1716                    Messages.get().getBundle().key(
1717                        Messages.LOG_START_PUBLISHING_PROJECT_2,
1718                        dbc.currentProject().getName(),
1719                        dbc.currentUser().getName()));
1720            }
1721
1722            publishedFolderCount = 0;
1723            int foldersSize = publishList.getFolderList().size();
1724            if (foldersSize > 0) {
1725                report.println(
1726                    Messages.get().container(Messages.RPT_PUBLISH_FOLDERS_BEGIN_0),
1727                    I_CmsReport.FORMAT_HEADLINE);
1728            }
1729
1730            Iterator<CmsResource> itFolders = publishList.getFolderList().iterator();
1731            I_CmsProjectDriver projectDriver = m_driverManager.getProjectDriver(dbc);
1732            I_CmsHistoryDriver historyDriver = m_driverManager.getHistoryDriver(dbc);
1733            while (itFolders.hasNext()) {
1734                CmsResource currentFolder = itFolders.next();
1735                try {
1736                    if (currentFolder.getState().isNew() || currentFolder.getState().isChanged()) {
1737                        // bounce the current publish task through all project drivers
1738                        projectDriver.publishFolder(
1739                            dbc,
1740                            report,
1741                            ++publishedFolderCount,
1742                            foldersSize,
1743                            onlineProject,
1744                            new CmsFolder(currentFolder),
1745                            publishList.getPublishHistoryId(),
1746                            publishTag);
1747
1748                        dbc.pop();
1749
1750                        publishedIds.add(currentFolder.getStructureId());
1751                        // log it
1752                        CmsLogEntryType type = currentFolder.getState().isNew()
1753                        ? CmsLogEntryType.RESOURCE_PUBLISHED_NEW
1754                        : CmsLogEntryType.RESOURCE_PUBLISHED_MODIFIED;
1755                        m_driverManager.log(
1756                            dbc,
1757                            new CmsLogEntry(
1758                                dbc,
1759                                currentFolder.getStructureId(),
1760                                type,
1761                                new String[] {currentFolder.getRootPath()}),
1762                            true);
1763
1764                        // delete old historical entries
1765                        historyDriver.deleteEntries(
1766                            dbc,
1767                            new CmsHistoryFile(currentFolder),
1768                            OpenCms.getSystemInfo().getHistoryVersions(),
1769                            -1);
1770
1771                        // reset the resource state to UNCHANGED and the last-modified-in-project-ID to 0
1772                        internalResetResourceState(dbc, currentFolder);
1773
1774                        m_driverManager.unlockResource(dbc, currentFolder, true, true);
1775                    } else {
1776                        // state == unchanged !!?? something went really wrong
1777                        report.print(Messages.get().container(Messages.RPT_PUBLISH_FOLDER_0), I_CmsReport.FORMAT_NOTE);
1778                        report.print(
1779                            org.opencms.report.Messages.get().container(
1780                                org.opencms.report.Messages.RPT_ARGUMENT_1,
1781                                dbc.removeSiteRoot(currentFolder.getRootPath())));
1782                        report.print(
1783                            org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1784                        report.println(
1785                            org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0),
1786                            I_CmsReport.FORMAT_ERROR);
1787
1788                        if (LOG.isErrorEnabled()) {
1789                            // the whole resource is printed out here
1790                            LOG.error(
1791                                Messages.get().getBundle().key(
1792                                    Messages.LOG_PUBLISHING_FILE_3,
1793                                    String.valueOf(++publishedFolderCount),
1794                                    String.valueOf(foldersSize),
1795                                    currentFolder));
1796                        }
1797                    }
1798
1799                    dbc.pop();
1800                } catch (Throwable t) {
1801                    dbc.report(
1802                        report,
1803                        Messages.get().container(Messages.ERR_ERROR_PUBLISHING_FOLDER_1, currentFolder.getRootPath()),
1804                        t);
1805                }
1806            }
1807
1808            if (foldersSize > 0) {
1809                report.println(
1810                    Messages.get().container(Messages.RPT_PUBLISH_FOLDERS_END_0),
1811                    I_CmsReport.FORMAT_HEADLINE);
1812            }
1813
1814            ///////////////////////////////////////////////////////////////////////////////////////
1815            // publish changed/new/deleted files
1816
1817            publishedFileCount = 0;
1818            int filesSize = publishList.getFileList().size();
1819
1820            if (filesSize > 0) {
1821                report.println(
1822                    Messages.get().container(Messages.RPT_PUBLISH_FILES_BEGIN_0),
1823                    I_CmsReport.FORMAT_HEADLINE);
1824            }
1825
1826            Set<CmsUUID> deletedResourceIds = new HashSet<CmsUUID>();
1827            Set<CmsUUID> changedResourceIds = new HashSet<CmsUUID>();
1828            for (CmsResource res : publishList.getFileList()) {
1829                if (res.getState().isDeleted()) {
1830                    deletedResourceIds.add(res.getResourceId());
1831                } else {
1832                    changedResourceIds.add(res.getResourceId());
1833                }
1834            }
1835            Set<CmsUUID> changedAndDeletedResourceIds = Sets.intersection(deletedResourceIds, changedResourceIds);
1836            dbc.setAttribute(CmsDriverManager.KEY_CHANGED_AND_DELETED, changedAndDeletedResourceIds);
1837
1838            Iterator<CmsResource> itFiles = publishList.getFileList().iterator();
1839            while (itFiles.hasNext()) {
1840                CmsResource currentResource = itFiles.next();
1841                try {
1842                    // bounce the current publish task through all project drivers
1843                    projectDriver.publishFile(
1844                        dbc,
1845                        report,
1846                        ++publishedFileCount,
1847                        filesSize,
1848                        onlineProject,
1849                        currentResource,
1850                        publishedContentIds,
1851                        publishList.getPublishHistoryId(),
1852                        publishTag);
1853
1854                    CmsResourceState state = currentResource.getState();
1855                    if (!state.isDeleted()) {
1856                        // reset the resource state to UNCHANGED and the last-modified-in-project-ID to 0
1857                        internalResetResourceState(dbc, currentResource);
1858                    }
1859
1860                    // unlock it
1861                    m_driverManager.unlockResource(dbc, currentResource, true, true);
1862                    // log it
1863                    CmsLogEntryType type = state.isNew()
1864                    ? CmsLogEntryType.RESOURCE_PUBLISHED_NEW
1865                    : (state.isDeleted()
1866                    ? CmsLogEntryType.RESOURCE_PUBLISHED_DELETED
1867                    : CmsLogEntryType.RESOURCE_PUBLISHED_MODIFIED);
1868                    m_driverManager.log(
1869                        dbc,
1870                        new CmsLogEntry(
1871                            dbc,
1872                            currentResource.getStructureId(),
1873                            type,
1874                            new String[] {currentResource.getRootPath()}),
1875                        true);
1876
1877                    publishedIds.add(currentResource.getStructureId());
1878                    dbc.pop();
1879                } catch (Throwable t) {
1880                    dbc.report(
1881                        report,
1882                        Messages.get().container(Messages.ERR_ERROR_PUBLISHING_FILE_1, currentResource.getRootPath()),
1883                        t);
1884                }
1885            }
1886
1887            if (filesSize > 0) {
1888                report.println(Messages.get().container(Messages.RPT_PUBLISH_FILES_END_0), I_CmsReport.FORMAT_HEADLINE);
1889            }
1890
1891            ////////////////////////////////////////////////////////////////////////////////////////
1892
1893            // publish deleted folders
1894            List<CmsResource> deletedFolders = publishList.getDeletedFolderList();
1895            if (deletedFolders.isEmpty()) {
1896                return;
1897            }
1898
1899            deletedFolderCount = 0;
1900            int deletedFoldersSize = deletedFolders.size();
1901            if (deletedFoldersSize > 0) {
1902                report.println(
1903                    Messages.get().container(Messages.RPT_DELETE_FOLDERS_BEGIN_0),
1904                    I_CmsReport.FORMAT_HEADLINE);
1905            }
1906
1907            Iterator<CmsResource> itDeletedFolders = deletedFolders.iterator();
1908            while (itDeletedFolders.hasNext()) {
1909                CmsResource currentFolder = itDeletedFolders.next();
1910
1911                try {
1912                    // bounce the current publish task through all project drivers
1913                    projectDriver.publishDeletedFolder(
1914                        dbc,
1915                        report,
1916                        ++deletedFolderCount,
1917                        deletedFoldersSize,
1918                        onlineProject,
1919                        new CmsFolder(currentFolder),
1920                        publishList.getPublishHistoryId(),
1921                        publishTag);
1922
1923                    dbc.pop();
1924                    // delete old historical entries
1925                    m_driverManager.getHistoryDriver(dbc).deleteEntries(
1926                        dbc,
1927                        new CmsHistoryFile(currentFolder),
1928                        OpenCms.getSystemInfo().getHistoryVersionsAfterDeletion(),
1929                        -1);
1930
1931                    publishedIds.add(currentFolder.getStructureId());
1932                    // unlock it
1933                    m_driverManager.unlockResource(dbc, currentFolder, true, true);
1934                    // log it
1935                    m_driverManager.log(
1936                        dbc,
1937                        new CmsLogEntry(
1938                            dbc,
1939                            currentFolder.getStructureId(),
1940                            CmsLogEntryType.RESOURCE_PUBLISHED_DELETED,
1941                            new String[] {currentFolder.getRootPath()}),
1942                        true);
1943
1944                    dbc.pop();
1945                } catch (Throwable t) {
1946                    dbc.report(
1947                        report,
1948                        Messages.get().container(
1949                            Messages.ERR_ERROR_PUBLISHING_DELETED_FOLDER_1,
1950                            currentFolder.getRootPath()),
1951                        t);
1952                }
1953            }
1954
1955            if (deletedFoldersSize > 0) {
1956                report.println(
1957                    Messages.get().container(Messages.RPT_DELETE_FOLDERS_END_0),
1958                    I_CmsReport.FORMAT_HEADLINE);
1959            }
1960        } catch (OutOfMemoryError o) {
1961            // clear all caches to reclaim memory
1962            OpenCms.fireCmsEvent(
1963                new CmsEvent(I_CmsEventListener.EVENT_CLEAR_CACHES, Collections.<String, Object> emptyMap()));
1964
1965            CmsMessageContainer message = Messages.get().container(Messages.ERR_OUT_OF_MEMORY_0);
1966            if (LOG.isErrorEnabled()) {
1967                LOG.error(message.key(), o);
1968            }
1969            throw new CmsDataAccessException(message, o);
1970        } finally {
1971            // reset vfs driver internal info after publishing
1972            m_driverManager.getVfsDriver(dbc).publishVersions(dbc, null, false);
1973            Object[] msgArgs = new Object[] {
1974                String.valueOf(publishedFileCount),
1975                String.valueOf(publishedFolderCount),
1976                String.valueOf(deletedFolderCount),
1977                report.formatRuntime()};
1978
1979            CmsMessageContainer message = Messages.get().container(Messages.RPT_PUBLISH_STAT_4, msgArgs);
1980            if (LOG.isInfoEnabled()) {
1981                LOG.info(message.key());
1982            }
1983            report.println(message);
1984        }
1985    }
1986
1987    /**
1988     * @see org.opencms.db.I_CmsProjectDriver#readLocks(org.opencms.db.CmsDbContext)
1989     */
1990    public List<CmsLock> readLocks(CmsDbContext dbc) throws CmsDataAccessException {
1991
1992        Connection conn = null;
1993        PreparedStatement stmt = null;
1994        List<CmsTempResourceLock> tmpLocks = new ArrayList<CmsTempResourceLock>(256);
1995        List<CmsLock> locks = new ArrayList<CmsLock>(256);
1996        try {
1997            conn = m_sqlManager.getConnection(dbc);
1998            stmt = m_sqlManager.getPreparedStatement(conn, "C_RESOURCE_LOCKS_READALL");
1999            ResultSet rs = stmt.executeQuery();
2000            while (rs.next()) {
2001                String resourcePath = rs.getString(m_sqlManager.readQuery("C_RESOURCE_LOCKS_RESOURCE_PATH"));
2002                CmsUUID userId = new CmsUUID(rs.getString(m_sqlManager.readQuery("C_RESOURCE_LOCKS_USER_ID")));
2003                CmsUUID projectId = new CmsUUID(rs.getString(m_sqlManager.readQuery("C_RESOURCE_LOCKS_PROJECT_ID")));
2004                int lockType = rs.getInt(m_sqlManager.readQuery("C_RESOURCE_LOCKS_LOCK_TYPE"));
2005                CmsTempResourceLock tmpLock = new CmsTempResourceLock(resourcePath, userId, projectId, lockType);
2006                tmpLocks.add(tmpLock);
2007            }
2008        } catch (SQLException e) {
2009            throw new CmsDbSqlException(
2010                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2011                e);
2012        } finally {
2013            m_sqlManager.closeAll(dbc, conn, stmt, null);
2014        }
2015
2016        for (CmsTempResourceLock tmpLock : tmpLocks) {
2017            CmsProject project;
2018            try {
2019                project = readProject(dbc, tmpLock.getProjectId());
2020            } catch (CmsDataAccessException dae) {
2021                // the project does not longer exist, ignore this lock (should usually not happen)
2022                project = null;
2023            }
2024            if (project != null) {
2025                CmsLock lock = new CmsLock(
2026                    tmpLock.getResourcePath(),
2027                    tmpLock.getUserId(),
2028                    project,
2029                    CmsLockType.valueOf(tmpLock.getLockType()));
2030                locks.add(lock);
2031            }
2032        }
2033        if (LOG.isDebugEnabled()) {
2034            LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_READ_LOCKS_1, new Integer(locks.size())));
2035        }
2036        return locks;
2037    }
2038
2039    /**
2040     * @see org.opencms.db.I_CmsProjectDriver#readLog(org.opencms.db.CmsDbContext, org.opencms.db.log.CmsLogFilter)
2041     */
2042    public List<CmsLogEntry> readLog(CmsDbContext dbc, CmsLogFilter filter) throws CmsDataAccessException {
2043
2044        List<CmsLogEntry> entries = new ArrayList<CmsLogEntry>();
2045
2046        Connection conn = null;
2047        PreparedStatement stmt = null;
2048        ResultSet res = null;
2049
2050        try {
2051            conn = m_sqlManager.getConnection(dbc);
2052            // compose statement
2053            StringBuffer queryBuf = new StringBuffer(256);
2054            queryBuf.append(m_sqlManager.readQuery("C_LOG_READ_ENTRIES"));
2055            CmsPair<String, List<I_CmsPreparedStatementParameter>> conditionsAndParameters = prepareLogConditions(
2056                filter);
2057            List<I_CmsPreparedStatementParameter> params = conditionsAndParameters.getSecond();
2058            queryBuf.append(conditionsAndParameters.getFirst());
2059
2060            if (LOG.isDebugEnabled()) {
2061                LOG.debug(queryBuf.toString());
2062            }
2063            stmt = m_sqlManager.getPreparedStatementForSql(conn, queryBuf.toString());
2064            for (int i = 0; i < params.size(); i++) {
2065                I_CmsPreparedStatementParameter param = params.get(i);
2066                param.insertIntoStatement(stmt, i + 1);
2067            }
2068
2069            // execute
2070            res = stmt.executeQuery();
2071            while (res.next()) {
2072                // get results
2073                entries.add(internalReadLogEntry(res));
2074            }
2075        } catch (SQLException e) {
2076            throw new CmsDbSqlException(
2077                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2078                e);
2079        } finally {
2080            m_sqlManager.closeAll(dbc, conn, stmt, res);
2081        }
2082        return entries;
2083    }
2084
2085    /**
2086     * @see org.opencms.db.I_CmsProjectDriver#readProject(org.opencms.db.CmsDbContext, CmsUUID)
2087     */
2088    public CmsProject readProject(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException {
2089
2090        PreparedStatement stmt = null;
2091        CmsProject project = null;
2092        ResultSet res = null;
2093        Connection conn = null;
2094
2095        try {
2096            conn = m_sqlManager.getConnection(dbc);
2097            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_1");
2098
2099            stmt.setString(1, id.toString());
2100            res = stmt.executeQuery();
2101
2102            if (res.next()) {
2103                project = internalCreateProject(res);
2104                while (res.next()) {
2105                    // do nothing only move through all rows because of mssql odbc driver
2106                }
2107            } else {
2108                throw new CmsDbEntryNotFoundException(
2109                    Messages.get().container(Messages.ERR_NO_PROJECT_WITH_ID_1, String.valueOf(id)));
2110            }
2111        } catch (SQLException e) {
2112            throw new CmsDbSqlException(
2113                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2114                e);
2115        } finally {
2116            m_sqlManager.closeAll(dbc, conn, stmt, res);
2117        }
2118
2119        return project;
2120    }
2121
2122    /**
2123     * @see org.opencms.db.I_CmsProjectDriver#readProject(org.opencms.db.CmsDbContext, java.lang.String)
2124     */
2125    public CmsProject readProject(CmsDbContext dbc, String projectFqn) throws CmsDataAccessException {
2126
2127        PreparedStatement stmt = null;
2128        CmsProject project = null;
2129        ResultSet res = null;
2130        Connection conn = null;
2131
2132        try {
2133            conn = m_sqlManager.getConnection(dbc);
2134            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_BYNAME_2");
2135
2136            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(projectFqn));
2137            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(projectFqn));
2138            res = stmt.executeQuery();
2139
2140            if (res.next()) {
2141                project = internalCreateProject(res);
2142                while (res.next()) {
2143                    // do nothing only move through all rows because of mssql odbc driver
2144                }
2145            } else {
2146                throw new CmsDbEntryNotFoundException(
2147                    Messages.get().container(Messages.ERR_NO_PROJECT_WITH_NAME_1, projectFqn));
2148            }
2149        } catch (SQLException e) {
2150            throw new CmsDbSqlException(
2151                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2152                e);
2153        } finally {
2154            m_sqlManager.closeAll(dbc, conn, stmt, res);
2155        }
2156
2157        return project;
2158    }
2159
2160    /**
2161     * @see org.opencms.db.I_CmsProjectDriver#readProjectResource(org.opencms.db.CmsDbContext, CmsUUID, java.lang.String)
2162     */
2163    public String readProjectResource(CmsDbContext dbc, CmsUUID projectId, String resourcePath)
2164    throws CmsDataAccessException {
2165
2166        PreparedStatement stmt = null;
2167        Connection conn = null;
2168        ResultSet res = null;
2169        String resName = null;
2170
2171        try {
2172            conn = getSqlManager().getConnection(dbc);
2173            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTRESOURCES_READ_2");
2174
2175            // select resource from the database
2176            stmt.setString(1, projectId.toString());
2177            stmt.setString(2, resourcePath);
2178            res = stmt.executeQuery();
2179
2180            if (res.next()) {
2181                resName = res.getString("RESOURCE_PATH");
2182                while (res.next()) {
2183                    // do nothing only move through all rows because of mssql odbc driver
2184                }
2185            } else {
2186                throw new CmsVfsResourceNotFoundException(
2187                    Messages.get().container(Messages.ERR_NO_PROJECTRESOURCE_1, resourcePath));
2188            }
2189        } catch (SQLException e) {
2190            throw new CmsDbSqlException(
2191                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2192                e);
2193        } finally {
2194            m_sqlManager.closeAll(dbc, conn, stmt, res);
2195        }
2196        return resName;
2197    }
2198
2199    /**
2200     * @see org.opencms.db.I_CmsProjectDriver#readProjectResources(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject)
2201     */
2202    public List<String> readProjectResources(CmsDbContext dbc, CmsProject project) throws CmsDataAccessException {
2203
2204        PreparedStatement stmt = null;
2205        Connection conn = null;
2206        ResultSet res = null;
2207        List<String> result = new ArrayList<String>();
2208
2209        try {
2210            conn = m_sqlManager.getConnection(dbc);
2211            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTRESOURCES_READ_BY_ID_1");
2212            stmt.setString(1, project.getUuid().toString());
2213            res = stmt.executeQuery();
2214
2215            while (res.next()) {
2216                result.add(res.getString("RESOURCE_PATH"));
2217            }
2218        } catch (SQLException e) {
2219            throw new CmsDbSqlException(
2220                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2221                e);
2222        } finally {
2223            m_sqlManager.closeAll(dbc, conn, stmt, res);
2224        }
2225
2226        return result;
2227    }
2228
2229    /**
2230     * @see org.opencms.db.I_CmsProjectDriver#readProjects(org.opencms.db.CmsDbContext, String)
2231     */
2232    public List<CmsProject> readProjects(CmsDbContext dbc, String ouFqn) throws CmsDataAccessException {
2233
2234        if ((dbc.getRequestContext() != null)
2235            && (dbc.getRequestContext().getAttribute(DBC_ATTR_READ_PROJECT_FOR_RESOURCE) != null)) {
2236            dbc.getRequestContext().removeAttribute(DBC_ATTR_READ_PROJECT_FOR_RESOURCE);
2237            // TODO: this should get its own method in the interface
2238            return readProjectsForResource(dbc, ouFqn);
2239        }
2240        List<CmsProject> projects = new ArrayList<CmsProject>();
2241        ResultSet res = null;
2242        PreparedStatement stmt = null;
2243        Connection conn = null;
2244
2245        try {
2246            // create the statement
2247            conn = m_sqlManager.getConnection(dbc);
2248            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_BYOU_1");
2249
2250            stmt.setString(1, CmsOrganizationalUnit.SEPARATOR + ouFqn + "%");
2251            res = stmt.executeQuery();
2252
2253            while (res.next()) {
2254                projects.add(internalCreateProject(res));
2255            }
2256        } catch (SQLException e) {
2257            throw new CmsDbSqlException(
2258                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2259                e);
2260        } finally {
2261            m_sqlManager.closeAll(dbc, conn, stmt, res);
2262        }
2263
2264        return (projects);
2265    }
2266
2267    /**
2268     * @see org.opencms.db.I_CmsProjectDriver#readProjectsForGroup(org.opencms.db.CmsDbContext, org.opencms.file.CmsGroup)
2269     */
2270    public List<CmsProject> readProjectsForGroup(CmsDbContext dbc, CmsGroup group) throws CmsDataAccessException {
2271
2272        List<CmsProject> projects = new ArrayList<CmsProject>();
2273        ResultSet res = null;
2274        Connection conn = null;
2275        PreparedStatement stmt = null;
2276
2277        try {
2278            // create the statement
2279            conn = m_sqlManager.getConnection(dbc);
2280            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_BYGROUP_2");
2281
2282            stmt.setString(1, group.getId().toString());
2283            stmt.setString(2, group.getId().toString());
2284            res = stmt.executeQuery();
2285
2286            while (res.next()) {
2287                projects.add(internalCreateProject(res));
2288            }
2289        } catch (SQLException e) {
2290            throw new CmsDbSqlException(
2291                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2292                e);
2293        } finally {
2294            m_sqlManager.closeAll(dbc, conn, stmt, res);
2295        }
2296        return (projects);
2297    }
2298
2299    /**
2300     * @see org.opencms.db.I_CmsProjectDriver#readProjectsForManagerGroup(org.opencms.db.CmsDbContext, org.opencms.file.CmsGroup)
2301     */
2302    public List<CmsProject> readProjectsForManagerGroup(CmsDbContext dbc, CmsGroup group)
2303    throws CmsDataAccessException {
2304
2305        List<CmsProject> projects = new ArrayList<CmsProject>();
2306        ResultSet res = null;
2307        PreparedStatement stmt = null;
2308        Connection conn = null;
2309
2310        try {
2311            // create the statement
2312            conn = m_sqlManager.getConnection(dbc);
2313            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_BYMANAGER_1");
2314
2315            stmt.setString(1, group.getId().toString());
2316            res = stmt.executeQuery();
2317
2318            while (res.next()) {
2319                projects.add(internalCreateProject(res));
2320            }
2321        } catch (SQLException e) {
2322            throw new CmsDbSqlException(
2323                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2324                e);
2325        } finally {
2326            m_sqlManager.closeAll(dbc, conn, stmt, res);
2327        }
2328        return (projects);
2329    }
2330
2331    /**
2332     * Returns the projects of a given resource.<p>
2333     *
2334     * @param dbc the database context
2335     * @param rootPath the resource root path
2336     *
2337     * @return the projects of the resource, as a list of projects
2338     *
2339     * @throws CmsDataAccessException if something goes wrong
2340     */
2341    public List<CmsProject> readProjectsForResource(CmsDbContext dbc, String rootPath) throws CmsDataAccessException {
2342
2343        PreparedStatement stmt = null;
2344        List<CmsProject> projects = new ArrayList<CmsProject>();
2345        ResultSet res = null;
2346        Connection conn = null;
2347
2348        try {
2349            conn = m_sqlManager.getConnection(dbc);
2350            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_BYRESOURCE_1");
2351
2352            stmt.setString(1, rootPath + "%");
2353            res = stmt.executeQuery();
2354
2355            if (res.next()) {
2356                projects.add(internalCreateProject(res));
2357                while (res.next()) {
2358                    // do nothing only move through all rows because of mssql odbc driver
2359                }
2360            }
2361        } catch (SQLException e) {
2362            throw new CmsDbSqlException(
2363                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2364                e);
2365        } finally {
2366            m_sqlManager.closeAll(dbc, conn, stmt, res);
2367        }
2368
2369        return projects;
2370    }
2371
2372    /**
2373     * @see org.opencms.db.I_CmsProjectDriver#readProjectsForUser(org.opencms.db.CmsDbContext, org.opencms.file.CmsUser)
2374     */
2375    public List<CmsProject> readProjectsForUser(CmsDbContext dbc, CmsUser user) throws CmsDataAccessException {
2376
2377        List<CmsProject> projects = new ArrayList<CmsProject>();
2378        ResultSet res = null;
2379        PreparedStatement stmt = null;
2380        Connection conn = null;
2381
2382        try {
2383            // create the statement
2384            conn = m_sqlManager.getConnection(dbc);
2385            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_READ_BYUSER_1");
2386
2387            stmt.setString(1, user.getId().toString());
2388            res = stmt.executeQuery();
2389
2390            while (res.next()) {
2391                projects.add(internalCreateProject(res));
2392            }
2393        } catch (SQLException e) {
2394            throw new CmsDbSqlException(
2395                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2396                e);
2397        } finally {
2398            m_sqlManager.closeAll(dbc, conn, stmt, res);
2399        }
2400        return (projects);
2401    }
2402
2403    /**
2404     * @see org.opencms.db.I_CmsProjectDriver#readPublishedResources(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
2405     */
2406    public List<CmsPublishedResource> readPublishedResources(CmsDbContext dbc, CmsUUID publishHistoryId)
2407    throws CmsDataAccessException {
2408
2409        Connection conn = null;
2410        PreparedStatement stmt = null;
2411        ResultSet res = null;
2412        List<CmsPublishedResource> publishedResources = new ArrayList<CmsPublishedResource>();
2413
2414        try {
2415            conn = m_sqlManager.getConnection(dbc);
2416            stmt = m_sqlManager.getPreparedStatement(conn, "C_SELECT_PUBLISHED_RESOURCES");
2417            stmt.setString(1, publishHistoryId.toString());
2418            res = stmt.executeQuery();
2419
2420            while (res.next()) {
2421                CmsUUID structureId = new CmsUUID(res.getString("STRUCTURE_ID"));
2422                CmsUUID resourceId = new CmsUUID(res.getString("RESOURCE_ID"));
2423                String rootPath = res.getString("RESOURCE_PATH");
2424                int resourceState = res.getInt("RESOURCE_STATE");
2425                int resourceType = res.getInt("RESOURCE_TYPE");
2426                int siblingCount = res.getInt("SIBLING_COUNT");
2427                int publishTag = res.getInt("PUBLISH_TAG");
2428
2429                // compose the resource state
2430                CmsResourceState state;
2431                if (resourceState == CmsPublishedResource.STATE_MOVED_SOURCE.getState()) {
2432                    state = CmsPublishedResource.STATE_MOVED_SOURCE;
2433                } else if (resourceState == CmsPublishedResource.STATE_MOVED_DESTINATION.getState()) {
2434                    state = CmsPublishedResource.STATE_MOVED_DESTINATION;
2435                } else {
2436                    state = CmsResourceState.valueOf(resourceState);
2437                }
2438
2439                publishedResources.add(
2440                    new CmsPublishedResource(
2441                        structureId,
2442                        resourceId,
2443                        publishTag,
2444                        rootPath,
2445                        resourceType,
2446                        structureId.isNullUUID() ? false : CmsFolder.isFolderType(resourceType),
2447                        state,
2448                        siblingCount));
2449            }
2450        } catch (SQLException e) {
2451            throw new CmsDbSqlException(
2452                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2453                e);
2454        } finally {
2455            m_sqlManager.closeAll(dbc, conn, stmt, res);
2456        }
2457
2458        return publishedResources;
2459    }
2460
2461    /**
2462     * @see org.opencms.db.I_CmsProjectDriver#readPublishJob(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
2463     */
2464    public CmsPublishJobInfoBean readPublishJob(CmsDbContext dbc, CmsUUID publishHistoryId)
2465    throws CmsDataAccessException {
2466
2467        Connection conn = null;
2468        PreparedStatement stmt = null;
2469        ResultSet res = null;
2470
2471        CmsPublishJobInfoBean result = null;
2472        try {
2473            conn = m_sqlManager.getConnection(dbc);
2474            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_READ_JOB");
2475            stmt.setString(1, publishHistoryId.toString());
2476            res = stmt.executeQuery();
2477
2478            if (res.next()) {
2479                result = createPublishJobInfoBean(res);
2480                while (res.next()) {
2481                    // do nothing only move through all rows because of mssql odbc driver
2482                }
2483            } else {
2484                throw new CmsDbEntryNotFoundException(
2485                    Messages.get().container(Messages.ERR_READ_PUBLISH_JOB_1, publishHistoryId.toString()));
2486            }
2487        } catch (SQLException e) {
2488            throw new CmsDbSqlException(
2489                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2490                e);
2491        } finally {
2492            m_sqlManager.closeAll(dbc, conn, stmt, res);
2493        }
2494
2495        return result;
2496    }
2497
2498    /**
2499     * @see org.opencms.db.I_CmsProjectDriver#readPublishJobs(org.opencms.db.CmsDbContext, long, long)
2500     */
2501    public List<CmsPublishJobInfoBean> readPublishJobs(CmsDbContext dbc, long startTime, long endTime)
2502    throws CmsDataAccessException {
2503
2504        Connection conn = null;
2505        PreparedStatement stmt = null;
2506        ResultSet res = null;
2507
2508        List<CmsPublishJobInfoBean> result = null;
2509        try {
2510            conn = m_sqlManager.getConnection(dbc);
2511            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_READ_JOBS_IN_TIMERANGE");
2512            stmt.setLong(1, startTime);
2513            stmt.setLong(2, endTime);
2514            res = stmt.executeQuery();
2515
2516            result = new ArrayList<CmsPublishJobInfoBean>();
2517            while (res.next()) {
2518                result.add(createPublishJobInfoBean(res));
2519            }
2520        } catch (SQLException e) {
2521            throw new CmsDbSqlException(
2522                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2523                e);
2524        } finally {
2525            m_sqlManager.closeAll(dbc, conn, stmt, res);
2526        }
2527
2528        return result;
2529    }
2530
2531    /**
2532     * @see org.opencms.db.I_CmsProjectDriver#readPublishList(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
2533     */
2534    public CmsPublishList readPublishList(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsDataAccessException {
2535
2536        Connection conn = null;
2537        PreparedStatement stmt = null;
2538        ResultSet res = null;
2539        CmsPublishList publishList = null;
2540
2541        try {
2542            conn = m_sqlManager.getConnection(dbc);
2543            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_READ_PUBLISHLIST");
2544            stmt.setString(1, publishHistoryId.toString());
2545            res = stmt.executeQuery();
2546
2547            if (res.next()) {
2548                byte[] bytes = m_sqlManager.getBytes(res, "PUBLISH_LIST");
2549                publishList = internalDeserializePublishList(bytes);
2550                while (res.next()) {
2551                    // do nothing only move through all rows because of mssql odbc driver
2552                }
2553            } else {
2554                throw new CmsDataAccessException(
2555                    Messages.get().container(Messages.ERR_READ_PUBLISH_JOB_1, publishHistoryId.toString()));
2556            }
2557        } catch (SQLException e) {
2558            throw new CmsDbSqlException(
2559                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2560                e);
2561        } catch (Exception e) {
2562            throw new CmsDataAccessException(
2563                Messages.get().container(Messages.ERR_PUBLISHLIST_DESERIALIZATION_FAILED_1, publishHistoryId),
2564                e);
2565        } finally {
2566            m_sqlManager.closeAll(dbc, conn, stmt, res);
2567        }
2568
2569        return publishList;
2570    }
2571
2572    /**
2573     * @see org.opencms.db.I_CmsProjectDriver#readPublishReportContents(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
2574     */
2575    public byte[] readPublishReportContents(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsDataAccessException {
2576
2577        PreparedStatement stmt = null;
2578        ResultSet res = null;
2579        Connection conn = null;
2580        byte[] bytes = null;
2581
2582        try {
2583            conn = m_sqlManager.getConnection(dbc);
2584
2585            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_READ_REPORT");
2586            stmt.setString(1, publishHistoryId.toString());
2587            res = stmt.executeQuery();
2588
2589            if (res.next()) {
2590                // query to read Array of bytes for the given attribute
2591                bytes = m_sqlManager.getBytes(res, "PUBLISH_REPORT");
2592                while (res.next()) {
2593                    // do nothing only move through all rows because of mssql odbc driver
2594                }
2595            } else {
2596                throw new CmsDataAccessException(
2597                    Messages.get().container(Messages.ERR_READ_PUBLISH_JOB_1, publishHistoryId.toString()));
2598            }
2599        } catch (SQLException e) {
2600            LOG.error(CmsDbSqlException.getErrorQuery(stmt), e);
2601            bytes = Messages.get().container(
2602                Messages.ERR_GENERIC_SQL_1,
2603                CmsDbSqlException.getErrorQuery(stmt)).key().getBytes();
2604        } finally {
2605            m_sqlManager.closeAll(dbc, conn, stmt, res);
2606        }
2607        return bytes;
2608    }
2609
2610    /**
2611     * @see org.opencms.db.I_CmsProjectDriver#readStaticExportPublishedResourceParameters(org.opencms.db.CmsDbContext, java.lang.String)
2612     */
2613    public String readStaticExportPublishedResourceParameters(CmsDbContext dbc, String rfsName)
2614    throws CmsDataAccessException {
2615
2616        String returnValue = null;
2617        Connection conn = null;
2618        PreparedStatement stmt = null;
2619        ResultSet res = null;
2620
2621        try {
2622            conn = m_sqlManager.getConnection(dbc);
2623            stmt = m_sqlManager.getPreparedStatement(conn, "C_STATICEXPORT_READ_PUBLISHED_LINK_PARAMETERS");
2624            stmt.setString(1, rfsName);
2625            res = stmt.executeQuery();
2626            // add all resourcenames to the list of return values
2627            if (res.next()) {
2628                returnValue = res.getString(1);
2629                while (res.next()) {
2630                    // do nothing only move through all rows because of mssql odbc driver
2631                }
2632            }
2633        } catch (SQLException e) {
2634            throw new CmsDbSqlException(
2635                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2636                e);
2637        } finally {
2638            m_sqlManager.closeAll(dbc, conn, stmt, res);
2639        }
2640
2641        return returnValue;
2642    }
2643
2644    /**
2645     * @see org.opencms.db.I_CmsProjectDriver#readStaticExportResources(org.opencms.db.CmsDbContext, int, long)
2646     */
2647    public List<String> readStaticExportResources(CmsDbContext dbc, int parameterResources, long timestamp)
2648    throws CmsDataAccessException {
2649
2650        Connection conn = null;
2651        PreparedStatement stmt = null;
2652        ResultSet res = null;
2653        List<String> returnValue = new ArrayList<String>();
2654
2655        if (parameterResources == CmsStaticExportManager.EXPORT_LINK_WITHOUT_PARAMETER) {
2656            timestamp = 0;
2657        }
2658        try {
2659            conn = m_sqlManager.getConnection(dbc);
2660            stmt = m_sqlManager.getPreparedStatement(conn, "C_STATICEXPORT_READ_ALL_PUBLISHED_LINKS");
2661            stmt.setInt(1, parameterResources);
2662            stmt.setLong(2, timestamp);
2663            res = stmt.executeQuery();
2664            // add all resourcenames to the list of return values
2665            while (res.next()) {
2666                returnValue.add(res.getString(1));
2667            }
2668        } catch (SQLException e) {
2669            throw new CmsDbSqlException(
2670                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2671                e);
2672        } finally {
2673            m_sqlManager.closeAll(dbc, conn, stmt, res);
2674        }
2675
2676        return returnValue;
2677    }
2678
2679    /**
2680     * @see org.opencms.db.I_CmsProjectDriver#setDriverManager(org.opencms.db.CmsDriverManager)
2681     */
2682    public void setDriverManager(CmsDriverManager driverManager) {
2683
2684        m_driverManager = driverManager;
2685    }
2686
2687    /**
2688     * @see org.opencms.db.I_CmsProjectDriver#setSqlManager(org.opencms.db.CmsSqlManager)
2689     */
2690    public void setSqlManager(org.opencms.db.CmsSqlManager manager) {
2691
2692        m_sqlManager = (CmsSqlManager)manager;
2693    }
2694
2695    /**
2696     * @see org.opencms.db.I_CmsProjectDriver#unmarkProjectResources(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject)
2697     */
2698    public void unmarkProjectResources(CmsDbContext dbc, CmsProject project) throws CmsDataAccessException {
2699
2700        // finally remove the project id form all resources
2701
2702        Connection conn = null;
2703        PreparedStatement stmt = null;
2704        try {
2705            conn = m_sqlManager.getConnection(dbc);
2706            stmt = m_sqlManager.getPreparedStatement(conn, "C_RESOURCES_UNMARK");
2707            // create the statement
2708            stmt.setString(1, project.getUuid().toString());
2709            stmt.executeUpdate();
2710        } catch (SQLException e) {
2711            throw new CmsDbSqlException(
2712                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2713                e);
2714        } finally {
2715            m_sqlManager.closeAll(dbc, conn, stmt, null);
2716        }
2717    }
2718
2719    /**
2720     * @see org.opencms.db.I_CmsProjectDriver#writeLocks(org.opencms.db.CmsDbContext, java.util.List)
2721     */
2722    public void writeLocks(CmsDbContext dbc, List<CmsLock> locks) throws CmsDataAccessException {
2723
2724        Connection conn = null;
2725        PreparedStatement stmt = null;
2726        try {
2727            conn = m_sqlManager.getConnection(dbc);
2728            stmt = m_sqlManager.getPreparedStatement(conn, "C_RESOURCE_LOCKS_DELETEALL");
2729            int deleted = stmt.executeUpdate();
2730            if (LOG.isDebugEnabled()) {
2731                LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_CLEAR_LOCKS_1, new Integer(deleted)));
2732            }
2733            stmt = m_sqlManager.getPreparedStatement(conn, "C_RESOURCE_LOCK_WRITE");
2734            if (LOG.isDebugEnabled()) {
2735                LOG.debug("SQL :" + m_sqlManager.readQuery("C_RESOURCE_LOCK_WRITE"));
2736            }
2737            Iterator<CmsLock> i = locks.iterator();
2738            int count = 0;
2739            while (i.hasNext()) {
2740                CmsLock lock = i.next();
2741                // only persist locks that should be written to the DB
2742                CmsLock sysLock = lock.getSystemLock();
2743                if (sysLock.isPersistent()) {
2744                    // persist system lock
2745                    stmt.setString(1, sysLock.getResourceName());
2746                    stmt.setString(2, sysLock.getUserId().toString());
2747                    stmt.setString(3, sysLock.getProjectId().toString());
2748                    stmt.setInt(4, sysLock.getType().hashCode());
2749                    stmt.executeUpdate();
2750                    count++;
2751                }
2752                CmsLock editLock = lock.getEditionLock();
2753                if (editLock.isPersistent()) {
2754                    // persist edition lock
2755                    stmt.setString(1, editLock.getResourceName());
2756                    stmt.setString(2, editLock.getUserId().toString());
2757                    stmt.setString(3, editLock.getProjectId().toString());
2758                    stmt.setInt(4, editLock.getType().hashCode());
2759                    stmt.executeUpdate();
2760                    count++;
2761                }
2762            }
2763            if (LOG.isDebugEnabled()) {
2764                LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_WRITE_LOCKS_1, new Integer(count)));
2765            }
2766        } catch (SQLException e) {
2767            throw new CmsDbSqlException(
2768                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2769                e);
2770        } finally {
2771            m_sqlManager.closeAll(dbc, conn, stmt, null);
2772        }
2773    }
2774
2775    /**
2776     * @see org.opencms.db.I_CmsProjectDriver#writeProject(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject)
2777     */
2778    public void writeProject(CmsDbContext dbc, CmsProject project) throws CmsDataAccessException {
2779
2780        if (CmsStringUtil.isEmptyOrWhitespaceOnly(project.getDescription())) {
2781            project.setDescription(" ");
2782        }
2783        Connection conn = null;
2784        PreparedStatement stmt = null;
2785
2786        try {
2787            // get a JDBC connection from the OpenCms standard pools
2788            conn = m_sqlManager.getConnection(dbc);
2789
2790            stmt = m_sqlManager.getPreparedStatement(conn, "C_PROJECTS_WRITE_6");
2791            stmt.setString(1, project.getDescription());
2792            stmt.setString(2, project.getGroupId().toString());
2793            stmt.setString(3, project.getManagerGroupId().toString());
2794            stmt.setInt(4, project.getFlags());
2795            stmt.setInt(5, project.getType().getMode());
2796            stmt.setString(6, project.getUuid().toString());
2797            stmt.executeUpdate();
2798        } catch (SQLException e) {
2799            throw new CmsDbSqlException(
2800                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2801                e);
2802        } finally {
2803            m_sqlManager.closeAll(dbc, conn, stmt, null);
2804        }
2805    }
2806
2807    /**
2808     * @see org.opencms.db.I_CmsProjectDriver#writePublishHistory(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, org.opencms.db.CmsPublishedResource)
2809     */
2810    public void writePublishHistory(CmsDbContext dbc, CmsUUID publishId, CmsPublishedResource resource)
2811    throws CmsDataAccessException {
2812
2813        Connection conn = null;
2814        PreparedStatement stmt = null;
2815
2816        try {
2817            conn = m_sqlManager.getConnection(dbc);
2818            stmt = m_sqlManager.getPreparedStatement(conn, "C_RESOURCES_WRITE_PUBLISH_HISTORY");
2819            stmt.setInt(1, resource.getPublishTag());
2820            stmt.setString(2, resource.getStructureId().toString());
2821            stmt.setString(3, resource.getResourceId().toString());
2822            stmt.setString(4, resource.getRootPath());
2823            stmt.setInt(5, resource.getMovedState().getState());
2824            stmt.setInt(6, resource.getType());
2825            stmt.setString(7, publishId.toString());
2826            stmt.setInt(8, resource.getSiblingCount());
2827            stmt.executeUpdate();
2828        } catch (SQLException e) {
2829            throw new CmsDbSqlException(
2830                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2831                e);
2832        } finally {
2833            m_sqlManager.closeAll(dbc, conn, stmt, null);
2834        }
2835    }
2836
2837    /**
2838     * @see org.opencms.db.I_CmsProjectDriver#writePublishJob(org.opencms.db.CmsDbContext, org.opencms.publish.CmsPublishJobInfoBean)
2839     */
2840    public void writePublishJob(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsDataAccessException {
2841
2842        Connection conn = null;
2843        PreparedStatement stmt = null;
2844
2845        try {
2846            conn = m_sqlManager.getConnection(dbc);
2847            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_WRITE");
2848            stmt.setString(1, publishJob.getProjectId().toString());
2849            stmt.setString(2, publishJob.getProjectName());
2850            stmt.setString(3, publishJob.getUserId().toString());
2851            stmt.setString(4, publishJob.getLocale().toString());
2852            stmt.setInt(5, publishJob.getFlags());
2853            stmt.setInt(6, publishJob.getSize());
2854            stmt.setLong(7, publishJob.getEnqueueTime());
2855            stmt.setLong(8, publishJob.getStartTime());
2856            stmt.setLong(9, publishJob.getFinishTime());
2857            stmt.setString(10, publishJob.getPublishHistoryId().toString());
2858            stmt.executeUpdate();
2859        } catch (SQLException e) {
2860            throw new CmsDbSqlException(
2861                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2862                e);
2863        } finally {
2864            m_sqlManager.closeAll(dbc, conn, stmt, null);
2865        }
2866    }
2867
2868    /**
2869     * @see org.opencms.db.I_CmsProjectDriver#writePublishReport(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, byte[])
2870     */
2871    public void writePublishReport(CmsDbContext dbc, CmsUUID publishId, byte[] content) throws CmsDataAccessException {
2872
2873        Connection conn = null;
2874        PreparedStatement stmt = null;
2875
2876        try {
2877            conn = m_sqlManager.getConnection(dbc);
2878            stmt = m_sqlManager.getPreparedStatement(conn, "C_PUBLISHJOB_WRITE_REPORT");
2879
2880            if (content.length < 2000) {
2881                stmt.setBytes(1, content);
2882            } else {
2883                stmt.setBinaryStream(1, new ByteArrayInputStream(content), content.length);
2884            }
2885
2886            stmt.setString(2, publishId.toString());
2887            stmt.executeUpdate();
2888        } catch (SQLException e) {
2889            throw new CmsDbSqlException(
2890                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2891                e);
2892        } finally {
2893            m_sqlManager.closeAll(dbc, conn, stmt, null);
2894        }
2895    }
2896
2897    /**
2898     * @see org.opencms.db.I_CmsProjectDriver#writeStaticExportPublishedResource(org.opencms.db.CmsDbContext, java.lang.String, int, java.lang.String, long)
2899     */
2900    public void writeStaticExportPublishedResource(
2901        CmsDbContext dbc,
2902        String resourceName,
2903        int linkType,
2904        String linkParameter,
2905        long timestamp)
2906    throws CmsDataAccessException {
2907
2908        Connection conn = null;
2909        PreparedStatement stmt = null;
2910        ResultSet res = null;
2911        int returnValue = 0;
2912        // first check if a record with this resource name does already exist
2913        try {
2914            conn = m_sqlManager.getConnection(dbc);
2915            stmt = m_sqlManager.getPreparedStatement(conn, "C_STATICEXPORT_READ_PUBLISHED_RESOURCES");
2916            stmt.setString(1, resourceName);
2917            res = stmt.executeQuery();
2918            if (res.next()) {
2919                returnValue = res.getInt(1);
2920                while (res.next()) {
2921                    // do nothing only move through all rows because of mssql odbc driver
2922                }
2923            }
2924        } catch (SQLException e) {
2925            throw new CmsDbSqlException(
2926                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2927                e);
2928        } finally {
2929            m_sqlManager.closeAll(dbc, conn, stmt, res);
2930        }
2931
2932        // there was no entry found, so add it to the database
2933        if (returnValue == 0) {
2934            try {
2935                conn = m_sqlManager.getConnection(dbc);
2936                stmt = m_sqlManager.getPreparedStatement(conn, "C_STATICEXPORT_WRITE_PUBLISHED_LINKS");
2937                stmt.setString(1, new CmsUUID().toString());
2938                stmt.setString(2, resourceName);
2939                stmt.setInt(3, linkType);
2940                stmt.setString(4, linkParameter);
2941                stmt.setLong(5, timestamp);
2942                stmt.executeUpdate();
2943            } catch (SQLException e) {
2944                throw new CmsDbSqlException(Messages.get().container(Messages.ERR_GENERIC_SQL_1, stmt), e);
2945            } finally {
2946                m_sqlManager.closeAll(dbc, conn, stmt, null);
2947            }
2948        }
2949    }
2950
2951    /**
2952     * @see org.opencms.db.I_CmsProjectDriver#writeUserPublishListEntries(org.opencms.db.CmsDbContext, java.util.List)
2953     */
2954    public void writeUserPublishListEntries(CmsDbContext dbc, List<CmsUserPublishListEntry> publishListAdditions)
2955    throws CmsDbSqlException {
2956
2957        if (publishListAdditions.isEmpty()) {
2958            return;
2959        }
2960
2961        // first remove all entries with the same keys
2962        deleteUserPublishListEntries(dbc, publishListAdditions);
2963
2964        Connection conn = null;
2965        PreparedStatement stmt = null;
2966        try {
2967            conn = m_sqlManager.getConnection(dbc);
2968            String sql = m_sqlManager.readQuery("C_USER_PUBLISH_LIST_INSERT_3");
2969            stmt = m_sqlManager.getPreparedStatementForSql(conn, sql);
2970            for (CmsUserPublishListEntry entry : publishListAdditions) {
2971                stmt.setString(1, entry.getUserId().toString());
2972                stmt.setString(2, entry.getStructureId().toString());
2973                stmt.setLong(3, entry.getDateChanged());
2974                stmt.addBatch();
2975            }
2976            stmt.executeBatch();
2977        } catch (SQLException e) {
2978            throw new CmsDbSqlException(
2979                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2980                e);
2981        } finally {
2982            m_sqlManager.closeAll(dbc, conn, stmt, null);
2983        }
2984
2985    }
2986
2987    /**
2988     * Creates a <code>CmsPublishJobInfoBean</code> from a result set.<p>
2989     *
2990     * @param res the result set
2991     * @return an initialized <code>CmsPublishJobInfoBean</code>
2992     * @throws SQLException if something goes wrong
2993     */
2994    protected CmsPublishJobInfoBean createPublishJobInfoBean(ResultSet res) throws SQLException {
2995
2996        return new CmsPublishJobInfoBean(
2997            new CmsUUID(res.getString("HISTORY_ID")),
2998            new CmsUUID(res.getString("PROJECT_ID")),
2999            res.getString("PROJECT_NAME"),
3000            new CmsUUID(res.getString("USER_ID")),
3001            res.getString("PUBLISH_LOCALE"),
3002            res.getInt("PUBLISH_FLAGS"),
3003            res.getInt("RESOURCE_COUNT"),
3004            res.getLong("ENQUEUE_TIME"),
3005            res.getLong("START_TIME"),
3006            res.getLong("FINISH_TIME"));
3007    }
3008
3009    /**
3010     * Checks if the given resource (by id) is available in the online project,
3011     * if there exists a resource with a different path (a moved file), then the
3012     * online entry is moved to the right (new) location before publishing.<p>
3013     *
3014     * @param dbc the db context
3015     * @param onlineProject the online project
3016     * @param offlineResource the offline resource to check
3017     * @param publishHistoryId the publish history id
3018     * @param publishTag the publish tag
3019     *
3020     * @return <code>true</code> if the resource has actually been moved
3021     *
3022     * @throws CmsDataAccessException if something goes wrong
3023     */
3024    protected CmsResourceState fixMovedResource(
3025        CmsDbContext dbc,
3026        CmsProject onlineProject,
3027        CmsResource offlineResource,
3028        CmsUUID publishHistoryId,
3029        int publishTag)
3030    throws CmsDataAccessException {
3031
3032        CmsResource onlineResource;
3033        // check if the resource has been moved since last publishing
3034        try {
3035            onlineResource = m_driverManager.getVfsDriver(
3036                dbc).readResource(dbc, onlineProject.getUuid(), offlineResource.getStructureId(), true);
3037            if (onlineResource.getRootPath().equals(offlineResource.getRootPath())) {
3038                // resource changed, not moved
3039                return offlineResource.getState();
3040            }
3041        } catch (CmsVfsResourceNotFoundException e) {
3042            // ok, resource new, not moved
3043            return offlineResource.getState();
3044        }
3045
3046        // move the online resource to the new position
3047        m_driverManager.getVfsDriver(
3048            dbc).moveResource(dbc, onlineProject.getUuid(), onlineResource, offlineResource.getRootPath());
3049
3050        try {
3051            // write the resource to the publish history
3052            m_driverManager.getProjectDriver(dbc).writePublishHistory(
3053                dbc,
3054                publishHistoryId,
3055                new CmsPublishedResource(onlineResource, publishTag, CmsPublishedResource.STATE_MOVED_SOURCE));
3056        } catch (CmsDataAccessException e) {
3057            if (LOG.isErrorEnabled()) {
3058                LOG.error(
3059                    Messages.get().getBundle().key(
3060                        Messages.LOG_WRITING_PUBLISHING_HISTORY_1,
3061                        onlineResource.getRootPath()),
3062                    e);
3063            }
3064            throw e;
3065        }
3066        return offlineResource.getState().isDeleted()
3067        ? CmsResource.STATE_DELETED
3068        : CmsPublishedResource.STATE_MOVED_DESTINATION;
3069    }
3070
3071    /**
3072     * Returns a SQL parameter string for the given data.<p>
3073     *
3074     * @param data the data
3075     *
3076     * @return the SQL parameter
3077     */
3078    protected String getParameterString(Collection<?> data) {
3079
3080        StringBuffer conditions = new StringBuffer();
3081        conditions.append(BEGIN_CONDITION);
3082        Iterator<?> it = data.iterator();
3083        while (it.hasNext()) {
3084            it.next();
3085            conditions.append("?");
3086            if (it.hasNext()) {
3087                conditions.append(", ");
3088            }
3089        }
3090        conditions.append(END_CONDITION);
3091        return conditions.toString();
3092    }
3093
3094    /**
3095     * Implementation of reading the user publish list which uses the log table.<p>
3096     *
3097     * This is the old implementation of the user publish list and can get pretty slow.<p>
3098     *
3099     * @param dbc the current database context
3100     * @param userId the id of the user for which we want the user publish list
3101     *
3102     * @return the publish list for the given user
3103     *
3104     * @throws CmsDataAccessException if something goes wrong
3105     */
3106    protected List<CmsResource> getUsersPubListFromLog(CmsDbContext dbc, CmsUUID userId) throws CmsDataAccessException {
3107
3108        Connection conn = null;
3109        PreparedStatement stmt = null;
3110        ResultSet res = null;
3111
3112        List<CmsResource> result = null;
3113        try {
3114            conn = m_sqlManager.getConnection(dbc);
3115            stmt = m_sqlManager.getPreparedStatement(conn, dbc.currentProject().getUuid(), "C_LOG_READ_PUBLISH_LIST_2");
3116            stmt.setString(1, userId.toString());
3117            stmt.setString(2, userId.toString());
3118            res = stmt.executeQuery();
3119
3120            result = new ArrayList<CmsResource>();
3121            while (res.next()) {
3122                CmsResource resource = m_driverManager.getVfsDriver(dbc).createResource(
3123                    res,
3124                    dbc.currentProject().getUuid());
3125                long date = res.getLong(m_sqlManager.readQuery("C_LOG_DATE"));
3126                resource.setDateLastModified(date);
3127                result.add(resource);
3128            }
3129        } catch (SQLException e) {
3130            throw new CmsDbSqlException(
3131                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
3132                e);
3133        } finally {
3134            m_sqlManager.closeAll(dbc, conn, stmt, res);
3135        }
3136        return result;
3137    }
3138
3139    /**
3140     * Creates a new project from the current row of the given result set.<p>
3141     *
3142     * @param res the result set
3143     *
3144     * @return the new project
3145     *
3146     * @throws SQLException is something goes wrong
3147     */
3148    protected CmsProject internalCreateProject(ResultSet res) throws SQLException {
3149
3150        String ou = CmsOrganizationalUnit.removeLeadingSeparator(
3151            res.getString(m_sqlManager.readQuery("C_PROJECTS_PROJECT_OU_0")));
3152        return new CmsProject(
3153            new CmsUUID(res.getString(m_sqlManager.readQuery("C_PROJECTS_PROJECT_ID_0"))),
3154            ou + res.getString(m_sqlManager.readQuery("C_PROJECTS_PROJECT_NAME_0")),
3155            res.getString(m_sqlManager.readQuery("C_PROJECTS_PROJECT_DESCRIPTION_0")),
3156            new CmsUUID(res.getString(m_sqlManager.readQuery("C_PROJECTS_USER_ID_0"))),
3157            new CmsUUID(res.getString(m_sqlManager.readQuery("C_PROJECTS_GROUP_ID_0"))),
3158            new CmsUUID(res.getString(m_sqlManager.readQuery("C_PROJECTS_MANAGERGROUP_ID_0"))),
3159            res.getInt(m_sqlManager.readQuery("C_PROJECTS_PROJECT_FLAGS_0")),
3160            res.getLong(m_sqlManager.readQuery("C_PROJECTS_DATE_CREATED_0")),
3161            CmsProject.CmsProjectType.valueOf(res.getInt(m_sqlManager.readQuery("C_PROJECTS_PROJECT_TYPE_0"))));
3162    }
3163
3164    /**
3165     * Builds a publish list from serialized data.<p>
3166     *
3167     * @param bytes the byte array containing the serailized data for the publish list
3168     * @return the initialized publish list
3169     *
3170     * @throws IOException if deserialization fails
3171     * @throws ClassNotFoundException if deserialization fails
3172     */
3173    protected CmsPublishList internalDeserializePublishList(byte[] bytes) throws IOException, ClassNotFoundException {
3174
3175        ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
3176        ObjectInputStream oin = new ObjectInputStream(bin);
3177        return (CmsPublishList)oin.readObject();
3178    }
3179
3180    /**
3181     * Creates a new {@link CmsLogEntry} object from the given result set entry.<p>
3182     *
3183     * @param res the result set
3184     *
3185     * @return the new {@link CmsLogEntry} object
3186     *
3187     * @throws SQLException if something goes wrong
3188     */
3189    protected CmsLogEntry internalReadLogEntry(ResultSet res) throws SQLException {
3190
3191        CmsUUID userId = new CmsUUID(res.getString(m_sqlManager.readQuery("C_LOG_USER_ID")));
3192        long date = res.getLong(m_sqlManager.readQuery("C_LOG_DATE"));
3193        CmsUUID structureId = new CmsUUID(res.getString(m_sqlManager.readQuery("C_LOG_STRUCTURE_ID")));
3194        CmsLogEntryType type = CmsLogEntryType.valueOf(res.getInt(m_sqlManager.readQuery("C_LOG_TYPE")));
3195        String[] data = CmsStringUtil.splitAsArray(res.getString(m_sqlManager.readQuery("C_LOG_DATA")), '|');
3196        return new CmsLogEntry(userId, date, structureId, type, data);
3197    }
3198
3199    /**
3200     * Resets the state to UNCHANGED for a specified resource.<p>
3201     *
3202     * @param dbc the current database context
3203     * @param resource the Cms resource
3204     *
3205     * @throws CmsDataAccessException if something goes wrong
3206     */
3207    protected void internalResetResourceState(CmsDbContext dbc, CmsResource resource) throws CmsDataAccessException {
3208
3209        try {
3210            // reset the resource state
3211            resource.setState(CmsResource.STATE_UNCHANGED);
3212            m_driverManager.getVfsDriver(
3213                dbc).writeResourceState(dbc, dbc.currentProject(), resource, CmsDriverManager.UPDATE_ALL, true);
3214        } catch (CmsDataAccessException e) {
3215            if (LOG.isErrorEnabled()) {
3216                LOG.error(
3217                    Messages.get().getBundle().key(
3218                        Messages.LOG_ERROR_RESETTING_RESOURCE_STATE_1,
3219                        resource.getRootPath()),
3220                    e);
3221            }
3222            throw e;
3223        }
3224    }
3225
3226    /**
3227     * Serialize publish list to write it as byte array to the database.<p>
3228     *
3229     * @param publishList the publish list
3230     * @return byte array containing the publish list data
3231     * @throws IOException if something goes wrong
3232     */
3233    protected byte[] internalSerializePublishList(CmsPublishList publishList) throws IOException {
3234
3235        // serialize the publish list
3236        ByteArrayOutputStream bout = new ByteArrayOutputStream();
3237        ObjectOutputStream oout = new ObjectOutputStream(bout);
3238        oout.writeObject(publishList);
3239        oout.close();
3240        return bout.toByteArray();
3241    }
3242
3243    /**
3244     * Writes the needed history entries.<p>
3245     *
3246     * @param dbc the current database context
3247     * @param resource the offline resource
3248     * @param state the state to store in the publish history entry
3249     * @param properties the offline properties
3250     * @param publishHistoryId the current publish process id
3251     * @param publishTag the current publish process tag
3252     *
3253     * @throws CmsDataAccessException if something goes wrong
3254     */
3255    protected void internalWriteHistory(
3256        CmsDbContext dbc,
3257        CmsResource resource,
3258        CmsResourceState state,
3259        List<CmsProperty> properties,
3260        CmsUUID publishHistoryId,
3261        int publishTag)
3262    throws CmsDataAccessException {
3263
3264        try {
3265            if (OpenCms.getSystemInfo().isHistoryEnabled()) {
3266                // write the resource to the historical archive
3267                if (properties == null) {
3268                    properties = m_driverManager.getVfsDriver(dbc).readPropertyObjects(
3269                        dbc,
3270                        dbc.currentProject(),
3271                        resource);
3272                }
3273                m_driverManager.getHistoryDriver(dbc).writeResource(dbc, resource, properties, publishTag);
3274            }
3275            // write the resource to the publish history
3276            m_driverManager.getProjectDriver(dbc).writePublishHistory(
3277                dbc,
3278                publishHistoryId,
3279                new CmsPublishedResource(resource, publishTag, state));
3280        } catch (CmsDataAccessException e) {
3281            if (LOG.isErrorEnabled()) {
3282                LOG.error(
3283                    Messages.get().getBundle().key(Messages.LOG_WRITING_PUBLISHING_HISTORY_1, resource.getRootPath()),
3284                    e);
3285            }
3286            throw e;
3287        }
3288    }
3289
3290    /**
3291     * Build the whole WHERE SQL statement part for the given log entry filter.<p>
3292     *
3293     * @param filter the filter
3294     *
3295     * @return a pair containing both the SQL and the parameters for it
3296     */
3297    protected CmsPair<String, List<I_CmsPreparedStatementParameter>> prepareLogConditions(CmsLogFilter filter) {
3298
3299        List<I_CmsPreparedStatementParameter> params = new ArrayList<I_CmsPreparedStatementParameter>();
3300        StringBuffer conditions = new StringBuffer();
3301
3302        // user id filter
3303        if (filter.getUserId() != null) {
3304            if (conditions.length() == 0) {
3305                conditions.append(BEGIN_CONDITION);
3306            } else {
3307                conditions.append(BEGIN_INCLUDE_CONDITION);
3308            }
3309            conditions.append(m_sqlManager.readQuery("C_LOG_FILTER_USER_ID"));
3310            params.add(new CmsPreparedStatementStringParameter(filter.getUserId().toString()));
3311            conditions.append(END_CONDITION);
3312        }
3313
3314        // resource id filter
3315        if (filter.getStructureId() != null) {
3316            if (conditions.length() == 0) {
3317                conditions.append(BEGIN_CONDITION);
3318            } else {
3319                conditions.append(BEGIN_INCLUDE_CONDITION);
3320            }
3321            conditions.append(m_sqlManager.readQuery("C_LOG_FILTER_RESOURCE_ID"));
3322            params.add(new CmsPreparedStatementStringParameter(filter.getStructureId().toString()));
3323            conditions.append(END_CONDITION);
3324        }
3325
3326        // date from filter
3327        if (filter.getDateFrom() != CmsResource.DATE_RELEASED_DEFAULT) {
3328            if (conditions.length() == 0) {
3329                conditions.append(BEGIN_CONDITION);
3330            } else {
3331                conditions.append(BEGIN_INCLUDE_CONDITION);
3332            }
3333            conditions.append(m_sqlManager.readQuery("C_LOG_FILTER_DATE_FROM"));
3334            params.add(new CmsPreparedStatementLongParameter(filter.getDateFrom()));
3335            conditions.append(END_CONDITION);
3336        }
3337
3338        // date to filter
3339        if (filter.getDateTo() != CmsResource.DATE_RELEASED_DEFAULT) {
3340            if (conditions.length() == 0) {
3341                conditions.append(BEGIN_CONDITION);
3342            } else {
3343                conditions.append(BEGIN_INCLUDE_CONDITION);
3344            }
3345            conditions.append(m_sqlManager.readQuery("C_LOG_FILTER_DATE_TO"));
3346            params.add(new CmsPreparedStatementLongParameter(filter.getDateTo()));
3347            conditions.append(END_CONDITION);
3348        }
3349
3350        // include type filter
3351        Set<CmsLogEntryType> includeTypes = filter.getIncludeTypes();
3352        if (!includeTypes.isEmpty()) {
3353            if (conditions.length() == 0) {
3354                conditions.append(BEGIN_CONDITION);
3355            } else {
3356                conditions.append(BEGIN_INCLUDE_CONDITION);
3357            }
3358            conditions.append(m_sqlManager.readQuery("C_LOG_FILTER_INCLUDE_TYPE"));
3359            conditions.append(BEGIN_CONDITION);
3360            Iterator<CmsLogEntryType> it = includeTypes.iterator();
3361            while (it.hasNext()) {
3362                CmsLogEntryType type = it.next();
3363                conditions.append("?");
3364                params.add(new CmsPreparedStatementIntParameter(type.getId()));
3365                if (it.hasNext()) {
3366                    conditions.append(", ");
3367                }
3368            }
3369            conditions.append(END_CONDITION);
3370            conditions.append(END_CONDITION);
3371        }
3372
3373        // exclude type filter
3374        Set<CmsLogEntryType> excludeTypes = filter.getExcludeTypes();
3375        if (!excludeTypes.isEmpty()) {
3376            if (conditions.length() == 0) {
3377                conditions.append(BEGIN_CONDITION);
3378            } else {
3379                conditions.append(BEGIN_INCLUDE_CONDITION);
3380            }
3381            conditions.append(m_sqlManager.readQuery("C_LOG_FILTER_EXCLUDE_TYPE"));
3382            conditions.append(BEGIN_CONDITION);
3383            Iterator<CmsLogEntryType> it = excludeTypes.iterator();
3384            while (it.hasNext()) {
3385                CmsLogEntryType type = it.next();
3386                conditions.append("?");
3387                params.add(new CmsPreparedStatementIntParameter(type.getId()));
3388                if (it.hasNext()) {
3389                    conditions.append(", ");
3390                }
3391            }
3392            conditions.append(END_CONDITION);
3393            conditions.append(END_CONDITION);
3394        }
3395        return CmsPair.create(conditions.toString(), params);
3396    }
3397
3398    /**
3399     * Publishes a changed file.<p>
3400     *
3401     * @param dbc the current database context
3402     * @param onlineProject the online project
3403     * @param offlineResource the resource to publish
3404     * @param publishedResourceIds contains the UUIDs of already published content records
3405     * @param publishHistoryId the publish history id
3406     * @param publishTag the publish tag
3407     *
3408     * @throws CmsDataAccessException is something goes wrong
3409     */
3410    protected void publishChangedFile(
3411        CmsDbContext dbc,
3412        CmsProject onlineProject,
3413        CmsResource offlineResource,
3414        Set<CmsUUID> publishedResourceIds,
3415        CmsUUID publishHistoryId,
3416        int publishTag)
3417    throws CmsDataAccessException {
3418
3419        CmsResource onlineResource = null;
3420        boolean needToUpdateContent = true;
3421        boolean existsOnline = m_driverManager.getVfsDriver(dbc).validateStructureIdExists(
3422            dbc,
3423            CmsProject.ONLINE_PROJECT_ID,
3424            offlineResource.getStructureId());
3425        CmsResourceState resourceState = existsOnline
3426        ? fixMovedResource(dbc, onlineProject, offlineResource, publishHistoryId, publishTag)
3427        : offlineResource.getState();
3428        try {
3429            // reset the labeled link flag before writing the online file
3430            int flags = offlineResource.getFlags();
3431            flags &= ~CmsResource.FLAG_LABELED;
3432            offlineResource.setFlags(flags);
3433
3434            if (existsOnline) {
3435                // read the file header online
3436                onlineResource = m_driverManager.getVfsDriver(
3437                    dbc).readResource(dbc, onlineProject.getUuid(), offlineResource.getStructureId(), false);
3438                needToUpdateContent = (onlineResource.getDateContent() < offlineResource.getDateContent());
3439                // delete the properties online
3440                m_driverManager.getVfsDriver(dbc).deletePropertyObjects(
3441                    dbc,
3442                    onlineProject.getUuid(),
3443                    onlineResource,
3444                    CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
3445
3446                // if the offline file has a resource ID different from the online file
3447                // (probably because a deleted file was replaced by a new file with the
3448                // same name), the properties mapped to the "old" resource ID have to be
3449                // deleted also offline. if this is the case, the online and offline structure
3450                // ID's do match, but the resource ID's are different. structure IDs are reused
3451                // to prevent orphan structure records in the online project.
3452
3453                // Addendum (2023): It shouldn't be possible for resources to be in this state anymore,
3454                // since creating new resources over deleted ones isn't really possible anymore,
3455                // but apparently it can still happen, though I can't reproduce it.
3456                if (!onlineResource.getResourceId().equals(offlineResource.getResourceId())) {
3457                    List<CmsProperty> offlineProperties = m_driverManager.getVfsDriver(dbc).readPropertyObjects(
3458                        dbc,
3459                        dbc.currentProject(),
3460                        onlineResource);
3461                    if (offlineProperties.size() > 0) {
3462                        List<CmsProperty> newProperties = new ArrayList<>();
3463                        for (int i = 0; i < offlineProperties.size(); i++) {
3464                            CmsProperty oldProperty = offlineProperties.get(i);
3465                            // property may be frozen (non-modifiable), so create a new one
3466                            CmsProperty newProperty = new CmsProperty(
3467                                oldProperty.getName(),
3468                                null,
3469                                CmsProperty.DELETE_VALUE);
3470                            newProperties.add(newProperty);
3471                        }
3472                        m_driverManager.getVfsDriver(
3473                            dbc).writePropertyObjects(dbc, dbc.currentProject(), onlineResource, newProperties);
3474                    }
3475                }
3476            }
3477        } catch (CmsDataAccessException e) {
3478            if (LOG.isErrorEnabled()) {
3479                LOG.error(
3480                    Messages.get().getBundle().key(Messages.LOG_DELETING_PROPERTIES_1, offlineResource.toString()),
3481                    e);
3482            }
3483            throw e;
3484        }
3485
3486        CmsFile newFile;
3487        try {
3488            // publish the file content
3489            newFile = m_driverManager.getProjectDriver(dbc).publishFileContent(
3490                dbc,
3491                dbc.currentProject(),
3492                onlineProject,
3493                offlineResource,
3494                publishedResourceIds,
3495                needToUpdateContent,
3496                publishTag);
3497
3498        } catch (CmsDataAccessException e) {
3499            if (LOG.isErrorEnabled()) {
3500                LOG.error(
3501                    Messages.get().getBundle().key(Messages.LOG_PUBLISHING_RESOURCE_1, offlineResource.getRootPath()),
3502                    e);
3503            }
3504            throw e;
3505        }
3506
3507        List<CmsProperty> offlineProperties;
3508        try {
3509            // write the properties online
3510            offlineProperties = m_driverManager.getVfsDriver(dbc).readPropertyObjects(
3511                dbc,
3512                dbc.currentProject(),
3513                offlineResource);
3514            CmsProperty.setAutoCreatePropertyDefinitions(offlineProperties, true);
3515            m_driverManager.getVfsDriver(dbc).writePropertyObjects(dbc, onlineProject, newFile, offlineProperties);
3516        } catch (CmsDataAccessException e) {
3517            if (LOG.isErrorEnabled()) {
3518                LOG.error(
3519                    Messages.get().getBundle().key(Messages.LOG_PUBLISHING_PROPERTIES_1, newFile.getRootPath()),
3520                    e);
3521            }
3522            throw e;
3523        }
3524
3525        try {
3526            // write the ACL online
3527            m_driverManager.getUserDriver(dbc).publishAccessControlEntries(
3528                dbc,
3529                dbc.currentProject(),
3530                onlineProject,
3531                newFile.getResourceId(),
3532                offlineResource.getResourceId());
3533        } catch (CmsDataAccessException e) {
3534            if (LOG.isErrorEnabled()) {
3535                LOG.error(Messages.get().getBundle().key(Messages.LOG_PUBLISHING_ACL_1, newFile.getRootPath()), e);
3536            }
3537            throw e;
3538        }
3539
3540        CmsFile offlineFile = new CmsFile(offlineResource);
3541        offlineFile.setContents(newFile.getContents());
3542        internalWriteHistory(dbc, offlineFile, resourceState, offlineProperties, publishHistoryId, publishTag);
3543
3544        m_driverManager.getVfsDriver(dbc).updateRelations(dbc, onlineProject, offlineResource);
3545    }
3546
3547    /**
3548     * Publishes a deleted file.<p>
3549     *
3550     * @param dbc the current database context
3551     * @param onlineProject the online project
3552     * @param offlineResource the resource to publish
3553     * @param publishHistoryId the publish history id
3554     * @param publishTag the publish tag
3555     *
3556     * @throws CmsDataAccessException is something goes wrong
3557     */
3558    protected void publishDeletedFile(
3559        CmsDbContext dbc,
3560        CmsProject onlineProject,
3561        CmsResource offlineResource,
3562        CmsUUID publishHistoryId,
3563        int publishTag)
3564    throws CmsDataAccessException {
3565
3566        CmsResourceState resourceState = fixMovedResource(
3567            dbc,
3568            onlineProject,
3569            offlineResource,
3570            publishHistoryId,
3571            publishTag);
3572
3573        boolean existsOnline = m_driverManager.getVfsDriver(dbc).validateStructureIdExists(
3574            dbc,
3575            CmsProject.ONLINE_PROJECT_ID,
3576            offlineResource.getStructureId());
3577        CmsResource onlineResource = null;
3578        if (existsOnline) {
3579            try {
3580                // read the file header online
3581                onlineResource = m_driverManager.getVfsDriver(
3582                    dbc).readResource(dbc, onlineProject.getUuid(), offlineResource.getStructureId(), true);
3583            } catch (CmsDataAccessException e) {
3584                if (LOG.isErrorEnabled()) {
3585                    LOG.error(
3586                        Messages.get().getBundle().key(Messages.LOG_READING_RESOURCE_1, offlineResource.getRootPath()),
3587                        e);
3588                }
3589                throw e;
3590            }
3591        }
3592        if (offlineResource.isLabeled() && !m_driverManager.labelResource(dbc, offlineResource, null, 2)) {
3593            // update the resource flags to "unlabeled" of the siblings of the offline resource
3594            int flags = offlineResource.getFlags();
3595            flags &= ~CmsResource.FLAG_LABELED;
3596            offlineResource.setFlags(flags);
3597        }
3598
3599        // write history before deleting
3600        CmsFile offlineFile = new CmsFile(offlineResource);
3601        offlineFile.setContents(
3602            m_driverManager.getVfsDriver(dbc).readContent(
3603                dbc,
3604                dbc.currentProject().getUuid(),
3605                offlineFile.getResourceId()));
3606        internalWriteHistory(dbc, offlineFile, resourceState, null, publishHistoryId, publishTag);
3607
3608        int propertyDeleteOption = -1;
3609        try {
3610            // delete the properties online and offline
3611            if (offlineResource.getSiblingCount() > 1) {
3612                // there are other siblings- delete only structure property values and keep the resource property values
3613                propertyDeleteOption = CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_VALUES;
3614            } else {
3615                // there are no other siblings- delete both the structure and resource property values
3616                propertyDeleteOption = CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES;
3617            }
3618
3619            if (existsOnline) {
3620                m_driverManager.getVfsDriver(
3621                    dbc).deletePropertyObjects(dbc, onlineProject.getUuid(), onlineResource, propertyDeleteOption);
3622            }
3623            m_driverManager.getVfsDriver(
3624                dbc).deletePropertyObjects(dbc, dbc.currentProject().getUuid(), offlineResource, propertyDeleteOption);
3625
3626            // if the offline file has a resource ID different from the online file
3627            // (probably because a (deleted) file was replaced by a new file with the
3628            // same name), the properties with the "old" resource ID have to be
3629            // deleted also offline
3630            if (existsOnline
3631                && (onlineResource != null)
3632                && !onlineResource.getResourceId().equals(offlineResource.getResourceId())) {
3633                m_driverManager.getVfsDriver(dbc).deletePropertyObjects(
3634                    dbc,
3635                    dbc.currentProject().getUuid(),
3636                    onlineResource,
3637                    CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
3638            }
3639        } catch (CmsDataAccessException e) {
3640            if (LOG.isErrorEnabled()) {
3641                LOG.error(
3642                    Messages.get().getBundle().key(Messages.LOG_DELETING_PROPERTIES_1, offlineResource.getRootPath()),
3643                    e);
3644            }
3645            throw e;
3646        }
3647
3648        try {
3649            // remove the file online and offline
3650            m_driverManager.getVfsDriver(dbc).removeFile(dbc, dbc.currentProject().getUuid(), offlineResource);
3651            if (existsOnline && (onlineResource != null)) {
3652                m_driverManager.getVfsDriver(dbc).removeFile(dbc, onlineProject.getUuid(), onlineResource);
3653            }
3654        } catch (CmsDataAccessException e) {
3655            if (LOG.isErrorEnabled()) {
3656                LOG.error(
3657                    Messages.get().getBundle().key(Messages.LOG_REMOVING_RESOURCE_1, offlineResource.getRootPath()),
3658                    e);
3659            }
3660            throw e;
3661        }
3662
3663        // delete the ACL online and offline
3664        try {
3665            if (existsOnline && (onlineResource != null) && (onlineResource.getSiblingCount() == 1)) {
3666                // only if no siblings left
3667                m_driverManager.getUserDriver(dbc).removeAccessControlEntries(
3668                    dbc,
3669                    onlineProject,
3670                    onlineResource.getResourceId());
3671            }
3672            if (offlineResource.getSiblingCount() == 1) {
3673                // only if no siblings left
3674                m_driverManager.getUserDriver(dbc).removeAccessControlEntries(
3675                    dbc,
3676                    dbc.currentProject(),
3677                    offlineResource.getResourceId());
3678            }
3679        } catch (CmsDataAccessException e) {
3680            if (LOG.isErrorEnabled()) {
3681                LOG.error(Messages.get().getBundle().key(Messages.LOG_REMOVING_ACL_1, offlineResource.toString()), e);
3682            }
3683            throw e;
3684        }
3685
3686        try {
3687            // delete relations online and offline
3688            m_driverManager.getVfsDriver(
3689                dbc).deleteRelations(dbc, onlineProject.getUuid(), offlineResource, CmsRelationFilter.TARGETS);
3690            m_driverManager.getVfsDriver(
3691                dbc).deleteRelations(dbc, dbc.currentProject().getUuid(), offlineResource, CmsRelationFilter.TARGETS);
3692        } catch (CmsDataAccessException e) {
3693            if (LOG.isErrorEnabled()) {
3694                LOG.error(
3695                    Messages.get().getBundle().key(Messages.LOG_REMOVING_RELATIONS_1, offlineResource.toString()),
3696                    e);
3697            }
3698            throw e;
3699        }
3700
3701        if (OpenCms.getSubscriptionManager().isEnabled()) {
3702            try {
3703                // delete visited information for resource from log
3704                CmsVisitEntryFilter filter = CmsVisitEntryFilter.ALL.filterResource(offlineResource.getStructureId());
3705                m_driverManager.getSubscriptionDriver().deleteVisits(
3706                    dbc,
3707                    OpenCms.getSubscriptionManager().getPoolName(),
3708                    filter);
3709            } catch (CmsDataAccessException e) {
3710                if (LOG.isErrorEnabled()) {
3711                    LOG.error(
3712                        Messages.get().getBundle().key(Messages.LOG_REMOVING_VISITEDLOG_1, offlineResource.toString()),
3713                        e);
3714                }
3715                throw e;
3716            }
3717
3718            try {
3719                // mark the subscribed resource as deleted
3720                /* changed to subscription driver */
3721                //                m_driverManager.getUserDriver(dbc).setSubscribedResourceAsDeleted(
3722                //                    dbc,
3723                //                    OpenCms.getSubscriptionManager().getPoolName(),
3724                //                    offlineResource);
3725                m_driverManager.getSubscriptionDriver().setSubscribedResourceAsDeleted(
3726                    dbc,
3727                    OpenCms.getSubscriptionManager().getPoolName(),
3728                    offlineResource);
3729            } catch (CmsDataAccessException e) {
3730                if (LOG.isErrorEnabled()) {
3731                    LOG.error(
3732                        Messages.get().getBundle().key(
3733                            Messages.LOG_REMOVING_SUBSCRIPTIONS_1,
3734                            offlineResource.toString()),
3735                        e);
3736                }
3737                throw e;
3738            }
3739        }
3740    }
3741
3742    /**
3743     * Publishes a new file.<p>
3744     *
3745     * @param dbc the current database context
3746     * @param onlineProject the online project
3747     * @param offlineResource the resource to publish
3748     * @param publishedContentIds contains the UUIDs of already published content records
3749     * @param publishHistoryId the publish history id
3750     * @param publishTag the publish tag
3751     *
3752     * @throws CmsDataAccessException is something goes wrong
3753     */
3754    protected void publishNewFile(
3755        CmsDbContext dbc,
3756        CmsProject onlineProject,
3757        CmsResource offlineResource,
3758        Set<CmsUUID> publishedContentIds,
3759        CmsUUID publishHistoryId,
3760        int publishTag)
3761    throws CmsDataAccessException {
3762
3763        CmsResourceState resourceState = fixMovedResource(
3764            dbc,
3765            onlineProject,
3766            offlineResource,
3767            publishHistoryId,
3768            publishTag);
3769
3770        CmsFile newFile;
3771        try {
3772            // reset the labeled link flag before writing the online file
3773            int flags = offlineResource.getFlags();
3774            flags &= ~CmsResource.FLAG_LABELED;
3775            offlineResource.setFlags(flags);
3776
3777            // publish the file content
3778            newFile = m_driverManager.getProjectDriver(dbc).publishFileContent(
3779                dbc,
3780                dbc.currentProject(),
3781                onlineProject,
3782                offlineResource,
3783                publishedContentIds,
3784                true,
3785                publishTag);
3786
3787        } catch (CmsVfsResourceAlreadyExistsException e) {
3788            try {
3789                // remove the existing file and ensure that it's content is written
3790                // in any case by removing it's resource ID from the set of published resource IDs
3791                m_driverManager.getVfsDriver(dbc).removeFile(dbc, onlineProject.getUuid(), offlineResource);
3792                publishedContentIds.remove(offlineResource.getResourceId());
3793                newFile = m_driverManager.getProjectDriver(dbc).publishFileContent(
3794                    dbc,
3795                    dbc.currentProject(),
3796                    onlineProject,
3797                    offlineResource,
3798                    publishedContentIds,
3799                    true,
3800                    publishTag);
3801
3802            } catch (CmsDataAccessException e1) {
3803                if (LOG.isErrorEnabled()) {
3804                    LOG.error(
3805                        Messages.get().getBundle().key(
3806                            Messages.LOG_PUBLISHING_RESOURCE_1,
3807                            offlineResource.getRootPath()),
3808                        e);
3809                }
3810                throw e1;
3811            }
3812        } catch (CmsDataAccessException e) {
3813            if (LOG.isErrorEnabled()) {
3814                LOG.error(
3815                    Messages.get().getBundle().key(Messages.LOG_PUBLISHING_RESOURCE_1, offlineResource.getRootPath()),
3816                    e);
3817            }
3818            throw e;
3819        }
3820
3821        List<CmsProperty> offlineProperties;
3822        try {
3823            // write the properties online
3824            offlineProperties = m_driverManager.getVfsDriver(dbc).readPropertyObjects(
3825                dbc,
3826                dbc.currentProject(),
3827                offlineResource);
3828            CmsProperty.setAutoCreatePropertyDefinitions(offlineProperties, true);
3829            m_driverManager.getVfsDriver(dbc).writePropertyObjects(dbc, onlineProject, newFile, offlineProperties);
3830        } catch (CmsDataAccessException e) {
3831            if (LOG.isErrorEnabled()) {
3832                LOG.error(
3833                    Messages.get().getBundle().key(Messages.LOG_PUBLISHING_PROPERTIES_1, newFile.getRootPath()),
3834                    e);
3835            }
3836
3837            throw e;
3838        }
3839
3840        try {
3841            // write the ACL online
3842            m_driverManager.getUserDriver(dbc).publishAccessControlEntries(
3843                dbc,
3844                dbc.currentProject(),
3845                onlineProject,
3846                offlineResource.getResourceId(),
3847                newFile.getResourceId());
3848        } catch (CmsDataAccessException e) {
3849            if (LOG.isErrorEnabled()) {
3850                LOG.error(Messages.get().getBundle().key(Messages.LOG_PUBLISHING_ACL_1, newFile.getRootPath()), e);
3851            }
3852            throw e;
3853        }
3854
3855        CmsFile offlineFile = new CmsFile(offlineResource);
3856        offlineFile.setContents(newFile.getContents());
3857        internalWriteHistory(dbc, offlineFile, resourceState, offlineProperties, publishHistoryId, publishTag);
3858
3859        m_driverManager.getVfsDriver(dbc).updateRelations(dbc, onlineProject, offlineResource);
3860    }
3861
3862}