org.opencms.db.jpa.CmsVfsDriver.java Source code

Java tutorial

Introduction

Here is the source code for org.opencms.db.jpa.CmsVfsDriver.java

Source

/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.db.jpa;

import org.opencms.configuration.CmsConfigurationManager;
import org.opencms.configuration.CmsParameterConfiguration;
import org.opencms.db.CmsDbConsistencyException;
import org.opencms.db.CmsDbContext;
import org.opencms.db.CmsDbEntryNotFoundException;
import org.opencms.db.CmsDbSqlException;
import org.opencms.db.CmsDriverManager;
import org.opencms.db.CmsResourceState;
import org.opencms.db.CmsVfsOnlineResourceAlreadyExistsException;
import org.opencms.db.I_CmsDriver;
import org.opencms.db.I_CmsProjectDriver;
import org.opencms.db.I_CmsVfsDriver;
import org.opencms.db.jpa.persistence.CmsDAOContents;
import org.opencms.db.jpa.persistence.CmsDAOCounters;
import org.opencms.db.jpa.persistence.CmsDAOOfflineContents;
import org.opencms.db.jpa.persistence.CmsDAOOfflineProperties;
import org.opencms.db.jpa.persistence.CmsDAOOfflinePropertyDef;
import org.opencms.db.jpa.persistence.CmsDAOOfflineResourceRelations;
import org.opencms.db.jpa.persistence.CmsDAOOfflineResources;
import org.opencms.db.jpa.persistence.CmsDAOOfflineStructure;
import org.opencms.db.jpa.persistence.CmsDAOOfflineUrlNameMappings;
import org.opencms.db.jpa.persistence.CmsDAOOnlineProperties;
import org.opencms.db.jpa.persistence.CmsDAOOnlinePropertyDef;
import org.opencms.db.jpa.persistence.CmsDAOOnlineResourceRelations;
import org.opencms.db.jpa.persistence.CmsDAOOnlineResources;
import org.opencms.db.jpa.persistence.CmsDAOOnlineStructure;
import org.opencms.db.jpa.persistence.CmsDAOOnlineUrlNameMappings;
import org.opencms.db.jpa.persistence.I_CmsDAOProperties;
import org.opencms.db.jpa.persistence.I_CmsDAOPropertyDef;
import org.opencms.db.jpa.persistence.I_CmsDAOResourceRelations;
import org.opencms.db.jpa.persistence.I_CmsDAOResources;
import org.opencms.db.jpa.persistence.I_CmsDAOStructure;
import org.opencms.db.jpa.persistence.I_CmsDAOUrlNameMappings;
import org.opencms.db.jpa.utils.CmsQueryIntParameter;
import org.opencms.db.jpa.utils.CmsQueryStringParameter;
import org.opencms.db.jpa.utils.I_CmsQueryParameter;
import org.opencms.db.urlname.CmsUrlNameMappingEntry;
import org.opencms.db.urlname.CmsUrlNameMappingFilter;
import org.opencms.file.CmsDataAccessException;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsFolder;
import org.opencms.file.CmsProject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.CmsVfsException;
import org.opencms.file.CmsVfsResourceAlreadyExistsException;
import org.opencms.file.CmsVfsResourceNotFoundException;
import org.opencms.file.I_CmsResource;
import org.opencms.file.history.I_CmsHistoryResource;
import org.opencms.file.types.CmsResourceTypeJsp;
import org.opencms.main.CmsEvent;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.I_CmsEventListener;
import org.opencms.main.OpenCms;
import org.opencms.relations.CmsRelation;
import org.opencms.relations.CmsRelationFilter;
import org.opencms.relations.CmsRelationType;
import org.opencms.security.CmsOrganizationalUnit;
import org.opencms.security.CmsPermissionSet;
import org.opencms.util.CmsDataTypeUtil;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsPair;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.apache.commons.logging.Log;

/**
 * JPA database server implementation of the vfs driver methods.<p>
 * 
 * @since 8.0.0 
 */
public class CmsVfsDriver implements I_CmsDriver, I_CmsVfsDriver {

    /** Internal presentation of empty binary content. */
    public static final byte[] EMPTY_BLOB = new byte[0];

    /** Query key. */
    private static final String C_DELETE_RELATIONS = "C_DELETE_RELATIONS";

    /** Query key. */
    private static final String C_DELETE_URLNAME_MAPPINGS = "C_DELETE_URLNAME_MAPPINGS";

    /** Query key. */
    private static final String C_HISTORY_CONTENTS_UPDATE = "C_HISTORY_CONTENTS_UPDATE";

    /** Query key. */
    private static final String C_MOVE_RELATIONS_SOURCE = "C_MOVE_RELATIONS_SOURCE";

    /** Query key. */
    private static final String C_MOVE_RELATIONS_TARGET = "C_MOVE_RELATIONS_TARGET";

    /** Query key. */
    private static final String C_OFFLINE_CONTENTS_UPDATE = "C_OFFLINE_CONTENTS_UPDATE";

    /** Query key. */
    private static final String C_OFFLINE_FILE_CONTENT_DELETE = "C_OFFLINE_FILE_CONTENT_DELETE";

    /** Query key. */
    private static final String C_ONLINE_CONTENTS_DELETE = "C_ONLINE_CONTENTS_DELETE";

    /** Query key. */
    private static final String C_ONLINE_CONTENTS_HISTORY = "C_ONLINE_CONTENTS_HISTORY";

    /** Query key. */
    private static final String C_ONLINE_FILES_CONTENT = "C_ONLINE_FILES_CONTENT";

    /** Query key. */
    private static final String C_PROPERTIES_DELETE = "C_PROPERTIES_DELETE";

    /** Query key. */
    private static final String C_PROPERTIES_DELETE_ALL_STRUCTURE_AND_RESOURCE_VALUES = "C_PROPERTIES_DELETE_ALL_STRUCTURE_AND_RESOURCE_VALUES";

    /** Query key. */
    private static final String C_PROPERTIES_DELETE_ALL_VALUES_FOR_MAPPING_TYPE = "C_PROPERTIES_DELETE_ALL_VALUES_FOR_MAPPING_TYPE";

    /** Query key. */
    private static final String C_PROPERTIES_READ = "C_PROPERTIES_READ";

    /** Query key. */
    private static final String C_PROPERTIES_READALL = "C_PROPERTIES_READALL";

    /** Query key. */
    private static final String C_PROPERTIES_READALL_COUNT = "C_PROPERTIES_READALL_COUNT";

    /** Query key. */
    private static final String C_PROPERTIES_UPDATE = "C_PROPERTIES_UPDATE";

    /** Query key. */
    private static final String C_PROPERTYDEF_DELETE = "C_PROPERTYDEF_DELETE";

    /** Query key. */
    private static final String C_PROPERTYDEF_READ = "C_PROPERTYDEF_READ";

    /** Query key. */
    private static final String C_PROPERTYDEF_READALL = "C_PROPERTYDEF_READALL";

    /** Query key. */
    private static final String C_READ_RELATIONS = "C_READ_RELATIONS";

    /** Query key. */
    private static final String C_READ_RESOURCE_OUS = "C_READ_RESOURCE_OUS";

    /** Query key. */
    private static final String C_READ_RESOURCE_STATE = "C_READ_RESOURCE_STATE";

    /** Query key. */
    private static final String C_READ_STRUCTURE_STATE = "C_READ_STRUCTURE_STATE";

    /** Query key. */
    private static final String C_READ_URLNAME_MAPPINGS = "C_READ_URLNAME_MAPPINGS";

    /** Query key. */
    private static final String C_RELATION_FILTER_SOURCE_ID = "C_RELATION_FILTER_SOURCE_ID";

    /** Query key. */
    private static final String C_RELATION_FILTER_SOURCE_PATH = "C_RELATION_FILTER_SOURCE_PATH";

    /** Query key. */
    private static final String C_RELATION_FILTER_TARGET_ID = "C_RELATION_FILTER_TARGET_ID";

    /** Query key. */
    private static final String C_RELATION_FILTER_TARGET_PATH = "C_RELATION_FILTER_TARGET_PATH";

    /** Query key. */
    private static final String C_RELATION_FILTER_TYPE = "C_RELATION_FILTER_TYPE";

    /** Query key. */
    private static final String C_RELATIONS_REPAIR_BROKEN = "C_RELATIONS_REPAIR_BROKEN";

    /** Query key. */
    private static final String C_RELATIONS_UPDATE_BROKEN = "C_RELATIONS_UPDATE_BROKEN";

    /** Query key. */
    private static final String C_RESOURCE_REPLACE = "C_RESOURCE_REPLACE";

    /** Query key. */
    private static final String C_RESOURCES_COUNT_SIBLINGS = "C_RESOURCES_COUNT_SIBLINGS";

    /** Query key. */
    private static final String C_RESOURCES_DELETE_BY_RESOURCEID = "C_RESOURCES_DELETE_BY_RESOURCEID";

    /** Query key. */
    private static final String C_RESOURCES_GET_RESOURCE_IN_PROJECT_IGNORE_STATE = "C_RESOURCES_GET_RESOURCE_IN_PROJECT_IGNORE_STATE";

    /** Query key. */
    private static final String C_RESOURCES_GET_RESOURCE_IN_PROJECT_WITH_STATE = "C_RESOURCES_GET_RESOURCE_IN_PROJECT_WITH_STATE";

    /** Query key. */
    private static final String C_RESOURCES_GET_RESOURCE_IN_PROJECT_WITHOUT_STATE = "C_RESOURCES_GET_RESOURCE_IN_PROJECT_WITHOUT_STATE";

    /** Query key. */
    private static final String C_RESOURCES_GET_RESOURCE_WITH_PROPERTYDEF = "C_RESOURCES_GET_RESOURCE_WITH_PROPERTYDEF";

    /** Query key. */
    private static final String C_RESOURCES_GET_RESOURCE_WITH_PROPERTYDEF_VALUE = "C_RESOURCES_GET_RESOURCE_WITH_PROPERTYDEF_VALUE";

    /** Query key. */
    private static final String C_RESOURCES_GET_SUBRESOURCES = "C_RESOURCES_GET_SUBRESOURCES";

    /** Query key. */
    private static final String C_RESOURCES_GET_SUBRESOURCES_GET_FILES = "C_RESOURCES_GET_SUBRESOURCES_GET_FILES";

    /** Query key. */
    private static final String C_RESOURCES_GET_SUBRESOURCES_GET_FOLDERS = "C_RESOURCES_GET_SUBRESOURCES_GET_FOLDERS";

    /** Query key. */
    private static final String C_RESOURCES_MOVE = "C_RESOURCES_MOVE";

    /** Query key. */
    private static final String C_RESOURCES_ORDER_BY_PATH = "C_RESOURCES_ORDER_BY_PATH";

    /** Query key. */
    private static final String C_RESOURCES_READ = "C_RESOURCES_READ";

    /** Query key. */
    private static final String C_RESOURCES_READ_PARENT_BY_ID = "C_RESOURCES_READ_PARENT_BY_ID";

    /** Query key. */
    private static final String C_RESOURCES_READ_PARENT_STRUCTURE_ID = "C_RESOURCES_READ_PARENT_STRUCTURE_ID";

    /** Query key. */
    private static final String C_RESOURCES_READ_RESOURCE_STATE = "C_RESOURCES_READ_RESOURCE_STATE";

    /** Query key. */
    private static final String C_RESOURCES_READ_TREE = "C_RESOURCES_READ_TREE";

    /** Query key. */
    private static final String C_RESOURCES_READ_VERSION_RES = "C_RESOURCES_READ_VERSION_RES";

    /** Query key. */
    private static final String C_RESOURCES_READ_VERSION_STR = "C_RESOURCES_READ_VERSION_STR";

    /** Query key. */
    private static final String C_RESOURCES_READ_WITH_ACE_1 = "C_RESOURCES_READ_WITH_ACE_1";

    /** Query key. */
    private static final String C_RESOURCES_READBYID = "C_RESOURCES_READBYID";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_DATE_LASTMODIFIED_AFTER = "C_RESOURCES_SELECT_BY_DATE_LASTMODIFIED_AFTER";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_DATE_LASTMODIFIED_BEFORE = "C_RESOURCES_SELECT_BY_DATE_LASTMODIFIED_BEFORE";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_PARENT_UUID = "C_RESOURCES_SELECT_BY_PARENT_UUID";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_PATH_PREFIX = "C_RESOURCES_SELECT_BY_PATH_PREFIX";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_PROJECT_LASTMODIFIED = "C_RESOURCES_SELECT_BY_PROJECT_LASTMODIFIED";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_RESOURCE_STATE = "C_RESOURCES_SELECT_BY_RESOURCE_STATE";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_BY_RESOURCE_TYPE = "C_RESOURCES_SELECT_BY_RESOURCE_TYPE";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_ONLY_FILES = "C_RESOURCES_SELECT_ONLY_FILES";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_ONLY_FOLDERS = "C_RESOURCES_SELECT_ONLY_FOLDERS";

    /** Query key. */
    private static final String C_RESOURCES_SELECT_STRUCTURE_ID = "C_RESOURCES_SELECT_STRUCTURE_ID";

    /** Query key. */
    private static final String C_RESOURCES_TRANSFER_RESOURCE = "C_RESOURCES_TRANSFER_RESOURCE";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_FLAGS = "C_RESOURCES_UPDATE_FLAGS";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_PROJECT_LASTMODIFIED = "C_RESOURCES_UPDATE_PROJECT_LASTMODIFIED";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RELEASE_EXPIRED = "C_RESOURCES_UPDATE_RELEASE_EXPIRED";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RESOURCE_PROJECT = "C_RESOURCES_UPDATE_RESOURCE_PROJECT";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RESOURCE_STATE = "C_RESOURCES_UPDATE_RESOURCE_STATE";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RESOURCE_STATELASTMODIFIED = "C_RESOURCES_UPDATE_RESOURCE_STATELASTMODIFIED";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RESOURCE_VERSION = "C_RESOURCES_UPDATE_RESOURCE_VERSION";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RESOURCES = "C_RESOURCES_UPDATE_RESOURCES";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_RESOURCES_WITHOUT_STATE = "C_RESOURCES_UPDATE_RESOURCES_WITHOUT_STATE";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_SIBLING_COUNT = "C_RESOURCES_UPDATE_SIBLING_COUNT";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_STRUCTURE = "C_RESOURCES_UPDATE_STRUCTURE";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_STRUCTURE_STATE = "C_RESOURCES_UPDATE_STRUCTURE_STATE";

    /** Query key. */
    private static final String C_RESOURCES_UPDATE_STRUCTURE_VERSION = "C_RESOURCES_UPDATE_STRUCTURE_VERSION";

    /** Query key. */
    private static final String C_SELECT_NONDELETED_VFS_SIBLINGS = "C_SELECT_NONDELETED_VFS_SIBLINGS";

    /** Query key. */
    private static final String C_SELECT_RESOURCES_FOR_PRINCIPAL_ACE = "C_SELECT_RESOURCES_FOR_PRINCIPAL_ACE";

    /** Query key. */
    private static final String C_SELECT_RESOURCES_FOR_PRINCIPAL_ATTR1 = "C_SELECT_RESOURCES_FOR_PRINCIPAL_ATTR1";

    /** Query key. */
    private static final String C_SELECT_RESOURCES_FOR_PRINCIPAL_ATTR2 = "C_SELECT_RESOURCES_FOR_PRINCIPAL_ATTR2";

    /** Query key. */
    private static final String C_SELECT_VFS_SIBLINGS = "C_SELECT_VFS_SIBLINGS";

    /** Query key. */
    private static final String C_STRUCTURE_DELETE_BY_STRUCTUREID = "C_STRUCTURE_DELETE_BY_STRUCTUREID";

    /** Query key. */
    private static final String C_STRUCTURE_SELECT_BY_DATE_EXPIRED_AFTER = "C_STRUCTURE_SELECT_BY_DATE_EXPIRED_AFTER";

    /** Query key. */
    private static final String C_STRUCTURE_SELECT_BY_DATE_EXPIRED_BEFORE = "C_STRUCTURE_SELECT_BY_DATE_EXPIRED_BEFORE";

    /** Query key. */
    private static final String C_STRUCTURE_SELECT_BY_DATE_RELEASED_AFTER = "C_STRUCTURE_SELECT_BY_DATE_RELEASED_AFTER";

    /** Query key. */
    private static final String C_STRUCTURE_SELECT_BY_DATE_RELEASED_BEFORE = "C_STRUCTURE_SELECT_BY_DATE_RELEASED_BEFORE";

    /** The log object for this class. */
    private static final Log LOG = CmsLog.getLog(org.opencms.db.jpa.CmsVfsDriver.class);

    /** The driver manager. */
    protected CmsDriverManager m_driverManager;

    /** 
     * This field is temporarily used to compute the versions during publishing.<p>
     * 
     * @see #publishVersions(CmsDbContext, CmsResource, boolean) 
     */
    protected List<CmsUUID> m_resOp = new ArrayList<CmsUUID>();

    /** The sql manager. */
    protected CmsSqlManager m_sqlManager;

    /**
     * Escapes the database wildcards within the resource path.<p>
     * 
     * This method is required to ensure chars in the resource path that have a special 
     * meaning in SQL (for example "_", which is the "any char" operator) are escaped.<p>
     * 
     * It will escape the following chars: 
     * <ul>
     * <li>"_" to "|_"</li>
     * </ul>
     * 
     * @param path the resource path
     * @return the escaped resource path
     */
    public static String escapeDbWildcard(String path) {

        return CmsStringUtil.substitute(path, "_", "|_");
    }

    /**
     * This method prepares the JPQL conditions for mapping entries for a given URL name mapping filter.<p>
     * 
     * @param filter the filter from which the JPQL conditions should be generated 
     * 
     * @return a pair consisting of an JPQL string and a list of the query parameters for the JPQL 
     */
    public static CmsPair<String, List<I_CmsQueryParameter>> prepareUrlNameMappingConditions(
            CmsUrlNameMappingFilter filter) {

        List<String> sqlConditions = new ArrayList<String>();
        List<I_CmsQueryParameter> parameters = new ArrayList<I_CmsQueryParameter>();
        if (filter.getName() != null) {
            sqlConditions.add("T_CmsDAO%(PROJECT)UrlNameMappings.m_name = ?");
            parameters.add(new CmsQueryStringParameter(filter.getName()));
        }

        if (filter.getStructureId() != null) {
            sqlConditions.add("T_CmsDAO%(PROJECT)UrlNameMappings.m_structureId = ?");
            parameters.add(new CmsQueryStringParameter(filter.getStructureId().toString()));
        }

        if (filter.getNamePattern() != null) {
            sqlConditions.add("T_CmsDAO%(PROJECT)UrlNameMappings.m_name LIKE ? ");
            parameters.add(new CmsQueryStringParameter(filter.getNamePattern()));
        }

        if (filter.getState() != null) {
            sqlConditions.add("T_CmsDAO%(PROJECT)UrlNameMappings.m_state = ?");
            parameters.add(new CmsQueryIntParameter(filter.getState().intValue()));
        }

        if (filter.getRejectStructureId() != null) {
            sqlConditions.add("T_CmsDAO%(PROJECT)UrlNameMappings.m_structureId <> ? ");
            parameters.add(new CmsQueryStringParameter(filter.getRejectStructureId().toString()));
        }

        if (filter.getLocale() != null) {
            sqlConditions.add("T_CmsDAO%(PROJECT)UrlNameMappings.m_locale = ? ");
            parameters.add(new CmsQueryStringParameter(filter.getLocale()));
        }

        String conditionString = CmsStringUtil.listAsString(sqlConditions, " AND ");
        return CmsPair.create(conditionString, parameters);
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#addUrlNameMappingEntry(org.opencms.db.CmsDbContext, boolean, org.opencms.db.urlname.CmsUrlNameMappingEntry)
     */
    public void addUrlNameMappingEntry(CmsDbContext dbc, boolean online, CmsUrlNameMappingEntry entry) {

        I_CmsDAOUrlNameMappings m = online ? new CmsDAOOnlineUrlNameMappings() : new CmsDAOOfflineUrlNameMappings();

        m.setName(entry.getName());
        m.setStructureId(entry.getStructureId().toString());
        m.setState(entry.getState());
        m.setDateChanged(entry.getDateChanged());
        m.setLocale(entry.getLocale());
        m_sqlManager.persist(dbc, m);

    }

    /**
     * Counts the number of siblings of a resource.<p>
     * 
     * @param dbc the current database context
     * @param projectId the current project id
     * @param resourceId the resource id to count the number of siblings from
     * 
     * @return number of siblings
     * @throws CmsDataAccessException if something goes wrong
     */
    public int countSiblings(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId)
            throws CmsDataAccessException {

        int count = 0;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_COUNT_SIBLINGS);
            q.setParameter(1, resourceId.toString());
            try {
                count = CmsDataTypeUtil.numberToInt((Number) q.getSingleResult());
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return count;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createContent(CmsDbContext, CmsUUID, CmsUUID, byte[])
     */
    public void createContent(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId, byte[] content)
            throws CmsDataAccessException {

        try {
            CmsDAOOfflineContents oc = new CmsDAOOfflineContents();

            oc.setResourceId(resourceId.toString());
            oc.setFileContent(content);

            m_sqlManager.persist(dbc, oc);
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * Creates a {@link CmsFile} instance from a jpa ResultSet.<p>
     * 
     * @param o the jpa ResultSet
     * @param projectId the project id
     * @param hasFileContentInResultSet flag to include the file content
     * 
     * @return the created file
     */
    public CmsFile createFile(Object[] o, CmsUUID projectId, boolean hasFileContentInResultSet) {

        I_CmsDAOResources r = (I_CmsDAOResources) o[0];
        I_CmsDAOStructure s = (I_CmsDAOStructure) o[1];
        String lockedInProjectParameter = (String) o[2];

        byte[] content = null;

        CmsUUID resProjectId = null;

        CmsUUID structureId = new CmsUUID(s.getStructureId());
        CmsUUID resourceId = new CmsUUID(r.getResourceId());
        String resourcePath = s.getResourcePath();
        int resourceType = r.getResourceType();
        int resourceFlags = r.getResourceFlags();
        int resourceState = r.getResourceState();
        int structureState = s.getStructureState();
        long dateCreated = r.getDateCreated();
        long dateLastModified = r.getDateLastModified();
        long dateReleased = s.getDateReleased();
        long dateExpired = s.getDateExpired();
        int resourceSize = r.getResourceSize();
        CmsUUID userCreated = new CmsUUID(r.getUserCreated());
        CmsUUID userLastModified = new CmsUUID(r.getUserLastModified());
        CmsUUID lockedInProject = new CmsUUID(lockedInProjectParameter);
        int siblingCount = r.getSiblingCount();
        long dateContent = r.getDateContent();
        int resourceVersion = r.getResourceVersion();
        int structureVersion = s.getStructureVersion();

        // in case of folder type ensure, that the root path has a trailing slash
        if (CmsFolder.isFolderType(resourceType)) {
            resourcePath = CmsFileUtil.addTrailingSeparator(resourcePath);
        }
        if (hasFileContentInResultSet) {
            //content = m_sqlManager.getBytes(res, m_sqlManager.readQuery("C_RESOURCES_FILE_CONTENT"));
            throw new RuntimeException(
                    "CCmsVfsDriver: public CmsFile createFile(Object[] o, CmsUUID projectId, boolean hasFileContentInResultSet) throws SQLException ");
        }
        resProjectId = lockedInProject;
        int newState = (structureState > resourceState) ? structureState : resourceState;

        return new CmsFile(structureId, resourceId, resourcePath, resourceType, resourceFlags, resProjectId,
                CmsResourceState.valueOf(newState), dateCreated, userCreated, dateLastModified, userLastModified,
                dateReleased, dateExpired, siblingCount, resourceSize, dateContent,
                resourceVersion + structureVersion, content);
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createFile(java.sql.ResultSet, org.opencms.util.CmsUUID)
     */
    public CmsFile createFile(ResultSet res, CmsUUID projectId) {

        LOG.error("This method is not implemented!");
        return null;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createFile(java.sql.ResultSet, org.opencms.util.CmsUUID, boolean)
     */
    public CmsFile createFile(ResultSet res, CmsUUID projectId, boolean hasFileContentInResultSet) {

        LOG.error("This method is not implemented!");
        return null;
    }

    /**
     * Creates a {@link CmsFolder} instance from a jpa ResultSet.<p>
     * 
     * @param o the JDBC ResultSet
     * @param projectId the ID of the current project
     * @param hasProjectIdInResultSet true if the SQL select query includes the PROJECT_ID table attribute
     * 
     * @return the created folder
     */
    public CmsFolder createFolder(Object[] o, CmsUUID projectId, boolean hasProjectIdInResultSet) {

        I_CmsDAOResources r = (I_CmsDAOResources) o[0];
        I_CmsDAOStructure s = (I_CmsDAOStructure) o[1];
        String lockedInProjectParameter = (String) o[2];

        CmsUUID structureId = new CmsUUID(s.getStructureId());
        CmsUUID resourceId = new CmsUUID(r.getResourceId());
        String resourcePath = s.getResourcePath();
        int resourceType = r.getResourceType();
        int resourceFlags = r.getResourceFlags();
        int resourceState = r.getResourceState();
        int structureState = s.getStructureState();
        long dateCreated = r.getDateCreated();
        long dateLastModified = r.getDateLastModified();
        long dateReleased = s.getDateReleased();
        long dateExpired = s.getDateExpired();
        CmsUUID userCreated = new CmsUUID(r.getUserCreated());
        CmsUUID userLastModified = new CmsUUID(r.getUserLastModified());
        CmsUUID resProjectId = new CmsUUID(lockedInProjectParameter);
        int resourceVersion = r.getResourceVersion();
        int structureVersion = s.getStructureVersion();
        int resourceSize = r.getResourceSize();

        // in case of folder type ensure, that the root path has a trailing slash
        if (CmsFolder.isFolderSize(resourceSize)) {
            resourcePath = CmsFileUtil.addTrailingSeparator(resourcePath);
        }

        int newState = (structureState > resourceState) ? structureState : resourceState;

        return new CmsFolder(structureId, resourceId, resourcePath, resourceType, resourceFlags, resProjectId,
                CmsResourceState.valueOf(newState), dateCreated, userCreated, dateLastModified, userLastModified,
                dateReleased, dateExpired, resourceVersion + structureVersion);
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createFolder(java.sql.ResultSet, org.opencms.util.CmsUUID, boolean)
     */
    public CmsFolder createFolder(ResultSet res, CmsUUID projectId, boolean hasProjectIdInResultSet) {

        LOG.error("This method is not implemented!");
        return null;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createOnlineContent(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, byte[], int, boolean, boolean)
     */
    public void createOnlineContent(CmsDbContext dbc, CmsUUID resourceId, byte[] contents, int publishTag,
            boolean keepOnline, boolean needToUpdateContent) throws CmsDataAccessException {

        try {
            boolean dbcHasProjectId = (dbc.getProjectId() != null) && !dbc.getProjectId().isNullUUID();

            if (needToUpdateContent || dbcHasProjectId) {
                if (dbcHasProjectId || !OpenCms.getSystemInfo().isHistoryEnabled()) {
                    // remove the online content for this resource id
                    Query q = m_sqlManager.createQuery(dbc, "C_ONLINE_CONTENTS_DELETE");
                    q.setParameter(1, resourceId.toString());
                    q.executeUpdate();
                } else {
                    // put the online content in the history, only if explicit requested
                    Query q = m_sqlManager.createQuery(dbc, "C_ONLINE_CONTENTS_HISTORY");
                    q.setParameter(1, resourceId.toString());
                    @SuppressWarnings("unchecked")
                    List<CmsDAOContents> res = q.getResultList();
                    for (CmsDAOContents c : res) {
                        c.setOnlineFlag(0);
                    }
                }

                // create new online content
                CmsDAOContents c = new CmsDAOContents();

                c.setResourceId(resourceId.toString());
                c.setFileContent(contents);
                c.setPublishTagFrom(publishTag);
                c.setPublishTagTo(publishTag);
                c.setOnlineFlag(keepOnline ? 1 : 0);

                m_sqlManager.persist(dbc, c);
            } else {
                // update old content entry
                Query q = m_sqlManager.createQuery(dbc, C_HISTORY_CONTENTS_UPDATE);
                q.setParameter(1, resourceId.toString());
                @SuppressWarnings("unchecked")
                List<CmsDAOContents> res = q.getResultList();
                for (CmsDAOContents c : res) {
                    c.setPublishTagTo(publishTag);
                }

                if (!keepOnline) {
                    // put the online content in the history 
                    q = m_sqlManager.createQuery(dbc, C_ONLINE_CONTENTS_HISTORY);
                    q.setParameter(1, resourceId.toString());
                    @SuppressWarnings("unchecked")
                    List<CmsDAOContents> res1 = q.getResultList();
                    for (CmsDAOContents c : res1) {
                        c.setOnlineFlag(0);
                    }
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createPropertyDefinition(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, java.lang.String, org.opencms.file.CmsPropertyDefinition.CmsPropertyType)
     */
    public CmsPropertyDefinition createPropertyDefinition(CmsDbContext dbc, CmsUUID projectId, String name,
            CmsPropertyDefinition.CmsPropertyType type) throws CmsDataAccessException {

        try {
            I_CmsDAOPropertyDef pd = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlinePropertyDef()
                    : new CmsDAOOfflinePropertyDef();

            pd.setPropertyDefId(new CmsUUID().toString());
            pd.setPropertyDefName(name);
            pd.setPropertyDefType(type.getMode());

            m_sqlManager.persist(dbc, pd);
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return readPropertyDefinition(dbc, name, projectId);
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createRelation(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.relations.CmsRelation)
     */
    public void createRelation(CmsDbContext dbc, CmsUUID projectId, CmsRelation relation)
            throws CmsDataAccessException {

        try {
            I_CmsDAOResourceRelations rr = CmsProject.isOnlineProject(projectId)
                    ? new CmsDAOOnlineResourceRelations()
                    : new CmsDAOOfflineResourceRelations();

            rr.setRelationSourceId(relation.getSourceId().toString());
            rr.setRelationSourcePath(relation.getSourcePath());
            rr.setRelationTargetId(relation.getTargetId().toString());
            rr.setRelationTargetPath(relation.getTargetPath());
            rr.setRelationType(relation.getType().getId());

            m_sqlManager.persist(dbc, rr);

            if (LOG.isDebugEnabled()) {
                LOG.debug(Messages.get().getBundle().key(Messages.LOG_CREATE_RELATION_2, String.valueOf(projectId),
                        relation));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createResource(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsResource, byte[])
     */
    public CmsResource createResource(CmsDbContext dbc, CmsUUID projectId, CmsResource resource, byte[] content)
            throws CmsDataAccessException {

        CmsUUID newStructureId = null;

        // check the resource path
        String resourcePath = CmsFileUtil.removeTrailingSeparator(resource.getRootPath());
        if (resourcePath.length() > CmsDriverManager.MAX_VFS_RESOURCE_PATH_LENGTH) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_RESOURCENAME_TOO_LONG_2,
                    resourcePath, new Integer(CmsDriverManager.MAX_VFS_RESOURCE_PATH_LENGTH)));
        }

        // check if the parent folder of the resource exists and if is not deleted
        if (!resource.getRootPath().equals("/")) {
            String parentFolderName = CmsResource.getParentFolder(resource.getRootPath());
            CmsFolder parentFolder = m_driverManager.getVfsDriver(dbc).readFolder(dbc, projectId, parentFolderName);
            if (parentFolder.getState().isDeleted()) {
                throw new CmsDbEntryNotFoundException(
                        Messages.get().container(Messages.ERR_PARENT_FOLDER_DELETED_1, resource.getRootPath()));
            }
        }

        // validate the resource length
        internalValidateResourceLength(resource);

        // set the resource state and modification dates
        CmsResourceState newState;
        long dateModified;
        long dateCreated;
        long dateContent = System.currentTimeMillis();

        if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
            newState = CmsResource.STATE_UNCHANGED;
            dateCreated = resource.getDateCreated();
            dateModified = resource.getDateLastModified();
        } else {
            newState = CmsResource.STATE_NEW;
            if (resource.isTouched()) {
                dateCreated = resource.getDateCreated();
                dateModified = resource.getDateLastModified();
            } else {
                dateCreated = System.currentTimeMillis();
                dateModified = dateCreated;
            }
        }

        // check if the resource already exists
        newStructureId = resource.getStructureId();

        try {
            CmsResource existingResource = m_driverManager.getVfsDriver().readResource(dbc,
                    dbc.getProjectId().isNullUUID() ? projectId : dbc.getProjectId(), resourcePath, true);
            if (existingResource.getState().isDeleted()) {
                // if an existing resource is deleted, it will be finally removed now.
                // but we have to reuse its id in order to avoid orphans in the online project
                newStructureId = existingResource.getStructureId();
                newState = CmsResource.STATE_CHANGED;

                // remove the existing file and it's properties
                List<CmsResource> modifiedResources = m_driverManager.getVfsDriver(dbc).readSiblings(dbc, projectId,
                        existingResource, false);
                int propertyDeleteOption = (existingResource.getSiblingCount() > 1)
                        ? CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_VALUES
                        : CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES;
                deletePropertyObjects(dbc, projectId, existingResource, propertyDeleteOption);
                removeFile(dbc, projectId, existingResource);

                OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCES_MODIFIED, Collections
                        .<String, Object>singletonMap(I_CmsEventListener.KEY_RESOURCES, modifiedResources)));
                OpenCms.fireCmsEvent(
                        new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections
                                .<String, Object>singletonMap(I_CmsEventListener.KEY_RESOURCE, existingResource)));
            } else {
                // we have a collision: there exists already a resource with the same path/name which cannot be removed
                throw new CmsVfsResourceAlreadyExistsException(
                        Messages.get().container(Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1,
                                dbc.removeSiteRoot(resource.getRootPath())));
            }
        } catch (CmsVfsResourceNotFoundException e) {
            // that's what we want in the best case- anything else should be thrown
        }

        try {
            // read the parent id
            String parentId = internalReadParentId(dbc, projectId, resourcePath);

            // use consistent version numbers if the file is being restored
            int lastVersion = m_driverManager.getHistoryDriver(dbc).readLastVersion(dbc, newStructureId);
            int newStrVersion = 0;
            int newResVersion = 0;
            if (lastVersion > 0) {
                I_CmsHistoryResource histRes = m_driverManager.getHistoryDriver(dbc).readResource(dbc,
                        newStructureId, lastVersion);
                newStrVersion = histRes.getStructureVersion();
                newResVersion = histRes.getResourceVersion();
            }

            // write the structure
            I_CmsDAOStructure s = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlineStructure()
                    : new CmsDAOOfflineStructure();

            s.setStructureId(newStructureId.toString());
            s.setResourceId(resource.getResourceId().toString());
            s.setResourcePath(resourcePath);
            s.setStructureState(newState.getState());
            s.setDateReleased(resource.getDateReleased());
            s.setDateExpired(resource.getDateExpired());
            s.setParentId(parentId);
            s.setStructureVersion(newStrVersion);

            m_sqlManager.persist(dbc, s);

            if (!validateResourceIdExists(dbc, projectId, resource.getResourceId())) {

                // create the resource record
                I_CmsDAOResources r = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlineResources()
                        : new CmsDAOOfflineResources();
                r.setResourceId(resource.getResourceId().toString());
                r.setResourceType(resource.getTypeId());
                r.setResourceFlags(resource.getFlags());
                r.setDateCreated(dateCreated);
                r.setUserCreated(resource.getUserCreated().toString());
                r.setDateLastModified(dateModified);
                r.setUserLastModified(resource.getUserLastModified().toString());
                r.setResourceState(newState.getState());
                r.setResourceSize(resource.getLength());
                r.setDateContent(dateContent);
                r.setProjectLastModified(projectId.toString());
                r.setSiblingCount(1);
                r.setResourceVersion(newResVersion);

                m_sqlManager.persist(dbc, r);

                if (resource.isFile() && (content != null)) {
                    // create the file content
                    createContent(dbc, projectId, resource.getResourceId(), content);
                }
            } else {
                if ((content != null) || !resource.getState().isKeep()) {
                    CmsUUID projLastMod = projectId;
                    CmsResourceState state = CmsResource.STATE_CHANGED;
                    if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
                        // in case a sibling is being published
                        projLastMod = resource.getProjectLastModified();
                        state = CmsResource.STATE_UNCHANGED;
                    }
                    // update the resource record only if state has changed or new content is provided
                    Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_RESOURCES);

                    q.setParameter(1, resource.getResourceId().toString());

                    @SuppressWarnings("unchecked")
                    List<I_CmsDAOResources> res = q.getResultList();
                    for (I_CmsDAOResources r : res) {
                        r.setResourceType(resource.getTypeId());
                        r.setResourceFlags(resource.getFlags());
                        r.setDateLastModified(dateModified);
                        r.setUserLastModified(resource.getUserLastModified().toString());
                        r.setResourceState(state.getState());
                        r.setResourceSize(resource.getLength());
                        r.setDateContent(resource.getDateContent());
                        r.setProjectLastModified(projLastMod.toString());
                        r.setSiblingCount(countSiblings(dbc, projectId, resource.getResourceId()));
                    }

                }

                if (resource.isFile()) {
                    if (content != null) {
                        // update the file content
                        writeContent(dbc, resource.getResourceId(), content);
                    } else if (resource.getState().isKeep()) {
                        // special case sibling creation - update the link Count
                        Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_SIBLING_COUNT);
                        q.setParameter(1, resource.getResourceId().toString());
                        @SuppressWarnings("unchecked")
                        List<I_CmsDAOResources> res = q.getResultList();

                        for (I_CmsDAOResources r : res) {
                            r.setSiblingCount(countSiblings(dbc, projectId, resource.getResourceId()));
                        }

                        // update the resource flags
                        q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_FLAGS);
                        q.setParameter(1, resource.getResourceId().toString());
                        @SuppressWarnings("unchecked")
                        List<I_CmsDAOResources> resf = q.getResultList();

                        for (I_CmsDAOResources r : resf) {
                            r.setResourceFlags(resource.getFlags());
                        }
                    }
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
        repairBrokenRelations(dbc, projectId, resource.getStructureId(), resource.getRootPath());
        return readResource(dbc, projectId, newStructureId, false);
    }

    /**
     * Creates a CmsResource instance from a jpa ResultSet.<p>
     * 
     * @param o the jpa ResultSet
     * @param projectId the ID of the current project to adjust the modification date in case the resource is a VFS link
     * 
     * @return the created resource
     */
    public CmsResource createResource(Object[] o, CmsUUID projectId) {

        I_CmsDAOResources r = (I_CmsDAOResources) o[0];
        I_CmsDAOStructure s = (I_CmsDAOStructure) o[1];

        CmsUUID structureId = new CmsUUID(s.getStructureId());
        CmsUUID resourceId = new CmsUUID(r.getResourceId());
        String resourcePath = s.getResourcePath();
        int resourceType = r.getResourceType();
        int resourceFlags = r.getResourceFlags();
        CmsUUID resourceProjectLastModified = new CmsUUID(r.getProjectLastModified());
        int resourceState = r.getResourceState();
        int structureState = s.getStructureState();
        long dateCreated = r.getDateCreated();
        long dateLastModified = r.getDateLastModified();
        long dateReleased = s.getDateReleased();
        long dateExpired = s.getDateExpired();
        int resourceSize = r.getResourceSize();
        boolean isFolder = CmsFolder.isFolderSize(resourceSize);
        if (isFolder) {
            // in case of folder type ensure, that the root path has a trailing slash
            resourcePath = CmsFileUtil.addTrailingSeparator(resourcePath);
        }
        long dateContent = isFolder ? -1 : r.getDateContent();
        CmsUUID userCreated = new CmsUUID(r.getUserCreated());
        CmsUUID userLastModified = new CmsUUID(r.getUserLastModified());
        int siblingCount = r.getSiblingCount();
        int resourceVersion = r.getResourceVersion();
        int structureVersion = s.getStructureVersion();

        int newState = (structureState > resourceState) ? structureState : resourceState;
        // if there is a change increase the version number
        int newVersion = resourceVersion + structureVersion + (newState > 0 ? 1 : 0);

        CmsResource newResource = new CmsResource(structureId, resourceId, resourcePath, resourceType, isFolder,
                resourceFlags, resourceProjectLastModified, CmsResourceState.valueOf(newState), dateCreated,
                userCreated, dateLastModified, userLastModified, dateReleased, dateExpired, siblingCount,
                resourceSize, dateContent, newVersion);

        return newResource;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createResource(java.sql.ResultSet, org.opencms.util.CmsUUID)
     */
    public CmsResource createResource(ResultSet res, CmsUUID projectId) {

        LOG.error("This method is not implemented!");
        return null;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#createSibling(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource)
     */
    public void createSibling(CmsDbContext dbc, CmsProject project, CmsResource resource)
            throws CmsDataAccessException {

        if (!project.getUuid().equals(CmsProject.ONLINE_PROJECT_ID)) {
            // this method is only intended to be used during publishing
            return;
        }

        // check if the resource already exists
        CmsResource existingSibling = null;
        CmsUUID newStructureId = resource.getStructureId();

        try {
            existingSibling = readResource(dbc, project.getUuid(), resource.getRootPath(), true);

            if (existingSibling.getState().isDeleted()) {
                // if an existing resource is deleted, it will be finally removed now.
                // but we have to reuse its id in order to avoid orphans in the online project.
                newStructureId = existingSibling.getStructureId();

                // remove the existing file and it's properties
                List<CmsResource> modifiedResources = readSiblings(dbc, project.getUuid(), existingSibling, false);
                int propertyDeleteOption = (existingSibling.getSiblingCount() > 1)
                        ? CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_VALUES
                        : CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES;
                deletePropertyObjects(dbc, project.getUuid(), existingSibling, propertyDeleteOption);
                removeFile(dbc, project.getUuid(), existingSibling);

                OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCES_MODIFIED, Collections
                        .<String, Object>singletonMap(I_CmsEventListener.KEY_RESOURCES, modifiedResources)));
                OpenCms.fireCmsEvent(
                        new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections
                                .<String, Object>singletonMap(I_CmsEventListener.KEY_RESOURCE, existingSibling)));
            } else {
                // we have a collision: there exists already a resource with the same path/name which could not be removed
                throw new CmsVfsResourceAlreadyExistsException(
                        Messages.get().container(Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1,
                                dbc.removeSiteRoot(resource.getRootPath())));
            }
        } catch (CmsVfsResourceNotFoundException e) {
            // that's what we want in the best case- anything else should be thrown
        }

        // check if a resource with the specified ID already exists
        if (!validateResourceIdExists(dbc, project.getUuid(), resource.getResourceId())) {
            throw new CmsVfsResourceNotFoundException(Messages.get().container(
                    Messages.ERR_CREATE_SIBLING_FILE_NOT_FOUND_1, dbc.removeSiteRoot(resource.getRootPath())));
        }

        // write a new structure referring to the resource
        try {
            // use consistent version numbers if the file is being restored
            int lastVersion = m_driverManager.getHistoryDriver(dbc).readLastVersion(dbc, newStructureId);
            int newStrVersion = 0;
            if (lastVersion > 0) {
                I_CmsHistoryResource histRes = m_driverManager.getHistoryDriver(dbc).readResource(dbc,
                        newStructureId, lastVersion);
                newStrVersion = histRes.getStructureVersion();
            }

            // read the parent id
            String parentId = internalReadParentId(dbc, project.getUuid(), resource.getRootPath());

            // write the structure
            I_CmsDAOStructure s = CmsProject.isOnlineProject(project.getUuid()) ? new CmsDAOOnlineStructure()
                    : new CmsDAOOfflineStructure();

            s.setStructureId(newStructureId.toString());
            s.setResourceId(resource.getResourceId().toString());
            s.setResourcePath(resource.getRootPath());
            s.setStructureState(CmsResource.STATE_UNCHANGED.getState());
            s.setDateReleased(resource.getDateReleased());
            s.setDateExpired(resource.getDateExpired());
            s.setParentId(parentId);
            s.setStructureVersion(newStrVersion);

            m_sqlManager.persist(dbc, s);

            // update the link Count
            Query q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_SIBLING_COUNT);
            q.setParameter(1, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResources> res = q.getResultList();

            for (I_CmsDAOResources r : res) {
                r.setSiblingCount(countSiblings(dbc, project.getUuid(), resource.getResourceId()));
            }

            // update the project last modified and flags
            q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_RESOURCE_PROJECT);
            q.setParameter(1, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResources> resr = q.getResultList();

            for (I_CmsDAOResources r : resr) {
                r.setResourceFlags(resource.getFlags());
                r.setProjectLastModified(resource.getProjectLastModified().toString());
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        repairBrokenRelations(dbc, project.getUuid(), resource.getStructureId(), resource.getRootPath());
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#deletePropertyDefinition(org.opencms.db.CmsDbContext, org.opencms.file.CmsPropertyDefinition)
     */
    public void deletePropertyDefinition(CmsDbContext dbc, CmsPropertyDefinition metadef)
            throws CmsDataAccessException {

        try {
            if ((internalCountProperties(dbc, metadef, CmsProject.ONLINE_PROJECT_ID) != 0)
                    || (internalCountProperties(dbc, metadef, CmsUUID.getOpenCmsUUID()) != 0)) { // HACK: to get an offline project

                throw new CmsDataAccessException(
                        Messages.get().container(Messages.ERR_DELETE_USED_PROPERTY_1, metadef.getName()));
            }
            Query q;
            for (int i = 0; i < 2; i++) {
                if (i == 0) {
                    // delete the offline property definition
                    q = m_sqlManager.createQuery(dbc, CmsUUID.getOpenCmsUUID(), C_PROPERTYDEF_DELETE); // HACK: to get an offline project
                } else {
                    // delete the online property definition
                    q = m_sqlManager.createQuery(dbc, CmsProject.ONLINE_PROJECT_ID, C_PROPERTYDEF_DELETE);
                }

                q.setParameter(1, metadef.getId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOPropertyDef> res = q.getResultList();
                for (I_CmsDAOPropertyDef pd : res) {
                    m_sqlManager.remove(dbc, pd);
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#deletePropertyObjects(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsResource, int)
     */
    public void deletePropertyObjects(CmsDbContext dbc, CmsUUID projectId, CmsResource resource, int deleteOption)
            throws CmsDataAccessException {

        try {
            Query q;

            if (deleteOption == CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES) {
                // delete both the structure and resource property values mapped to the specified resource
                q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_DELETE_ALL_STRUCTURE_AND_RESOURCE_VALUES);
                q.setParameter(1, resource.getResourceId().toString());
                q.setParameter(2, Integer.valueOf(CmsProperty.RESOURCE_RECORD_MAPPING));
                q.setParameter(3, String.valueOf(resource.getStructureId()));
                q.setParameter(4, Integer.valueOf(CmsProperty.STRUCTURE_RECORD_MAPPING));
            } else if (deleteOption == CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_VALUES) {
                // delete the structure values mapped to the specified resource
                q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_DELETE_ALL_VALUES_FOR_MAPPING_TYPE);
                q.setParameter(1, resource.getStructureId().toString());
                q.setParameter(2, Integer.valueOf(CmsProperty.STRUCTURE_RECORD_MAPPING));
            } else if (deleteOption == CmsProperty.DELETE_OPTION_DELETE_RESOURCE_VALUES) {
                // delete the resource property values mapped to the specified resource
                q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_DELETE_ALL_VALUES_FOR_MAPPING_TYPE);
                q.setParameter(1, resource.getResourceId().toString());
                q.setParameter(2, Integer.valueOf(CmsProperty.RESOURCE_RECORD_MAPPING));
            } else {
                throw new CmsDataAccessException(Messages.get().container(Messages.ERR_INVALID_DELETE_OPTION_1));
            }

            @SuppressWarnings("unchecked")
            List<I_CmsDAOProperties> res = q.getResultList();
            for (I_CmsDAOProperties p : res) {
                m_sqlManager.remove(dbc, p);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#deleteRelations(org.opencms.db.CmsDbContext, CmsUUID, CmsResource, org.opencms.relations.CmsRelationFilter)
     */
    public void deleteRelations(CmsDbContext dbc, CmsUUID projectId, CmsResource resource, CmsRelationFilter filter)
            throws CmsDataAccessException {

        try {
            if (filter.isSource()) {
                List params = new ArrayList(7);

                StringBuffer queryBuf = new StringBuffer(256);
                queryBuf.append(m_sqlManager.readQuery(projectId, C_DELETE_RELATIONS));
                queryBuf.append(prepareRelationConditions(projectId, filter, resource, params, true));

                Query q = m_sqlManager.createQueryFromJPQL(dbc, queryBuf.toString());
                for (int i = 0; i < params.size(); i++) {
                    q.setParameter(i + 1, params.get(i));
                }
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResourceRelations> res = q.getResultList();
                for (I_CmsDAOResourceRelations rr : res) {
                    m_sqlManager.remove(dbc, rr);
                }
            }
            if (filter.isTarget()) {
                List params = new ArrayList(7);

                StringBuffer queryBuf = new StringBuffer(256);
                queryBuf.append(m_sqlManager.readQuery(projectId, C_DELETE_RELATIONS));
                queryBuf.append(prepareRelationConditions(projectId, filter, resource, params, false));

                Query q = m_sqlManager.createQueryFromJPQL(dbc, queryBuf.toString());
                for (int i = 0; i < params.size(); i++) {
                    q.setParameter(i + 1, params.get(i));
                }

                @SuppressWarnings("unchecked")
                List<I_CmsDAOResourceRelations> res = q.getResultList();
                for (I_CmsDAOResourceRelations rr : res) {
                    m_sqlManager.remove(dbc, rr);
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
        // update broken remaining relations
        updateBrokenRelations(dbc, projectId, resource.getRootPath());
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#deleteUrlNameMappingEntries(org.opencms.db.CmsDbContext, boolean, org.opencms.db.urlname.CmsUrlNameMappingFilter)
     */
    public void deleteUrlNameMappingEntries(CmsDbContext dbc, boolean online, CmsUrlNameMappingFilter filter)
            throws CmsDataAccessException {

        try {
            String query = m_sqlManager.readQuery(C_DELETE_URLNAME_MAPPINGS);
            query = replaceProject(query, online);
            Query q = getQueryForFilter(dbc, query, filter, online);
            @SuppressWarnings("unchecked")
            List<I_CmsDAOUrlNameMappings> res = q.getResultList();

            for (I_CmsDAOUrlNameMappings m : res) {
                m_sqlManager.remove(dbc, m);
            }

        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#destroy()
     */
    public void destroy() throws Throwable {

        m_sqlManager = null;
        m_driverManager = null;

        if (CmsLog.INIT.isInfoEnabled()) {
            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_DRIVER_1, getClass().getName()));
        }
    }

    /**
     * Returns all organizational units for the given resource.<p>
     * 
     * @param dbc the database context
     * @param projectId the id of the project
     * @param resource the resource
     * 
     * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects
     * 
     * @throws CmsDataAccessException 
     */
    public List<CmsOrganizationalUnit> getResourceOus(CmsDbContext dbc, CmsUUID projectId, CmsResource resource)
            throws CmsDataAccessException {

        List<CmsOrganizationalUnit> ous = new ArrayList<CmsOrganizationalUnit>();
        String resName = resource.getRootPath();
        if (resource.isFolder() && !resName.endsWith("/")) {
            resName += "/";
        }

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_READ_RESOURCE_OUS);
            q.setParameter(1, Integer.valueOf(CmsRelationType.OU_RESOURCE.getId()));
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResourceRelations> res = internalResourceOus(q.getResultList(), resName);
            for (I_CmsDAOResourceRelations rr : res) {
                CmsRelation rel = internalReadRelation(rr);
                try {
                    ous.add(m_driverManager.readOrganizationalUnit(dbc,
                            rel.getSourcePath().substring(CmsUserDriver.ORGUNIT_BASE_FOLDER.length())));
                } catch (CmsException e) {
                    // should never happen
                    if (LOG.isErrorEnabled()) {
                        LOG.error(e.getLocalizedMessage(), e);
                    }
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
        return ous;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#getSqlManager()
     */
    public CmsSqlManager getSqlManager() {

        return m_sqlManager;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#incrementCounter(org.opencms.db.CmsDbContext, java.lang.String)
     */
    public int incrementCounter(CmsDbContext dbc, String name) {

        CmsDAOCounters c = m_sqlManager.find(dbc, CmsDAOCounters.class, name);
        int result = 0;

        if (c != null) {
            result = c.getCounter();
            c.setCounter(c.getCounter() + 1);
        } else {
            c = new CmsDAOCounters();
            c.setName(name);
            c.setCounter(1);
            m_sqlManager.persist(dbc, c);
        }

        return result;
    }

    /**
     * @see org.opencms.db.I_CmsDriver#init(org.opencms.db.CmsDbContext, org.opencms.configuration.CmsConfigurationManager, java.util.List, org.opencms.db.CmsDriverManager)
     */
    public void init(CmsDbContext dbc, CmsConfigurationManager configurationManager, List<String> successiveDrivers,
            CmsDriverManager driverManager) {

        CmsParameterConfiguration config = configurationManager.getConfiguration();

        String poolUrl = config.get("db.vfs.pool");
        String classname = config.get("db.vfs.sqlmanager");

        m_sqlManager = this.initSqlManager(classname);

        m_driverManager = driverManager;

        if (CmsLog.INIT.isInfoEnabled()) {
            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ASSIGNED_POOL_1, poolUrl));
        }

        if ((successiveDrivers != null) && !successiveDrivers.isEmpty()) {
            if (LOG.isWarnEnabled()) {
                LOG.warn(Messages.get().getBundle().key(Messages.LOG_SUCCESSIVE_DRIVERS_UNSUPPORTED_1,
                        getClass().getName()));
            }
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#initSqlManager(String)
     */
    public CmsSqlManager initSqlManager(String classname) {

        return CmsSqlManager.getInstance(classname);
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#moveResource(CmsDbContext, CmsUUID, CmsResource, String)
     */
    public void moveResource(CmsDbContext dbc, CmsUUID projectId, CmsResource source, String destinationPath)
            throws CmsDataAccessException {

        if ((dbc.getRequestContext() != null)
                && (dbc.getRequestContext().getAttribute(REQ_ATTR_CHECK_PERMISSIONS) != null)) {
            // only check write permissions
            checkWritePermissionsInFolder(dbc, source);
            return;
        }

        // determine destination folder        
        String destinationFoldername = CmsResource.getParentFolder(destinationPath);

        // read the destination folder (will also check read permissions)
        CmsFolder destinationFolder = m_driverManager.readFolder(dbc, destinationFoldername, CmsResourceFilter.ALL);

        if (!projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
            // check online resource
            try {
                CmsResource onlineResource = m_driverManager.getVfsDriver(dbc).readResource(dbc,
                        CmsProject.ONLINE_PROJECT_ID, destinationPath, true);

                if (!onlineResource.getStructureId().equals(source.getStructureId())) {
                    // source resource has been moved and it is not the 
                    // same as the resource that is being trying to move back
                    CmsResource offlineResource = null;
                    try {
                        // read new location in offline project
                        offlineResource = readResource(dbc, dbc.getRequestContext().getCurrentProject().getUuid(),
                                onlineResource.getStructureId(), true);
                    } catch (CmsException e) {
                        // should never happen
                        if (LOG.isErrorEnabled()) {
                            LOG.error(e.getMessage(), e);
                        }
                    }

                    throw new CmsVfsOnlineResourceAlreadyExistsException(Messages.get().container(
                            Messages.ERR_OVERWRITE_MOVED_RESOURCE_3, dbc.removeSiteRoot(source.getRootPath()),
                            dbc.removeSiteRoot(destinationPath), dbc.removeSiteRoot(
                                    offlineResource == null ? "__ERROR__" : offlineResource.getRootPath())));
                }
            } catch (CmsVfsResourceNotFoundException e) {
                // ok, no online resource
            }
        }

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_MOVE);
            q.setParameter(1, source.getStructureId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOStructure> res = q.getResultList();

            for (I_CmsDAOStructure s : res) {
                s.setResourcePath(CmsFileUtil.removeTrailingSeparator(destinationPath)); // must remove trailing slash
                s.setParentId(destinationFolder.getStructureId().toString());
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        moveRelations(dbc, projectId, source.getStructureId(), destinationPath);
        repairBrokenRelations(dbc, projectId, source.getStructureId(), destinationPath);
        try {
            m_driverManager.repairCategories(dbc, projectId, readResource(dbc, projectId, destinationPath, true));
        } catch (CmsException e) {
            throw new CmsDataAccessException(e.getMessageContainer(), e);
        }
        // repair project resources
        if (!projectId.equals(CmsProject.ONLINE_PROJECT_ID) && (dbc.getRequestContext() != null)) {
            String deletedResourceRootPath = source.getRootPath();
            dbc.getRequestContext().setAttribute(CmsProjectDriver.DBC_ATTR_READ_PROJECT_FOR_RESOURCE, Boolean.TRUE);
            I_CmsProjectDriver projectDriver = m_driverManager.getProjectDriver(dbc);
            Iterator<CmsProject> itProjects = projectDriver.readProjects(dbc, deletedResourceRootPath).iterator();
            while (itProjects.hasNext()) {
                CmsProject project = itProjects.next();
                projectDriver.deleteProjectResource(dbc, project.getUuid(), deletedResourceRootPath);
                projectDriver.createProjectResource(dbc, project.getUuid(), destinationPath);
            }
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#publishResource(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource, org.opencms.file.CmsResource)
     */
    public void publishResource(CmsDbContext dbc, CmsProject onlineProject, CmsResource onlineResource,
            CmsResource offlineResource) throws CmsDataAccessException {

        // validate the resource length
        internalValidateResourceLength(offlineResource);
        int resourceSize = offlineResource.getLength();

        String resourcePath = CmsFileUtil.removeTrailingSeparator(offlineResource.getRootPath());
        Query q;

        try {
            boolean resourceExists = validateResourceIdExists(dbc, onlineProject.getUuid(),
                    offlineResource.getResourceId());
            if (resourceExists) {
                // the resource record exists online already
                // update the online resource record
                q = m_sqlManager.createQuery(dbc, onlineProject, C_RESOURCES_UPDATE_RESOURCES);
                q.setParameter(1, offlineResource.getResourceId().toString());

                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res = q.getResultList();

                for (I_CmsDAOResources r : res) {
                    r.setResourceType(offlineResource.getTypeId());
                    r.setResourceFlags(offlineResource.getFlags());
                    r.setDateLastModified(offlineResource.getDateLastModified());
                    r.setUserLastModified(offlineResource.getUserLastModified().toString());
                    r.setResourceState(CmsResource.STATE_UNCHANGED.getState());
                    r.setResourceSize(resourceSize);
                    r.setDateContent(offlineResource.getDateContent());
                    r.setProjectLastModified(offlineResource.getProjectLastModified().toString());
                    r.setSiblingCount(countSiblings(dbc, onlineProject.getUuid(), onlineResource.getResourceId()));
                }
            } else {
                // the resource record does NOT exist online yet
                // create the resource record online
                I_CmsDAOResources r = CmsProject.isOnlineProject(onlineProject.getUuid())
                        ? new CmsDAOOnlineResources()
                        : new CmsDAOOfflineResources();

                r.setResourceId(offlineResource.getResourceId().toString());
                r.setResourceType(offlineResource.getTypeId());
                r.setResourceFlags(offlineResource.getFlags());
                r.setDateCreated(offlineResource.getDateCreated());
                r.setUserCreated(offlineResource.getUserCreated().toString());
                r.setDateLastModified(offlineResource.getDateLastModified());
                r.setUserLastModified(offlineResource.getUserLastModified().toString());
                r.setResourceState(CmsResource.STATE_UNCHANGED.getState());
                r.setResourceSize(resourceSize);
                r.setDateContent(offlineResource.getDateContent());
                r.setProjectLastModified(offlineResource.getProjectLastModified().toString());
                r.setSiblingCount(1); // initial siblings count
                r.setResourceVersion(1); // initial resource version

                m_sqlManager.persist(dbc, r);
            }

            // read the parent id
            String parentId = internalReadParentId(dbc, onlineProject.getUuid(), resourcePath);

            if (validateStructureIdExists(dbc, onlineProject.getUuid(), offlineResource.getStructureId())) {
                // update the online structure record
                q = m_sqlManager.createQuery(dbc, onlineProject, C_RESOURCES_UPDATE_STRUCTURE);
                q.setParameter(1, offlineResource.getStructureId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOStructure> res = q.getResultList();

                for (I_CmsDAOStructure s : res) {
                    s.setResourceId(offlineResource.getResourceId().toString());
                    s.setResourcePath(resourcePath);
                    s.setStructureState(CmsResource.STATE_UNCHANGED.getState());
                    s.setDateReleased(offlineResource.getDateReleased());
                    s.setDateExpired(offlineResource.getDateExpired());
                    s.setParentId(parentId);
                }
            } else {
                I_CmsDAOStructure s = CmsProject.isOnlineProject(onlineProject.getUuid())
                        ? new CmsDAOOnlineStructure()
                        : new CmsDAOOfflineStructure();

                s.setStructureId(offlineResource.getStructureId().toString());
                s.setResourceId(offlineResource.getResourceId().toString());
                s.setResourcePath(resourcePath);
                s.setStructureState(CmsResource.STATE_UNCHANGED.getState());
                s.setDateReleased(offlineResource.getDateReleased());
                s.setDateExpired(offlineResource.getDateExpired());
                s.setParentId(parentId);
                s.setStructureVersion(resourceExists ? 1 : 0); // new resources start with 0, new siblings with 1

                m_sqlManager.persist(dbc, s);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#publishVersions(org.opencms.db.CmsDbContext, org.opencms.file.CmsResource, boolean)
     */
    public void publishVersions(CmsDbContext dbc, CmsResource resource, boolean firstSibling)
            throws CmsDataAccessException {

        // if resource is null just flush the internal cache
        if (resource == null) {
            m_resOp.clear();
            return;
        }

        if (!dbc.getProjectId().isNullUUID() || dbc.currentProject().isOnlineProject()) {
            // this method is supposed to be used only in the offline project
            return;
        }

        if (firstSibling) {
            // reset the resource operation flag
            m_resOp.remove(resource.getResourceId());
        }

        boolean resOp = false; // assume structure operation

        CmsResourceState resState = internalReadResourceState(dbc, dbc.currentProject().getUuid(), resource);
        CmsResourceState strState = internalReadStructureState(dbc, dbc.currentProject().getUuid(), resource);

        if (!resState.isUnchanged()) {
            if (strState.isDeleted()) {
                resOp = (resState.isDeleted() || (resource.getSiblingCount() == 1)
                        || (countSiblings(dbc, dbc.currentProject().getUuid(), resource.getResourceId()) == 1));
            } else {
                resOp = true;
            }
        }

        if (!firstSibling) {
            if (resOp) {
                return;
            }
            if (m_resOp.contains(resource.getResourceId())) {
                return;
            }
        }

        // read the offline version numbers
        Map<String, Integer> versions = readVersions(dbc, dbc.currentProject().getUuid(), resource.getResourceId(),
                resource.getStructureId());
        int strVersion = versions.get("structure").intValue();
        int resVersion = versions.get("resource").intValue();

        if (resOp) {
            if (resource.getSiblingCount() > 1) {
                m_resOp.add(resource.getResourceId());
            }
            resVersion++;
        }
        if (!resOp) {
            strVersion++;
        }

        try {
            if (resOp) {
                // update the resource version
                Query q = m_sqlManager.createQuery(dbc, CmsProject.ONLINE_PROJECT_ID,
                        C_RESOURCES_UPDATE_RESOURCE_VERSION);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res = q.getResultList();

                for (I_CmsDAOResources r : res) {
                    r.setResourceVersion(resVersion);
                }
            }
            if (!resOp || strState.isNew()) {
                // update the structure version
                Query q = m_sqlManager.createQuery(dbc, CmsProject.ONLINE_PROJECT_ID,
                        C_RESOURCES_UPDATE_STRUCTURE_VERSION);
                q.setParameter(1, resource.getStructureId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOStructure> res = q.getResultList();

                for (I_CmsDAOStructure s : res) {
                    s.setStructureVersion(strVersion);
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readChildResources(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource, boolean, boolean)
     */
    public List<CmsResource> readChildResources(CmsDbContext dbc, CmsProject currentProject, CmsResource resource,
            boolean getFolders, boolean getFiles) throws CmsDataAccessException {

        List<CmsResource> result = new ArrayList<CmsResource>();
        CmsUUID projectId = currentProject.getUuid();

        String resourceTypeClause;
        if (getFolders && getFiles) {
            resourceTypeClause = null;
        } else if (getFolders) {
            resourceTypeClause = m_sqlManager.readQuery(projectId, C_RESOURCES_GET_SUBRESOURCES_GET_FOLDERS);
        } else {
            resourceTypeClause = m_sqlManager.readQuery(projectId, C_RESOURCES_GET_SUBRESOURCES_GET_FILES);
        }
        StringBuffer query = new StringBuffer();
        query.append(m_sqlManager.readQuery(projectId, C_RESOURCES_GET_SUBRESOURCES));
        if (resourceTypeClause != null) {
            query.append(' ');
            query.append(resourceTypeClause);
        }

        try {
            Query q = m_sqlManager.createQueryFromJPQL(dbc, query.toString());
            q.setParameter(1, resource.getStructureId().toString());
            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();
            I_CmsDAOResources r;
            for (Object[] o : res) {
                r = (I_CmsDAOResources) o[0];
                long size = r.getResourceSize();
                if (CmsFolder.isFolderSize(size)) {
                    result.add(createFolder(o, projectId, false));
                } else {
                    result.add(createFile(o, projectId, false));
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        // sort result in memory, this is to avoid DB dependencies in the result order
        Collections.sort(result, I_CmsResource.COMPARE_ROOT_PATH_IGNORE_CASE_FOLDERS_FIRST);
        return result;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readContent(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID)
     */
    public byte[] readContent(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId)
            throws CmsDataAccessException {

        byte[] byteRes = null;
        boolean resourceExists = false;

        try {
            if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
                // ONLINE PROJECT
                Query q = m_sqlManager.createQuery(dbc, projectId, C_ONLINE_FILES_CONTENT);
                q.setParameter(1, resourceId.toString());
                try {
                    byteRes = ((CmsDAOContents) q.getSingleResult()).getFileContent();
                    resourceExists = true;
                } catch (NoResultException e) {
                    // do nothing
                }
            } else {
                // OFFLINE PROJECT
                CmsDAOOfflineContents c = m_sqlManager.find(dbc, CmsDAOOfflineContents.class,
                        resourceId.toString());
                if (c != null) {
                    byteRes = c.getFileContent();
                    resourceExists = true;
                }

            }

            if (!resourceExists) {
                throw new CmsVfsResourceNotFoundException(
                        Messages.get().container(Messages.ERR_READ_CONTENT_WITH_RESOURCE_ID_2, resourceId,
                                Boolean.valueOf(projectId.equals(CmsProject.ONLINE_PROJECT_ID))));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return byteRes == null ? EMPTY_BLOB : byteRes;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readFolder(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID)
     */
    public CmsFolder readFolder(CmsDbContext dbc, CmsUUID projectId, CmsUUID folderId)
            throws CmsDataAccessException {

        CmsFolder folder = null;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READBYID);
            q.setParameter(1, folderId.toString());
            try {
                Object[] o = (Object[]) q.getSingleResult();
                folder = createFolder(o, projectId, true);
            } catch (NoResultException e) {
                throw new CmsVfsResourceNotFoundException(
                        Messages.get().container(Messages.ERR_READ_FOLDER_WITH_ID_1, folderId));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return folder;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readFolder(org.opencms.db.CmsDbContext, CmsUUID, java.lang.String)
     */
    public CmsFolder readFolder(CmsDbContext dbc, CmsUUID projectId, String folderPath)
            throws CmsDataAccessException {

        CmsFolder folder = null;

        folderPath = CmsFileUtil.removeTrailingSeparator(folderPath);
        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ);

            q.setParameter(1, folderPath);

            try {
                Object[] o = (Object[]) q.getSingleResult();
                folder = createFolder(o, projectId, true);
            } catch (NoResultException e) {
                throw new CmsVfsResourceNotFoundException(
                        Messages.get().container(Messages.ERR_READ_FOLDER_1, dbc.removeSiteRoot(folderPath)));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return folder;

    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readParentFolder(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID)
     */
    public CmsFolder readParentFolder(CmsDbContext dbc, CmsUUID projectId, CmsUUID structureId)
            throws CmsDataAccessException {

        CmsFolder parent = null;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ_PARENT_BY_ID);
            q.setParameter(1, structureId.toString());

            try {
                Object[] o = (Object[]) q.getSingleResult();
                parent = new CmsFolder(createResource(o, projectId));
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return parent;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readPropertyDefinition(org.opencms.db.CmsDbContext, java.lang.String, CmsUUID)
     */
    public CmsPropertyDefinition readPropertyDefinition(CmsDbContext dbc, String name, CmsUUID projectId)
            throws CmsDataAccessException {

        CmsPropertyDefinition propDef = null;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTYDEF_READ);
            q.setParameter(1, name);

            try {
                I_CmsDAOPropertyDef pd = (I_CmsDAOPropertyDef) q.getSingleResult();
                propDef = new CmsPropertyDefinition(new CmsUUID(pd.getPropertyDefId()), pd.getPropertyDefName(),
                        CmsPropertyDefinition.CmsPropertyType.valueOf(pd.getPropertyDefType()));
            } catch (NoResultException e) {
                throw new CmsDbEntryNotFoundException(
                        Messages.get().container(Messages.ERR_NO_PROPERTYDEF_WITH_NAME_1, name));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return propDef;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readPropertyDefinitions(org.opencms.db.CmsDbContext, CmsUUID)
     */
    public List<CmsPropertyDefinition> readPropertyDefinitions(CmsDbContext dbc, CmsUUID projectId)
            throws CmsDataAccessException {

        ArrayList<CmsPropertyDefinition> propertyDefinitions = new ArrayList<CmsPropertyDefinition>();

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTYDEF_READALL);

            @SuppressWarnings("unchecked")
            List<I_CmsDAOPropertyDef> res = q.getResultList();
            for (I_CmsDAOPropertyDef pd : res) {
                propertyDefinitions
                        .add(new CmsPropertyDefinition(new CmsUUID(pd.getPropertyDefId()), pd.getPropertyDefName(),
                                CmsPropertyDefinition.CmsPropertyType.valueOf(pd.getPropertyDefType())));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return propertyDefinitions;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readPropertyObject(org.opencms.db.CmsDbContext, java.lang.String, org.opencms.file.CmsProject, org.opencms.file.CmsResource)
     */
    public CmsProperty readPropertyObject(CmsDbContext dbc, String key, CmsProject project, CmsResource resource)
            throws CmsDataAccessException {

        CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) ? project.getUuid()
                : dbc.getProjectId();

        String propertyValue = null;
        int mappingType = -1;
        CmsProperty property = null;
        int resultSize = 0;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_READ);

            q.setParameter(1, key);
            q.setParameter(2, resource.getStructureId().toString());
            q.setParameter(3, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOProperties> res = q.getResultList();

            for (I_CmsDAOProperties o : res) {
                if (resultSize >= 2) {
                    throw new CmsDbConsistencyException(Messages.get().container(Messages.ERR_TOO_MANY_PROPERTIES_3,
                            key, resource.getRootPath(), new Integer(resultSize)));
                }

                if (property == null) {
                    property = new CmsProperty();
                    property.setName(key);
                }

                propertyValue = o.getPropertyValue();
                mappingType = o.getPropertyMappingType();

                if (mappingType == CmsProperty.STRUCTURE_RECORD_MAPPING) {
                    property.setStructureValue(propertyValue);
                } else if (mappingType == CmsProperty.RESOURCE_RECORD_MAPPING) {
                    property.setResourceValue(propertyValue);
                } else {
                    throw new CmsDbConsistencyException(
                            Messages.get().container(Messages.ERR_UNKNOWN_PROPERTY_VALUE_MAPPING_3,
                                    resource.getRootPath(), new Integer(mappingType), key));
                }

                resultSize++;
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return (property != null) ? property : CmsProperty.getNullProperty();
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readPropertyObjects(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource)
     */
    public List<CmsProperty> readPropertyObjects(CmsDbContext dbc, CmsProject project, CmsResource resource)
            throws CmsDataAccessException {

        CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) ? project.getUuid()
                : dbc.getProjectId();

        int mappingType = -1;
        Map<String, CmsProperty> propertyMap = new HashMap<String, CmsProperty>();

        String propertyKey;
        String propertyValue;
        CmsProperty property;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_READALL);
            q.setParameter(1, resource.getStructureId().toString());
            q.setParameter(2, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();

            for (Object[] o : res) {
                propertyKey = null;
                propertyValue = null;
                mappingType = -1;

                propertyKey = ((I_CmsDAOPropertyDef) o[0]).getPropertyDefName();
                propertyValue = ((I_CmsDAOProperties) o[1]).getPropertyValue();
                mappingType = ((I_CmsDAOProperties) o[1]).getPropertyMappingType();

                property = propertyMap.get(propertyKey);
                if (property == null) {
                    // there doesn't exist a property object for this key yet
                    property = new CmsProperty();
                    property.setName(propertyKey);
                    propertyMap.put(propertyKey, property);
                }

                if (mappingType == CmsProperty.STRUCTURE_RECORD_MAPPING) {
                    // this property value is mapped to a structure record
                    property.setStructureValue(propertyValue);
                } else if (mappingType == CmsProperty.RESOURCE_RECORD_MAPPING) {
                    // this property value is mapped to a resource record
                    property.setResourceValue(propertyValue);
                } else {
                    throw new CmsDbConsistencyException(
                            Messages.get().container(Messages.ERR_UNKNOWN_PROPERTY_VALUE_MAPPING_3,
                                    resource.getRootPath(), new Integer(mappingType), propertyKey));
                }
                property.setOrigin(resource.getRootPath());
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return new ArrayList<CmsProperty>(propertyMap.values());
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readRelations(org.opencms.db.CmsDbContext, CmsUUID, CmsResource, org.opencms.relations.CmsRelationFilter)
     */
    public List<CmsRelation> readRelations(CmsDbContext dbc, CmsUUID projectId, CmsResource resource,
            CmsRelationFilter filter) throws CmsDataAccessException {

        Set<CmsRelation> relations = new HashSet<CmsRelation>();

        try {
            if (filter.isSource()) {
                List<String> params = new ArrayList<String>(7);

                StringBuffer queryBuf = new StringBuffer(256);
                queryBuf.append(m_sqlManager.readQuery(projectId, C_READ_RELATIONS));
                queryBuf.append(prepareRelationConditions(projectId, filter, resource, params, true));
                if (LOG.isDebugEnabled()) {
                    LOG.debug(queryBuf.toString());
                }

                Query q = m_sqlManager.createQueryFromJPQL(dbc, queryBuf.toString());
                for (int i = 0; i < params.size(); i++) {
                    q.setParameter(i + 1, params.get(i));
                }
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResourceRelations> res = q.getResultList();
                for (I_CmsDAOResourceRelations rr : res) {
                    relations.add(internalReadRelation(rr));
                }
            }

            if (filter.isTarget()) {
                List<String> params = new ArrayList<String>(7);

                StringBuffer queryBuf = new StringBuffer(256);
                queryBuf.append(m_sqlManager.readQuery(projectId, C_READ_RELATIONS));
                queryBuf.append(prepareRelationConditions(projectId, filter, resource, params, false));
                if (LOG.isDebugEnabled()) {
                    LOG.debug(queryBuf.toString());
                }

                Query q = m_sqlManager.createQueryFromJPQL(dbc, queryBuf.toString());
                for (int i = 0; i < params.size(); i++) {
                    q.setParameter(i + 1, params.get(i));
                }
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResourceRelations> res = q.getResultList();
                for (I_CmsDAOResourceRelations rr : res) {
                    relations.add(internalReadRelation(rr));
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        List<CmsRelation> result = new ArrayList<CmsRelation>(relations);
        Collections.sort(result, CmsRelation.COMPARATOR);
        return result;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResource(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID, boolean)
     */
    public CmsResource readResource(CmsDbContext dbc, CmsUUID projectId, CmsUUID structureId,
            boolean includeDeleted) throws CmsDataAccessException {

        CmsResource resource = null;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READBYID);

            q.setParameter(1, structureId.toString());

            try {
                Object[] o = (Object[]) q.getSingleResult();
                resource = createResource(o, projectId);
            } catch (NoResultException e) {
                throw new CmsVfsResourceNotFoundException(
                        Messages.get().container(Messages.ERR_READ_RESOURCE_WITH_ID_1, structureId));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        // check if this resource is marked as deleted and if we are allowed to return a deleted resource
        if ((resource != null) && resource.getState().isDeleted() && !includeDeleted) {
            throw new CmsVfsResourceNotFoundException(Messages.get().container(Messages.ERR_READ_DELETED_RESOURCE_1,
                    dbc.removeSiteRoot(resource.getRootPath())));
        }

        return resource;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResource(org.opencms.db.CmsDbContext, CmsUUID, java.lang.String, boolean)
     */
    public CmsResource readResource(CmsDbContext dbc, CmsUUID projectId, String path, boolean includeDeleted)
            throws CmsDataAccessException {

        CmsResource resource = null;

        // must remove trailing slash
        path = CmsFileUtil.removeTrailingSeparator(path);
        boolean endsWithSlash = path.endsWith("/");

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ);

            q.setParameter(1, path);

            try {
                Object[] o = (Object[]) q.getSingleResult();
                resource = createResource(o, projectId);

                // check if the resource is a file, it is not allowed to end with a "/" then
                if (endsWithSlash && resource.isFile()) {
                    throw new CmsVfsResourceNotFoundException(
                            Messages.get().container(Messages.ERR_READ_RESOURCE_1, dbc.removeSiteRoot(path + "/")));
                }
            } catch (NoResultException e) {
                throw new CmsVfsResourceNotFoundException(
                        Messages.get().container(Messages.ERR_READ_RESOURCE_1, dbc.removeSiteRoot(path)));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        // check if this resource is marked as deleted and if we are allowed to return a deleted resource
        if ((resource != null) && resource.getState().isDeleted() && !includeDeleted) {
            throw new CmsVfsResourceNotFoundException(Messages.get().container(Messages.ERR_READ_DELETED_RESOURCE_1,
                    dbc.removeSiteRoot(resource.getRootPath())));
        }

        return resource;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResources(org.opencms.db.CmsDbContext, CmsUUID, CmsResourceState, int)
     */
    public List<CmsResource> readResources(CmsDbContext dbc, CmsUUID projectId, CmsResourceState state, int mode)
            throws CmsDataAccessException {

        List<CmsResource> result = new ArrayList<CmsResource>();
        Query q;

        try {
            if (mode == CmsDriverManager.READMODE_MATCHSTATE) {
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_GET_RESOURCE_IN_PROJECT_WITH_STATE);

                q.setParameter(1, projectId.toString());
                q.setParameter(2, Integer.valueOf(state.getState()));
                q.setParameter(3, Integer.valueOf(state.getState()));
                q.setParameter(4, Integer.valueOf(state.getState()));
                q.setParameter(5, Integer.valueOf(state.getState()));
            } else if (mode == CmsDriverManager.READMODE_UNMATCHSTATE) {
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_GET_RESOURCE_IN_PROJECT_WITHOUT_STATE);
                q.setParameter(1, projectId.toString());
                q.setParameter(2, Integer.valueOf(state.getState()));
                q.setParameter(3, Integer.valueOf(state.getState()));
            } else {
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_GET_RESOURCE_IN_PROJECT_IGNORE_STATE);
                q.setParameter(1, projectId.toString());
            }

            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();
            for (Object[] o : res) {
                CmsResource resource = createResource(o, projectId);
                result.add(resource);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return result;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResourcesForPrincipalACE(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID)
     */
    public List<CmsResource> readResourcesForPrincipalACE(CmsDbContext dbc, CmsProject project, CmsUUID principalId)
            throws CmsDataAccessException {

        CmsResource currentResource = null;
        List<CmsResource> resources = new ArrayList<CmsResource>();

        try {
            Query q = m_sqlManager.createQuery(dbc, project, C_SELECT_RESOURCES_FOR_PRINCIPAL_ACE);

            q.setParameter(1, principalId.toString());
            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();

            for (Object[] o : res) {
                currentResource = createFile(o, project.getUuid(), false);
                resources.add(currentResource);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return resources;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResourcesForPrincipalAttr(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID)
     */
    public List<CmsResource> readResourcesForPrincipalAttr(CmsDbContext dbc, CmsProject project,
            CmsUUID principalId) throws CmsDataAccessException {

        CmsResource currentResource = null;
        List<CmsResource> resources = new ArrayList<CmsResource>();

        try {
            // JPQL does not support UNION clause
            String[] queries = { C_SELECT_RESOURCES_FOR_PRINCIPAL_ATTR1, C_SELECT_RESOURCES_FOR_PRINCIPAL_ATTR2 };
            String[] parameters = { principalId.toString(), principalId.toString() };
            Query q;

            for (int i = 0; i < queries.length; i++) {
                q = m_sqlManager.createQuery(dbc, project, queries[i]);
                q.setParameter(1, parameters[i]);
                @SuppressWarnings("unchecked")
                List<Object[]> res = q.getResultList();
                for (Object[] o : res) {
                    currentResource = createFile(o, project.getUuid(), false);
                    resources.add(currentResource);
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return resources;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResourcesWithProperty(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID, String, String)
     */
    public List<CmsResource> readResourcesWithProperty(CmsDbContext dbc, CmsUUID projectId, CmsUUID propertyDef,
            String path, String value) throws CmsDataAccessException {

        List<CmsResource> resources = new ArrayList<CmsResource>();
        Query q;
        List<Object[]> res = new ArrayList<Object[]>();
        try {
            if (value == null) {
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_GET_RESOURCE_WITH_PROPERTYDEF);
                q.setParameter(1, propertyDef.toString());
                q.setParameter(2, escapeDbWildcard(path + "%"));
                res.addAll(q.getResultList());
            } else {
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_GET_RESOURCE_WITH_PROPERTYDEF_VALUE);
                q.setParameter(1, propertyDef.toString());
                q.setParameter(2, escapeDbWildcard(path + "%"));
                q.setParameter(3, "%" + value + "%");
                q.setParameter(4, escapeDbWildcard(path + "%"));
                q.setParameter(5, "%" + value + "%");
                res.addAll(q.getResultList());
            }

            for (Object[] o : res) {
                CmsResource resource = createResource(o, projectId);
                resources.add(resource);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return resources;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readResourceTree(org.opencms.db.CmsDbContext, CmsUUID, java.lang.String, int, CmsResourceState, long, long, long, long, long, long, int)
     */
    public List<CmsResource> readResourceTree(CmsDbContext dbc, CmsUUID projectId, String parentPath, int type,
            CmsResourceState state, long lastModifiedAfter, long lastModifiedBefore, long releasedAfter,
            long releasedBefore, long expiredAfter, long expiredBefore, int mode) throws CmsDataAccessException {

        List<CmsResource> result = new ArrayList<CmsResource>();

        StringBuffer conditions = new StringBuffer();
        List params = new ArrayList(5);

        // prepare the selection criteria
        prepareProjectCondition(projectId, mode, conditions, params);
        prepareResourceCondition(projectId, mode, conditions);
        prepareTypeCondition(projectId, type, mode, conditions, params);
        prepareTimeRangeCondition(projectId, lastModifiedAfter, lastModifiedBefore, conditions, params);
        prepareReleasedTimeRangeCondition(projectId, releasedAfter, releasedBefore, conditions, params);
        prepareExpiredTimeRangeCondition(projectId, expiredAfter, expiredBefore, conditions, params);
        preparePathCondition(projectId, parentPath, mode, conditions, params);
        prepareStateCondition(projectId, state, mode, conditions, params);

        // now read matching resources within the subtree 

        try {
            StringBuffer queryBuf = new StringBuffer(256);
            queryBuf.append(m_sqlManager.readQuery(projectId, C_RESOURCES_READ_TREE));
            queryBuf.append(conditions);
            queryBuf.append(" ");
            queryBuf.append(m_sqlManager.readQuery(projectId, C_RESOURCES_ORDER_BY_PATH));
            Query q = m_sqlManager.createQueryFromJPQL(dbc, queryBuf.toString());
            for (int i = 0; i < params.size(); i++) {
                q.setParameter(i + 1, params.get(i));
            }

            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();
            for (Object[] o : res) {
                CmsResource resource = createResource(o, projectId);
                result.add(resource);
            }

        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return result;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readSiblings(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsResource, boolean)
     */
    public List<CmsResource> readSiblings(CmsDbContext dbc, CmsUUID projectId, CmsResource resource,
            boolean includeDeleted) throws CmsDataAccessException {

        CmsResource currentResource = null;
        List<CmsResource> vfsLinks = new ArrayList<CmsResource>();
        Query q;

        try {
            if (includeDeleted) {
                q = m_sqlManager.createQuery(dbc, projectId, C_SELECT_VFS_SIBLINGS);
            } else {
                q = m_sqlManager.createQuery(dbc, projectId, C_SELECT_NONDELETED_VFS_SIBLINGS);
            }

            q.setParameter(1, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();

            for (Object[] o : res) {
                currentResource = createFile(o, projectId, false);
                vfsLinks.add(currentResource);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return vfsLinks;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readUrlNameMappingEntries(org.opencms.db.CmsDbContext, boolean, org.opencms.db.urlname.CmsUrlNameMappingFilter)
     */
    public List<CmsUrlNameMappingEntry> readUrlNameMappingEntries(CmsDbContext dbc, boolean online,
            CmsUrlNameMappingFilter filter) throws CmsDataAccessException {

        List<CmsUrlNameMappingEntry> result = new ArrayList<CmsUrlNameMappingEntry>();
        try {
            String query = m_sqlManager.readQuery(C_READ_URLNAME_MAPPINGS);
            Query q = getQueryForFilter(dbc, query, filter, online);
            @SuppressWarnings("unchecked")
            List<I_CmsDAOUrlNameMappings> res = q.getResultList();
            for (I_CmsDAOUrlNameMappings m : res) {
                CmsUrlNameMappingEntry entry = internalCreateUrlNameMappingEntry(m);
                result.add(entry);
            }
            return result;
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#readVersions(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
     */
    public Map<String, Integer> readVersions(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId,
            CmsUUID structureId) throws CmsDataAccessException {

        int structureVersion = -1;
        int resourceVersion = -1;
        Query q;

        try {
            // read the offline version numbers, first for the resource entry
            q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ_VERSION_RES);
            q.setParameter(1, resourceId.toString());
            try {
                resourceVersion = CmsDataTypeUtil.numberToInt((Number) q.getSingleResult());
            } catch (NoResultException e) {
                // do nothing
            }

            // then for the structure entry
            q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ_VERSION_STR);
            q.setParameter(1, structureId.toString());

            try {
                structureVersion = CmsDataTypeUtil.numberToInt((Number) q.getSingleResult());
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        Map<String, Integer> result = new HashMap<String, Integer>();
        result.put("structure", new Integer(structureVersion));
        result.put(I_CmsEventListener.KEY_RESOURCE, new Integer(resourceVersion));
        return result;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#removeFile(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsResource)
     */
    public void removeFile(CmsDbContext dbc, CmsUUID projectId, CmsResource resource)
            throws CmsDataAccessException {

        int siblingCount = 0;

        try {
            // delete the structure record
            Query q = m_sqlManager.createQuery(dbc, projectId, C_STRUCTURE_DELETE_BY_STRUCTUREID);
            q.setParameter(1, resource.getStructureId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOStructure> res = q.getResultList();
            for (I_CmsDAOStructure ps : res) {
                m_sqlManager.remove(dbc, ps);
            }

            // count the references to the resource
            siblingCount = countSiblings(dbc, projectId, resource.getResourceId());

            if (siblingCount > 0) {
                // update the link Count
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_SIBLING_COUNT);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> ress = q.getResultList();

                for (I_CmsDAOResources r : ress) {
                    r.setSiblingCount(siblingCount);
                }

                // update the resource flags
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_FLAGS);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> resf = q.getResultList();

                for (I_CmsDAOResources r : resf) {
                    r.setResourceFlags(resource.getFlags());
                }

            } else {
                // if not referenced any longer, also delete the resource and the content record
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_DELETE_BY_RESOURCEID);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res1 = q.getResultList();
                for (I_CmsDAOResources pr : res1) {
                    m_sqlManager.remove(dbc, pr);
                }

                boolean dbcHasProjectId = (dbc.getProjectId() != null) && !dbc.getProjectId().isNullUUID();

                // if online we have to keep historical content
                if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
                    // put the online content in the history 
                    q = m_sqlManager.createQuery(dbc, C_ONLINE_CONTENTS_HISTORY);
                    q.setParameter(1, resource.getResourceId().toString());
                    @SuppressWarnings("unchecked")
                    List<CmsDAOContents> res2 = q.getResultList();
                    for (CmsDAOContents c : res2) {
                        c.setOnlineFlag(0);
                    }
                } else if (dbcHasProjectId) {
                    // remove current online version
                    q = m_sqlManager.createQuery(dbc, C_ONLINE_CONTENTS_DELETE);
                    q.setParameter(1, resource.getResourceId().toString());
                    q.executeUpdate();
                } else {
                    // delete content records with this resource id
                    q = m_sqlManager.createQuery(dbc, C_OFFLINE_FILE_CONTENT_DELETE);
                    q.setParameter(1, resource.getResourceId().toString());
                    q.executeUpdate();
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#removeFolder(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource)
     */
    public void removeFolder(CmsDbContext dbc, CmsProject currentProject, CmsResource resource)
            throws CmsDataAccessException {

        if ((dbc.getRequestContext() != null)
                && (dbc.getRequestContext().getAttribute(REQ_ATTR_CHECK_PERMISSIONS) != null)) {
            // only check write permissions
            checkWritePermissionsInFolder(dbc, resource);
            return;
        }

        // check if the folder has any resources in it
        Iterator<CmsResource> childResources = readChildResources(dbc, currentProject, resource, true, true)
                .iterator();

        CmsUUID projectId = CmsProject.ONLINE_PROJECT_ID;
        if (currentProject.isOnlineProject()) {
            projectId = CmsUUID.getOpenCmsUUID(); // HACK: to get an offline project id
        }

        // collect the names of the resources inside the folder, excluding the moved resources
        StringBuffer errorResNames = new StringBuffer(128);
        while (childResources.hasNext()) {
            CmsResource errorRes = childResources.next();
            // if deleting offline, or not moved, or just renamed inside the deleted folder
            // so, it may remain some orphan online entries for moved resources
            // which will be fixed during the publishing of the moved resources
            boolean error = !currentProject.isOnlineProject();
            if (!error) {
                try {
                    String originalPath = m_driverManager.getVfsDriver()
                            .readResource(dbc, projectId, errorRes.getRootPath(), true).getRootPath();
                    error = originalPath.equals(errorRes.getRootPath())
                            || originalPath.startsWith(resource.getRootPath());
                } catch (CmsVfsResourceNotFoundException e) {
                    // ignore
                }
            }
            if (error) {
                if (errorResNames.length() != 0) {
                    errorResNames.append(", ");
                }
                errorResNames.append("[" + dbc.removeSiteRoot(errorRes.getRootPath()) + "]");
            }
        }

        // the current implementation only deletes empty folders
        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(errorResNames.toString())) {

            throw new CmsVfsException(Messages.get().container(Messages.ERR_DELETE_NONEMTY_FOLDER_2,
                    dbc.removeSiteRoot(resource.getRootPath()), errorResNames.toString()));
        }
        internalRemoveFolder(dbc, currentProject, resource);

        // remove project resources
        String deletedResourceRootPath = resource.getRootPath();
        if (dbc.getRequestContext() != null) {
            dbc.getRequestContext().setAttribute(CmsProjectDriver.DBC_ATTR_READ_PROJECT_FOR_RESOURCE, Boolean.TRUE);
            I_CmsProjectDriver projectDriver = m_driverManager.getProjectDriver(dbc);
            Iterator<CmsProject> itProjects = projectDriver.readProjects(dbc, deletedResourceRootPath).iterator();
            while (itProjects.hasNext()) {
                CmsProject project = itProjects.next();
                projectDriver.deleteProjectResource(dbc, project.getUuid(), deletedResourceRootPath);
            }
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#replaceResource(org.opencms.db.CmsDbContext, org.opencms.file.CmsResource, byte[], int)
     */
    public void replaceResource(CmsDbContext dbc, CmsResource newResource, byte[] resContent, int newResourceType)
            throws CmsDataAccessException {

        if (resContent == null) {
            // nothing to do
            return;
        }

        try {
            // write the file content
            writeContent(dbc, newResource.getResourceId(), resContent);

            // update the resource record
            Query q = m_sqlManager.createQuery(dbc, dbc.currentProject(), C_RESOURCE_REPLACE);
            q.setParameter(1, newResource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResources> res = q.getResultList();

            for (I_CmsDAOResources r : res) {
                r.setResourceType(newResourceType);
                r.setResourceSize(resContent.length);
                r.setDateContent(System.currentTimeMillis());
            }

        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#setDriverManager(org.opencms.db.CmsDriverManager)
     */
    public void setDriverManager(CmsDriverManager driverManager) {

        m_driverManager = driverManager;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#setSqlManager(org.opencms.db.CmsSqlManager)
     */
    public void setSqlManager(org.opencms.db.CmsSqlManager sqlManager) {

        m_sqlManager = (CmsSqlManager) sqlManager;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#transferResource(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
     */
    public void transferResource(CmsDbContext dbc, CmsProject project, CmsResource resource, CmsUUID createdUser,
            CmsUUID lastModifiedUser) throws CmsDataAccessException {

        if (createdUser == null) {
            createdUser = resource.getUserCreated();
        }
        if (lastModifiedUser == null) {
            lastModifiedUser = resource.getUserLastModified();
        }

        try {
            Query q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_TRANSFER_RESOURCE);
            q.setParameter(1, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResources> res = q.getResultList();

            for (I_CmsDAOResources r : res) {
                r.setUserCreated(createdUser.toString());
                r.setUserLastModified(lastModifiedUser.toString());
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#updateRelations(CmsDbContext, CmsProject, CmsResource)
     */
    public void updateRelations(CmsDbContext dbc, CmsProject onlineProject, CmsResource offlineResource)
            throws CmsDataAccessException {

        // delete online relations
        I_CmsVfsDriver vfsDriver = m_driverManager.getVfsDriver(dbc);
        vfsDriver.deleteRelations(dbc, onlineProject.getUuid(), offlineResource, CmsRelationFilter.TARGETS);

        CmsUUID projectId;
        if (!dbc.getProjectId().isNullUUID()) {
            projectId = CmsProject.ONLINE_PROJECT_ID;
        } else {
            projectId = dbc.currentProject().getUuid();
        }

        // copy offline to online relations
        CmsUUID dbcProjectId = dbc.getProjectId();
        dbc.setProjectId(CmsUUID.getNullUUID());
        Iterator<CmsRelation> itRelations = m_driverManager.getVfsDriver(dbc)
                .readRelations(dbc, projectId, offlineResource, CmsRelationFilter.TARGETS).iterator();
        dbc.setProjectId(dbcProjectId);
        while (itRelations.hasNext()) {
            vfsDriver.createRelation(dbc, onlineProject.getUuid(), itRelations.next());
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#validateResourceIdExists(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID)
     */
    public boolean validateResourceIdExists(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId)
            throws CmsDataAccessException {

        boolean exists = false;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ_RESOURCE_STATE);
            q.setParameter(1, resourceId.toString());

            try {
                @SuppressWarnings("unused")
                int state = CmsDataTypeUtil.numberToInt((Number) q.getSingleResult());
                exists = true;
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return exists;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#validateStructureIdExists(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID)
     */
    public boolean validateStructureIdExists(CmsDbContext dbc, CmsUUID projectId, CmsUUID structureId)
            throws CmsDataAccessException {

        boolean found = false;
        int count = 0;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_SELECT_STRUCTURE_ID);
            q.setParameter(1, structureId.toString());

            try {
                count = CmsDataTypeUtil.numberToInt((Number) q.getSingleResult());
                found = (count == 1);
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return found;
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#writeContent(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, byte[])
     */
    public void writeContent(CmsDbContext dbc, CmsUUID resourceId, byte[] content) throws CmsDataAccessException {

        try {
            Query q = m_sqlManager.createQuery(dbc, dbc.currentProject(), C_OFFLINE_CONTENTS_UPDATE);
            // update the file content in the database.
            q.setParameter(1, resourceId.toString());
            @SuppressWarnings("unchecked")
            List<CmsDAOOfflineContents> res = q.getResultList();

            for (CmsDAOOfflineContents oc : res) {
                oc.setFileContent(content);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#writeLastModifiedProjectId(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, CmsUUID, org.opencms.file.CmsResource)
     */
    public void writeLastModifiedProjectId(CmsDbContext dbc, CmsProject project, CmsUUID projectId,
            CmsResource resource) throws CmsDataAccessException {

        try {
            Query q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_PROJECT_LASTMODIFIED);
            q.setParameter(1, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResources> res = q.getResultList();

            for (I_CmsDAOResources r : res) {
                r.setProjectLastModified(projectId.toString());
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#writePropertyObject(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource, org.opencms.file.CmsProperty)
     */
    public void writePropertyObject(CmsDbContext dbc, CmsProject project, CmsResource resource,
            CmsProperty property) throws CmsDataAccessException {

        CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) ? project.getUuid()
                : dbc.getProjectId();

        // TODO: check if we need autocreation for link property definition types too
        CmsPropertyDefinition propertyDefinition = null;
        try {
            // read the property definition
            propertyDefinition = readPropertyDefinition(dbc, property.getName(), projectId);
        } catch (CmsDbEntryNotFoundException e) {
            if (property.autoCreatePropertyDefinition()) {
                propertyDefinition = createPropertyDefinition(dbc, projectId, property.getName(),
                        CmsPropertyDefinition.TYPE_NORMAL);
                try {
                    readPropertyDefinition(dbc, property.getName(), CmsProject.ONLINE_PROJECT_ID);
                } catch (CmsDataAccessException e1) {
                    createPropertyDefinition(dbc, CmsProject.ONLINE_PROJECT_ID, property.getName(),
                            CmsPropertyDefinition.TYPE_NORMAL);
                }
                try {
                    m_driverManager.getHistoryDriver(dbc).readPropertyDefinition(dbc, property.getName());
                } catch (CmsDataAccessException e1) {
                    m_driverManager.getHistoryDriver(dbc).createPropertyDefinition(dbc, property.getName(),
                            CmsPropertyDefinition.TYPE_NORMAL);
                }
                OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_PROPERTY_DEFINITION_CREATED,
                        Collections.<String, Object>singletonMap("propertyDefinition", propertyDefinition)));
            } else {
                throw new CmsDbEntryNotFoundException(
                        Messages.get().container(Messages.ERR_NO_PROPERTYDEF_WITH_NAME_1, property.getName()));
            }
        }

        try {
            // read the existing property to test if we need the 
            // insert or update query to write a property value
            CmsProperty existingProperty = readPropertyObject(dbc, propertyDefinition.getName(), project, resource);

            if (existingProperty.isIdentical(property)) {
                // property already has the identical values set, no write required
                return;
            }

            for (int i = 0; i < 2; i++) {
                int mappingType = -1;
                String value = null;
                CmsUUID id = null;
                boolean existsPropertyValue = false;
                boolean deletePropertyValue = false;

                // 1) take any required decisions to choose and fill the correct SQL query

                if (i == 0) {
                    // write/delete the *structure value* on the first cycle
                    if ((existingProperty.getStructureValue() != null) && property.isDeleteStructureValue()) {
                        // this property value is marked to be deleted
                        deletePropertyValue = true;
                    } else {
                        value = property.getStructureValue();
                        if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) {
                            // no structure value set or the structure value is an empty string, 
                            // continue with the resource value
                            continue;
                        }
                    }

                    // set the vars to be written to the database
                    mappingType = CmsProperty.STRUCTURE_RECORD_MAPPING;
                    id = resource.getStructureId();
                    existsPropertyValue = existingProperty.getStructureValue() != null;
                } else {
                    // write/delete the *resource value* on the second cycle
                    if ((existingProperty.getResourceValue() != null) && property.isDeleteResourceValue()) {
                        // this property value is marked to be deleted
                        deletePropertyValue = true;
                    } else {
                        value = property.getResourceValue();
                        if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) {
                            // no resource value set or the resource value is an empty string,
                            // break out of the loop
                            break;
                        }
                    }

                    // set the vars to be written to the database
                    mappingType = CmsProperty.RESOURCE_RECORD_MAPPING;
                    id = resource.getResourceId();
                    existsPropertyValue = existingProperty.getResourceValue() != null;
                }

                // 2) execute the SQL query
                Query q;
                if (!deletePropertyValue) {
                    // insert/update the property value                    
                    if (existsPropertyValue) {
                        // {structure|resource} property value already exists- use update statement
                        q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_UPDATE);
                        q.setParameter(1, id.toString());
                        q.setParameter(2, Integer.valueOf(mappingType));
                        q.setParameter(3, propertyDefinition.getId().toString());
                        @SuppressWarnings("unchecked")
                        List<I_CmsDAOProperties> res = q.getResultList();

                        for (I_CmsDAOProperties p : res) {
                            p.setPropertyValue(m_sqlManager.validateEmpty(value));
                        }
                    } else {
                        // {structure|resource} property value doesn't exist- use create statement
                        I_CmsDAOProperties p = CmsProject.isOnlineProject(project.getUuid())
                                ? new CmsDAOOnlineProperties()
                                : new CmsDAOOfflineProperties();

                        p.setPropertyId(new CmsUUID().toString());
                        p.setPropertyDefId(propertyDefinition.getId().toString());
                        p.setPropertyMappingId(id.toString());
                        p.setPropertyMappingType(mappingType);
                        p.setPropertyValue(m_sqlManager.validateEmpty(value));

                        m_sqlManager.persist(dbc, p);
                    }
                } else {
                    // {structure|resource} property value marked as deleted- use delete statement
                    q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_DELETE);
                    q.setParameter(1, propertyDefinition.getId().toString());
                    q.setParameter(2, id.toString());
                    q.setParameter(3, Integer.valueOf(mappingType));
                    @SuppressWarnings("unchecked")
                    List<I_CmsDAOProperties> res = q.getResultList();
                    for (I_CmsDAOProperties pr : res) {
                        m_sqlManager.remove(dbc, pr);
                    }
                }
            }

        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#writePropertyObjects(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource, java.util.List)
     */
    public void writePropertyObjects(CmsDbContext dbc, CmsProject project, CmsResource resource,
            List<CmsProperty> properties) throws CmsDataAccessException {

        for (CmsProperty property : properties) {
            writePropertyObject(dbc, project, resource, property);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#writeResource(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsResource, int)
     */
    public void writeResource(CmsDbContext dbc, CmsUUID projectId, CmsResource resource, int changed)
            throws CmsDataAccessException {

        // validate the resource length
        internalValidateResourceLength(resource);

        String resourcePath = CmsFileUtil.removeTrailingSeparator(resource.getRootPath());

        // this task is split into two statements because some DBs (e.g. Oracle) doesn't support multi-table updates

        long resourceDateModified;

        if (resource.isTouched()) {
            resourceDateModified = resource.getDateLastModified();
        } else {
            resourceDateModified = System.currentTimeMillis();
        }

        CmsResourceState structureState = resource.getState();
        CmsResourceState resourceState = resource.getState();
        CmsResourceState structureStateOld = internalReadStructureState(dbc, projectId, resource);
        CmsResourceState resourceStateOld = internalReadResourceState(dbc, projectId, resource);
        CmsUUID projectLastModified = projectId;

        if (changed == CmsDriverManager.UPDATE_RESOURCE_STATE) {
            resourceState = resourceStateOld;
            resourceState = (resourceState.isNew() ? CmsResource.STATE_NEW : CmsResource.STATE_CHANGED);
            structureState = structureStateOld;
        } else if (changed == CmsDriverManager.UPDATE_STRUCTURE_STATE) {
            structureState = structureStateOld;
            structureState = (structureState.isNew() ? CmsResource.STATE_NEW : CmsResource.STATE_CHANGED);
        } else if (changed == CmsDriverManager.NOTHING_CHANGED) {
            projectLastModified = resource.getProjectLastModified();
        } else {
            resourceState = resourceStateOld;
            resourceState = (resourceState.isNew() ? CmsResource.STATE_NEW : CmsResource.STATE_CHANGED);
            structureState = structureStateOld;
            structureState = (structureState.isNew() ? CmsResource.STATE_NEW : CmsResource.STATE_CHANGED);
        }

        try {
            Query q;
            if (changed != CmsDriverManager.UPDATE_STRUCTURE_STATE) {
                // if the resource was unchanged
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_RESOURCES);
                q.setParameter(1, resource.getResourceId().toString());

                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res = q.getResultList();

                for (I_CmsDAOResources r : res) {
                    r.setResourceType(resource.getTypeId());
                    r.setResourceFlags(resource.getFlags());
                    r.setDateLastModified(resourceDateModified);
                    r.setUserLastModified(resource.getUserLastModified().toString());
                    r.setResourceState(resourceState.getState());
                    r.setResourceSize(resource.getLength());
                    r.setDateContent(resource.getDateContent());
                    r.setProjectLastModified(projectLastModified.toString());
                    r.setSiblingCount(countSiblings(dbc, projectId, resource.getResourceId()));
                }
            } else {
                q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_RESOURCES_WITHOUT_STATE);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res = q.getResultList();

                for (I_CmsDAOResources r : res) {
                    r.setResourceType(resource.getTypeId());
                    r.setResourceFlags(resource.getFlags());
                    r.setDateLastModified(resourceDateModified);
                    r.setUserLastModified(resource.getUserLastModified().toString());
                    r.setResourceSize(resource.getLength());
                    r.setDateContent(resource.getDateContent());
                    r.setProjectLastModified(projectLastModified.toString());
                    r.setSiblingCount(countSiblings(dbc, projectId, resource.getResourceId()));
                }
            }

            // read the parent id
            String parentId = internalReadParentId(dbc, projectId, resourcePath);

            // update the structure
            q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_UPDATE_STRUCTURE);
            q.setParameter(1, resource.getStructureId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOStructure> res = q.getResultList();

            for (I_CmsDAOStructure s : res) {
                s.setResourceId(resource.getResourceId().toString());
                s.setResourcePath(resourcePath);
                s.setStructureState(structureState.getState());
                s.setDateReleased(resource.getDateReleased());
                s.setDateExpired(resource.getDateExpired());
                s.setParentId(parentId);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * @see org.opencms.db.I_CmsVfsDriver#writeResourceState(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsResource, int, boolean)
     */
    public void writeResourceState(CmsDbContext dbc, CmsProject project, CmsResource resource, int changed,
            boolean isPublishing) throws CmsDataAccessException {

        if (project.getUuid().equals(CmsProject.ONLINE_PROJECT_ID)) {
            return;
        }

        try {
            Query q;

            if (changed == CmsDriverManager.UPDATE_RESOURCE_PROJECT) {
                q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_RESOURCE_PROJECT);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> resr = q.getResultList();

                for (I_CmsDAOResources r : resr) {
                    r.setResourceFlags(resource.getFlags());
                    r.setProjectLastModified(project.getUuid().toString());
                }
            }

            if (changed == CmsDriverManager.UPDATE_RESOURCE) {
                q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_RESOURCE_STATELASTMODIFIED);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res = q.getResultList();

                for (I_CmsDAOResources r : res) {
                    r.setResourceState(resource.getState().getState());
                    r.setDateLastModified(resource.getDateLastModified());
                    r.setUserLastModified(resource.getUserLastModified().toString());
                    r.setProjectLastModified(project.getUuid().toString());
                }
            }

            if ((changed == CmsDriverManager.UPDATE_RESOURCE_STATE) || (changed == CmsDriverManager.UPDATE_ALL)) {
                q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_RESOURCE_STATE);
                q.setParameter(1, resource.getResourceId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOResources> res = q.getResultList();

                for (I_CmsDAOResources r : res) {
                    r.setResourceState(resource.getState().getState());
                    r.setProjectLastModified(project.getUuid().toString());
                }
            }

            if ((changed == CmsDriverManager.UPDATE_STRUCTURE) || (changed == CmsDriverManager.UPDATE_ALL)
                    || (changed == CmsDriverManager.UPDATE_STRUCTURE_STATE)) {
                q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_STRUCTURE_STATE);
                q.setParameter(1, resource.getStructureId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOStructure> res = q.getResultList();

                for (I_CmsDAOStructure s : res) {
                    s.setStructureState(resource.getState().getState());
                }
            }

            if ((changed == CmsDriverManager.UPDATE_STRUCTURE) || (changed == CmsDriverManager.UPDATE_ALL)) {
                q = m_sqlManager.createQuery(dbc, project, C_RESOURCES_UPDATE_RELEASE_EXPIRED);
                q.setParameter(1, resource.getStructureId().toString());
                @SuppressWarnings("unchecked")
                List<I_CmsDAOStructure> res = q.getResultList();

                for (I_CmsDAOStructure s : res) {
                    s.setDateReleased(resource.getDateReleased());
                    s.setDateExpired(resource.getDateExpired());
                }
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        if (isPublishing) {
            internalUpdateVersions(dbc, resource);
        }
    }

    /**
     * Checks that the current user has write permissions for all subresources of the given folder.<p>
     * 
     * @param dbc the current database context
     * @param folder the folder to check
     * 
     * @throws CmsDataAccessException if something goes wrong 
     */
    protected void checkWritePermissionsInFolder(CmsDbContext dbc, CmsResource folder)
            throws CmsDataAccessException {

        CmsUUID projectId = dbc.getRequestContext().getCurrentProject().getUuid();

        // first read all subresources with ACEs
        List<CmsResource> resources = new ArrayList<CmsResource>();
        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ_WITH_ACE_1);
            q.setParameter(1, escapeDbWildcard(folder.getRootPath() + "%"));

            @SuppressWarnings("unchecked")
            List<Object[]> res = q.getResultList();

            for (Object[] o : res) {
                resources.add(createResource(o, projectId));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        // check current user write permission for each of these resources
        Iterator<CmsResource> itResources = resources.iterator();
        while (itResources.hasNext()) {
            CmsResource resource = itResources.next();
            try {
                m_driverManager.getSecurityManager().checkPermissions(dbc.getRequestContext(), resource,
                        CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
            } catch (CmsException e) {
                throw new CmsDataAccessException(e.getMessageContainer(), e);
            }
        }

        // then check for possible jsp pages without permissions
        CmsResourceFilter filter = CmsResourceFilter.ALL;
        itResources = readTypesInResourceTree(dbc, projectId, folder.getRootPath(),
                CmsResourceTypeJsp.getJspResourceTypeIds(), filter.getState(), filter.getModifiedAfter(),
                filter.getModifiedBefore(), filter.getReleaseAfter(), filter.getReleaseBefore(),
                filter.getExpireAfter(), filter.getExpireBefore(), CmsDriverManager.READMODE_INCLUDE_TREE)
                        .iterator();
        while (itResources.hasNext()) {
            CmsResource resource = itResources.next();
            try {
                m_driverManager.getSecurityManager().checkPermissions(dbc.getRequestContext(), resource,
                        CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
            } catch (CmsException e) {
                throw new CmsDataAccessException(e.getMessageContainer(), e);
            }
        }
    }

    /**
     * Returns the count of properties for a property definition.<p>
     * 
     * @param dbc the current database context
     * @param propertyDefinition the property definition to test
     * @param projectId the ID of the current project
     * 
     * @return the amount of properties for a property definition
     * @throws CmsDataAccessException if something goes wrong
     */
    protected int internalCountProperties(CmsDbContext dbc, CmsPropertyDefinition propertyDefinition,
            CmsUUID projectId) throws CmsDataAccessException {

        int count = 0;

        try {
            // create statement
            Query q = m_sqlManager.createQuery(dbc, projectId, C_PROPERTIES_READALL_COUNT);
            q.setParameter(1, propertyDefinition.getId().toString());

            try {
                count = CmsDataTypeUtil.numberToInt((Number) q.getSingleResult());
            } catch (NoResultException e) {
                throw new CmsDbConsistencyException(
                        Messages.get().container(Messages.ERR_COUNTING_PROPERTIES_1, propertyDefinition.getName()));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return count;
    }

    /**
     * Creates an URL name mapping entry from a result set.<p>
     * 
     * @param m a I_CmsDAOUrlNameMappings 
     * @return the URL name mapping entry created from the result set 
     * 
     */
    protected CmsUrlNameMappingEntry internalCreateUrlNameMappingEntry(I_CmsDAOUrlNameMappings m) {

        String name = m.getName();
        CmsUUID structureId = new CmsUUID(m.getStructureId());
        int state = m.getState();
        long dateChanged = m.getDateChanged();
        String locale = m.getLocale();
        return new CmsUrlNameMappingEntry(name, structureId, state, dateChanged, locale);
    }

    /**
     * Returns the parent id of the given resource.<p>
     * 
     * @param dbc the current database context
     * @param projectId the current project id 
     * @param resourcename the resource name to read the parent id for
     * 
     * @return  the parent id of the given resource
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected String internalReadParentId(CmsDbContext dbc, CmsUUID projectId, String resourcename)
            throws CmsDataAccessException {

        if ("/".equalsIgnoreCase(resourcename)) {
            return CmsUUID.getNullUUID().toString();
        }

        String parent = CmsResource.getParentFolder(resourcename);
        parent = CmsFileUtil.removeTrailingSeparator(parent);

        String parentId = null;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RESOURCES_READ_PARENT_STRUCTURE_ID);
            q.setParameter(1, parent);

            try {
                parentId = (String) q.getSingleResult();
            } catch (NoResultException e) {
                throw new CmsVfsResourceNotFoundException(
                        Messages.get().container(Messages.ERR_READ_PARENT_ID_1, dbc.removeSiteRoot(resourcename)));
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return parentId;
    }

    /**
     * Creates a new {@link CmsRelation} object from the given result set entry.<p>
     * 
     * @param rr the resource relation 
     *  
     * @return the new {@link CmsRelation} object
     */
    protected CmsRelation internalReadRelation(I_CmsDAOResourceRelations rr) {

        CmsUUID sourceId = new CmsUUID(rr.getRelationSourceId());
        String sourcePath = rr.getRelationSourcePath();
        CmsUUID targetId = new CmsUUID(rr.getRelationTargetId());
        String targetPath = rr.getRelationTargetPath();
        int type = rr.getRelationType();
        return new CmsRelation(sourceId, sourcePath, targetId, targetPath, CmsRelationType.valueOf(type));
    }

    /**
     * Returns the resource state of the given resource.<p>
     * 
     * @param dbc the database context
     * @param projectId the id of the project
     * @param resource the resource to read the resource state for
     * 
     * @return the resource state of the given resource
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected CmsResourceState internalReadResourceState(CmsDbContext dbc, CmsUUID projectId, CmsResource resource)
            throws CmsDataAccessException {

        CmsResourceState state = CmsResource.STATE_KEEP;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_READ_RESOURCE_STATE);
            q.setParameter(1, resource.getResourceId().toString());

            try {
                state = CmsResourceState.valueOf(CmsDataTypeUtil.numberToInt((Number) q.getSingleResult()));
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return state;
    }

    /**
     * Returns the structure state of the given resource.<p>
     * 
     * @param dbc the database context
     * @param projectId the id of the project
     * @param resource the resource to read the structure state for
     * 
     * @return the structure state of the given resource
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected CmsResourceState internalReadStructureState(CmsDbContext dbc, CmsUUID projectId, CmsResource resource)
            throws CmsDataAccessException {

        CmsResourceState state = CmsResource.STATE_KEEP;

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_READ_STRUCTURE_STATE);
            q.setParameter(1, resource.getStructureId().toString());

            try {
                state = CmsResourceState.valueOf(CmsDataTypeUtil.numberToInt((Number) q.getSingleResult()));
            } catch (NoResultException e) {
                // do nothing
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }

        return state;
    }

    /**
     * Removes a resource physically in the database.<p>
     * 
     * @param dbc the current database context
     * @param currentProject the current project
     * @param resource the folder to remove
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected void internalRemoveFolder(CmsDbContext dbc, CmsProject currentProject, CmsResource resource)
            throws CmsDataAccessException {

        try {
            // delete the structure record            
            Query q = m_sqlManager.createQuery(dbc, currentProject, C_STRUCTURE_DELETE_BY_STRUCTUREID);
            q.setParameter(1, resource.getStructureId().toString());
            I_CmsDAOStructure s = (I_CmsDAOStructure) q.getSingleResult();
            m_sqlManager.remove(dbc, s);

            // delete the resource record
            q = m_sqlManager.createQuery(dbc, currentProject, C_RESOURCES_DELETE_BY_RESOURCEID);
            q.setParameter(1, resource.getResourceId().toString());
            I_CmsDAOResources r = (I_CmsDAOResources) q.getSingleResult();
            m_sqlManager.remove(dbc, r);
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * Postprocess C_READ_RESOURCE_OUS query, because some databases 
     * do not support indexOf function.
     * 
     * @param set - result of C_READ_RESOURCE_OUS query
     * @param resName - string for comparison
     * 
     * @return - the result of original C_READ_RESOURCE_OUS query
     */
    protected List<I_CmsDAOResourceRelations> internalResourceOus(List<I_CmsDAOResourceRelations> set,
            String resName) {

        List<I_CmsDAOResourceRelations> result = new ArrayList<I_CmsDAOResourceRelations>();

        if (resName == null) {
            return result;
        }

        for (I_CmsDAOResourceRelations rr : set) {
            if ((rr.getRelationTargetPath() != null) && (resName.indexOf(rr.getRelationTargetPath()) != -1)) {
                result.add(rr);
            }
        }

        return result;
    }

    /**
     * Updates the offline version numbers.<p>
     *  
     * @param dbc the current database context
     * @param resource the resource to update the version number for
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected void internalUpdateVersions(CmsDbContext dbc, CmsResource resource) throws CmsDataAccessException {

        if (dbc.getRequestContext() == null) {
            // no needed during initialization 
            return;
        }
        if (dbc.currentProject().isOnlineProject()) {
            // this method is supposed to be used only in the offline project
            return;
        }

        // read the online version numbers
        Map<String, Integer> onlineVersions = readVersions(dbc, CmsProject.ONLINE_PROJECT_ID,
                resource.getResourceId(), resource.getStructureId());
        int onlineStructureVersion = onlineVersions.get("structure").intValue();
        int onlineResourceVersion = onlineVersions.get("resource").intValue();

        try {
            // update the resource version
            Query q = m_sqlManager.createQuery(dbc, dbc.currentProject(), C_RESOURCES_UPDATE_RESOURCE_VERSION);
            q.setParameter(1, resource.getResourceId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResources> res = q.getResultList();

            for (I_CmsDAOResources r : res) {
                r.setResourceVersion(onlineResourceVersion);
            }

            // update the structure version
            q = m_sqlManager.createQuery(dbc, dbc.currentProject(), C_RESOURCES_UPDATE_STRUCTURE_VERSION);
            q.setParameter(1, resource.getStructureId().toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOStructure> ress = q.getResultList();

            for (I_CmsDAOStructure s : ress) {
                s.setStructureVersion(onlineStructureVersion);
            }

        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * Validates that the length setting of a resource is always correct.<p>
     * 
     * Files need to have a resource length of >= 0, while folders require
     * a resource length of -1.<p>
     * 
     * @param resource the resource to check the length for
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected void internalValidateResourceLength(CmsResource resource) throws CmsDataAccessException {

        if (resource.isFolder() && (resource.getLength() == -1)) {
            return;
        }

        if (resource.isFile() && (resource.getLength() >= 0)) {
            return;
        }

        throw new CmsDataAccessException(Messages.get().container(Messages.ERR_INVALID_RESOURCE_LENGTH_2,
                new Integer(resource.getLength()), resource.getRootPath()));
    }

    /**
     * Moves all relations of a resource to the new path.<p>
     * 
     * @param dbc the current database context
     * @param projectId the id of the project to apply the changes 
     * @param structureId the structure id of the resource to apply the changes to
     * @param rootPath the new root path
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected void moveRelations(CmsDbContext dbc, CmsUUID projectId, CmsUUID structureId, String rootPath)
            throws CmsDataAccessException {

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_MOVE_RELATIONS_SOURCE);
            q.setParameter(1, structureId.toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResourceRelations> res = q.getResultList();
            I_CmsDAOResourceRelations newR;
            for (I_CmsDAOResourceRelations rr : res) {
                newR = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlineResourceRelations()
                        : new CmsDAOOfflineResourceRelations();

                newR.setRelationSourceId(rr.getRelationSourceId());
                newR.setRelationSourcePath(rootPath);
                newR.setRelationTargetId(rr.getRelationTargetId());
                newR.setRelationTargetPath(rr.getRelationTargetPath());
                newR.setRelationType(rr.getRelationType());

                m_sqlManager.remove(dbc, rr);
                m_sqlManager.persist(dbc, newR);
            }

            q = m_sqlManager.createQuery(dbc, projectId, C_MOVE_RELATIONS_TARGET);
            q.setParameter(1, structureId.toString());
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResourceRelations> res1 = q.getResultList();
            for (I_CmsDAOResourceRelations rr : res1) {
                newR = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlineResourceRelations()
                        : new CmsDAOOfflineResourceRelations();

                newR.setRelationSourceId(rr.getRelationSourceId());
                newR.setRelationSourcePath(rr.getRelationSourcePath());
                newR.setRelationTargetId(rr.getRelationTargetId());
                newR.setRelationTargetPath(rootPath);
                newR.setRelationType(rr.getRelationType());

                m_sqlManager.remove(dbc, rr);
                m_sqlManager.persist(dbc, newR);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * Appends the appropriate selection criteria related with the expiration date.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param startTime the start time
     * @param endTime the end time
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareExpiredTimeRangeCondition(CmsUUID projectId, long startTime, long endTime,
            StringBuffer conditions, List params) {

        if (startTime > 0L) {
            // READ_IGNORE_TIME: if NOT set, add condition to match expired date against startTime
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_STRUCTURE_SELECT_BY_DATE_EXPIRED_AFTER));
            conditions.append(END_CONDITION);
            params.add(Long.valueOf(startTime));
        }

        if (endTime > 0L) {
            // READ_IGNORE_TIME: if NOT set, add condition to match expired date against endTime
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_STRUCTURE_SELECT_BY_DATE_EXPIRED_BEFORE));
            conditions.append(END_CONDITION);
            params.add(Long.valueOf(endTime));
        }
    }

    /**
     * Appends the appropriate selection criteria related with the parentPath.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param parent the parent path or UUID (if mode is C_READMODE_EXCLUDE_TREE)
     * @param mode the selection mode
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void preparePathCondition(CmsUUID projectId, String parent, int mode, StringBuffer conditions,
            List params) {

        if (parent == CmsDriverManager.READ_IGNORE_PARENT) {
            // parent can be ignored
            return;
        }

        if ((mode & CmsDriverManager.READMODE_EXCLUDE_TREE) > 0) {
            // only return immediate children - use UUID optimization            
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_PARENT_UUID));
            conditions.append(END_CONDITION);
            params.add(parent);
            return;
        }

        if ("/".equalsIgnoreCase(parent)) {
            // if root folder is parent, no additional condition is needed since all resources match anyway
            return;
        }

        // add condition to read path subtree        
        conditions.append(BEGIN_INCLUDE_CONDITION);
        conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_PATH_PREFIX));
        conditions.append(END_CONDITION);
        params.add(CmsFileUtil.addTrailingSeparator(escapeDbWildcard(parent)) + "%");
    }

    /**
     * Appends the appropriate selection criteria related with the projectId.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param mode the selection mode
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareProjectCondition(CmsUUID projectId, int mode, StringBuffer conditions, List params) {

        if ((mode & CmsDriverManager.READMODE_INCLUDE_PROJECT) > 0) {
            // C_READMODE_INCLUDE_PROJECT: add condition to match the PROJECT_ID
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_PROJECT_LASTMODIFIED));
            conditions.append(END_CONDITION);
            params.add(String.valueOf(projectId));
        }
    }

    /**
     * Build the whole WHERE sql statement part for the given relation filter.<p>
     * 
     * @param projectId the current project id
     * @param filter the filter
     * @param resource the resource (may be null, if you want to delete all relations for the resource in the filter)
     * @param params the parameter values (return parameter)
     * @param checkSource if the query is for the source relations 
     * 
     * @return the WHERE sql statement part string
     */
    protected String prepareRelationConditions(CmsUUID projectId, CmsRelationFilter filter, CmsResource resource,
            List params, boolean checkSource) {

        StringBuffer conditions = new StringBuffer(128);
        params.clear(); // be sure the parameters list is clear

        // source or target filter
        if (filter.isSource() || filter.isTarget()) {
            // source or target id filter from resource
            if (resource != null) {
                conditions.append(BEGIN_CONDITION);
                if (filter.isSource() && checkSource) {
                    if (!filter.isIncludeSubresources()) {
                        conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_TARGET_ID));
                        params.add(resource.getStructureId().toString());
                    } else {
                        conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_TARGET_PATH));
                        params.add(resource.getRootPath() + '%');
                    }
                } else if (filter.isTarget() && !checkSource) {
                    if (!filter.isIncludeSubresources()) {
                        conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_SOURCE_ID));
                        params.add(resource.getStructureId().toString());
                    } else {
                        conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_SOURCE_PATH));
                        params.add(resource.getRootPath() + '%');
                    }
                }
                conditions.append(END_CONDITION);
            }

            // target or source id filter from filter parameter
            if (filter.getStructureId() != null) {
                if (conditions.length() == 0) {
                    conditions.append(BEGIN_CONDITION);
                } else {
                    conditions.append(BEGIN_INCLUDE_CONDITION);
                }

                if (filter.isSource() && checkSource) {
                    conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_SOURCE_ID));
                    params.add(filter.getStructureId().toString());
                } else if (filter.isTarget() && !checkSource) {
                    conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_TARGET_ID));
                    params.add(filter.getStructureId().toString());
                }
                conditions.append(END_CONDITION);
            }

            // target or source path filter from filter parameter
            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(filter.getPath())) {
                if (conditions.length() == 0) {
                    conditions.append(BEGIN_CONDITION);
                } else {
                    conditions.append(BEGIN_INCLUDE_CONDITION);
                }

                String queryPath = filter.getPath();
                if (filter.isIncludeSubresources()) {
                    queryPath += '%';
                }
                if (filter.isSource() && checkSource) {
                    conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_SOURCE_PATH));
                    params.add(queryPath);
                } else if (filter.isTarget() && !checkSource) {
                    conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_TARGET_PATH));
                    params.add(queryPath);
                }
                conditions.append(END_CONDITION);
            }
        }

        // relation type filter
        Set types = filter.getTypes();
        if (!types.isEmpty()) {
            if (conditions.length() == 0) {
                conditions.append(BEGIN_CONDITION);
            } else {
                conditions.append(BEGIN_INCLUDE_CONDITION);
            }
            conditions.append(m_sqlManager.readQuery(projectId, C_RELATION_FILTER_TYPE));
            conditions.append(BEGIN_CONDITION);
            Iterator it = types.iterator();
            while (it.hasNext()) {
                CmsRelationType type = (CmsRelationType) it.next();
                conditions.append("?");
                params.add(Integer.valueOf(type.getId()));
                if (it.hasNext()) {
                    conditions.append(", ");
                }
            }
            conditions.append(END_CONDITION);
            conditions.append(END_CONDITION);
        }
        return conditions.toString();
    }

    /**
     * Appends the appropriate selection criteria related with the released date.<p>
     * 
     * @param projectId the id of the project
     * @param startTime the start time
     * @param endTime the stop time
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareReleasedTimeRangeCondition(CmsUUID projectId, long startTime, long endTime,
            StringBuffer conditions, List params) {

        if (startTime > 0L) {
            // READ_IGNORE_TIME: if NOT set, add condition to match released date against startTime
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_STRUCTURE_SELECT_BY_DATE_RELEASED_AFTER));
            conditions.append(END_CONDITION);
            params.add(Long.valueOf(startTime));
        }

        if (endTime > 0L) {
            // READ_IGNORE_TIME: if NOT set, add condition to match released date against endTime
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_STRUCTURE_SELECT_BY_DATE_RELEASED_BEFORE));
            conditions.append(END_CONDITION);
            params.add(Long.valueOf(endTime));
        }
    }

    /**
     * Appends the appropriate selection criteria related with the read mode.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param mode the selection mode
     * @param conditions buffer to append the selection criteria
     */
    protected void prepareResourceCondition(CmsUUID projectId, int mode, StringBuffer conditions) {

        if ((mode & CmsDriverManager.READMODE_ONLY_FOLDERS) > 0) {
            // C_READMODE_ONLY_FOLDERS: add condition to match only folders
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_ONLY_FOLDERS));
            conditions.append(END_CONDITION);
        } else if ((mode & CmsDriverManager.READMODE_ONLY_FILES) > 0) {
            // C_READMODE_ONLY_FILES: add condition to match only files
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_ONLY_FILES));
            conditions.append(END_CONDITION);
        }
    }

    /**
     * Appends the appropriate selection criteria related with the resource state.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param state the resource state
     * @param mode the selection mode
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareStateCondition(CmsUUID projectId, CmsResourceState state, int mode,
            StringBuffer conditions, List params) {

        if (state != null) {
            if ((mode & CmsDriverManager.READMODE_EXCLUDE_STATE) > 0) {
                // C_READ_MODIFIED_STATES: add condition to match against any state but not given state
                conditions.append(BEGIN_EXCLUDE_CONDITION);
            } else {
                // otherwise add condition to match against given state if necessary
                conditions.append(BEGIN_INCLUDE_CONDITION);
            }
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_RESOURCE_STATE));
            conditions.append(END_CONDITION);
            params.add(Integer.valueOf(state.getState()));
            params.add(Integer.valueOf(state.getState()));
        }
    }

    /**
     * Appends the appropriate selection criteria related with the date of the last modification.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param startTime start of the time range
     * @param endTime end of the time range
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareTimeRangeCondition(CmsUUID projectId, long startTime, long endTime,
            StringBuffer conditions, List params) {

        if (startTime > 0L) {
            // READ_IGNORE_TIME: if NOT set, add condition to match last modified date against startTime
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_DATE_LASTMODIFIED_AFTER));
            conditions.append(END_CONDITION);
            params.add(Long.valueOf(startTime));
        }

        if (endTime > 0L) {
            // READ_IGNORE_TIME: if NOT set, add condition to match last modified date against endTime
            conditions.append(BEGIN_INCLUDE_CONDITION);
            conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_DATE_LASTMODIFIED_BEFORE));
            conditions.append(END_CONDITION);
            params.add(Long.valueOf(endTime));
        }
    }

    /**
     * Appends the appropriate selection criteria related with the resource type.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param type the resource type
     * @param mode the selection mode
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareTypeCondition(CmsUUID projectId, int type, int mode, StringBuffer conditions,
            List params) {

        if (type != CmsDriverManager.READ_IGNORE_TYPE) {
            if ((mode & CmsDriverManager.READMODE_EXCLUDE_TYPE) > 0) {
                // C_READ_FILE_TYPES: add condition to match against any type, but not given type
                conditions.append(BEGIN_EXCLUDE_CONDITION);
                conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_RESOURCE_TYPE));
                conditions.append(END_CONDITION);
                params.add(Integer.valueOf(type));
            } else {
                //otherwise add condition to match against given type if necessary
                conditions.append(BEGIN_INCLUDE_CONDITION);
                conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_RESOURCE_TYPE));
                conditions.append(END_CONDITION);
                params.add(Integer.valueOf(type));
            }
        }
    }

    /**
     * Appends the appropriate selection criteria related with the resource type.<p>
     * 
     * @param projectId the id of the project of the resources
     * @param types the resource type id's
     * @param mode the selection mode
     * @param conditions buffer to append the selection criteria
     * @param params list to append the selection parameters
     */
    protected void prepareTypesCondition(CmsUUID projectId, List<Integer> types, int mode, StringBuffer conditions,
            List params) {

        if ((types == null) || types.isEmpty()) {
            if ((mode & CmsDriverManager.READMODE_EXCLUDE_TYPE) > 0) {
                // C_READ_FILE_TYPES: add condition to match against any type, but not given type
                conditions.append(BEGIN_EXCLUDE_CONDITION);
                conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_RESOURCE_TYPE));
                conditions.append(END_CONDITION);
                params.add(Integer.valueOf(CmsDriverManager.READ_IGNORE_TYPE));
            } else {
                //otherwise add condition to match against given type if necessary
                conditions.append(BEGIN_INCLUDE_CONDITION);
                Iterator<Integer> typeIt = types.iterator();
                while (typeIt.hasNext()) {
                    conditions.append(m_sqlManager.readQuery(projectId, C_RESOURCES_SELECT_BY_RESOURCE_TYPE));
                    params.add(typeIt.next());
                    if (typeIt.hasNext()) {
                        conditions.append(OR_CONDITION);
                    }
                }
                conditions.append(END_CONDITION);
            }
        }
    }

    /**
     * Reads all resources inside a given project matching the criteria specified by parameter values.<p>
     * 
     * Important: If {@link CmsDriverManager#READMODE_EXCLUDE_TREE} is true (or {@link CmsDriverManager#READMODE_INCLUDE_TREE} is false), 
     * the provided parent String must be the UUID of the parent folder, NOT the parent folder path.<p>
     * 
     * @param dbc the current database context
     * @param projectId the project id for matching resources
     * @param parentPath the path to the resource used as root of the searched subtree or {@link CmsDriverManager#READ_IGNORE_PARENT}, 
     *               {@link CmsDriverManager#READMODE_EXCLUDE_TREE} means to read immediate children only 
     * @param types the resource types of matching resources or <code>null</code> (meaning inverted by {@link CmsDriverManager#READMODE_EXCLUDE_TYPE}
     * @param state the state of matching resources (meaning inverted by {@link CmsDriverManager#READMODE_EXCLUDE_STATE} or <code>null</code> to ignore
     * @param lastModifiedAfter the start of the time range for the last modification date of matching resources or READ_IGNORE_TIME 
     * @param lastModifiedBefore the end of the time range for the last modification date of matching resources or READ_IGNORE_TIME
     * @param releasedAfter the start of the time range for the release date of matching resources
     * @param releasedBefore the end of the time range for the release date of matching resources
     * @param expiredAfter the start of the time range for the expire date of matching resources
     * @param expiredBefore the end of the time range for the expire date of matching resources
     * @param mode additional mode flags:
     * <ul>
     *  <li>{@link CmsDriverManager#READMODE_INCLUDE_TREE}
     *  <li>{@link CmsDriverManager#READMODE_EXCLUDE_TREE}
     *  <li>{@link CmsDriverManager#READMODE_INCLUDE_PROJECT}
     *  <li>{@link CmsDriverManager#READMODE_EXCLUDE_TYPE}
     *  <li>{@link CmsDriverManager#READMODE_EXCLUDE_STATE}
     * </ul>
     * 
     * @return a list of CmsResource objects matching the given criteria
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected List<CmsResource> readTypesInResourceTree(CmsDbContext dbc, CmsUUID projectId, String parentPath,
            List<Integer> types, CmsResourceState state, long lastModifiedAfter, long lastModifiedBefore,
            long releasedAfter, long releasedBefore, long expiredAfter, long expiredBefore, int mode)
            throws CmsDataAccessException {

        List<CmsResource> result = new ArrayList<CmsResource>();

        StringBuffer conditions = new StringBuffer();
        List params = new ArrayList(5);

        // prepare the selection criteria
        prepareProjectCondition(projectId, mode, conditions, params);
        prepareResourceCondition(projectId, mode, conditions);
        prepareTypesCondition(projectId, types, mode, conditions, params);
        prepareTimeRangeCondition(projectId, lastModifiedAfter, lastModifiedBefore, conditions, params);
        prepareReleasedTimeRangeCondition(projectId, releasedAfter, releasedBefore, conditions, params);
        prepareExpiredTimeRangeCondition(projectId, expiredAfter, expiredBefore, conditions, params);
        preparePathCondition(projectId, parentPath, mode, conditions, params);
        prepareStateCondition(projectId, state, mode, conditions, params);

        // now read matching resources within the subtree 
        List<Object[]> res = null;

        try {
            StringBuffer queryBuf = new StringBuffer(256);
            queryBuf.append(m_sqlManager.readQuery(projectId, C_RESOURCES_READ_TREE));
            queryBuf.append(conditions);
            queryBuf.append(" ");
            queryBuf.append(m_sqlManager.readQuery(projectId, C_RESOURCES_ORDER_BY_PATH));
            Query q = m_sqlManager.createQueryFromJPQL(dbc, queryBuf.toString());

            for (int i = 0; i < params.size(); i++) {
                if (params.get(i) instanceof Integer) {
                    q.setParameter(i + 1, ((Integer) params.get(i)).intValue());
                } else if (params.get(i) instanceof Long) {
                    q.setParameter(i + 1, ((Long) params.get(i)).longValue());
                } else {
                    q.setParameter(i + 1, params.get(i));
                }
            }

            res = q.getResultList();
            for (Object[] obj : res) {
                CmsResource resource = createResource(obj, projectId);
                result.add(resource);
            }

        } catch (PersistenceException e) {
            throw new CmsDbSqlException(Messages.get().container(Messages.ERR_GENERIC_SQL_1, C_RESOURCES_READ_TREE),
                    e);
        }

        return result;
    }

    /**
     * Repairs broken links.<p>
     * 
     * When a resource is created any relation pointing to it is updated to use the right id.<p>
     * 
     * @param dbc the current database context
     * @param projectId the project id
     * @param structureId the structure id of the resource that may help to repair broken links
     * @param rootPath the path of the resource that may help to repair broken links
     * 
     * @throws CmsDataAccessException if something goes wrong
     */
    protected void repairBrokenRelations(CmsDbContext dbc, CmsUUID projectId, CmsUUID structureId, String rootPath)
            throws CmsDataAccessException {

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RELATIONS_REPAIR_BROKEN);
            q.setParameter(1, rootPath);
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResourceRelations> res = q.getResultList();
            I_CmsDAOResourceRelations newR;
            for (I_CmsDAOResourceRelations rr : res) {
                newR = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlineResourceRelations()
                        : new CmsDAOOfflineResourceRelations();

                newR.setRelationSourceId(rr.getRelationSourceId());
                newR.setRelationSourcePath(rr.getRelationSourcePath());
                newR.setRelationTargetId(structureId.toString());
                newR.setRelationTargetPath(rr.getRelationTargetPath());
                newR.setRelationType(rr.getRelationType());

                m_sqlManager.remove(dbc, rr);
                m_sqlManager.persist(dbc, newR);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * Updates broken links.<p>
     * 
     * When a resource is deleted, then the relations pointing to 
     * the deleted resource are set to the null uuid.<p>
     * 
     * @param dbc the current database context
     * @param projectId the project id
     * @param rootPath the root path of the resource that has been deleted 
     * 
     * @throws CmsDataAccessException if something goes wrong 
     */
    protected void updateBrokenRelations(CmsDbContext dbc, CmsUUID projectId, String rootPath)
            throws CmsDataAccessException {

        try {
            Query q = m_sqlManager.createQuery(dbc, projectId, C_RELATIONS_UPDATE_BROKEN);
            q.setParameter(1, rootPath);
            @SuppressWarnings("unchecked")
            List<I_CmsDAOResourceRelations> res = q.getResultList();
            I_CmsDAOResourceRelations newR;
            for (I_CmsDAOResourceRelations rr : res) {
                newR = CmsProject.isOnlineProject(projectId) ? new CmsDAOOnlineResourceRelations()
                        : new CmsDAOOfflineResourceRelations();

                newR.setRelationSourceId(rr.getRelationSourceId());
                newR.setRelationSourcePath(rr.getRelationSourcePath());
                newR.setRelationTargetId(CmsUUID.getNullUUID().toString());
                newR.setRelationTargetPath(rr.getRelationTargetPath());
                newR.setRelationType(rr.getRelationType());

                m_sqlManager.remove(dbc, rr);
                m_sqlManager.persist(dbc, newR);
            }
        } catch (PersistenceException e) {
            throw new CmsDataAccessException(Messages.get().container(Messages.ERR_JPA_PERSITENCE, e), e);
        }
    }

    /**
     * Creates a query by combining a base query with the generated JPQL conditions for a given
     * URL name mapping filter.<p>
     *  
     * @param dbc the db context 
     * @param baseQuery the base query to which the conditions should be appended 
     * @param filter the filter from which to generate the conditions 
     * @param online what project to use - ONLINE or OFFLINE project
     * 
     * @return the created prepared statement 
     * 
     * @throws PersistenceException if something goes wrong
     */
    private Query getQueryForFilter(CmsDbContext dbc, String baseQuery, CmsUrlNameMappingFilter filter,
            boolean online) throws PersistenceException {

        CmsPair<String, List<I_CmsQueryParameter>> conditionData = prepareUrlNameMappingConditions(filter);
        String whereClause = "";
        if (!conditionData.getFirst().equals("")) {
            whereClause = " WHERE " + conditionData.getFirst();
        }
        String query = baseQuery + whereClause;
        query = replaceProject(query, online);
        Query q = m_sqlManager.createQueryFromJPQL(dbc, query);
        int counter = 1;
        for (I_CmsQueryParameter param : conditionData.getSecond()) {
            param.insertIntoQuery(q, counter);
            counter += 1;
        }
        return q;
    }

    /**
     * Replaces the %(PROJECT) macro inside a query with either Online or Offline, depending on the value 
     * of a flag.<p>
     * 
     * We use this instead of the ${PROJECT} replacement mechanism when we need explicit control over the 
     * project, and don't want to implicitly use the project of the DB context.<p>
     * 
     * @param query the query in which the macro should be replaced 
     * @param online if true, the macro will be replaced with "ONLINE", else "OFFLINE"
     * 
     * @return the query with the replaced macro 
     */
    private String replaceProject(String query, boolean online) {

        return query.replace("%(PROJECT)", online ? CmsSqlManager.ONLINE_PROJECT : CmsSqlManager.OFFLINE_PROJECT);
    }
}