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